Repository: primefaces/primefaces (java)

Issue:
Barcode:  Check digits disallowed in PF15
### Describe the bug

The check digit cannot be accepted as part of an input data.

The data as in the picture is not working in PF15 (OkapiBarcode)
https://barcode.tec-it.com/en/EAN13?data=1234567890128

![Image](https://github.com/user-attachments/assets/36fc30c2-0441-4348-a9af-e28a81b20f25)

https://barcode.tec-it.com/en/UPCA?data=123456789012
![Image](https://github.com/user-attachments/assets/183e6708-dc0a-4ce5-b66b-09fedbe9bde3)

### Reproducer

_No response_

### Expected behavior

_No response_

### PrimeFaces edition

None

### PrimeFaces version

15

### Theme

_No response_

### JSF implementation

Mojarra

### JSF version

4

### Java version

17

### Browser(s)

_No response_

Pull request:
Fix #13548: 15.0.2 Barcode be lenient with EAN/UPC check digits
Fix #13548: 15.0.2 Barcode be lenient with EAN/UPC check digits

Patch:
diff --git a/primefaces-showcase/src/main/java/org/primefaces/showcase/view/input/CalendarJava8View.java b/primefaces-showcase/src/main/java/org/primefaces/showcase/view/input/CalendarJava8View.java
index 7ede301165..5df7f7ffea 100644
--- a/primefaces-showcase/src/main/java/org/primefaces/showcase/view/input/CalendarJava8View.java
+++ b/primefaces-showcase/src/main/java/org/primefaces/showcase/view/input/CalendarJava8View.java
@@ -139,6 +139,15 @@ public class CalendarJava8View implements Serializable {
         facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Date Selected", event.getObject().format(formatter)));
     }
 
+    public void onDateRangeSelect(SelectEvent<List<LocalDate>> event) {
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
+        String range = event.getObject().get(0).format(formatter)
+                + " - "
+                + event.getObject().get(event.getObject().size() - 1).format(formatter);
+        facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Range Selected", range));
+    }
+
     public void onDateTimeSelect(SelectEvent<LocalDateTime> event) {
         FacesContext facesContext = FacesContext.getCurrentInstance();
         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
diff --git a/primefaces-showcase/src/main/webapp/ui/input/datepicker/datePickerJava8.xhtml b/primefaces-showcase/src/main/webapp/ui/input/datepicker/datePickerJava8.xhtml
index 4d7becb426..68c23ed3c8 100644
--- a/primefaces-showcase/src/main/webapp/ui/input/datepicker/datePickerJava8.xhtml
+++ b/primefaces-showcase/src/main/webapp/ui/input/datepicker/datePickerJava8.xhtml
@@ -70,7 +70,9 @@
 
                     <div class="field col-12 md:col-4">
                         <p:outputLabel for="@next" value="Week Picker" />
-                        <p:datePicker id="week" view="week" value="#{calendarJava8View.week}" />
+                        <p:datePicker id="week" view="week" value="#{calendarJava8View.week}">
+                            <p:ajax event="dateSelect" listener="#{calendarJava8View.onDateRangeSelect}" update="msgs" />
+                        </p:datePicker>
                     </div>
 
                     <div class="field col-12 md:col-4">
diff --git a/primefaces-showcase/src/main/webapp/ui/multimedia/barcode.xhtml b/primefaces-showcase/src/main/webapp/ui/multimedia/barcode.xhtml
index c2bc26ef45..eb16ee0e22 100644
--- a/primefaces-showcase/src/main/webapp/ui/multimedia/barcode.xhtml
+++ b/primefaces-showcase/src/main/webapp/ui/multimedia/barcode.xhtml
@@ -16,7 +16,7 @@
             &lt;dependency&gt;
                &lt;groupId>uk.org.okapibarcode&lt;/groupId&gt;
                &lt;artifactId>okapibarcode&lt;/artifactId&gt;
-               &lt;version>0.4.9&lt;/version&gt;
+               &lt;version>0.5.0&lt;/version&gt;
             &lt;/dependency&gt;
             </code></pre>
     </ui:define>
@@ -39,16 +39,16 @@
                 <p:barcode value="0123456789" type="code128"/>
 
                 <h:outputText value="EAN-8"/>
-                <p:barcode value="1234567" type="ean8"/>
+                <p:barcode value="12345670" type="ean8"/>
 
                 <h:outputText value="EAN-13"/>
-                <p:barcode value="123456789012+12345" type="ean13"/>
+                <p:barcode value="1234567890128" type="ean13"/>
 
                 <h:outputText value="UPC-A (PNG)"/>
-                <p:barcode value="01234567895" type="upca" format="png"/>
+                <p:barcode value="012345678958" type="upca" format="png"/>
 
                 <h:outputText value="UPC-E (Vertical)"/>
-                <p:barcode value="0123457" type="upce" orientation="90"/>
+                <p:barcode value="0123456" type="upce" orientation="90"/>
 
                 <h:outputText value="PDF417"/>
                 <p:barcode value="0123456789" type="pdf417"/>
diff --git a/primefaces/src/main/java/org/primefaces/component/barcode/BarcodeHandler.java b/primefaces/src/main/java/org/primefaces/component/barcode/BarcodeHandler.java
index 0cdeb549b3..879de681d5 100644
--- a/primefaces/src/main/java/org/primefaces/component/barcode/BarcodeHandler.java
+++ b/primefaces/src/main/java/org/primefaces/component/barcode/BarcodeHandler.java
@@ -105,6 +105,25 @@ public class BarcodeHandler extends BaseDynamicContentHandler {
             int quietZoneHorizontal = Integer.parseInt(params.get("mh"));
             int quietZoneVertical = Integer.parseInt(params.get("mv"));
 
+            // #13548 be lenient with EAN13 and EAN8 for check digits
+            if (generator instanceof Ean) {
+                Ean ean = (Ean) generator;
+                if (ean.getMode() == Ean.Mode.EAN13 && value.length() == 13) {
+                    value = value.substring(0, 12);
+                }
+                else if (ean.getMode() == Ean.Mode.EAN8 && value.length() == 8) {
+                    value = value.substring(0, 7);
+                }
+            }
+
+            // #13548 be lenient with UPC-A for check digits
+            if (generator instanceof Upc) {
+                Upc upc = (Upc) generator;
+                if (upc.getMode() == Mode.UPCA && value.length() == 12) {
+                    value = value.substring(0, 11);
+                }
+            }
+
             generator.setHumanReadableLocation(HumanReadableLocation.valueOf(hrp.toUpperCase(Locale.ROOT)));
             generator.setContent(value);
             generator.setQuietZoneHorizontal(quietZoneHorizontal);
diff --git a/primefaces/src/main/java/org/primefaces/component/datepicker/DatePickerRenderer.java b/primefaces/src/main/java/org/primefaces/component/datepicker/DatePickerRenderer.java
index 260ec7e79a..d8e916d811 100644
--- a/primefaces/src/main/java/org/primefaces/component/datepicker/DatePickerRenderer.java
+++ b/primefaces/src/main/java/org/primefaces/component/datepicker/DatePickerRenderer.java
@@ -377,7 +377,8 @@ public class DatePickerRenderer extends BaseCalendarRenderer {
 
                 return multi;
             case "range":
-                List<String> rangeStr = CalendarUtils.splitRange(submittedValue, datePicker.calculatePattern(), datePicker.getRangeSeparator());
+                List<String> rangeStr = CalendarUtils.splitRange(submittedValue, datePicker.calculatePattern(),
+                        datePicker.getRangeSeparator(), "week".equals(datePicker.getView()));
                 List<Object> range = new ArrayList<>();
                 if (rangeStr.size() == 2) {
                     for (int i = 0; i < rangeStr.size(); i++) {
diff --git a/primefaces/src/main/java/org/primefaces/component/splitbutton/SplitButtonRenderer.java b/primefaces/src/main/java/org/primefaces/component/splitbutton/SplitButtonRenderer.java
index 6563fed247..909f79bce9 100644
--- a/primefaces/src/main/java/org/primefaces/component/splitbutton/SplitButtonRenderer.java
+++ b/primefaces/src/main/java/org/primefaces/component/splitbutton/SplitButtonRenderer.java
@@ -106,9 +106,6 @@ public class SplitButtonRenderer extends MenuItemAwareRenderer {
         writer.startElement("div", button);
         writer.writeAttribute("id", clientId, "id");
         writer.writeAttribute("class", styleClass, "id");
-        writer.writeAttribute(HTML.ARIA_HASPOPUP, Boolean.toString(hasOverlay), null);
-        writer.writeAttribute(HTML.ARIA_CONTROLS, menuId, null);
-        writer.writeAttribute(HTML.ARIA_EXPANDED, "false", null);
         if (button.getStyle() != null) {
             writer.writeAttribute("style", button.getStyle(), "id");
         }
@@ -116,7 +113,7 @@ public class SplitButtonRenderer extends MenuItemAwareRenderer {
         encodeDefaultButton(context, button, buttonId);
         OverlayPanel customOverlay = button.getCustomOverlay();
         if (customOverlay != null || button.getElementsCount() > 0) {
-            encodeMenuIcon(context, button, menuButtonId);
+            encodeMenuIcon(context, button, menuButtonId, menuId, hasOverlay);
             if (hasOverlay) {
                 encodeMenu(context, button, menuId);
             }
@@ -187,7 +184,7 @@ public class SplitButtonRenderer extends MenuItemAwareRenderer {
         writer.endElement("button");
     }
 
-    protected void encodeMenuIcon(FacesContext context, SplitButton button, String id) throws IOException {
+    protected void encodeMenuIcon(FacesContext context, SplitButton button, String id, String menuId, boolean hasOverlay) throws IOException {
         ResponseWriter writer = context.getResponseWriter();
         String buttonClass = SplitButton.MENU_ICON_BUTTON_CLASS;
         if (button.isDisabled()) {
@@ -199,6 +196,9 @@ public class SplitButtonRenderer extends MenuItemAwareRenderer {
         writer.writeAttribute("name", id, null);
         writer.writeAttribute("type", "button", null);
         writer.writeAttribute("class", buttonClass, null);
+        writer.writeAttribute(HTML.ARIA_HASPOPUP, hasOverlay ? "menu" : "false", null);
+        writer.writeAttribute(HTML.ARIA_CONTROLS, menuId, null);
+        writer.writeAttribute(HTML.ARIA_EXPANDED, "false", null);
 
         if (button.isDisabled()) {
             writer.writeAttribute("disabled", "disabled", "disabled");
diff --git a/primefaces/src/main/java/org/primefaces/util/CalendarUtils.java b/primefaces/src/main/java/org/primefaces/util/CalendarUtils.java
index 4b52098383..2162b226ab 100644
--- a/primefaces/src/main/java/org/primefaces/util/CalendarUtils.java
+++ b/primefaces/src/main/java/org/primefaces/util/CalendarUtils.java
@@ -41,7 +41,8 @@ import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
 import java.time.temporal.Temporal;
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
@@ -637,19 +638,30 @@ public class CalendarUtils {
         return now;
     }
 
-    public static List<String> splitRange(final String dateRange, final String pattern, final String separator) {
-        final String token = Constants.SPACE + separator + Constants.SPACE;
-        if (pattern.contains(token)) {
-            throw new FacesException("Pattern '" + pattern + "' contains separator '" + token + "'");
+    public static List<String> splitRange(String input, String datePattern, String rangeSeparator,
+                                          boolean week) {
+
+        // security check
+        String token = Constants.SPACE + rangeSeparator + Constants.SPACE;
+        if (datePattern.contains(token)) {
+            throw new FacesException("Pattern '" + datePattern + "' contains separator '" + token + "'");
         }
-        final List<String> dates = new ArrayList<>();
-        if (!dateRange.contains(token)) {
-            return dates;
+
+        // fast return
+        if (!input.contains(token)) {
+            return Collections.emptyList();
         }
-        final int index = dateRange.indexOf(token);
-        dates.add(dateRange.substring(0, index));
-        dates.add(dateRange.substring(index + token.length()));
-        return dates;
+
+        int tokenIndex = input.indexOf(token);
+        String from = input.substring(0, tokenIndex);
+        String to = input.substring(tokenIndex + token.length());
+        if (week) {
+            // hardcoded pattern, see JS:
+            // formattedValue += ' (' + this.options.locale.weekHeader + ' ' + week + ')';
+            to = to.substring(0, to.lastIndexOf(" ("));
+        }
+
+        return Arrays.asList(from, to);
     }
 
 }
diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/accordion/accordion.js b/primefaces/src/main/resources/META-INF/resources/primefaces/accordion/accordion.js
index f13b77b3db..ed469ba434 100644
--- a/primefaces/src/main/resources/META-INF/resources/primefaces/accordion/accordion.js
+++ b/primefaces/src/main/resources/META-INF/resources/primefaces/accordion/accordion.js
@@ -367,7 +367,8 @@ PrimeFaces.widget.AccordionPanel = PrimeFaces.widget.BaseWidget.extend({
                 params: [
                     { name: this.id + '_contentLoad', value: true },
                     { name: this.id + '_currentTab', value: panel.attr('id') },
-                    { name: this.id + '_tabindex', value: parseInt(panel.index() / 2) }
+                    { name: this.id + '_tabindex', value: parseInt(panel.index() / 2) },
+                    { name: this.id + '_active', value: this.cfg.active }
                 ],
                 onsuccess: function(responseXML, status, xhr) {
                     PrimeFaces.ajax.Response.handle(responseXML, status, xhr, {
diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/core/core.js b/primefaces/src/main/resources/META-INF/resources/primefaces/core/core.js
index 12a7d2996d..db7eb5e2b3 100644
--- a/primefaces/src/main/resources/META-INF/resources/primefaces/core/core.js
+++ b/primefaces/src/main/resources/META-INF/resources/primefaces/core/core.js
@@ -1739,6 +1739,7 @@
                 "jumpToPageDropdownLabel": "Jump to Page Dropdown",
                 "jumpToPageInputLabel": "Jump to Page Input",
                 "lastPageLabel": "Last Page",
+                "listLabel": "Options List",
                 "listView": "List View",
                 "moveAllToSource": "Move All to Source",
                 "moveAllToTarget": "Move All to Target",
diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/forms/forms.selectoneradio.js b/primefaces/src/main/resources/META-INF/resources/primefaces/forms/forms.selectoneradio.js
index 50489d2105..5ed96965c0 100644
--- a/primefaces/src/main/resources/META-INF/resources/primefaces/forms/forms.selectoneradio.js
+++ b/primefaces/src/main/resources/META-INF/resources/primefaces/forms/forms.selectoneradio.js
@@ -171,7 +171,10 @@ PrimeFaces.widget.SelectOneRadio = PrimeFaces.widget.BaseWidget.extend({
                 else
                     radio = target.children('.ui-radiobutton-box'); //custom layout
 
-                radio.trigger('click.selectOneRadio');
+                // #13546 only trigger radio if its not already active
+                if (!radio.hasClass('ui-state-active')) {
+                    radio.trigger('click.selectOneRadio');
+                }
 
                 e.preventDefault();
             });
diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/forms/forms.splitbutton.js b/primefaces/src/main/resources/META-INF/resources/primefaces/forms/forms.splitbutton.js
index e0c6c8da67..f1187c7dbd 100644
--- a/primefaces/src/main/resources/META-INF/resources/primefaces/forms/forms.splitbutton.js
+++ b/primefaces/src/main/resources/META-INF/resources/primefaces/forms/forms.splitbutton.js
@@ -120,6 +120,7 @@ PrimeFaces.widget.SplitButton = PrimeFaces.widget.BaseWidget.extend({
         this.button.data('primefaces-overlay-target', true).find('*').data('primefaces-overlay-target', true);
 
         // toggle menu
+        this.menuButton.attr('aria-label', this.getAriaLabel('listLabel'));
         this.menuButton.on('click.splitbutton', function() {
             if(!$this.cfg.disabled && $this.menu.is(':hidden'))
                 $this.show();
@@ -487,7 +488,7 @@ PrimeFaces.widget.SplitButton = PrimeFaces.widget.BaseWidget.extend({
                 onEntered: function() {
                     $this.bindPanelEvents();
 
-                    $this.jq.attr('aria-expanded', true);
+                    $this.menuButton.attr('aria-expanded', true);
 
                     if ($this.cfg.filter && $this.cfg.filterInputAutoFocus) {
                         $this.filterInput.trigger('focus');
@@ -513,7 +514,7 @@ PrimeFaces.widget.SplitButton = PrimeFaces.widget.BaseWidget.extend({
                     $this.unbindPanelEvents();
                 },
                 onExited: function() {
-                    $this.jq.attr('aria-expanded', false);
+                    $this.menuButton.attr('aria-expanded', false);
                     $this.menuitems.filter('.ui-state-hover').removeClass('ui-state-hover');
                     $this.menuButton.removeClass('ui-state-focus');
                 }
diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/locales/locale-en.js b/primefaces/src/main/resources/META-INF/resources/primefaces/locales/locale-en.js
index 6fa73b3254..64d3d9c538 100644
--- a/primefaces/src/main/resources/META-INF/resources/primefaces/locales/locale-en.js
+++ b/primefaces/src/main/resources/META-INF/resources/primefaces/locales/locale-en.js
@@ -87,6 +87,7 @@ if (window.PrimeFaces) {
       jumpToPageDropdownLabel: "Jump to Page Dropdown",
       jumpToPageInputLabel: "Jump to Page Input",
       lastPageLabel: "Last Page",
+      listLabel: "Options List",
       listView: "List View",
       moveAllToSource: "Move All to Source",
       moveAllToTarget: "Move All to Target",


Test patch:
diff --git a/primefaces/src/test/java/org/primefaces/util/CalendarUtilsTest.java b/primefaces/src/test/java/org/primefaces/util/CalendarUtilsTest.java
index 12f13be530..cff2f05e74 100644
--- a/primefaces/src/test/java/org/primefaces/util/CalendarUtilsTest.java
+++ b/primefaces/src/test/java/org/primefaces/util/CalendarUtilsTest.java
@@ -217,18 +217,33 @@ class CalendarUtilsTest {
 
     @Test
     void splitRange() {
-        List<String> splitRange = CalendarUtils.splitRange("2021-03-01 - 2021-03-31", "yyyy-MM-dd", "-");
+        List<String> splitRange = CalendarUtils.splitRange("2021-03-01 - 2021-03-31", "yyyy-MM-dd", "-", false);
         assertEquals(2, splitRange.size());
         assertEquals("2021-03-01", splitRange.get(0));
         assertEquals("2021-03-31", splitRange.get(1));
-        splitRange = CalendarUtils.splitRange("2021-03-01", "yyyy-MM-dd", "-");
+        splitRange = CalendarUtils.splitRange("2021-03-01", "yyyy-MM-dd", "-", false);
         assertTrue(splitRange.isEmpty());
-        splitRange = CalendarUtils.splitRange("", "yyyy-MM-dd", "-");
+        splitRange = CalendarUtils.splitRange("", "yyyy-MM-dd", "-", false);
         assertTrue(splitRange.isEmpty());
 
         assertThrows(FacesException.class, () -> {
-            CalendarUtils.splitRange("2021 - 03 - 01 - 2021 - 03 - 31", "yyyy - MM - dd", "-");
+            CalendarUtils.splitRange("2021 - 03 - 01 - 2021 - 03 - 31", "yyyy - MM - dd", "-", false);
         });
     }
 
+    @Test
+    void splitRangeWeek() {
+        List<String> splitRange = CalendarUtils.splitRange("2021-03-01 - 2021-03-31 (Wk 21)", "yyyy-MM-dd", "-", true);
+        assertEquals(2, splitRange.size());
+        assertEquals("2021-03-01", splitRange.get(0));
+        assertEquals("2021-03-31", splitRange.get(1));
+        splitRange = CalendarUtils.splitRange("2021-03-01 (Wk 21)", "yyyy-MM-dd", "-", true);
+        assertTrue(splitRange.isEmpty());
+        splitRange = CalendarUtils.splitRange("", "yyyy-MM-dd (Wk 21)", "-", true);
+        assertTrue(splitRange.isEmpty());
+
+        assertThrows(FacesException.class, () -> {
+            CalendarUtils.splitRange("2021 - 03 - 01 - 2021 - 03 - 31 (Wk 21)", "yyyy - MM - dd", "-", true);
+        });
+    }
 }