Skip to content

Commit 41fd99e

Browse files
authored
Merge pull request primefaces#3133 from jasonex7/button-params
Fixes primefaces#2749 - p:button does not use nested f:param when using href attribute
2 parents 969f503 + 0e94bad commit 41fd99e

File tree

4 files changed

+126
-1
lines changed

4 files changed

+126
-1
lines changed

src/main/java/org/primefaces/renderkit/CoreRenderer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ protected String getResourceURL(FacesContext context, String value) {
9696
return ComponentUtils.getResourceURL(context, value);
9797
}
9898

99+
protected String getHrefURL(String baseUrl, Map<String, List<String>> params) {
100+
return ComponentUtils.getHrefURL(baseUrl, params);
101+
}
102+
99103
protected String getResourceRequestPath(FacesContext context, String resourceName) {
100104
Resource resource = context.getApplication().getResourceHandler().createResource(resourceName, "primefaces");
101105

src/main/java/org/primefaces/renderkit/OutcomeTargetRenderer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ protected String getTargetURL(FacesContext context, UIOutcomeTarget outcomeTarge
165165

166166
String href = outcomeTarget.getHref();
167167
if (href != null) {
168-
url = prependContextPathIfNecessary(context, href);
168+
url = getHrefURL(prependContextPathIfNecessary(context, href), outcomeTarget.getParams());
169169
}
170170
else {
171171
NavigationCase navCase = findNavigationCase(context, outcomeTarget);

src/main/java/org/primefaces/util/ComponentUtils.java

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,83 @@ else if (value.contains(ResourceHandler.RESOURCE_IDENTIFIER)) {
291291
return context.getExternalContext().encodeResourceURL(url);
292292
}
293293
}
294+
295+
/**
296+
* Generate an <code>href</code> URL considering a base URL and some other parameters.
297+
* This method consider existing query string and fragment in the base URL.
298+
* @param baseUrl An URL that may have query string and/or fragment.
299+
* @param params A map with parameters for adding to <code>baseUrl</code>.
300+
* @return An URL resulting in <code>params</code> added to <code>baseUrl</code> for using as <code>href</code> attribute.
301+
*/
302+
public static String getHrefURL(String baseUrl, Map<String, List<String>> params) {
303+
if (params == null || params.isEmpty()) {
304+
return baseUrl;
305+
}
306+
//Fragment
307+
String fragment = null;
308+
int fragmentIndex = baseUrl.indexOf("#");
309+
if (fragmentIndex != -1) {
310+
fragment = baseUrl.substring(fragmentIndex + 1).trim();
311+
baseUrl = baseUrl.substring(0, fragmentIndex);
312+
}
313+
314+
//Query string and path
315+
String queryString, path;
316+
int queryStringIndex = baseUrl.indexOf("?");
317+
if (queryStringIndex != -1) {
318+
queryString = baseUrl.substring(queryStringIndex + 1).trim();
319+
path = baseUrl.substring(0, queryStringIndex);
320+
}
321+
else {
322+
queryString = null;
323+
path = baseUrl;
324+
}
325+
326+
boolean hasParam = false;
327+
StringBuilder url = new StringBuilder(baseUrl.length() * 2);
328+
url.append(path)
329+
.append("?");
330+
//If has previous queryString, set that first as is
331+
if (!isValueBlank(queryString)) {
332+
for (String pair : queryString.split("&")) {
333+
String[] nameAndValue = pair.split("=");
334+
// ignore malformed pair
335+
if (nameAndValue.length != 2
336+
|| isValueBlank(nameAndValue[0])) {
337+
continue;
338+
}
339+
if (hasParam) {
340+
url.append("&");
341+
}
342+
url.append(nameAndValue[0])
343+
.append("=")
344+
.append(nameAndValue[1]);
345+
hasParam = true;
346+
}
347+
}
348+
//Setting params Map passed
349+
for (Map.Entry<String, List<String>> entry : params.entrySet()) {
350+
for (String value : entry.getValue()) {
351+
if (hasParam) {
352+
url.append("&");
353+
}
354+
try {
355+
url.append(entry.getKey())
356+
.append("=")
357+
.append(URLEncoder.encode(value, "UTF-8"));
358+
}
359+
catch (UnsupportedEncodingException e) {
360+
throw new RuntimeException(e);
361+
}
362+
hasParam = true;
363+
}
364+
}
365+
if (!isValueBlank(fragment)) {
366+
url.append("#")
367+
.append(fragment);
368+
}
369+
return url.toString();
370+
}
294371

295372
public static boolean isSkipIteration(VisitContext visitContext, FacesContext context) {
296373
if (PrimeApplicationContext.getCurrentInstance(context).getEnvironment().isAtLeastJsf21()) {

src/test/java/org/primefaces/util/ComponentUtilsTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
*/
1616
package org.primefaces.util;
1717

18+
import java.util.Arrays;
19+
import java.util.LinkedHashMap;
20+
import java.util.List;
21+
import java.util.Map;
1822
import static org.junit.Assert.*;
1923

2024
import org.junit.Test;
@@ -35,4 +39,44 @@ public void escapeSelector() {
3539
public void createContentDisposition() {
3640
assertEquals("attachment;filename=\"Test%20Spaces.txt\"; filename*=UTF-8''Test%20Spaces.txt", ComponentUtils.createContentDisposition("attachment", "Test Spaces.txt"));
3741
}
42+
43+
@Test
44+
public void getHrefURL() {
45+
Map<String, List<String>> params = new LinkedHashMap<String, List<String>>();
46+
47+
params.put("param1", Arrays.asList("value1"));
48+
params.put("param2", Arrays.asList("enc?de&"));//URLEncoded: enc%3Fde%26
49+
params.put("param3", Arrays.asList("two", "v@lues"));//v@lues URLEncoded: v%40lues
50+
51+
Map<String, String> testCases = new LinkedHashMap<String, String>();
52+
53+
//No query string nor fragment
54+
testCases.put("https://foo.bar/some/path",
55+
"https://foo.bar/some/path?param1=value1&param2=enc%3Fde%26&param3=two&param3=v%40lues");
56+
testCases.put("/internal/other/path",
57+
"/internal/other/path?param1=value1&param2=enc%3Fde%26&param3=two&param3=v%40lues");
58+
59+
//Just Fragment
60+
testCases.put("https://foo.bar/some/path#frg1",
61+
"https://foo.bar/some/path?param1=value1&param2=enc%3Fde%26&param3=two&param3=v%40lues#frg1");
62+
testCases.put("/internal/other/path#frg1",
63+
"/internal/other/path?param1=value1&param2=enc%3Fde%26&param3=two&param3=v%40lues#frg1");
64+
65+
//Just query string
66+
testCases.put("https://foo.bar/some/path?q1=123&q2=456",
67+
"https://foo.bar/some/path?q1=123&q2=456&param1=value1&param2=enc%3Fde%26&param3=two&param3=v%40lues");
68+
testCases.put("/internal/other/path?q1=123&q2=456",
69+
"/internal/other/path?q1=123&q2=456&param1=value1&param2=enc%3Fde%26&param3=two&param3=v%40lues");
70+
71+
//Query string and fragment
72+
testCases.put("https://foo.bar/some/path?q1=123&q2=456#frg1",
73+
"https://foo.bar/some/path?q1=123&q2=456&param1=value1&param2=enc%3Fde%26&param3=two&param3=v%40lues#frg1");
74+
testCases.put("/internal/other/path?q1=123&q2=456#frg1",
75+
"/internal/other/path?q1=123&q2=456&param1=value1&param2=enc%3Fde%26&param3=two&param3=v%40lues#frg1");
76+
77+
//Testing
78+
for (Map.Entry<String, String> test : testCases.entrySet()) {
79+
assertEquals(ComponentUtils.getHrefURL(test.getKey(), params), test.getValue());
80+
}
81+
}
3882
}

0 commit comments

Comments
 (0)