From f7b6a2d2184f75f5c9c0187918c1c4156ee3789d Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 30 Sep 2023 13:03:50 -0400 Subject: [PATCH 01/16] Automatically pass through all on* event attributes https://github.com/jakartaee/faces/issues/1507 --- .../facelets/tag/faces/core/AjaxHandler.java | 12 ++- .../sun/faces/renderkit/RenderKitUtils.java | 96 ++++++++++++++----- .../faces/component/UIComponentBase.java | 65 +++++-------- 3 files changed, 107 insertions(+), 66 deletions(-) diff --git a/impl/src/main/java/com/sun/faces/facelets/tag/faces/core/AjaxHandler.java b/impl/src/main/java/com/sun/faces/facelets/tag/faces/core/AjaxHandler.java index dda42ad98d..2fb60cd411 100644 --- a/impl/src/main/java/com/sun/faces/facelets/tag/faces/core/AjaxHandler.java +++ b/impl/src/main/java/com/sun/faces/facelets/tag/faces/core/AjaxHandler.java @@ -16,6 +16,8 @@ package com.sun.faces.facelets.tag.faces.core; +import static com.sun.faces.facelets.util.DevTools.isDevelopment; +import static jakarta.faces.application.ProjectStage.Development; import static jakarta.faces.component.UINamingContainer.getSeparatorChar; import static java.util.Arrays.stream; @@ -28,19 +30,23 @@ import java.util.Iterator; import java.util.List; import java.util.TreeSet; +import java.util.logging.Logger; import com.sun.faces.component.behavior.AjaxBehaviors; import com.sun.faces.facelets.tag.TagHandlerImpl; import com.sun.faces.facelets.tag.composite.BehaviorHolderWrapper; import com.sun.faces.facelets.tag.composite.RetargetedAjaxBehavior; import com.sun.faces.facelets.tag.faces.CompositeComponentTagHandler; +import com.sun.faces.facelets.util.DevTools; import com.sun.faces.renderkit.RenderKitUtils; +import com.sun.faces.util.FacesLogger; import jakarta.el.ELContext; import jakarta.el.MethodExpression; import jakarta.el.MethodNotFoundException; import jakarta.el.ValueExpression; import jakarta.faces.application.Application; +import jakarta.faces.application.ProjectStage; import jakarta.faces.application.ResourceHandler; import jakarta.faces.component.UIComponent; import jakarta.faces.component.behavior.AjaxBehavior; @@ -95,6 +101,8 @@ */ public final class AjaxHandler extends TagHandlerImpl implements BehaviorHolderAttachedObjectHandler { + private static final Logger LOGGER = FacesLogger.FACELETS_COMPILER.getLogger(); + private final TagAttribute event; private final TagAttribute execute; private final TagAttribute render; @@ -274,10 +282,10 @@ private void applyAttachedObject(FaceletContext ctx, UIComponent parent, String if (null == eventName) { throw new TagException(tag, "Event attribute could not be determined: " + eventName); } - } else { + } else if (ctx.getFacesContext().isProjectStage(Development)) { Collection eventNames = bHolder.getEventNames(); if (!eventNames.contains(eventName)) { - throw new TagException(tag, getUnsupportedEventMessage(eventName, eventNames, parent)); + LOGGER.warning(getUnsupportedEventMessage(eventName, eventNames, parent)); // TODO: improve message for faces#1507 } } diff --git a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java index 36b57a3b43..b69692e4f9 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java +++ b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java @@ -21,6 +21,8 @@ import static com.sun.faces.renderkit.RenderKitUtils.PredefinedPostbackParameter.PARTIAL_EVENT_PARAM; import static jakarta.faces.application.ResourceHandler.FACES_SCRIPT_LIBRARY_NAME; import static jakarta.faces.application.ResourceHandler.FACES_SCRIPT_RESOURCE_NAME; +import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.toList; import java.io.IOException; import java.io.Writer; @@ -35,6 +37,7 @@ import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; import com.sun.faces.RIConstants; import com.sun.faces.config.WebConfiguration; @@ -331,18 +334,17 @@ public static void renderPassThruAttributes(FacesContext context, ResponseWriter behaviors = Collections.emptyMap(); } - if (canBeOptimized(component, behaviors)) { - List setAttributes = (List) component.getAttributes().get(ATTRIBUTES_THAT_ARE_SET_KEY); - if (setAttributes != null) { - renderPassThruAttributesOptimized(context, writer, component, attributes, setAttributes, behaviors); - } + List setAttributes = (List) component.getAttributes().get(ATTRIBUTES_THAT_ARE_SET_KEY); + + if (setAttributes != null && canBeOptimized(component, behaviors)) { + renderPassThruAttributesOptimized(context, writer, component, attributes, setAttributes, behaviors); } else { // this block should only be hit by custom components leveraging // the RI's rendering code, or in cases where we have behaviors // attached to multiple events. We make no assumptions and loop // through - renderPassThruAttributesUnoptimized(context, writer, component, attributes, behaviors); + renderPassThruAttributesUnoptimized(context, writer, component, attributes, setAttributes, behaviors); } } @@ -607,7 +609,8 @@ private static void renderPassThruAttributesOptimized(FacesContext context, Resp boolean renderedBehavior = false; Collections.sort(setAttributes); - boolean isXhtml = RIConstants.XHTML_CONTENT_TYPE.equals(writer.getContentType()); + boolean isHtml5 = isOutputHtml5Doctype(context); + boolean isXhtml = !isHtml5 && RIConstants.XHTML_CONTENT_TYPE.equals(writer.getContentType()); Map attrMap = component.getAttributes(); for (String name : setAttributes) { @@ -624,6 +627,18 @@ private static void renderPassThruAttributesOptimized(FacesContext context, Resp if (isBehaviorEventAttribute(attr, behaviorEventName)) { renderHandler(context, component, null, name, value, behaviorEventName, null, false, false); + renderedBehavior = true; + } else { + writer.writeAttribute(prefixAttribute(name, isXhtml), value, name); + } + } + } + else if (isHtml5 && isBehaviorAttribute(name)) { + Object value = attrMap.get(name); + if (value != null && shouldRenderAttribute(value)) { + if (name.substring(2).equals(behaviorEventName)) { + renderHandler(context, component, null, name, value, behaviorEventName, null, false, false); + renderedBehavior = true; } else { writer.writeAttribute(prefixAttribute(name, isXhtml), value, name); @@ -636,18 +651,29 @@ private static void renderPassThruAttributesOptimized(FacesContext context, Resp // attribute rendering. Need to manually render it out now. if (behaviorEventName != null && !renderedBehavior) { + if (isHtml5) { + List behaviorAttributes = setAttributes.stream().filter(RenderKitUtils::isBehaviorAttribute).collect(toList()); + + for (String attrName : behaviorAttributes) { + String eventName = attrName.substring(2); + if (behaviorEventName.equals(eventName)) { + renderPassthruAttribute(context, writer, component, behaviors, isXhtml, attrMap, attrName, behaviorEventName); + return; + } + } + } + // Note that we can optimize this search by providing // an event name -> Attribute inverse look up map. // This would change the search time from O(n) to O(1). - for (int i = 0; i < knownAttributes.length; i++) { - Attribute attr = knownAttributes[i]; - String[] events = attr.getEvents(); - if (events != null && events.length > 0 && behaviorEventName.equals(events[0])) { - renderHandler(context, component, null, attr.getName(), null, behaviorEventName, null, false, false); + for (Attribute attribute : knownAttributes) { + String attrName = attribute.getName(); + String[] events = attribute.getEvents(); + if (events != null && events.length > 0 && behaviorEventName.equals(events[0])) { + renderHandler(context, component, null, attrName, null, behaviorEventName, null, false, false); } } - } } @@ -659,34 +685,54 @@ private static void renderPassThruAttributesOptimized(FacesContext context, Resp * @param writer the current writer * @param component the component whose attributes we're rendering * @param knownAttributes an array of pass-through attributes supported by this component + * @param setAttributes a List of attributes that have been set on the provided component * @param behaviors the non-null behaviors map for this request. * @throws IOException if an error occurs during the write */ private static void renderPassThruAttributesUnoptimized(FacesContext context, ResponseWriter writer, UIComponent component, Attribute[] knownAttributes, - Map> behaviors) throws IOException { + List setAttributes, Map> behaviors) throws IOException { - boolean isXhtml = RIConstants.XHTML_CONTENT_TYPE.equals(writer.getContentType()); + boolean isHtml5 = isOutputHtml5Doctype(context); + boolean isXhtml = !isHtml5 && RIConstants.XHTML_CONTENT_TYPE.equals(writer.getContentType()); Map attrMap = component.getAttributes(); + List behaviorAttributes = isHtml5 ? setAttributes.stream().filter(RenderKitUtils::isBehaviorAttribute).collect(toList()) : emptyList(); for (Attribute attribute : knownAttributes) { String attrName = attribute.getName(); String[] events = attribute.getEvents(); - boolean hasBehavior = events != null && events.length > 0 && behaviors.containsKey(events[0]); + String eventName = events != null && events.length > 0 ? events[0] : null; + renderPassthruAttribute(context, writer, component, behaviors, isXhtml, attrMap, attrName, eventName); + behaviorAttributes.remove(attrName); + } + + for (String attrName : behaviorAttributes) { + String eventName = attrName.substring(2); + renderPassthruAttribute(context, writer, component, behaviors, isXhtml, attrMap, attrName, eventName); + } + } - Object value = attrMap.get(attrName); + private static void renderPassthruAttribute(FacesContext context, ResponseWriter writer, UIComponent component, + Map> behaviors, boolean isXhtml, Map attrMap, String attrName, + String eventName) throws IOException { + boolean hasBehavior = eventName != null && behaviors.containsKey(eventName); - if (value != null && shouldRenderAttribute(value) && !hasBehavior) { - writer.writeAttribute(prefixAttribute(attrName, isXhtml), value, attrName); - } else if (hasBehavior) { + Object value = attrMap.get(attrName); - // If we've got a behavior for this attribute, - // we may need to chain scripts together, so use - // renderHandler(). - renderHandler(context, component, null, attrName, value, events[0], null, false, false); - } + if (value != null && shouldRenderAttribute(value) && !hasBehavior) { + writer.writeAttribute(prefixAttribute(attrName, isXhtml), value, attrName); + } else if (hasBehavior) { + + // If we've got a behavior for this attribute, + // we may need to chain scripts together, so use + // renderHandler(). + renderHandler(context, component, null, attrName, value, eventName, null, false, false); } } + + private static boolean isBehaviorAttribute(String name) { + return name.startsWith("on") && name.length() > 2; + } /** *

diff --git a/impl/src/main/java/jakarta/faces/component/UIComponentBase.java b/impl/src/main/java/jakarta/faces/component/UIComponentBase.java index a465224f4a..97771ef657 100644 --- a/impl/src/main/java/jakarta/faces/component/UIComponentBase.java +++ b/impl/src/main/java/jakarta/faces/component/UIComponentBase.java @@ -1526,53 +1526,40 @@ public void addClientBehavior(String eventName, ClientBehavior behavior) { // First, make sure that the event is supported. We don't want // to bother attaching behaviors for unsupported events. - Collection eventNames = getEventNames(); - - // getClientEventNames() is spec'ed to require a non-null Set. - // If getClientEventNames() returns null, throw an exception - // to indicate that the API in not being used properly. - if (eventNames == null) { - throw new IllegalStateException( - "Attempting to add a Behavior to a component " + "that does not support any event types. " + "getEventTypes() must return a non-null Set."); - } - - if (eventNames.contains(eventName)) { - - if (initialStateMarked()) { - // a Behavior has been added dynamically. Update existing - // Behaviors, if any, to save their full state. - if (behaviors != null) { - for (Entry> entry : behaviors.entrySet()) { - for (ClientBehavior b : entry.getValue()) { - if (b instanceof PartialStateHolder) { - ((PartialStateHolder) behavior).clearInitialState(); - } + if (initialStateMarked()) { + // a Behavior has been added dynamically. Update existing + // Behaviors, if any, to save their full state. + if (behaviors != null) { + for (Entry> entry : behaviors.entrySet()) { + for (ClientBehavior b : entry.getValue()) { + if (b instanceof PartialStateHolder) { + ((PartialStateHolder) behavior).clearInitialState(); } } } } - // We've got an event that we support, create our Map - // if necessary - - if (null == behaviors) { - // Typically we only have a small number of behaviors for - // any component - in most cases only 1. Using a very small - // initial capacity so that we keep the footprint to a minimum. - Map> modifiableMap = new HashMap<>(5, 1.0f); - behaviors = new BehaviorsMap(modifiableMap); - } + } + // We've got an event that we support, create our Map + // if necessary - List eventBehaviours = behaviors.get(eventName); + if (null == behaviors) { + // Typically we only have a small number of behaviors for + // any component - in most cases only 1. Using a very small + // initial capacity so that we keep the footprint to a minimum. + Map> modifiableMap = new HashMap<>(5, 1.0f); + behaviors = new BehaviorsMap(modifiableMap); + } - if (null == eventBehaviours) { - // Again using small initial capacity - we typically - // only have 1 Behavior per event type. - eventBehaviours = new ArrayList<>(3); - behaviors.getModifiableMap().put(eventName, eventBehaviours); - } + List eventBehaviours = behaviors.get(eventName); - eventBehaviours.add(behavior); + if (null == eventBehaviours) { + // Again using small initial capacity - we typically + // only have 1 Behavior per event type. + eventBehaviours = new ArrayList<>(3); + behaviors.getModifiableMap().put(eventName, eventBehaviours); } + + eventBehaviours.add(behavior); } /** From 6286b9cf23425813848377a60eeb97dd12ab8c5d Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 30 Sep 2023 13:36:25 -0400 Subject: [PATCH 02/16] Fix compilation error caused by locally reverted refactoring --- .../java/com/sun/faces/facelets/tag/faces/core/AjaxHandler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/impl/src/main/java/com/sun/faces/facelets/tag/faces/core/AjaxHandler.java b/impl/src/main/java/com/sun/faces/facelets/tag/faces/core/AjaxHandler.java index 2fb60cd411..1f81eb6ef2 100644 --- a/impl/src/main/java/com/sun/faces/facelets/tag/faces/core/AjaxHandler.java +++ b/impl/src/main/java/com/sun/faces/facelets/tag/faces/core/AjaxHandler.java @@ -16,7 +16,6 @@ package com.sun.faces.facelets.tag.faces.core; -import static com.sun.faces.facelets.util.DevTools.isDevelopment; import static jakarta.faces.application.ProjectStage.Development; import static jakarta.faces.component.UINamingContainer.getSeparatorChar; import static java.util.Arrays.stream; From 3bf2287dfcc1fa45ae54e967d68d92380b5391e9 Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 30 Sep 2023 13:49:30 -0400 Subject: [PATCH 03/16] Catch up Body/HeadRendererTest with adjusted RenderKitUtils behavior and fixed NPE which surfaced during HeadRendererTest https://github.com/jakartaee/faces/issues/1507 --- .../src/main/java/com/sun/faces/renderkit/RenderKitUtils.java | 2 +- .../com/sun/faces/renderkit/html_basic/BodyRendererTest.java | 4 ++-- .../com/sun/faces/renderkit/html_basic/HeadRendererTest.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java index b69692e4f9..ad9b347831 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java +++ b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java @@ -696,7 +696,7 @@ private static void renderPassThruAttributesUnoptimized(FacesContext context, Re boolean isXhtml = !isHtml5 && RIConstants.XHTML_CONTENT_TYPE.equals(writer.getContentType()); Map attrMap = component.getAttributes(); - List behaviorAttributes = isHtml5 ? setAttributes.stream().filter(RenderKitUtils::isBehaviorAttribute).collect(toList()) : emptyList(); + List behaviorAttributes = isHtml5 && setAttributes != null ? setAttributes.stream().filter(RenderKitUtils::isBehaviorAttribute).collect(toList()) : emptyList(); for (Attribute attribute : knownAttributes) { String attrName = attribute.getName(); diff --git a/impl/src/test/java/com/sun/faces/renderkit/html_basic/BodyRendererTest.java b/impl/src/test/java/com/sun/faces/renderkit/html_basic/BodyRendererTest.java index 170cc90120..5ab5614072 100644 --- a/impl/src/test/java/com/sun/faces/renderkit/html_basic/BodyRendererTest.java +++ b/impl/src/test/java/com/sun/faces/renderkit/html_basic/BodyRendererTest.java @@ -71,9 +71,9 @@ public void testEncodeBegin() throws Exception { expect(doctype.getPublic()).andReturn(null).anyTimes(); expect(doctype.getSystem()).andReturn(null).anyTimes(); - PowerMock.replay(facesContext); + PowerMock.replay(facesContext, viewRoot, doctype); bodyRenderer.encodeBegin(facesContext, htmlBody); - PowerMock.verify(facesContext); + PowerMock.verify(facesContext, viewRoot, doctype); String html = writer.toString(); assertTrue(html.contains(" Date: Sat, 30 Sep 2023 14:07:14 -0400 Subject: [PATCH 04/16] Also fix AjaxBehaviors (the case when wraps components) https://github.com/jakartaee/faces/issues/1507 --- .../sun/faces/component/behavior/AjaxBehaviors.java | 11 ++++++++--- .../java/com/sun/faces/renderkit/RenderKitUtils.java | 8 ++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/impl/src/main/java/com/sun/faces/component/behavior/AjaxBehaviors.java b/impl/src/main/java/com/sun/faces/component/behavior/AjaxBehaviors.java index 3002aebec7..1feb6c83d0 100644 --- a/impl/src/main/java/com/sun/faces/component/behavior/AjaxBehaviors.java +++ b/impl/src/main/java/com/sun/faces/component/behavior/AjaxBehaviors.java @@ -16,6 +16,9 @@ package com.sun.faces.component.behavior; +import static com.sun.faces.renderkit.RenderKitUtils.isHtml5BehaviorAttribute; +import static com.sun.faces.renderkit.RenderKitUtils.isOutputHtml5Doctype; + import java.io.Serializable; import java.util.ArrayDeque; import java.util.Iterator; @@ -23,6 +26,8 @@ import java.util.Map; import java.util.Set; +import com.sun.faces.renderkit.RenderKitUtils; + import jakarta.faces.application.Application; import jakarta.faces.component.behavior.AjaxBehavior; import jakarta.faces.component.behavior.ClientBehavior; @@ -136,7 +141,7 @@ public void addBehavior(FacesContext context, ClientBehaviorHolder behaviorHolde } // We only add the - if (shouldAddBehavior(behaviorHolder, myEventName)) { + if (shouldAddBehavior(context, behaviorHolder, myEventName)) { ClientBehavior behavior = createBehavior(context); behaviorHolder.addClientBehavior(myEventName, behavior); } @@ -145,11 +150,11 @@ public void addBehavior(FacesContext context, ClientBehaviorHolder behaviorHolde // Tests whether we should add an AjaxBehavior to the specified // ClientBehaviorHolder/event name. - private boolean shouldAddBehavior(ClientBehaviorHolder behaviorHolder, String eventName) { + private boolean shouldAddBehavior(FacesContext context, ClientBehaviorHolder behaviorHolder, String eventName) { // First need to make sure that this ClientBehaviorHolder // supports the specified event type. - if (!behaviorHolder.getEventNames().contains(eventName)) { + if (!behaviorHolder.getEventNames().contains(eventName) || !(isOutputHtml5Doctype(context) && isHtml5BehaviorAttribute(eventName))) { return false; } diff --git a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java index ad9b347831..1528b37b02 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java +++ b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java @@ -633,7 +633,7 @@ private static void renderPassThruAttributesOptimized(FacesContext context, Resp } } } - else if (isHtml5 && isBehaviorAttribute(name)) { + else if (isHtml5 && isHtml5BehaviorAttribute(name)) { Object value = attrMap.get(name); if (value != null && shouldRenderAttribute(value)) { if (name.substring(2).equals(behaviorEventName)) { @@ -652,7 +652,7 @@ else if (isHtml5 && isBehaviorAttribute(name)) { if (behaviorEventName != null && !renderedBehavior) { if (isHtml5) { - List behaviorAttributes = setAttributes.stream().filter(RenderKitUtils::isBehaviorAttribute).collect(toList()); + List behaviorAttributes = setAttributes.stream().filter(RenderKitUtils::isHtml5BehaviorAttribute).collect(toList()); for (String attrName : behaviorAttributes) { String eventName = attrName.substring(2); @@ -696,7 +696,7 @@ private static void renderPassThruAttributesUnoptimized(FacesContext context, Re boolean isXhtml = !isHtml5 && RIConstants.XHTML_CONTENT_TYPE.equals(writer.getContentType()); Map attrMap = component.getAttributes(); - List behaviorAttributes = isHtml5 && setAttributes != null ? setAttributes.stream().filter(RenderKitUtils::isBehaviorAttribute).collect(toList()) : emptyList(); + List behaviorAttributes = isHtml5 && setAttributes != null ? setAttributes.stream().filter(RenderKitUtils::isHtml5BehaviorAttribute).collect(toList()) : emptyList(); for (Attribute attribute : knownAttributes) { String attrName = attribute.getName(); @@ -730,7 +730,7 @@ private static void renderPassthruAttribute(FacesContext context, ResponseWriter } } - private static boolean isBehaviorAttribute(String name) { + public static boolean isHtml5BehaviorAttribute(String name) { return name.startsWith("on") && name.length() > 2; } From 959722b3e08c9690a96636349d9393dd594239d6 Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 30 Sep 2023 15:59:32 -0400 Subject: [PATCH 05/16] Further improved to let "unoptimized" path to also support f:ajax event which are not known as hardcoded component attributes https://github.com/jakartaee/faces/issues/1507 --- .../sun/faces/renderkit/RenderKitUtils.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java index 1528b37b02..4ee728b431 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java +++ b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java @@ -21,7 +21,6 @@ import static com.sun.faces.renderkit.RenderKitUtils.PredefinedPostbackParameter.PARTIAL_EVENT_PARAM; import static jakarta.faces.application.ResourceHandler.FACES_SCRIPT_LIBRARY_NAME; import static jakarta.faces.application.ResourceHandler.FACES_SCRIPT_RESOURCE_NAME; -import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; import java.io.IOException; @@ -32,12 +31,13 @@ import java.util.Collection; import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.stream.Collectors; import com.sun.faces.RIConstants; import com.sun.faces.config.WebConfiguration; @@ -696,19 +696,26 @@ private static void renderPassThruAttributesUnoptimized(FacesContext context, Re boolean isXhtml = !isHtml5 && RIConstants.XHTML_CONTENT_TYPE.equals(writer.getContentType()); Map attrMap = component.getAttributes(); - List behaviorAttributes = isHtml5 && setAttributes != null ? setAttributes.stream().filter(RenderKitUtils::isHtml5BehaviorAttribute).collect(toList()) : emptyList(); + Set behaviorEventNames = new LinkedHashSet<>(behaviors.size() + 2); + + if (isHtml5) { + behaviorEventNames.addAll(behaviors.keySet()); + + if (setAttributes != null) { + setAttributes.stream().filter(RenderKitUtils::isHtml5BehaviorAttribute).map(a -> a.substring(2)).forEach(behaviorEventNames::add); + } + } for (Attribute attribute : knownAttributes) { String attrName = attribute.getName(); String[] events = attribute.getEvents(); String eventName = events != null && events.length > 0 ? events[0] : null; renderPassthruAttribute(context, writer, component, behaviors, isXhtml, attrMap, attrName, eventName); - behaviorAttributes.remove(attrName); + behaviorEventNames.remove(eventName); } - - for (String attrName : behaviorAttributes) { - String eventName = attrName.substring(2); - renderPassthruAttribute(context, writer, component, behaviors, isXhtml, attrMap, attrName, eventName); + + for (String eventName : behaviorEventNames) { + renderPassthruAttribute(context, writer, component, behaviors, isXhtml, attrMap, "on" + eventName, eventName); } } From 69b16bb143cc465d81c09c436f034393b3c6cc7c Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 30 Sep 2023 16:00:49 -0400 Subject: [PATCH 06/16] Initial commit of new HtmlEvents class and adapted existing HTML components; reverted temp changes to AjaxHandler/UIComponentBase https://github.com/jakartaee/faces/issues/1507 --- .../faces/component/PassthroughElement.java | 8 +- .../facelets/tag/faces/core/AjaxHandler.java | 16 +- .../faces/component/UIComponentBase.java | 65 ++++---- .../faces/component/html/HtmlBody.java | 8 +- .../component/html/HtmlCommandButton.java | 8 +- .../faces/component/html/HtmlCommandLink.java | 8 +- .../faces/component/html/HtmlDataTable.java | 8 +- .../faces/component/html/HtmlEvents.java | 142 ++++++++++++++++++ .../faces/component/html/HtmlForm.java | 8 +- .../component/html/HtmlGraphicImage.java | 8 +- .../faces/component/html/HtmlInputFile.java | 8 +- .../faces/component/html/HtmlInputSecret.java | 8 +- .../faces/component/html/HtmlInputText.java | 8 +- .../component/html/HtmlInputTextarea.java | 8 +- .../html/HtmlOutcomeTargetButton.java | 8 +- .../component/html/HtmlOutcomeTargetLink.java | 8 +- .../faces/component/html/HtmlOutputLabel.java | 8 +- .../faces/component/html/HtmlOutputLink.java | 8 +- .../faces/component/html/HtmlPanelGrid.java | 8 +- .../faces/component/html/HtmlPanelGroup.java | 8 +- .../html/HtmlSelectBooleanCheckbox.java | 8 +- .../html/HtmlSelectManyCheckbox.java | 8 +- .../component/html/HtmlSelectManyListbox.java | 8 +- .../component/html/HtmlSelectManyMenu.java | 8 +- .../component/html/HtmlSelectOneListbox.java | 8 +- .../component/html/HtmlSelectOneMenu.java | 8 +- .../component/html/HtmlSelectOneRadio.java | 8 +- 27 files changed, 237 insertions(+), 178 deletions(-) create mode 100644 impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java diff --git a/impl/src/main/java/com/sun/faces/component/PassthroughElement.java b/impl/src/main/java/com/sun/faces/component/PassthroughElement.java index 1ea544a811..2a5a7f5d53 100644 --- a/impl/src/main/java/com/sun/faces/component/PassthroughElement.java +++ b/impl/src/main/java/com/sun/faces/component/PassthroughElement.java @@ -16,12 +16,15 @@ package com.sun.faces.component; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; + import java.util.ArrayList; import java.util.Collection; import java.util.List; import jakarta.el.ValueExpression; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.component.html.HtmlEvents; /** *

@@ -355,12 +358,9 @@ public void setStyleClass(java.lang.String styleClass) { getStateHelper().put(PropertyKeys.styleClass, styleClass); } - private static final List EVENT_NAMES = List.of( - "click", "dblclick", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup"); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/com/sun/faces/facelets/tag/faces/core/AjaxHandler.java b/impl/src/main/java/com/sun/faces/facelets/tag/faces/core/AjaxHandler.java index 1f81eb6ef2..c01e4f427d 100644 --- a/impl/src/main/java/com/sun/faces/facelets/tag/faces/core/AjaxHandler.java +++ b/impl/src/main/java/com/sun/faces/facelets/tag/faces/core/AjaxHandler.java @@ -16,7 +16,6 @@ package com.sun.faces.facelets.tag.faces.core; -import static jakarta.faces.application.ProjectStage.Development; import static jakarta.faces.component.UINamingContainer.getSeparatorChar; import static java.util.Arrays.stream; @@ -29,27 +28,24 @@ import java.util.Iterator; import java.util.List; import java.util.TreeSet; -import java.util.logging.Logger; import com.sun.faces.component.behavior.AjaxBehaviors; import com.sun.faces.facelets.tag.TagHandlerImpl; import com.sun.faces.facelets.tag.composite.BehaviorHolderWrapper; import com.sun.faces.facelets.tag.composite.RetargetedAjaxBehavior; import com.sun.faces.facelets.tag.faces.CompositeComponentTagHandler; -import com.sun.faces.facelets.util.DevTools; import com.sun.faces.renderkit.RenderKitUtils; -import com.sun.faces.util.FacesLogger; import jakarta.el.ELContext; import jakarta.el.MethodExpression; import jakarta.el.MethodNotFoundException; import jakarta.el.ValueExpression; import jakarta.faces.application.Application; -import jakarta.faces.application.ProjectStage; import jakarta.faces.application.ResourceHandler; import jakarta.faces.component.UIComponent; import jakarta.faces.component.behavior.AjaxBehavior; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.component.html.HtmlEvents; import jakarta.faces.context.FacesContext; import jakarta.faces.event.AbortProcessingException; import jakarta.faces.event.AjaxBehaviorEvent; @@ -100,8 +96,6 @@ */ public final class AjaxHandler extends TagHandlerImpl implements BehaviorHolderAttachedObjectHandler { - private static final Logger LOGGER = FacesLogger.FACELETS_COMPILER.getLogger(); - private final TagAttribute event; private final TagAttribute execute; private final TagAttribute render; @@ -281,10 +275,10 @@ private void applyAttachedObject(FaceletContext ctx, UIComponent parent, String if (null == eventName) { throw new TagException(tag, "Event attribute could not be determined: " + eventName); } - } else if (ctx.getFacesContext().isProjectStage(Development)) { + } else { Collection eventNames = bHolder.getEventNames(); if (!eventNames.contains(eventName)) { - LOGGER.warning(getUnsupportedEventMessage(eventName, eventNames, parent)); // TODO: improve message for faces#1507 + throw new TagException(tag, getUnsupportedEventMessage(eventName, eventNames, parent)); } } @@ -369,7 +363,9 @@ private String getUnsupportedEventMessage(String eventName, Collection e } } - builder.append("."); + builder.append(". In case you wish to add new ones, then you can specify them" + + " as space-separated value of context-param with name " + + HtmlEvents.ADDITIONAL_HTML_EVENT_NAMES_PARAM_NAME); return builder.toString(); } diff --git a/impl/src/main/java/jakarta/faces/component/UIComponentBase.java b/impl/src/main/java/jakarta/faces/component/UIComponentBase.java index 97771ef657..a465224f4a 100644 --- a/impl/src/main/java/jakarta/faces/component/UIComponentBase.java +++ b/impl/src/main/java/jakarta/faces/component/UIComponentBase.java @@ -1526,40 +1526,53 @@ public void addClientBehavior(String eventName, ClientBehavior behavior) { // First, make sure that the event is supported. We don't want // to bother attaching behaviors for unsupported events. - if (initialStateMarked()) { - // a Behavior has been added dynamically. Update existing - // Behaviors, if any, to save their full state. - if (behaviors != null) { - for (Entry> entry : behaviors.entrySet()) { - for (ClientBehavior b : entry.getValue()) { - if (b instanceof PartialStateHolder) { - ((PartialStateHolder) behavior).clearInitialState(); + Collection eventNames = getEventNames(); + + // getClientEventNames() is spec'ed to require a non-null Set. + // If getClientEventNames() returns null, throw an exception + // to indicate that the API in not being used properly. + if (eventNames == null) { + throw new IllegalStateException( + "Attempting to add a Behavior to a component " + "that does not support any event types. " + "getEventTypes() must return a non-null Set."); + } + + if (eventNames.contains(eventName)) { + + if (initialStateMarked()) { + // a Behavior has been added dynamically. Update existing + // Behaviors, if any, to save their full state. + if (behaviors != null) { + for (Entry> entry : behaviors.entrySet()) { + for (ClientBehavior b : entry.getValue()) { + if (b instanceof PartialStateHolder) { + ((PartialStateHolder) behavior).clearInitialState(); + } } } } } - } - // We've got an event that we support, create our Map - // if necessary + // We've got an event that we support, create our Map + // if necessary - if (null == behaviors) { - // Typically we only have a small number of behaviors for - // any component - in most cases only 1. Using a very small - // initial capacity so that we keep the footprint to a minimum. - Map> modifiableMap = new HashMap<>(5, 1.0f); - behaviors = new BehaviorsMap(modifiableMap); - } + if (null == behaviors) { + // Typically we only have a small number of behaviors for + // any component - in most cases only 1. Using a very small + // initial capacity so that we keep the footprint to a minimum. + Map> modifiableMap = new HashMap<>(5, 1.0f); + behaviors = new BehaviorsMap(modifiableMap); + } - List eventBehaviours = behaviors.get(eventName); + List eventBehaviours = behaviors.get(eventName); - if (null == eventBehaviours) { - // Again using small initial capacity - we typically - // only have 1 Behavior per event type. - eventBehaviours = new ArrayList<>(3); - behaviors.getModifiableMap().put(eventName, eventBehaviours); - } + if (null == eventBehaviours) { + // Again using small initial capacity - we typically + // only have 1 Behavior per event type. + eventBehaviours = new ArrayList<>(3); + behaviors.getModifiableMap().put(eventName, eventBehaviours); + } - eventBehaviours.add(behavior); + eventBehaviours.add(behavior); + } } /** diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlBody.java b/impl/src/main/java/jakarta/faces/component/html/HtmlBody.java index 54378293bb..be80723546 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlBody.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlBody.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getDocumentElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIOutput; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -576,12 +575,9 @@ public void setXmlns(java.lang.String xmlns) { handleAttribute(this, "xmlns", xmlns); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection( - Arrays.asList("click", "dblclick", "keydown", "keypress", "keyup", "load", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "unload")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getDocumentElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlCommandButton.java b/impl/src/main/java/jakarta/faces/component/html/HtmlCommandButton.java index f75ad1409a..639690ad02 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlCommandButton.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlCommandButton.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UICommand; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -823,12 +822,9 @@ public void setType(java.lang.String type) { getStateHelper().put(PropertyKeys.type, type); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "change", "click", "action", "dblclick", - "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "select")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlCommandLink.java b/impl/src/main/java/jakarta/faces/component/html/HtmlCommandLink.java index be89e5f976..7817604385 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlCommandLink.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlCommandLink.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UICommand; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -842,12 +841,9 @@ public void setType(java.lang.String type) { handleAttribute(this, "type", type); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "click", "action", "dblclick", "focus", - "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlDataTable.java b/impl/src/main/java/jakarta/faces/component/html/HtmlDataTable.java index 52c34a18a3..fc80e85240 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlDataTable.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlDataTable.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIData; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -934,12 +933,9 @@ public void setWidth(java.lang.String width) { handleAttribute(this, "width", width); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection( - Arrays.asList("click", "dblclick", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java b/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java new file mode 100644 index 0000000000..f082af8ae8 --- /dev/null +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java @@ -0,0 +1,142 @@ +package jakarta.faces.component.html; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import java.util.stream.Stream; + +import jakarta.faces.context.FacesContext; + +/** + * https://html.spec.whatwg.org/multipage/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects + * + * + * + * @since 5.0 + */ +public final class HtmlEvents { + + /** + * Events supported by all document elements. + */ + public enum DocumentElementEvent { + abort, + auxclick, + beforeinput, + beforematch, + eforetoggle, + cancel, + canplay, + canplaythrough, + change, + click, + close, + contextlost, + contextmenu, + contextrestored, + copy, + cuechange, + cut, + dblclick, + drag, + dragend, + dragenter, + dragleave, + dragover, + dragstart, + drop, + durationchange, + emptied, + ended, + formdata, + input, + invalid, + keydown, + keypress, + keyup, + loadeddata, + loadedmetadata, + loadstart, + mousedown, + mouseenter, + mouseleave, + mousemove, + mouseout, + mouseover, + mouseup, + paste, + pause, + play, + playing, + progress, + ratechange, + reset, + securitypolicyviolation, + seeked, + seeking, + select, + slotchange, + stalled, + submit, + suspend, + timeupdate, + toggle, + volumechange, + waiting, + wheel, + + } + + /** + * Events supported by all body elements, in addition to the events supported by all document elements. + */ + public enum BodyElementEvent { + blur, + error, + focus, + load, + resize, + scroll, + scrollend; + } + + /** + * The name of the context-param whose value must represent a space-separated list of additional HTML event names. + * All supported HTML event names are defined in the enums {@link DocumentElementEvent} and {@link BodyElementEvent}. + * Any HTML event name which you wish to add to these enums can be supplied via this context-param. + */ + public static final String ADDITIONAL_HTML_EVENT_NAMES_PARAM_NAME = "jakarta.faces.ADDITIONAL_HTML_EVENT_NAMES"; + + private static final Collection DOCUMENT_ELEMENT_EVENT_NAMES = Arrays.stream(DocumentElementEvent.values()).map(e -> e.name()).sorted().distinct().toList(); + private static final Collection BODY_ELEMENT_EVENT_NAMES = Stream.concat(DOCUMENT_ELEMENT_EVENT_NAMES.stream(), Arrays.stream(BodyElementEvent.values()).map(e -> e.name())).sorted().distinct().toList(); + + private HtmlEvents() { + throw new AssertionError(); + } + + /** + * @param context The involved faces context. + * @return All supported event names for document elements. + */ + public static Collection getDocumentElementEventNames(FacesContext context) { + return mergeAdditionalHtmlEventNamesIfNecessary(context, "jakarta.faces.component.html.HtmlEvents.DOCUMENT_ELEMENT_EVENT_NAMES", DOCUMENT_ELEMENT_EVENT_NAMES, Collections.emptyList()); + } + + /** + * @param context The involved faces context. + * @return All supported event names for body elements. + */ + public static Collection getBodyElementEventNames(FacesContext context) { + return mergeAdditionalHtmlEventNamesIfNecessary(context, "jakarta.faces.component.html.HtmlEvents.BODY_ELEMENT_EVENT_NAMES", DOCUMENT_ELEMENT_EVENT_NAMES, BODY_ELEMENT_EVENT_NAMES); + } + + @SuppressWarnings("unchecked") + private static Collection mergeAdditionalHtmlEventNamesIfNecessary(FacesContext context, String applicationKey, Collection documentEventNames, Collection bodyEventNames) { + return (Collection) context.getExternalContext().getApplicationMap().computeIfAbsent(applicationKey, $ -> { + String[] additionalHtmlEventNames = Optional.ofNullable(context.getExternalContext().getInitParameter(ADDITIONAL_HTML_EVENT_NAMES_PARAM_NAME)).map(p -> p.split("\\s+")).orElse(new String[0]); + return Stream.concat(Stream.concat(documentEventNames.stream(), bodyEventNames.stream()), Arrays.stream(additionalHtmlEventNames)).sorted().distinct().toList(); + }); + } + +} diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlForm.java b/impl/src/main/java/jakarta/faces/component/html/HtmlForm.java index dfa2357cdb..61cbca0ad1 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlForm.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlForm.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIForm; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -659,12 +658,9 @@ public void setTitle(java.lang.String title) { handleAttribute(this, "title", title); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection( - Arrays.asList("click", "dblclick", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlGraphicImage.java b/impl/src/main/java/jakarta/faces/component/html/HtmlGraphicImage.java index 8e60aefbb3..cc83f2086c 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlGraphicImage.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlGraphicImage.java @@ -17,10 +17,9 @@ */ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIGraphic; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -658,12 +657,9 @@ public void setWidth(java.lang.String width) { handleAttribute(this, "width", width); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection( - Arrays.asList("click", "dblclick", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlInputFile.java b/impl/src/main/java/jakarta/faces/component/html/HtmlInputFile.java index 7a8abe89b1..15fee6d466 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlInputFile.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlInputFile.java @@ -17,10 +17,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIInput; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -817,12 +816,9 @@ public void setTitle(java.lang.String title) { handleAttribute(this, "title", title); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "change", "valueChange", "click", "dblclick", - "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "select")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlInputSecret.java b/impl/src/main/java/jakarta/faces/component/html/HtmlInputSecret.java index 0a7fc1232e..58e321a150 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlInputSecret.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlInputSecret.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIInput; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -846,12 +845,9 @@ public void setTitle(java.lang.String title) { handleAttribute(this, "title", title); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "change", "valueChange", "click", "dblclick", - "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "select")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlInputText.java b/impl/src/main/java/jakarta/faces/component/html/HtmlInputText.java index 720c08ea15..c6965e2831 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlInputText.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlInputText.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIInput; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -876,12 +875,9 @@ public void setType(String type) { handleAttribute(this, "type", type); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "change", "valueChange", "click", "dblclick", - "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "select")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlInputTextarea.java b/impl/src/main/java/jakarta/faces/component/html/HtmlInputTextarea.java index a4a415fce2..20b96fc9d4 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlInputTextarea.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlInputTextarea.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIInput; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -789,12 +788,9 @@ public void setTitle(java.lang.String title) { handleAttribute(this, "title", title); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "change", "valueChange", "click", "dblclick", - "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "select")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetButton.java b/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetButton.java index 661d6a8358..26c62dd0a9 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetButton.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetButton.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIOutcomeTarget; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -693,12 +692,9 @@ public void setTitle(java.lang.String title) { handleAttribute(this, "title", title); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection( - Arrays.asList("blur", "click", "dblclick", "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetLink.java b/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetLink.java index 1d7aa385a3..96ded2fb9c 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetLink.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetLink.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIOutcomeTarget; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -840,12 +839,9 @@ public void setType(java.lang.String type) { handleAttribute(this, "type", type); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "click", "action", "dblclick", "focus", - "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLabel.java b/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLabel.java index 62fd088880..c6ec9e24cf 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLabel.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLabel.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIOutput; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -660,12 +659,9 @@ public void setTitle(java.lang.String title) { handleAttribute(this, "title", title); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection( - Arrays.asList("blur", "click", "dblclick", "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLink.java b/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLink.java index 0034ef3a9a..acf1741589 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLink.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLink.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIOutput; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -869,12 +868,9 @@ public void setType(java.lang.String type) { handleAttribute(this, "type", type); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "click", "action", "dblclick", "focus", - "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGrid.java b/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGrid.java index 59692f8d80..4c860e0bbc 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGrid.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGrid.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIPanel; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -959,12 +958,9 @@ public void setWidth(java.lang.String width) { handleAttribute(this, "width", width); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection( - Arrays.asList("click", "dblclick", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGroup.java b/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGroup.java index 2213639b5d..b956719749 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGroup.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGroup.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UIPanel; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -410,12 +409,9 @@ public void setStyleClass(java.lang.String styleClass) { getStateHelper().put(PropertyKeys.styleClass, styleClass); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection( - Arrays.asList("click", "dblclick", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectBooleanCheckbox.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectBooleanCheckbox.java index f1643c8bfe..f4d98cfd26 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectBooleanCheckbox.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectBooleanCheckbox.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UISelectBoolean; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -738,12 +737,9 @@ public void setTitle(java.lang.String title) { handleAttribute(this, "title", title); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "change", "click", "valueChange", "dblclick", - "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "select")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyCheckbox.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyCheckbox.java index 45cab1c88d..25a110b0e2 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyCheckbox.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyCheckbox.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UISelectMany; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -892,12 +891,9 @@ public void setUnselectedClass(java.lang.String unselectedClass) { getStateHelper().put(PropertyKeys.unselectedClass, unselectedClass); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "change", "click", "valueChange", "dblclick", - "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "select")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyListbox.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyListbox.java index d3b6e57a0c..5bf186f751 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyListbox.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyListbox.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UISelectMany; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -787,12 +786,9 @@ public void setTitle(java.lang.String title) { handleAttribute(this, "title", title); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "change", "valueChange", "click", "dblclick", - "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyMenu.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyMenu.java index 82a302acbe..7483aba5b1 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyMenu.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyMenu.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UISelectMany; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -761,12 +760,9 @@ public void setTitle(java.lang.String title) { handleAttribute(this, "title", title); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "change", "valueChange", "click", "dblclick", - "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneListbox.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneListbox.java index cd3623ee56..9880171fa6 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneListbox.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneListbox.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UISelectOne; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -787,12 +786,9 @@ public void setTitle(java.lang.String title) { handleAttribute(this, "title", title); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "change", "valueChange", "click", "dblclick", - "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneMenu.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneMenu.java index 8197f0bf9f..8ff72a92a2 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneMenu.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneMenu.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UISelectOne; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -762,12 +761,9 @@ public void setTitle(java.lang.String title) { handleAttribute(this, "title", title); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "change", "valueChange", "click", "dblclick", - "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneRadio.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneRadio.java index 5db40a2bce..a0cefdea0f 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneRadio.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneRadio.java @@ -18,10 +18,9 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; +import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import jakarta.faces.component.UISelectOne; import jakarta.faces.component.behavior.ClientBehaviorHolder; @@ -875,12 +874,9 @@ public void setTitle(java.lang.String title) { handleAttribute(this, "title", title); } - private static final Collection EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("blur", "change", "click", "valueChange", "dblclick", - "focus", "keydown", "keypress", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "select")); - @Override public Collection getEventNames() { - return EVENT_NAMES; + return getBodyElementEventNames(getFacesContext()); } @Override From d77e716fdaf675539f7b61cfba8aad22f4d46b96 Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 30 Sep 2023 16:07:02 -0400 Subject: [PATCH 07/16] Fixed compilation error caused by accidental usage of Java16 method https://github.com/jakartaee/faces/issues/1507 -- we still need to bump Java version of Faces 5.0 project to align with Jakarta EE 11 --- .../java/jakarta/faces/component/html/HtmlEvents.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java b/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java index f082af8ae8..08a28117d5 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java @@ -1,9 +1,12 @@ package jakarta.faces.component.html; +import static java.util.stream.Collectors.toList; + import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Optional; +import java.util.stream.Collectors; import java.util.stream.Stream; import jakarta.faces.context.FacesContext; @@ -108,8 +111,8 @@ public enum BodyElementEvent { */ public static final String ADDITIONAL_HTML_EVENT_NAMES_PARAM_NAME = "jakarta.faces.ADDITIONAL_HTML_EVENT_NAMES"; - private static final Collection DOCUMENT_ELEMENT_EVENT_NAMES = Arrays.stream(DocumentElementEvent.values()).map(e -> e.name()).sorted().distinct().toList(); - private static final Collection BODY_ELEMENT_EVENT_NAMES = Stream.concat(DOCUMENT_ELEMENT_EVENT_NAMES.stream(), Arrays.stream(BodyElementEvent.values()).map(e -> e.name())).sorted().distinct().toList(); + private static final Collection DOCUMENT_ELEMENT_EVENT_NAMES = Arrays.stream(DocumentElementEvent.values()).map(e -> e.name()).sorted().distinct().collect(toList()); + private static final Collection BODY_ELEMENT_EVENT_NAMES = Stream.concat(DOCUMENT_ELEMENT_EVENT_NAMES.stream(), Arrays.stream(BodyElementEvent.values()).map(e -> e.name())).sorted().distinct().collect(toList()); private HtmlEvents() { throw new AssertionError(); @@ -135,8 +138,8 @@ public static Collection getBodyElementEventNames(FacesContext context) private static Collection mergeAdditionalHtmlEventNamesIfNecessary(FacesContext context, String applicationKey, Collection documentEventNames, Collection bodyEventNames) { return (Collection) context.getExternalContext().getApplicationMap().computeIfAbsent(applicationKey, $ -> { String[] additionalHtmlEventNames = Optional.ofNullable(context.getExternalContext().getInitParameter(ADDITIONAL_HTML_EVENT_NAMES_PARAM_NAME)).map(p -> p.split("\\s+")).orElse(new String[0]); - return Stream.concat(Stream.concat(documentEventNames.stream(), bodyEventNames.stream()), Arrays.stream(additionalHtmlEventNames)).sorted().distinct().toList(); + return Stream.concat(Stream.concat(documentEventNames.stream(), bodyEventNames.stream()), Arrays.stream(additionalHtmlEventNames)).sorted().distinct().collect(toList()); }); } - + } From 2944ff23ac72c88c34eb8572fab69c0dc8d4033e Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 30 Sep 2023 16:10:08 -0400 Subject: [PATCH 08/16] Refactored inline constant https://github.com/jakartaee/faces/issues/1507 --- .../main/java/com/sun/faces/renderkit/RenderKitUtils.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java index 4ee728b431..9c95a8f0f0 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java +++ b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java @@ -149,7 +149,8 @@ public class RenderKitUtils { * UIViewRoot attribute key of a boolean value which remembers whether the view will be rendered with a HTML5 doctype. */ private static final String VIEW_ROOT_ATTRIBUTES_DOCTYPE_KEY = RenderKitUtils.class.getName() + ".isOutputHtml5Doctype"; - + + private static final String HTML5_BEHAVIOR_EVENT_ATTRIBUTE_PREFIX = "on"; protected static final Logger LOGGER = FacesLogger.RENDERKIT.getLogger(); @@ -715,7 +716,7 @@ private static void renderPassThruAttributesUnoptimized(FacesContext context, Re } for (String eventName : behaviorEventNames) { - renderPassthruAttribute(context, writer, component, behaviors, isXhtml, attrMap, "on" + eventName, eventName); + renderPassthruAttribute(context, writer, component, behaviors, isXhtml, attrMap, HTML5_BEHAVIOR_EVENT_ATTRIBUTE_PREFIX + eventName, eventName); } } @@ -738,7 +739,7 @@ private static void renderPassthruAttribute(FacesContext context, ResponseWriter } public static boolean isHtml5BehaviorAttribute(String name) { - return name.startsWith("on") && name.length() > 2; + return name.startsWith(HTML5_BEHAVIOR_EVENT_ATTRIBUTE_PREFIX) && name.length() > 2; } /** From ab3d22960327b10200806d8f383c7c01d7cabd9f Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 7 Oct 2023 18:00:27 -0400 Subject: [PATCH 09/16] Reverted temp change in AjaxBehaviors as HtmlEvents has been introduced --- .../sun/faces/component/behavior/AjaxBehaviors.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/impl/src/main/java/com/sun/faces/component/behavior/AjaxBehaviors.java b/impl/src/main/java/com/sun/faces/component/behavior/AjaxBehaviors.java index 1feb6c83d0..3002aebec7 100644 --- a/impl/src/main/java/com/sun/faces/component/behavior/AjaxBehaviors.java +++ b/impl/src/main/java/com/sun/faces/component/behavior/AjaxBehaviors.java @@ -16,9 +16,6 @@ package com.sun.faces.component.behavior; -import static com.sun.faces.renderkit.RenderKitUtils.isHtml5BehaviorAttribute; -import static com.sun.faces.renderkit.RenderKitUtils.isOutputHtml5Doctype; - import java.io.Serializable; import java.util.ArrayDeque; import java.util.Iterator; @@ -26,8 +23,6 @@ import java.util.Map; import java.util.Set; -import com.sun.faces.renderkit.RenderKitUtils; - import jakarta.faces.application.Application; import jakarta.faces.component.behavior.AjaxBehavior; import jakarta.faces.component.behavior.ClientBehavior; @@ -141,7 +136,7 @@ public void addBehavior(FacesContext context, ClientBehaviorHolder behaviorHolde } // We only add the - if (shouldAddBehavior(context, behaviorHolder, myEventName)) { + if (shouldAddBehavior(behaviorHolder, myEventName)) { ClientBehavior behavior = createBehavior(context); behaviorHolder.addClientBehavior(myEventName, behavior); } @@ -150,11 +145,11 @@ public void addBehavior(FacesContext context, ClientBehaviorHolder behaviorHolde // Tests whether we should add an AjaxBehavior to the specified // ClientBehaviorHolder/event name. - private boolean shouldAddBehavior(FacesContext context, ClientBehaviorHolder behaviorHolder, String eventName) { + private boolean shouldAddBehavior(ClientBehaviorHolder behaviorHolder, String eventName) { // First need to make sure that this ClientBehaviorHolder // supports the specified event type. - if (!behaviorHolder.getEventNames().contains(eventName) || !(isOutputHtml5Doctype(context) && isHtml5BehaviorAttribute(eventName))) { + if (!behaviorHolder.getEventNames().contains(eventName)) { return false; } From 8ffb4fdef49a44e69333c5bb35385d96ff77cb9d Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sun, 15 Oct 2023 12:49:48 -0400 Subject: [PATCH 10/16] Add FacesComponentEvent enum with action and valueChange; refactored rest where possible --- .../faces/component/PassthroughElement.java | 8 +- .../sun/faces/renderkit/RenderKitUtils.java | 39 +++++----- .../renderkit/html_basic/ButtonRenderer.java | 4 +- .../html_basic/CommandLinkRenderer.java | 4 +- .../html_basic/HtmlBasicInputRenderer.java | 6 +- .../behavior/ClientBehaviorHolder.java | 2 +- .../faces/component/html/HtmlBody.java | 4 +- .../component/html/HtmlCommandButton.java | 7 +- .../faces/component/html/HtmlCommandLink.java | 7 +- .../faces/component/html/HtmlDataTable.java | 4 +- .../faces/component/html/HtmlEvents.java | 74 +++++++++++++------ .../faces/component/html/HtmlForm.java | 4 +- .../component/html/HtmlGraphicImage.java | 4 +- .../faces/component/html/HtmlInputFile.java | 7 +- .../faces/component/html/HtmlInputSecret.java | 7 +- .../faces/component/html/HtmlInputText.java | 7 +- .../component/html/HtmlInputTextarea.java | 7 +- .../html/HtmlOutcomeTargetButton.java | 7 +- .../component/html/HtmlOutcomeTargetLink.java | 7 +- .../faces/component/html/HtmlOutputLabel.java | 4 +- .../faces/component/html/HtmlOutputLink.java | 7 +- .../faces/component/html/HtmlPanelGrid.java | 4 +- .../faces/component/html/HtmlPanelGroup.java | 4 +- .../html/HtmlSelectBooleanCheckbox.java | 7 +- .../html/HtmlSelectManyCheckbox.java | 7 +- .../component/html/HtmlSelectManyListbox.java | 7 +- .../component/html/HtmlSelectManyMenu.java | 7 +- .../component/html/HtmlSelectOneListbox.java | 7 +- .../component/html/HtmlSelectOneMenu.java | 7 +- .../component/html/HtmlSelectOneRadio.java | 7 +- .../jakarta/faces/event/BehaviorEvent.java | 23 ++++++ 31 files changed, 191 insertions(+), 109 deletions(-) diff --git a/impl/src/main/java/com/sun/faces/component/PassthroughElement.java b/impl/src/main/java/com/sun/faces/component/PassthroughElement.java index 2a5a7f5d53..55b1ef6da8 100644 --- a/impl/src/main/java/com/sun/faces/component/PassthroughElement.java +++ b/impl/src/main/java/com/sun/faces/component/PassthroughElement.java @@ -16,7 +16,7 @@ package com.sun.faces.component; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getHtmlBodyElementEventNames; import java.util.ArrayList; import java.util.Collection; @@ -24,7 +24,7 @@ import jakarta.el.ValueExpression; import jakarta.faces.component.behavior.ClientBehaviorHolder; -import jakarta.faces.component.html.HtmlEvents; +import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; /** *

@@ -360,12 +360,12 @@ public void setStyleClass(java.lang.String styleClass) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getHtmlBodyElementEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "click"; + return DocumentElementEvent.click.name(); } // TODO The same as jakarta.faces.component.html.HtmlComponentUtils#handleAttribute diff --git a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java index 049e108392..8eaa7646a3 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java +++ b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java @@ -68,6 +68,8 @@ import jakarta.faces.component.behavior.ClientBehaviorContext; import jakarta.faces.component.behavior.ClientBehaviorHint; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; import jakarta.faces.component.html.HtmlMessages; import jakarta.faces.context.ExternalContext; import jakarta.faces.context.FacesContext; @@ -356,11 +358,12 @@ public static void renderOnchange(FacesContext context, UIComponent component, b final String handlerName = "onchange"; final Object userHandler = component.getAttributes().get(handlerName); - String behaviorEventName = "valueChange"; + String behaviorEventName = FacesComponentEvent.valueChange.name(); + String domEventName = DocumentElementEvent.change.name(); if (component instanceof ClientBehaviorHolder) { Map behaviors = ((ClientBehaviorHolder) component).getClientBehaviors(); - if (null != behaviors && behaviors.containsKey("change")) { - behaviorEventName = "change"; + if (null != behaviors && behaviors.containsKey(domEventName)) { + behaviorEventName = domEventName; } } @@ -379,11 +382,12 @@ public static void renderSelectOnclick(FacesContext context, UIComponent compone final String handlerName = "onclick"; final Object userHandler = component.getAttributes().get(handlerName); - String behaviorEventName = "valueChange"; + String behaviorEventName = FacesComponentEvent.valueChange.name(); + String domEventName = DocumentElementEvent.click.name(); if (component instanceof ClientBehaviorHolder) { Map behaviors = ((ClientBehaviorHolder) component).getClientBehaviors(); - if (null != behaviors && behaviors.containsKey("click")) { - behaviorEventName = "click"; + if (null != behaviors && behaviors.containsKey(domEventName)) { + behaviorEventName = domEventName; } } @@ -405,18 +409,19 @@ public static void renderOnclick(FacesContext context, UIComponent component, Co final String handlerName = "onclick"; final Object userHandler = component.getAttributes().get(handlerName); - String behaviorEventName = "action"; + String behaviorEventName = FacesComponentEvent.action.name(); + String domEventName = DocumentElementEvent.click.name(); if (component instanceof ClientBehaviorHolder) { Map> behaviors = ((ClientBehaviorHolder) component).getClientBehaviors(); - boolean mixed = null != behaviors && behaviors.containsKey("click") && behaviors.containsKey("action"); + boolean mixed = null != behaviors && behaviors.containsKey(domEventName) && behaviors.containsKey(behaviorEventName); if (mixed) { - behaviorEventName = "click"; - List clickBehaviors = behaviors.get("click"); - List actionBehaviors = behaviors.get("action"); + List actionBehaviors = behaviors.get(behaviorEventName); + behaviorEventName = domEventName; + List clickBehaviors = behaviors.get(domEventName); clickBehaviors.addAll(actionBehaviors); actionBehaviors.clear(); - } else if (null != behaviors && behaviors.containsKey("click")) { - behaviorEventName = "click"; + } else if (null != behaviors && behaviors.containsKey(domEventName)) { + behaviorEventName = domEventName; } } @@ -427,7 +432,7 @@ public static void renderOnclick(FacesContext context, UIComponent component, Co public static void renderFunction(FacesContext context, UIComponent component, Collection params, String submitTarget) throws IOException { - ClientBehaviorContext behaviorContext = ClientBehaviorContext.createClientBehaviorContext(context, component, "action", submitTarget, params); + ClientBehaviorContext behaviorContext = ClientBehaviorContext.createClientBehaviorContext(context, component, FacesComponentEvent.action.name(), submitTarget, params); AjaxBehavior behavior = (AjaxBehavior) context.getApplication().createBehavior(AjaxBehavior.BEHAVIOR_ID); mapAttributes(component, behavior, "execute", "render", "onerror", "onevent", "resetValues"); @@ -1199,14 +1204,14 @@ public static boolean isPartialOrBehaviorAction(FacesContext context, String cli // First check for a Behavior action event. String behaviorEvent = BEHAVIOR_EVENT_PARAM.getValue(context); if (null != behaviorEvent) { - return "action".equals(behaviorEvent); + return FacesComponentEvent.action.name().equals(behaviorEvent); } // Not a Behavior-related request. Check for faces.ajax.request() // request params. String partialEvent = PARTIAL_EVENT_PARAM.getValue(context); - return "click".equals(partialEvent); + return DocumentElementEvent.click.name().equals(partialEvent); } /** @@ -1585,7 +1590,7 @@ private static String getChainedHandler(FacesContext context, UIComponent compon // If we're submitting (either via a behavior, or by rendering // a submit script), we need to return false to prevent the // default button/link action. - if (submitting && ("action".equals(behaviorEventName) || "click".equals(behaviorEventName))) { + if (submitting && (FacesComponentEvent.action.name().equals(behaviorEventName) || DocumentElementEvent.click.name().equals(behaviorEventName))) { builder.append(";return false"); } diff --git a/impl/src/main/java/com/sun/faces/renderkit/html_basic/ButtonRenderer.java b/impl/src/main/java/com/sun/faces/renderkit/html_basic/ButtonRenderer.java index b2c2b4bf16..80082311cc 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/html_basic/ButtonRenderer.java +++ b/impl/src/main/java/com/sun/faces/renderkit/html_basic/ButtonRenderer.java @@ -35,6 +35,8 @@ import jakarta.faces.component.UIComponent; import jakarta.faces.component.behavior.ClientBehavior; import jakarta.faces.component.behavior.ClientBehaviorContext; +import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; import jakarta.faces.context.FacesContext; import jakarta.faces.context.ResponseWriter; import jakarta.faces.event.ActionEvent; @@ -242,7 +244,7 @@ private static String getButtonType(UIComponent component) { // which allows us to take a more optimized code path. private static Map> getNonOnClickBehaviors(UIComponent component) { - return getPassThruBehaviors(component, "click", "action"); + return getPassThruBehaviors(component, DocumentElementEvent.click.name(), FacesComponentEvent.action.name()); } } // end of class ButtonRenderer diff --git a/impl/src/main/java/com/sun/faces/renderkit/html_basic/CommandLinkRenderer.java b/impl/src/main/java/com/sun/faces/renderkit/html_basic/CommandLinkRenderer.java index 40b40fdb97..01cb0e38ef 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/html_basic/CommandLinkRenderer.java +++ b/impl/src/main/java/com/sun/faces/renderkit/html_basic/CommandLinkRenderer.java @@ -32,6 +32,8 @@ import jakarta.faces.component.UIComponent; import jakarta.faces.component.behavior.ClientBehavior; import jakarta.faces.component.behavior.ClientBehaviorContext; +import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; import jakarta.faces.context.FacesContext; import jakarta.faces.context.ResponseWriter; import jakarta.faces.event.ActionEvent; @@ -199,7 +201,7 @@ private static boolean wasClicked(FacesContext context, UIComponent component, S // which allows us to take a more optimized code path. private static Map> getNonOnClickBehaviors(UIComponent component) { - return getPassThruBehaviors(component, "click", "action"); + return getPassThruBehaviors(component, DocumentElementEvent.click.name(), FacesComponentEvent.action.name()); } } // end of class CommandLinkRenderer diff --git a/impl/src/main/java/com/sun/faces/renderkit/html_basic/HtmlBasicInputRenderer.java b/impl/src/main/java/com/sun/faces/renderkit/html_basic/HtmlBasicInputRenderer.java index 8d07093a10..38eb1362ed 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/html_basic/HtmlBasicInputRenderer.java +++ b/impl/src/main/java/com/sun/faces/renderkit/html_basic/HtmlBasicInputRenderer.java @@ -33,6 +33,8 @@ import jakarta.faces.component.UIInput; import jakarta.faces.component.ValueHolder; import jakarta.faces.component.behavior.ClientBehavior; +import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; import jakarta.faces.context.FacesContext; import jakarta.faces.convert.Converter; import jakarta.faces.convert.ConverterException; @@ -178,7 +180,7 @@ protected Object getValue(UIComponent component) { // we pass a null Behaviors map into renderPassThruAttributes(), // which allows us to take a more optimized code path. protected static Map> getNonOnChangeBehaviors(UIComponent component) { - return getPassThruBehaviors(component, "change", "valueChange"); + return getPassThruBehaviors(component, DocumentElementEvent.change.name(), FacesComponentEvent.valueChange.name()); } // Returns the Behaviors map, but only if it contains some entry other @@ -188,7 +190,7 @@ protected static Map> getNonOnChangeBehaviors(UICom // we pass a null Behaviors map into renderPassThruAttributes(), // which allows us to take a more optimized code path. protected static Map> getNonOnClickSelectBehaviors(UIComponent component) { - return getPassThruBehaviors(component, "click", "valueChange"); + return getPassThruBehaviors(component, DocumentElementEvent.click.name(), FacesComponentEvent.valueChange.name()); } // --------------------------------------------------------- Private Methods diff --git a/impl/src/main/java/jakarta/faces/component/behavior/ClientBehaviorHolder.java b/impl/src/main/java/jakarta/faces/component/behavior/ClientBehaviorHolder.java index 60be7f8832..2aaeec1215 100644 --- a/impl/src/main/java/jakarta/faces/component/behavior/ClientBehaviorHolder.java +++ b/impl/src/main/java/jakarta/faces/component/behavior/ClientBehaviorHolder.java @@ -34,7 +34,7 @@ public interface ClientBehaviorHolder { /** *

* Attaches a {@link ClientBehavior} to the component implementing this interface for the specified event. Valid event - * names for a UIComponent implementation are defined by {@code ClientBehaviorHolder.getEventNames()}. + * names for a UIComponent implementation are defined by {@link ClientBehaviorHolder#getEventNames()}. *

* * @param eventName the logical name of the client-side event to attach the behavior to. diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlBody.java b/impl/src/main/java/jakarta/faces/component/html/HtmlBody.java index be80723546..8c375e595e 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlBody.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlBody.java @@ -18,7 +18,7 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getDocumentElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getHtmlDocumentElementEventNames; import java.util.Collection; @@ -577,7 +577,7 @@ public void setXmlns(java.lang.String xmlns) { @Override public Collection getEventNames() { - return getDocumentElementEventNames(getFacesContext()); + return getHtmlDocumentElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlCommandButton.java b/impl/src/main/java/jakarta/faces/component/html/HtmlCommandButton.java index 639690ad02..4f6f3d4c70 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlCommandButton.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlCommandButton.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getFacesActionSourceEventNames; import java.util.Collection; import jakarta.faces.component.UICommand; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** *

@@ -824,12 +825,12 @@ public void setType(java.lang.String type) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getFacesActionSourceEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "action"; + return FacesComponentEvent.action.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlCommandLink.java b/impl/src/main/java/jakarta/faces/component/html/HtmlCommandLink.java index 7817604385..96b7956d80 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlCommandLink.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlCommandLink.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getFacesActionSourceEventNames; import java.util.Collection; import jakarta.faces.component.UICommand; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** *

@@ -843,12 +844,12 @@ public void setType(java.lang.String type) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getFacesActionSourceEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "action"; + return FacesComponentEvent.action.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlDataTable.java b/impl/src/main/java/jakarta/faces/component/html/HtmlDataTable.java index fc80e85240..437f8c8a4d 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlDataTable.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlDataTable.java @@ -18,7 +18,7 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getHtmlBodyElementEventNames; import java.util.Collection; @@ -935,7 +935,7 @@ public void setWidth(java.lang.String width) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getHtmlBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java b/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java index 08a28117d5..1dfd7dad6c 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java @@ -1,20 +1,22 @@ package jakarta.faces.component.html; -import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toUnmodifiableList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Optional; -import java.util.stream.Collectors; +import java.util.function.Supplier; import java.util.stream.Stream; +import jakarta.faces.component.ActionSource; +import jakarta.faces.component.EditableValueHolder; import jakarta.faces.context.FacesContext; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** - * https://html.spec.whatwg.org/multipage/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects - * - * + *

+ * Events supported by HTML elements as per current spec. + *

* * @since 5.0 */ @@ -111,35 +113,65 @@ public enum BodyElementEvent { */ public static final String ADDITIONAL_HTML_EVENT_NAMES_PARAM_NAME = "jakarta.faces.ADDITIONAL_HTML_EVENT_NAMES"; - private static final Collection DOCUMENT_ELEMENT_EVENT_NAMES = Arrays.stream(DocumentElementEvent.values()).map(e -> e.name()).sorted().distinct().collect(toList()); - private static final Collection BODY_ELEMENT_EVENT_NAMES = Stream.concat(DOCUMENT_ELEMENT_EVENT_NAMES.stream(), Arrays.stream(BodyElementEvent.values()).map(e -> e.name())).sorted().distinct().collect(toList()); - private HtmlEvents() { throw new AssertionError(); } /** * @param context The involved faces context. - * @return All supported event names for document elements. + * @return All additional HTML event names specified via {@link #ADDITIONAL_HTML_EVENT_NAMES_PARAM_NAME}. + */ + public static Collection getAdditionalHtmlEventNames(FacesContext context) { + return collect(Arrays.stream(Optional.ofNullable(context.getExternalContext().getInitParameter(ADDITIONAL_HTML_EVENT_NAMES_PARAM_NAME)).map(p -> p.split("\\s+")).orElse(new String[0]))); + } + + /** + * @param context The involved faces context. + * @return All supported event names for HTML document elements, including additional HTML event names. + */ + public static Collection getHtmlDocumentElementEventNames(FacesContext context) { + return cache(context, "HtmlEvents.DOCUMENT_ELEMENT_EVENT_NAMES", () -> merge(DocumentElementEvent.values(), getAdditionalHtmlEventNames(context))); + } + + /** + * @param context The involved faces context. + * @return All supported event names for HTML body elements, including HTML document element event names. */ - public static Collection getDocumentElementEventNames(FacesContext context) { - return mergeAdditionalHtmlEventNamesIfNecessary(context, "jakarta.faces.component.html.HtmlEvents.DOCUMENT_ELEMENT_EVENT_NAMES", DOCUMENT_ELEMENT_EVENT_NAMES, Collections.emptyList()); + public static Collection getHtmlBodyElementEventNames(FacesContext context) { + return cache(context, "HtmlEvents.BODY_ELEMENT_EVENT_NAMES", () -> merge(BodyElementEvent.values(), getHtmlDocumentElementEventNames(context))); } /** * @param context The involved faces context. - * @return All supported event names for body elements. + * @return All supported event names for HTML implementations of Faces {@link ActionSource} components, including HTML body element event names. */ - public static Collection getBodyElementEventNames(FacesContext context) { - return mergeAdditionalHtmlEventNamesIfNecessary(context, "jakarta.faces.component.html.HtmlEvents.BODY_ELEMENT_EVENT_NAMES", DOCUMENT_ELEMENT_EVENT_NAMES, BODY_ELEMENT_EVENT_NAMES); + public static Collection getFacesActionSourceEventNames(FacesContext context) { + return cache(context, "HtmlEvents.FACES_ACTION_SOURCE_EVENT_NAMES", () -> merge(FacesComponentEvent.action, getHtmlBodyElementEventNames(context))); + } + + /** + * @param context The involved faces context. + * @return All supported event names for HTML implementations of Faces {@link EditableValueHolder} components, including HTML body element event names. + */ + public static Collection getFacesEditableValueHolderEventNames(FacesContext context) { + return cache(context, "HtmlEvents.FACES_EDITABLE_VALUE_HOLDER_EVENT_NAMES", () -> merge(FacesComponentEvent.valueChange, getHtmlBodyElementEventNames(context))); + } + + private static Collection collect(Stream stream) { + return stream.sorted().distinct().collect(toUnmodifiableList()); + } + + private static Collection merge(Enum enumValue, Collection eventNames) { + return merge(new Enum[] { enumValue }, eventNames); + } + + private static Collection merge(Enum[] enumValues, Collection eventNames) { + return collect(Stream.concat(Arrays.stream(enumValues).map(e -> e.name()), eventNames.stream())); } @SuppressWarnings("unchecked") - private static Collection mergeAdditionalHtmlEventNamesIfNecessary(FacesContext context, String applicationKey, Collection documentEventNames, Collection bodyEventNames) { - return (Collection) context.getExternalContext().getApplicationMap().computeIfAbsent(applicationKey, $ -> { - String[] additionalHtmlEventNames = Optional.ofNullable(context.getExternalContext().getInitParameter(ADDITIONAL_HTML_EVENT_NAMES_PARAM_NAME)).map(p -> p.split("\\s+")).orElse(new String[0]); - return Stream.concat(Stream.concat(documentEventNames.stream(), bodyEventNames.stream()), Arrays.stream(additionalHtmlEventNames)).sorted().distinct().collect(toList()); - }); + private static Collection cache(FacesContext context, String applicationKey, Supplier> supplier) { + return (Collection) context.getExternalContext().getApplicationMap().computeIfAbsent(applicationKey, $ -> supplier.get()); } - + } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlForm.java b/impl/src/main/java/jakarta/faces/component/html/HtmlForm.java index 61cbca0ad1..134e63eb87 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlForm.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlForm.java @@ -18,7 +18,7 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getHtmlBodyElementEventNames; import java.util.Collection; @@ -660,7 +660,7 @@ public void setTitle(java.lang.String title) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getHtmlBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlGraphicImage.java b/impl/src/main/java/jakarta/faces/component/html/HtmlGraphicImage.java index cc83f2086c..f0640ee626 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlGraphicImage.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlGraphicImage.java @@ -17,7 +17,7 @@ */ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getHtmlBodyElementEventNames; import java.util.Collection; @@ -659,7 +659,7 @@ public void setWidth(java.lang.String width) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getHtmlBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlInputFile.java b/impl/src/main/java/jakarta/faces/component/html/HtmlInputFile.java index 15fee6d466..faeaba2bbf 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlInputFile.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlInputFile.java @@ -17,12 +17,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getFacesEditableValueHolderEventNames; import java.util.Collection; import jakarta.faces.component.UIInput; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** * Represents an HTML input element of type file. @@ -818,12 +819,12 @@ public void setTitle(java.lang.String title) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getFacesEditableValueHolderEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "valueChange"; + return FacesComponentEvent.valueChange.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlInputSecret.java b/impl/src/main/java/jakarta/faces/component/html/HtmlInputSecret.java index 58e321a150..0dcb9686b3 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlInputSecret.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlInputSecret.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getFacesEditableValueHolderEventNames; import java.util.Collection; import jakarta.faces.component.UIInput; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** *

@@ -847,12 +848,12 @@ public void setTitle(java.lang.String title) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getFacesEditableValueHolderEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "valueChange"; + return FacesComponentEvent.valueChange.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlInputText.java b/impl/src/main/java/jakarta/faces/component/html/HtmlInputText.java index c6965e2831..32fddf25bd 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlInputText.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlInputText.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getFacesEditableValueHolderEventNames; import java.util.Collection; import jakarta.faces.component.UIInput; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** *

@@ -877,12 +878,12 @@ public void setType(String type) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getFacesEditableValueHolderEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "valueChange"; + return FacesComponentEvent.valueChange.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlInputTextarea.java b/impl/src/main/java/jakarta/faces/component/html/HtmlInputTextarea.java index 20b96fc9d4..18de75db0f 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlInputTextarea.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlInputTextarea.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getFacesEditableValueHolderEventNames; import java.util.Collection; import jakarta.faces.component.UIInput; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** *

@@ -790,12 +791,12 @@ public void setTitle(java.lang.String title) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getFacesEditableValueHolderEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "valueChange"; + return FacesComponentEvent.valueChange.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetButton.java b/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetButton.java index 26c62dd0a9..80f1db8013 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetButton.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetButton.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getHtmlBodyElementEventNames; import java.util.Collection; import jakarta.faces.component.UIOutcomeTarget; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; /** *

@@ -694,12 +695,12 @@ public void setTitle(java.lang.String title) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getHtmlBodyElementEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return null; + return DocumentElementEvent.click.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetLink.java b/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetLink.java index 96ded2fb9c..372d0ecdb7 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetLink.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetLink.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getHtmlBodyElementEventNames; import java.util.Collection; import jakarta.faces.component.UIOutcomeTarget; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; /** *

@@ -841,12 +842,12 @@ public void setType(java.lang.String type) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getHtmlBodyElementEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "action"; + return DocumentElementEvent.click.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLabel.java b/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLabel.java index c6ec9e24cf..fc852040d2 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLabel.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLabel.java @@ -18,7 +18,7 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getHtmlBodyElementEventNames; import java.util.Collection; @@ -661,7 +661,7 @@ public void setTitle(java.lang.String title) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getHtmlBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLink.java b/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLink.java index acf1741589..e5d2e00208 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLink.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLink.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getHtmlBodyElementEventNames; import java.util.Collection; import jakarta.faces.component.UIOutput; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; /** *

@@ -870,12 +871,12 @@ public void setType(java.lang.String type) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getHtmlBodyElementEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "action"; + return DocumentElementEvent.click.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGrid.java b/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGrid.java index 4c860e0bbc..5c3bab142d 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGrid.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGrid.java @@ -18,7 +18,7 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getHtmlBodyElementEventNames; import java.util.Collection; @@ -960,7 +960,7 @@ public void setWidth(java.lang.String width) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getHtmlBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGroup.java b/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGroup.java index b956719749..1645d67497 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGroup.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlPanelGroup.java @@ -18,7 +18,7 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getHtmlBodyElementEventNames; import java.util.Collection; @@ -411,7 +411,7 @@ public void setStyleClass(java.lang.String styleClass) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getHtmlBodyElementEventNames(getFacesContext()); } @Override diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectBooleanCheckbox.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectBooleanCheckbox.java index f4d98cfd26..a9e82950bc 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectBooleanCheckbox.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectBooleanCheckbox.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getFacesEditableValueHolderEventNames; import java.util.Collection; import jakarta.faces.component.UISelectBoolean; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** *

@@ -739,12 +740,12 @@ public void setTitle(java.lang.String title) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getFacesEditableValueHolderEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "valueChange"; + return FacesComponentEvent.valueChange.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyCheckbox.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyCheckbox.java index 25a110b0e2..2e4c7a79c0 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyCheckbox.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyCheckbox.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getFacesEditableValueHolderEventNames; import java.util.Collection; import jakarta.faces.component.UISelectMany; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** *

@@ -893,12 +894,12 @@ public void setUnselectedClass(java.lang.String unselectedClass) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getFacesEditableValueHolderEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "valueChange"; + return FacesComponentEvent.valueChange.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyListbox.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyListbox.java index 5bf186f751..5478291ea0 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyListbox.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyListbox.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getFacesEditableValueHolderEventNames; import java.util.Collection; import jakarta.faces.component.UISelectMany; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** *

@@ -788,12 +789,12 @@ public void setTitle(java.lang.String title) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getFacesEditableValueHolderEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "valueChange"; + return FacesComponentEvent.valueChange.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyMenu.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyMenu.java index 7483aba5b1..15aff94748 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyMenu.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectManyMenu.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getFacesEditableValueHolderEventNames; import java.util.Collection; import jakarta.faces.component.UISelectMany; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** *

@@ -762,12 +763,12 @@ public void setTitle(java.lang.String title) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getFacesEditableValueHolderEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "valueChange"; + return FacesComponentEvent.valueChange.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneListbox.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneListbox.java index 9880171fa6..afadf07513 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneListbox.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneListbox.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getFacesEditableValueHolderEventNames; import java.util.Collection; import jakarta.faces.component.UISelectOne; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** *

@@ -788,12 +789,12 @@ public void setTitle(java.lang.String title) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getFacesEditableValueHolderEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "valueChange"; + return FacesComponentEvent.valueChange.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneMenu.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneMenu.java index 8ff72a92a2..b2b6cb4016 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneMenu.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneMenu.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getFacesEditableValueHolderEventNames; import java.util.Collection; import jakarta.faces.component.UISelectOne; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** *

@@ -763,12 +764,12 @@ public void setTitle(java.lang.String title) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getFacesEditableValueHolderEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "valueChange"; + return FacesComponentEvent.valueChange.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneRadio.java b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneRadio.java index a0cefdea0f..95e6a13351 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneRadio.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlSelectOneRadio.java @@ -18,12 +18,13 @@ package jakarta.faces.component.html; import static jakarta.faces.component.html.HtmlComponentUtils.handleAttribute; -import static jakarta.faces.component.html.HtmlEvents.getBodyElementEventNames; +import static jakarta.faces.component.html.HtmlEvents.getFacesEditableValueHolderEventNames; import java.util.Collection; import jakarta.faces.component.UISelectOne; import jakarta.faces.component.behavior.ClientBehaviorHolder; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** *

@@ -876,12 +877,12 @@ public void setTitle(java.lang.String title) { @Override public Collection getEventNames() { - return getBodyElementEventNames(getFacesContext()); + return getFacesEditableValueHolderEventNames(getFacesContext()); } @Override public String getDefaultEventName() { - return "valueChange"; + return FacesComponentEvent.valueChange.name(); } } diff --git a/impl/src/main/java/jakarta/faces/event/BehaviorEvent.java b/impl/src/main/java/jakarta/faces/event/BehaviorEvent.java index 8b5eaf65bb..1e2a56be07 100644 --- a/impl/src/main/java/jakarta/faces/event/BehaviorEvent.java +++ b/impl/src/main/java/jakarta/faces/event/BehaviorEvent.java @@ -16,6 +16,8 @@ package jakarta.faces.event; +import jakarta.faces.component.ActionSource; +import jakarta.faces.component.EditableValueHolder; import jakarta.faces.component.UIComponent; import jakarta.faces.component.behavior.Behavior; import jakarta.faces.context.FacesContext; @@ -32,6 +34,27 @@ public abstract class BehaviorEvent extends FacesEvent { private static final long serialVersionUID = 6516644738910462065L; + /** + *

+ * Behavior events supported by Faces components. + *

+ * + * @since 5.0 + */ + public enum FacesComponentEvent { + + /** + * Default event of {@link ActionSource} components. + */ + action, + + /** + * Default event of {@link EditableValueHolder} components. + */ + valueChange; + + } + private final Behavior behavior; /** From c0565583a60a0b05022390deb3271b1cf5a1494d Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sun, 15 Oct 2023 13:13:19 -0400 Subject: [PATCH 11/16] Clean up after self-review --- .../java/com/sun/faces/renderkit/RenderKitUtils.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java index 8eaa7646a3..e756d78f6f 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java +++ b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java @@ -69,12 +69,12 @@ import jakarta.faces.component.behavior.ClientBehaviorHint; import jakarta.faces.component.behavior.ClientBehaviorHolder; import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; -import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; import jakarta.faces.component.html.HtmlMessages; import jakarta.faces.context.ExternalContext; import jakarta.faces.context.FacesContext; import jakarta.faces.context.PartialViewContext; import jakarta.faces.context.ResponseWriter; +import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; import jakarta.faces.model.SelectItem; import jakarta.faces.render.RenderKit; import jakarta.faces.render.RenderKitFactory; @@ -147,11 +147,6 @@ public class RenderKitUtils { */ private static final String ATTRIBUTES_THAT_ARE_SET_KEY = UIComponentBase.class.getName() + ".attributesThatAreSet"; - /** - * UIViewRoot attribute key of a boolean value which remembers whether the view will be rendered with a HTML5 doctype. - */ - private static final String VIEW_ROOT_ATTRIBUTES_DOCTYPE_KEY = RenderKitUtils.class.getName() + ".isOutputHtml5Doctype"; - private static final String HTML5_BEHAVIOR_EVENT_ATTRIBUTE_PREFIX = "on"; protected static final Logger LOGGER = FacesLogger.RENDERKIT.getLogger(); @@ -615,8 +610,8 @@ private static void renderPassThruAttributesOptimized(FacesContext context, Resp boolean renderedBehavior = false; Collections.sort(setAttributes); + boolean isXhtml = RIConstants.XHTML_CONTENT_TYPE.equals(writer.getContentType()); boolean isHtml5 = isOutputHtml5Doctype(context); - boolean isXhtml = !isHtml5 && RIConstants.XHTML_CONTENT_TYPE.equals(writer.getContentType()); Map attrMap = component.getAttributes(); for (String name : setAttributes) { @@ -698,8 +693,8 @@ else if (isHtml5 && isHtml5BehaviorAttribute(name)) { private static void renderPassThruAttributesUnoptimized(FacesContext context, ResponseWriter writer, UIComponent component, Attribute[] knownAttributes, List setAttributes, Map> behaviors) throws IOException { + boolean isXhtml = RIConstants.XHTML_CONTENT_TYPE.equals(writer.getContentType()); boolean isHtml5 = isOutputHtml5Doctype(context); - boolean isXhtml = !isHtml5 && RIConstants.XHTML_CONTENT_TYPE.equals(writer.getContentType()); Map attrMap = component.getAttributes(); Set behaviorEventNames = new LinkedHashSet<>(behaviors.size() + 2); From acf3d47bdd219ab786174a7440c1866df638fea3 Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sun, 22 Oct 2023 10:25:01 -0400 Subject: [PATCH 12/16] Fixed failing tests --- .../com/sun/faces/renderkit/html_basic/TestResponseWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impl/src/test/java/com/sun/faces/renderkit/html_basic/TestResponseWriter.java b/impl/src/test/java/com/sun/faces/renderkit/html_basic/TestResponseWriter.java index 0c84d691b1..87c3939104 100644 --- a/impl/src/test/java/com/sun/faces/renderkit/html_basic/TestResponseWriter.java +++ b/impl/src/test/java/com/sun/faces/renderkit/html_basic/TestResponseWriter.java @@ -40,7 +40,7 @@ public TestResponseWriter(Writer writer) { @Override public String getContentType() { - throw new UnsupportedOperationException("Not supported yet."); + return "text/html"; } @Override From 0bc83fd63df27636d4548af5a9befbc35f440125 Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 28 Oct 2023 09:38:43 -0400 Subject: [PATCH 13/16] Renamed the enums to have Html prefix and changed appmap by enummap --- .../faces/component/PassthroughElement.java | 4 +- .../sun/faces/renderkit/RenderKitUtils.java | 12 ++--- .../renderkit/html_basic/ButtonRenderer.java | 4 +- .../html_basic/CommandLinkRenderer.java | 4 +- .../html_basic/HtmlBasicInputRenderer.java | 6 +-- .../faces/component/html/HtmlEvents.java | 48 +++++++++++-------- .../html/HtmlOutcomeTargetButton.java | 4 +- .../component/html/HtmlOutcomeTargetLink.java | 4 +- .../faces/component/html/HtmlOutputLink.java | 4 +- 9 files changed, 49 insertions(+), 41 deletions(-) diff --git a/impl/src/main/java/com/sun/faces/component/PassthroughElement.java b/impl/src/main/java/com/sun/faces/component/PassthroughElement.java index 55b1ef6da8..c6662d36b5 100644 --- a/impl/src/main/java/com/sun/faces/component/PassthroughElement.java +++ b/impl/src/main/java/com/sun/faces/component/PassthroughElement.java @@ -24,7 +24,7 @@ import jakarta.el.ValueExpression; import jakarta.faces.component.behavior.ClientBehaviorHolder; -import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; +import jakarta.faces.component.html.HtmlEvents.HtmlDocumentElementEvent; /** *

@@ -365,7 +365,7 @@ public Collection getEventNames() { @Override public String getDefaultEventName() { - return DocumentElementEvent.click.name(); + return HtmlDocumentElementEvent.click.name(); } // TODO The same as jakarta.faces.component.html.HtmlComponentUtils#handleAttribute diff --git a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java index e756d78f6f..0851b6931a 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java +++ b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java @@ -68,7 +68,7 @@ import jakarta.faces.component.behavior.ClientBehaviorContext; import jakarta.faces.component.behavior.ClientBehaviorHint; import jakarta.faces.component.behavior.ClientBehaviorHolder; -import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; +import jakarta.faces.component.html.HtmlEvents.HtmlDocumentElementEvent; import jakarta.faces.component.html.HtmlMessages; import jakarta.faces.context.ExternalContext; import jakarta.faces.context.FacesContext; @@ -354,7 +354,7 @@ public static void renderOnchange(FacesContext context, UIComponent component, b final String handlerName = "onchange"; final Object userHandler = component.getAttributes().get(handlerName); String behaviorEventName = FacesComponentEvent.valueChange.name(); - String domEventName = DocumentElementEvent.change.name(); + String domEventName = HtmlDocumentElementEvent.change.name(); if (component instanceof ClientBehaviorHolder) { Map behaviors = ((ClientBehaviorHolder) component).getClientBehaviors(); if (null != behaviors && behaviors.containsKey(domEventName)) { @@ -378,7 +378,7 @@ public static void renderSelectOnclick(FacesContext context, UIComponent compone final String handlerName = "onclick"; final Object userHandler = component.getAttributes().get(handlerName); String behaviorEventName = FacesComponentEvent.valueChange.name(); - String domEventName = DocumentElementEvent.click.name(); + String domEventName = HtmlDocumentElementEvent.click.name(); if (component instanceof ClientBehaviorHolder) { Map behaviors = ((ClientBehaviorHolder) component).getClientBehaviors(); if (null != behaviors && behaviors.containsKey(domEventName)) { @@ -405,7 +405,7 @@ public static void renderOnclick(FacesContext context, UIComponent component, Co final String handlerName = "onclick"; final Object userHandler = component.getAttributes().get(handlerName); String behaviorEventName = FacesComponentEvent.action.name(); - String domEventName = DocumentElementEvent.click.name(); + String domEventName = HtmlDocumentElementEvent.click.name(); if (component instanceof ClientBehaviorHolder) { Map> behaviors = ((ClientBehaviorHolder) component).getClientBehaviors(); boolean mixed = null != behaviors && behaviors.containsKey(domEventName) && behaviors.containsKey(behaviorEventName); @@ -1206,7 +1206,7 @@ public static boolean isPartialOrBehaviorAction(FacesContext context, String cli // request params. String partialEvent = PARTIAL_EVENT_PARAM.getValue(context); - return DocumentElementEvent.click.name().equals(partialEvent); + return HtmlDocumentElementEvent.click.name().equals(partialEvent); } /** @@ -1585,7 +1585,7 @@ private static String getChainedHandler(FacesContext context, UIComponent compon // If we're submitting (either via a behavior, or by rendering // a submit script), we need to return false to prevent the // default button/link action. - if (submitting && (FacesComponentEvent.action.name().equals(behaviorEventName) || DocumentElementEvent.click.name().equals(behaviorEventName))) { + if (submitting && (FacesComponentEvent.action.name().equals(behaviorEventName) || HtmlDocumentElementEvent.click.name().equals(behaviorEventName))) { builder.append(";return false"); } diff --git a/impl/src/main/java/com/sun/faces/renderkit/html_basic/ButtonRenderer.java b/impl/src/main/java/com/sun/faces/renderkit/html_basic/ButtonRenderer.java index 80082311cc..b52ed05460 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/html_basic/ButtonRenderer.java +++ b/impl/src/main/java/com/sun/faces/renderkit/html_basic/ButtonRenderer.java @@ -35,7 +35,7 @@ import jakarta.faces.component.UIComponent; import jakarta.faces.component.behavior.ClientBehavior; import jakarta.faces.component.behavior.ClientBehaviorContext; -import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; +import jakarta.faces.component.html.HtmlEvents.HtmlDocumentElementEvent; import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; import jakarta.faces.context.FacesContext; import jakarta.faces.context.ResponseWriter; @@ -244,7 +244,7 @@ private static String getButtonType(UIComponent component) { // which allows us to take a more optimized code path. private static Map> getNonOnClickBehaviors(UIComponent component) { - return getPassThruBehaviors(component, DocumentElementEvent.click.name(), FacesComponentEvent.action.name()); + return getPassThruBehaviors(component, HtmlDocumentElementEvent.click.name(), FacesComponentEvent.action.name()); } } // end of class ButtonRenderer diff --git a/impl/src/main/java/com/sun/faces/renderkit/html_basic/CommandLinkRenderer.java b/impl/src/main/java/com/sun/faces/renderkit/html_basic/CommandLinkRenderer.java index 01cb0e38ef..e0937ba793 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/html_basic/CommandLinkRenderer.java +++ b/impl/src/main/java/com/sun/faces/renderkit/html_basic/CommandLinkRenderer.java @@ -32,7 +32,7 @@ import jakarta.faces.component.UIComponent; import jakarta.faces.component.behavior.ClientBehavior; import jakarta.faces.component.behavior.ClientBehaviorContext; -import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; +import jakarta.faces.component.html.HtmlEvents.HtmlDocumentElementEvent; import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; import jakarta.faces.context.FacesContext; import jakarta.faces.context.ResponseWriter; @@ -201,7 +201,7 @@ private static boolean wasClicked(FacesContext context, UIComponent component, S // which allows us to take a more optimized code path. private static Map> getNonOnClickBehaviors(UIComponent component) { - return getPassThruBehaviors(component, DocumentElementEvent.click.name(), FacesComponentEvent.action.name()); + return getPassThruBehaviors(component, HtmlDocumentElementEvent.click.name(), FacesComponentEvent.action.name()); } } // end of class CommandLinkRenderer diff --git a/impl/src/main/java/com/sun/faces/renderkit/html_basic/HtmlBasicInputRenderer.java b/impl/src/main/java/com/sun/faces/renderkit/html_basic/HtmlBasicInputRenderer.java index 38eb1362ed..3b1e928515 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/html_basic/HtmlBasicInputRenderer.java +++ b/impl/src/main/java/com/sun/faces/renderkit/html_basic/HtmlBasicInputRenderer.java @@ -33,7 +33,7 @@ import jakarta.faces.component.UIInput; import jakarta.faces.component.ValueHolder; import jakarta.faces.component.behavior.ClientBehavior; -import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; +import jakarta.faces.component.html.HtmlEvents.HtmlDocumentElementEvent; import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; import jakarta.faces.context.FacesContext; import jakarta.faces.convert.Converter; @@ -180,7 +180,7 @@ protected Object getValue(UIComponent component) { // we pass a null Behaviors map into renderPassThruAttributes(), // which allows us to take a more optimized code path. protected static Map> getNonOnChangeBehaviors(UIComponent component) { - return getPassThruBehaviors(component, DocumentElementEvent.change.name(), FacesComponentEvent.valueChange.name()); + return getPassThruBehaviors(component, HtmlDocumentElementEvent.change.name(), FacesComponentEvent.valueChange.name()); } // Returns the Behaviors map, but only if it contains some entry other @@ -190,7 +190,7 @@ protected static Map> getNonOnChangeBehaviors(UICom // we pass a null Behaviors map into renderPassThruAttributes(), // which allows us to take a more optimized code path. protected static Map> getNonOnClickSelectBehaviors(UIComponent component) { - return getPassThruBehaviors(component, DocumentElementEvent.click.name(), FacesComponentEvent.valueChange.name()); + return getPassThruBehaviors(component, HtmlDocumentElementEvent.click.name(), FacesComponentEvent.valueChange.name()); } // --------------------------------------------------------- Private Methods diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java b/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java index 1dfd7dad6c..7342859264 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java @@ -4,28 +4,32 @@ import java.util.Arrays; import java.util.Collection; +import java.util.EnumMap; +import java.util.Map; import java.util.Optional; import java.util.function.Supplier; import java.util.stream.Stream; import jakarta.faces.component.ActionSource; import jakarta.faces.component.EditableValueHolder; +import jakarta.faces.component.behavior.ClientBehaviorHolder; import jakarta.faces.context.FacesContext; import jakarta.faces.event.BehaviorEvent.FacesComponentEvent; /** *

* Events supported by HTML elements as per current spec. + * These can be used to supply {@link ClientBehaviorHolder#getEventNames()} and {@link ClientBehaviorHolder#getDefaultEventName()}. *

- * + * * @since 5.0 */ public final class HtmlEvents { /** - * Events supported by all document elements. + * Events supported by all HTML document elements. */ - public enum DocumentElementEvent { + public enum HtmlDocumentElementEvent { abort, auxclick, beforeinput, @@ -90,13 +94,13 @@ public enum DocumentElementEvent { volumechange, waiting, wheel, - + } /** - * Events supported by all body elements, in addition to the events supported by all document elements. + * Events supported by all HTML body elements, in addition to the events supported by all HTML document elements. */ - public enum BodyElementEvent { + public enum HtmlBodyElementEvent { blur, error, focus, @@ -108,11 +112,21 @@ public enum BodyElementEvent { /** * The name of the context-param whose value must represent a space-separated list of additional HTML event names. - * All supported HTML event names are defined in the enums {@link DocumentElementEvent} and {@link BodyElementEvent}. + * All supported HTML event names are defined in the enums {@link HtmlDocumentElementEvent} and {@link HtmlBodyElementEvent}. * Any HTML event name which you wish to add to these enums can be supplied via this context-param. + * Duplicates will be automatically filtered, case sensitive. */ public static final String ADDITIONAL_HTML_EVENT_NAMES_PARAM_NAME = "jakarta.faces.ADDITIONAL_HTML_EVENT_NAMES"; + private enum CacheKey { + HTML_DOCUMENT_ELEMENT_EVENT_NAMES, + HTML_BODY_ELEMENT_EVENT_NAMES, + FACES_ACTION_SOURCE_EVENT_NAMES, + FACES_EDITABLE_VALUE_HOLDER_EVENT_NAMES; + } + + private static final Map> CACHE = new EnumMap<>(CacheKey.class); + private HtmlEvents() { throw new AssertionError(); } @@ -130,7 +144,7 @@ public static Collection getAdditionalHtmlEventNames(FacesContext contex * @return All supported event names for HTML document elements, including additional HTML event names. */ public static Collection getHtmlDocumentElementEventNames(FacesContext context) { - return cache(context, "HtmlEvents.DOCUMENT_ELEMENT_EVENT_NAMES", () -> merge(DocumentElementEvent.values(), getAdditionalHtmlEventNames(context))); + return cache(CacheKey.HTML_DOCUMENT_ELEMENT_EVENT_NAMES, () -> merge(getAdditionalHtmlEventNames(context), HtmlDocumentElementEvent.values())); } /** @@ -138,7 +152,7 @@ public static Collection getHtmlDocumentElementEventNames(FacesContext c * @return All supported event names for HTML body elements, including HTML document element event names. */ public static Collection getHtmlBodyElementEventNames(FacesContext context) { - return cache(context, "HtmlEvents.BODY_ELEMENT_EVENT_NAMES", () -> merge(BodyElementEvent.values(), getHtmlDocumentElementEventNames(context))); + return cache(CacheKey.HTML_BODY_ELEMENT_EVENT_NAMES, () -> merge(getHtmlDocumentElementEventNames(context), HtmlBodyElementEvent.values())); } /** @@ -146,7 +160,7 @@ public static Collection getHtmlBodyElementEventNames(FacesContext conte * @return All supported event names for HTML implementations of Faces {@link ActionSource} components, including HTML body element event names. */ public static Collection getFacesActionSourceEventNames(FacesContext context) { - return cache(context, "HtmlEvents.FACES_ACTION_SOURCE_EVENT_NAMES", () -> merge(FacesComponentEvent.action, getHtmlBodyElementEventNames(context))); + return cache(CacheKey.FACES_ACTION_SOURCE_EVENT_NAMES, () -> merge(getHtmlBodyElementEventNames(context), FacesComponentEvent.action)); } /** @@ -154,24 +168,18 @@ public static Collection getFacesActionSourceEventNames(FacesContext con * @return All supported event names for HTML implementations of Faces {@link EditableValueHolder} components, including HTML body element event names. */ public static Collection getFacesEditableValueHolderEventNames(FacesContext context) { - return cache(context, "HtmlEvents.FACES_EDITABLE_VALUE_HOLDER_EVENT_NAMES", () -> merge(FacesComponentEvent.valueChange, getHtmlBodyElementEventNames(context))); + return cache(CacheKey.FACES_EDITABLE_VALUE_HOLDER_EVENT_NAMES, () -> merge(getHtmlBodyElementEventNames(context), FacesComponentEvent.valueChange)); } private static Collection collect(Stream stream) { return stream.sorted().distinct().collect(toUnmodifiableList()); } - private static Collection merge(Enum enumValue, Collection eventNames) { - return merge(new Enum[] { enumValue }, eventNames); - } - - private static Collection merge(Enum[] enumValues, Collection eventNames) { + private static Collection merge(Collection eventNames, Enum... enumValues) { return collect(Stream.concat(Arrays.stream(enumValues).map(e -> e.name()), eventNames.stream())); } - @SuppressWarnings("unchecked") - private static Collection cache(FacesContext context, String applicationKey, Supplier> supplier) { - return (Collection) context.getExternalContext().getApplicationMap().computeIfAbsent(applicationKey, $ -> supplier.get()); + private static Collection cache(CacheKey key, Supplier> supplier) { + return CACHE.computeIfAbsent(key, $ -> supplier.get()); } - } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetButton.java b/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetButton.java index 80f1db8013..55b723e0f2 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetButton.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetButton.java @@ -24,7 +24,7 @@ import jakarta.faces.component.UIOutcomeTarget; import jakarta.faces.component.behavior.ClientBehaviorHolder; -import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; +import jakarta.faces.component.html.HtmlEvents.HtmlDocumentElementEvent; /** *

@@ -700,7 +700,7 @@ public Collection getEventNames() { @Override public String getDefaultEventName() { - return DocumentElementEvent.click.name(); + return HtmlDocumentElementEvent.click.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetLink.java b/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetLink.java index 372d0ecdb7..693aa8fab4 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetLink.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlOutcomeTargetLink.java @@ -24,7 +24,7 @@ import jakarta.faces.component.UIOutcomeTarget; import jakarta.faces.component.behavior.ClientBehaviorHolder; -import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; +import jakarta.faces.component.html.HtmlEvents.HtmlDocumentElementEvent; /** *

@@ -847,7 +847,7 @@ public Collection getEventNames() { @Override public String getDefaultEventName() { - return DocumentElementEvent.click.name(); + return HtmlDocumentElementEvent.click.name(); } } diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLink.java b/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLink.java index e5d2e00208..0a6cd8195b 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLink.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlOutputLink.java @@ -24,7 +24,7 @@ import jakarta.faces.component.UIOutput; import jakarta.faces.component.behavior.ClientBehaviorHolder; -import jakarta.faces.component.html.HtmlEvents.DocumentElementEvent; +import jakarta.faces.component.html.HtmlEvents.HtmlDocumentElementEvent; /** *

@@ -876,7 +876,7 @@ public Collection getEventNames() { @Override public String getDefaultEventName() { - return DocumentElementEvent.click.name(); + return HtmlDocumentElementEvent.click.name(); } } From 7236717db399cb08aeb23331c5f16d83911e8913 Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 28 Oct 2023 10:35:43 -0400 Subject: [PATCH 14/16] Set in stone in spec --- .../metadata/taglib/faces.core.taglib.xml | 4 +- .../com/sun/faces/standard-html-renderkit.xml | 45 +++++++------------ 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/impl/src/main/resources/com/sun/faces/metadata/taglib/faces.core.taglib.xml b/impl/src/main/resources/com/sun/faces/metadata/taglib/faces.core.taglib.xml index fc008a3046..3a53879d44 100644 --- a/impl/src/main/resources/com/sun/faces/metadata/taglib/faces.core.taglib.xml +++ b/impl/src/main/resources/com/sun/faces/metadata/taglib/faces.core.taglib.xml @@ -148,11 +148,11 @@

A String or ValueExpression (that evalulates to a String) identifying the type of event the Ajax action will apply to. If specified, it must be one of the - events supported by the component the Ajax behavior is being applied to. + events supported by the component the Ajax behavior is being applied to as per ClientBehaviorHolder#getEventNames(). For HTML components this would be the set of supported DOM events for the component, plus "action" for Faces ActionSource components and "valueChange" for Faces EditableValueHolder components. If not specified, the default - event is determined for the component. The DOM event name is the actual DOM + event is determined for the component via ClientBehaviorHolder#getDefaultEventName(). The DOM event name is the actual DOM event name (for example: "click") as opposed to (for example: "onclick").

diff --git a/impl/src/main/resources/com/sun/faces/standard-html-renderkit.xml b/impl/src/main/resources/com/sun/faces/standard-html-renderkit.xml index 37ab87d66c..8500863421 100644 --- a/impl/src/main/resources/com/sun/faces/standard-html-renderkit.xml +++ b/impl/src/main/resources/com/sun/faces/standard-html-renderkit.xml @@ -29,33 +29,6 @@ standard HTML RenderKit. Please see the spec for additional details for the standard render-kit. -
-

The following new renderers have been - added in this release of the specification.

- -
-
jakarta.faces.Output
- -
jakarta.faces.Body -
- -
jakarta.faces.Head -
- -
jakarta.faces.resource.Script -
- -
jakarta.faces.resource.Stylesheet -
- -
jakarta.faces.Composite -
- - -
- -
-

General notes on decoding

    @@ -191,11 +164,13 @@ rendered content. Components may obtain script from multiple sources. Event handler scripts may be specified by page authors, scripts may be produced by client behaviors and renderers may produce ther own scripts. When multiple scripts are present, the scripts must be chained together in this order: +

    • User specified event handler scripts
    • client behavior scripts
    • renderer specific scripts
    +

    If any of the scripts in the chain returns false, subsequent script must not be executed. The specification provides a utility function faces.util.chain to handle this capability. If there are UIParameter children the parameter names and values must be passed into the client behavior @@ -205,7 +180,7 @@

    -

    Rendering Pass Through Attributes.

    +

    Rendering Pass Through Attributes.

      @@ -233,6 +208,20 @@
    +
    +

    Rendering Behavior Event Attributes.

    + +
      +

      + When the component is an instance of ClientBehaviorHolder + and the attribute name starts with 'on' + and the substring after 'on' is contained in ClientBehaviorHolder#getEventNames() + and it is not available as a renderer specific attribute, + then it must be rendered the same way as a pass through attribute. +

      +
    +
    +
]]> From 71ad216a4fbdffaa8cdd3e3f92d14182ff633f44 Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 28 Oct 2023 10:40:44 -0400 Subject: [PATCH 15/16] Remove HTML5 specificity --- .../sun/faces/renderkit/RenderKitUtils.java | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java index 0851b6931a..e77efe6aa3 100644 --- a/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java +++ b/impl/src/main/java/com/sun/faces/renderkit/RenderKitUtils.java @@ -147,7 +147,7 @@ public class RenderKitUtils { */ private static final String ATTRIBUTES_THAT_ARE_SET_KEY = UIComponentBase.class.getName() + ".attributesThatAreSet"; - private static final String HTML5_BEHAVIOR_EVENT_ATTRIBUTE_PREFIX = "on"; + private static final String BEHAVIOR_EVENT_ATTRIBUTE_PREFIX = "on"; protected static final Logger LOGGER = FacesLogger.RENDERKIT.getLogger(); @@ -611,7 +611,6 @@ private static void renderPassThruAttributesOptimized(FacesContext context, Resp Collections.sort(setAttributes); boolean isXhtml = RIConstants.XHTML_CONTENT_TYPE.equals(writer.getContentType()); - boolean isHtml5 = isOutputHtml5Doctype(context); Map attrMap = component.getAttributes(); for (String name : setAttributes) { @@ -634,7 +633,7 @@ private static void renderPassThruAttributesOptimized(FacesContext context, Resp } } } - else if (isHtml5 && isHtml5BehaviorAttribute(name)) { + else if (isBehaviorEventAttribute(name)) { Object value = attrMap.get(name); if (value != null && shouldRenderAttribute(value)) { if (name.substring(2).equals(behaviorEventName)) { @@ -652,15 +651,13 @@ else if (isHtml5 && isHtml5BehaviorAttribute(name)) { // attribute rendering. Need to manually render it out now. if (behaviorEventName != null && !renderedBehavior) { - if (isHtml5) { - List behaviorAttributes = setAttributes.stream().filter(RenderKitUtils::isHtml5BehaviorAttribute).collect(toList()); + List behaviorAttributes = setAttributes.stream().filter(RenderKitUtils::isBehaviorEventAttribute).collect(toList()); - for (String attrName : behaviorAttributes) { - String eventName = attrName.substring(2); - if (behaviorEventName.equals(eventName)) { - renderPassthruAttribute(context, writer, component, behaviors, isXhtml, attrMap, attrName, behaviorEventName); - return; - } + for (String attrName : behaviorAttributes) { + String eventName = attrName.substring(2); + if (behaviorEventName.equals(eventName)) { + renderPassthruAttribute(context, writer, component, behaviors, isXhtml, attrMap, attrName, behaviorEventName); + return; } } @@ -694,17 +691,14 @@ private static void renderPassThruAttributesUnoptimized(FacesContext context, Re List setAttributes, Map> behaviors) throws IOException { boolean isXhtml = RIConstants.XHTML_CONTENT_TYPE.equals(writer.getContentType()); - boolean isHtml5 = isOutputHtml5Doctype(context); Map attrMap = component.getAttributes(); Set behaviorEventNames = new LinkedHashSet<>(behaviors.size() + 2); - if (isHtml5) { - behaviorEventNames.addAll(behaviors.keySet()); + behaviorEventNames.addAll(behaviors.keySet()); - if (setAttributes != null) { - setAttributes.stream().filter(RenderKitUtils::isHtml5BehaviorAttribute).map(a -> a.substring(2)).forEach(behaviorEventNames::add); - } + if (setAttributes != null) { + setAttributes.stream().filter(RenderKitUtils::isBehaviorEventAttribute).map(a -> a.substring(BEHAVIOR_EVENT_ATTRIBUTE_PREFIX.length())).forEach(behaviorEventNames::add); } for (Attribute attribute : knownAttributes) { @@ -716,7 +710,7 @@ private static void renderPassThruAttributesUnoptimized(FacesContext context, Re } for (String eventName : behaviorEventNames) { - renderPassthruAttribute(context, writer, component, behaviors, isXhtml, attrMap, HTML5_BEHAVIOR_EVENT_ATTRIBUTE_PREFIX + eventName, eventName); + renderPassthruAttribute(context, writer, component, behaviors, isXhtml, attrMap, BEHAVIOR_EVENT_ATTRIBUTE_PREFIX + eventName, eventName); } } @@ -737,9 +731,9 @@ private static void renderPassthruAttribute(FacesContext context, ResponseWriter renderHandler(context, component, null, attrName, value, eventName, null, false, false); } } - - public static boolean isHtml5BehaviorAttribute(String name) { - return name.startsWith(HTML5_BEHAVIOR_EVENT_ATTRIBUTE_PREFIX) && name.length() > 2; + + public static boolean isBehaviorEventAttribute(String name) { + return name.startsWith(BEHAVIOR_EVENT_ATTRIBUTE_PREFIX) && name.length() > 2; } /** @@ -1273,7 +1267,7 @@ public static String getImageSource(FacesContext context, UIComponent component, ResourceHandler handler = context.getApplication().getResourceHandler(); if (resName != null) { String libName = (String) component.getAttributes().get("library"); - + if (libName == null && ApplicationAssociate.getInstance(context).getResourceManager().isContractsResource(resName)) { if (context.isProjectStage(ProjectStage.Development)) { String msg = "Illegal path, direct contract references are not allowed: " + resName; From 52b935d5ec9c2ea61a17ec5f78c5aedd1f1ff55a Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 4 Nov 2023 13:20:13 -0400 Subject: [PATCH 16/16] Fix typo --- impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java b/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java index 7342859264..506f7f7588 100644 --- a/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java +++ b/impl/src/main/java/jakarta/faces/component/html/HtmlEvents.java @@ -34,7 +34,7 @@ public enum HtmlDocumentElementEvent { auxclick, beforeinput, beforematch, - eforetoggle, + beforetoggle, cancel, canplay, canplaythrough,