This is an automated email from the ASF dual-hosted git repository.
mridulpathak pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push:
new 35d68ab0e8 Improved: MacroFormRenderer builds the check, radio,
submit, reset, hidden and field title macro calls with
RenderableFtlFormElementsBuilder (OFBIZ-13679)
35d68ab0e8 is described below
commit 35d68ab0e80984dfbe9d90d967449c23e4aebb2c
Author: Mridul Pathak <[email protected]>
AuthorDate: Fri Oct 16 11:13:13 2026 +0530
Improved: MacroFormRenderer builds the check, radio, submit, reset, hidden
and field title macro calls with RenderableFtlFormElementsBuilder (OFBIZ-13679)
MacroFormRenderer built the macro calls of the check, radio, submit, reset
and hidden fields, of the field titles and of the sort field as text and
compiled them. RenderableFtlFormElementsBuilder now creates these macro calls,
so that FtlWriter passes their values as data: the options of the check and
radio fields are lists of maps instead of hash literals, and the quotes that
the form fields escaped for a FreeMarker string literal are no longer escaped.
The macro signatures and the o [...]
---
.../widget/renderer/macro/MacroFormRenderer.java | 396 ++-------------------
.../macro/RenderableFtlFormElementsBuilder.java | 280 ++++++++++++++-
.../renderer/macro/MacroFormRendererTest.java | 117 +++---
.../RenderableFtlFormElementsBuilderTest.java | 181 ++++++++++
4 files changed, 538 insertions(+), 436 deletions(-)
diff --git
a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRenderer.java
b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRenderer.java
index cc28442ca6..e1cb37ba1f 100644
---
a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRenderer.java
+++
b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRenderer.java
@@ -22,7 +22,6 @@ import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URI;
-import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
@@ -175,6 +174,17 @@ public final class MacroFormRenderer implements
FormStringRenderer {
return value;
}
+ private String encodeForMacro(String value, ModelFormField modelFormField,
Map<String, Object> context) {
+ if (UtilValidate.isEmpty(value)) {
+ return value;
+ }
+ UtilCodec.SimpleEncoder encoder = (UtilCodec.SimpleEncoder)
context.get("simpleEncoder");
+ if (modelFormField.getEncodeOutput() && encoder != null) {
+ value = encoder.encode(value);
+ }
+ return value;
+ }
+
public void renderLabel(Appendable writer, Map<String, Object> context,
ModelScreenWidget.Label label) {
final RenderableFtl renderableFtl =
renderableFtlFormElementsBuilder.label(context, label);
writeFtlElement(writer, renderableFtl);
@@ -282,294 +292,26 @@ public final class MacroFormRenderer implements
FormStringRenderer {
@Override
public void renderCheckField(Appendable writer, Map<String, Object>
context, CheckField checkField) throws IOException {
- ModelFormField modelFormField = checkField.getModelFormField();
- String currentValue = modelFormField.getEntry(context);
- String conditionGroup = modelFormField.getConditionGroup();
- Boolean allChecked = checkField.isAllChecked(context);
- boolean disabled = modelFormField.getDisabled(context);
- String id = modelFormField.getCurrentContainerId(context);
- String className = "";
- String alert = "false";
- String name = modelFormField.getParameterName(context);
- String event = modelFormField.getEvent();
- String action = modelFormField.getAction(context);
- StringBuilder items = new StringBuilder();
- String checkBox = checkField.getModelFormField().getAttributeName();
- List<String> checkedByDefault = new ArrayList<String>();
-
- if (context.containsKey(checkBox) && context.get(checkBox) != null
- && !context.get(checkBox).getClass().equals(String.class)) {
- checkedByDefault = context.containsKey(checkBox) ?
StringUtil.toList(context.get(checkBox).toString())
- : List.of();
- }
-
- if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
- className = modelFormField.getWidgetStyle();
- if (modelFormField.shouldBeRed(context)) {
- alert = "true";
- }
- }
- String tabindex = modelFormField.getTabindex();
-
- List<String> currentValueList = null;
- if (UtilValidate.isNotEmpty(currentValue)) {
- if (currentValue.startsWith("[")) {
- currentValueList = StringUtil.toList(currentValue);
- } else {
- currentValueList = UtilMisc.toList(currentValue);
- }
- }
-
- List<ModelFormField.OptionValue> allOptionValues =
checkField.getAllOptionValues(context, WidgetWorker.getDelegator(context));
- items.append("[");
- for (ModelFormField.OptionValue optionValue : allOptionValues) {
- boolean checked;
-
- if (UtilValidate.isNotEmpty(currentValueList)) {
- checked = currentValueList.contains(optionValue.getKey());
- } else {
- if (UtilValidate.isNotEmpty(checkedByDefault)) {
- checked = checkedByDefault.contains(optionValue.getKey());
- } else checked = allChecked;
- }
- String data = String.format(
- "{'value':'%s', 'description':'%s', 'checked':'%s'}",
- optionValue.getKey(),
- encode(optionValue.getDescription(), modelFormField,
context),
- checked);
- items.append(data);
- items.append(",");
- }
- if (items.length() > 0) {
- items.deleteCharAt(items.length() - 1);
- }
- items.append("]");
- StringWriter sr = new StringWriter();
- sr.append("<@renderCheckField ");
- sr.append("items=");
- sr.append(items.toString());
- sr.append(" className=\"");
- sr.append(className);
- sr.append("\" alert=\"");
- sr.append(alert);
- sr.append("\" id=\"");
- sr.append(id);
- sr.append("\" conditionGroup=\"");
- sr.append(conditionGroup);
- sr.append("\" currentValue=\"");
- sr.append(currentValue);
- sr.append("\" name=\"");
- sr.append(name);
- sr.append("\" event=\"");
- if (event != null) {
- sr.append(event);
- }
- sr.append("\" action=\"");
- if (action != null) {
- sr.append(action);
- }
- sr.append("\" tabindex=\"");
- sr.append(tabindex);
- sr.append("\" disabled=");
- sr.append(Boolean.toString(disabled));
- sr.append(" />");
- executeMacro(writer, sr.toString());
- this.appendTooltip(writer, context, modelFormField);
+ writeFtlElement(writer,
renderableFtlFormElementsBuilder.checkField(context, checkField));
+ this.appendTooltip(writer, context, checkField.getModelFormField());
}
@Override
public void renderRadioField(Appendable writer, Map<String, Object>
context, RadioField radioField) throws IOException {
- ModelFormField modelFormField = radioField.getModelFormField();
- List<ModelFormField.OptionValue> allOptionValues =
radioField.getAllOptionValues(context, WidgetWorker.getDelegator(context));
- String currentValue = modelFormField.getEntry(context);
- String conditionGroup = modelFormField.getConditionGroup();
- boolean disabled = modelFormField.getDisabled(context);
- String className = "";
- String alert = "false";
- String name = modelFormField.getParameterName(context);
- String event = modelFormField.getEvent();
- String action = modelFormField.getAction(context);
- StringBuilder items = new StringBuilder();
- if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
- className = modelFormField.getWidgetStyle();
- if (modelFormField.shouldBeRed(context)) {
- alert = "true";
- }
- }
- String noCurrentSelectedKey =
radioField.getNoCurrentSelectedKey(context);
- String tabindex = modelFormField.getTabindex();
- items.append("[");
- for (ModelFormField.OptionValue optionValue : allOptionValues) {
- if (items.length() > 1) {
- items.append(",");
- }
- items.append("{'key':'");
- items.append(optionValue.getKey());
- items.append("', 'description':'" +
encode(optionValue.getDescription(), modelFormField, context));
- items.append("'}");
- }
- items.append("]");
- StringWriter sr = new StringWriter();
- sr.append("<@renderRadioField ");
- sr.append("items=");
- sr.append(items.toString());
- sr.append(" className=\"");
- sr.append(className);
- sr.append("\" alert=\"");
- sr.append(alert);
- sr.append("\" currentValue=\"");
- sr.append(currentValue);
- sr.append("\" noCurrentSelectedKey=\"");
- sr.append(noCurrentSelectedKey);
- sr.append("\" name=\"");
- sr.append(name);
- sr.append("\" event=\"");
- if (event != null) {
- sr.append(event);
- }
- sr.append("\" action=\"");
- if (action != null) {
- sr.append(action);
- }
- sr.append("\" conditionGroup=\"");
- sr.append(conditionGroup);
- sr.append("\" tabindex=\"");
- sr.append(tabindex);
- sr.append("\" disabled=");
- sr.append(Boolean.toString(disabled));
- sr.append(" />");
- executeMacro(writer, sr.toString());
- this.appendTooltip(writer, context, modelFormField);
+ writeFtlElement(writer,
renderableFtlFormElementsBuilder.radioField(context, radioField));
+ this.appendTooltip(writer, context, radioField.getModelFormField());
}
@Override
public void renderSubmitField(Appendable writer, Map<String, Object>
context, SubmitField submitField) throws IOException {
- ModelFormField modelFormField = submitField.getModelFormField();
- ModelForm modelForm = modelFormField.getModelForm();
- String id = modelFormField.getCurrentContainerId(context);
- String event = modelFormField.getEvent();
- String action = modelFormField.getAction(context);
- String title = modelFormField.getTitle(context);
- String name = modelFormField.getParameterName(context);
- String buttonType = submitField.getButtonType();
- String formName = FormRenderer.getCurrentFormName(modelForm, context);
- String imgSrc = submitField.getImageLocation(context);
- String confirmation = submitField.getConfirmation(context);
- String className = "";
- String alert = "false";
- if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
- className = modelFormField.getWidgetStyle();
- if (modelFormField.shouldBeRed(context)) {
- alert = "true";
- }
- }
- String formId = FormRenderer.getCurrentContainerId(modelForm, context);
- List<ModelForm.UpdateArea> updateAreas = new LinkedList<>();
- List<ModelForm.UpdateArea> onSubmitUpdateAreas =
modelForm.getOnSubmitUpdateAreas();
- if (UtilValidate.isNotEmpty(onSubmitUpdateAreas)) {
- updateAreas.addAll(onSubmitUpdateAreas);
- }
-
- // Retrieve on click event for submit field
- List<ModelForm.UpdateArea> onClickUpdateAreas =
modelFormField.getOnClickUpdateAreas();
- if (UtilValidate.isNotEmpty(onClickUpdateAreas)) {
- updateAreas.addAll(onClickUpdateAreas);
- }
-
- // This is here for backwards compatibility. Use on-event-update-area
- // elements instead.
- String backgroundSubmitRefreshTarget =
submitField.getBackgroundSubmitRefreshTarget(context);
- ModelForm.UpdateArea jwtCallback =
ModelForm.UpdateArea.fromJwtToken(context);
- if (UtilValidate.isNotEmpty(backgroundSubmitRefreshTarget)) {
- updateAreas.add(ModelForm.UpdateArea.literal("submit", formId,
backgroundSubmitRefreshTarget));
- }
-
- // In context a callback is present and no other update area to call
after the submit, so trigger it.
- if (UtilValidate.isEmpty(updateAreas) && jwtCallback != null &&
!submitField.getPropagateCallback()) {
- updateAreas = UtilMisc.toList(jwtCallback);
- }
- boolean ajaxEnabled = UtilValidate.isNotEmpty(updateAreas) &&
this.javaScriptEnabled;
- String ajaxUrl = "";
- if (ajaxEnabled) {
- Map<String, Object> extraParams =
CommonWidgetModels.propagateCallbackInParameterMap(context,
- submitField.getPropagateCallback(), jwtCallback);
- ajaxUrl =
MacroCommonRenderer.createAjaxParamsFromUpdateAreas(updateAreas, extraParams,
modelForm, "", context);
- }
- String tabindex = modelFormField.getTabindex();
- boolean disabled = modelFormField.getDisabled(context);
- StringWriter sr = new StringWriter();
- sr.append("<@renderSubmitField ");
- sr.append("buttonType=\"");
- sr.append(buttonType);
- sr.append("\" className=\"");
- sr.append(className);
- sr.append("\" alert=\"");
- sr.append(alert);
- sr.append("\" formName=\"");
- sr.append(formName);
- sr.append("\" title=\"");
- sr.append(encode(title, modelFormField, context));
- sr.append("\" name=\"");
- sr.append(name);
- sr.append("\" id=\"");
- sr.append(id);
- sr.append("\" event=\"");
- if (event != null) {
- sr.append(event);
- }
- sr.append("\" action=\"");
- if (action != null) {
- sr.append(action);
- }
- sr.append("\" imgSrc=\"");
- sr.append(imgSrc);
- sr.append("\" containerId=\"");
- if (ajaxEnabled) {
- sr.append(formId);
- }
- sr.append("\" confirmation =\"");
- sr.append(confirmation);
- sr.append("\" ajaxUrl=\"");
- if (ajaxEnabled) {
- sr.append(ajaxUrl);
- }
- sr.append("\" tabindex=\"");
- sr.append(tabindex);
- sr.append("\" disabled=");
- sr.append(Boolean.toString(disabled));
- sr.append(" closeOnSubmit=\"");
- sr.append(String.valueOf(!submitField.getPropagateCallback()));
- sr.append("\" />");
- executeMacro(writer, sr.toString());
- this.appendTooltip(writer, context, modelFormField);
+ writeFtlElement(writer,
renderableFtlFormElementsBuilder.submitField(context, submitField,
this.javaScriptEnabled));
+ this.appendTooltip(writer, context, submitField.getModelFormField());
}
@Override
public void renderResetField(Appendable writer, Map<String, Object>
context, ResetField resetField) throws IOException {
- ModelFormField modelFormField = resetField.getModelFormField();
- String name = modelFormField.getParameterName(context);
- String className = "";
- String alert = "false";
- if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
- className = modelFormField.getWidgetStyle();
- if (modelFormField.shouldBeRed(context)) {
- alert = "true";
- }
- }
- String title = modelFormField.getTitle(context);
- StringWriter sr = new StringWriter();
- sr.append("<@renderResetField ");
- sr.append(" className=\"");
- sr.append(className);
- sr.append("\" alert=\"");
- sr.append(alert);
- sr.append("\" name=\"");
- sr.append(name);
- sr.append("\" title=\"");
- sr.append(title);
- sr.append("\" />");
- executeMacro(writer, sr.toString());
- this.appendTooltip(writer, context, modelFormField);
+ writeFtlElement(writer,
renderableFtlFormElementsBuilder.resetField(context, resetField));
+ this.appendTooltip(writer, context, resetField.getModelFormField());
}
@Override
@@ -581,34 +323,7 @@ public final class MacroFormRenderer implements
FormStringRenderer {
@Override
public void renderHiddenField(Appendable writer, Map<String, Object>
context, ModelFormField modelFormField, String value) throws IOException {
- String name = modelFormField.getParameterName(context);
- String action = modelFormField.getAction(context);
- String conditionGroup = modelFormField.getConditionGroup();
- String event = modelFormField.getEvent();
- String id = modelFormField.getCurrentContainerId(context);
- boolean disabled = modelFormField.getDisabled(context);
- StringWriter sr = new StringWriter();
- sr.append("<@renderHiddenField ");
- sr.append(" name=\"");
- sr.append(name);
- sr.append("\" conditionGroup=\"");
- sr.append(conditionGroup);
- sr.append("\" value=\"");
- sr.append(value);
- sr.append("\" id=\"");
- sr.append(id);
- sr.append("\" event=\"");
- if (event != null) {
- sr.append(event);
- }
- sr.append("\" action=\"");
- if (action != null) {
- sr.append(action);
- }
- sr.append("\" disabled=");
- sr.append(Boolean.toString(disabled));
- sr.append(" />");
- executeMacro(writer, sr.toString());
+ writeFtlElement(writer,
renderableFtlFormElementsBuilder.hiddenField(context, modelFormField, value));
}
@Override
@@ -623,12 +338,13 @@ public final class MacroFormRenderer implements
FormStringRenderer {
String titleText = modelFormField.getTitle(context);
String style = modelFormField.getTitleStyle();
String id = modelFormField.getCurrentContainerId(context);
- StringBuilder sb = new StringBuilder();
+ String title = "";
if (UtilValidate.isNotEmpty(titleText)) {
if (" ".equals(titleText)) {
- executeMacro(writer, "<@renderFormatEmptySpace />");
+ writeFtlElement(writer,
renderableFtlFormElementsBuilder.formatEmptySpace());
} else {
titleText = UtilHttp.encodeAmpersands(titleText);
+ final String encodedTitleText = encodeForMacro(titleText,
modelFormField, context);
titleText = encode(titleText, modelFormField, context);
if (UtilValidate.isNotEmpty(modelFormField.getHeaderLink())) {
StringBuilder targetBuffer = new StringBuilder();
@@ -643,32 +359,20 @@ public final class MacroFormRenderer implements
FormStringRenderer {
StringWriter sr = new StringWriter();
makeHyperlinkString(sr,
modelFormField.getHeaderLinkStyle(), targetType, targetBuffer.toString(), null,
titleText, "",
modelFormField, this.request, this.response,
context, "");
- String title = sr.toString().replace("\"", "\'");
- sr = new StringWriter();
- sr.append("<@renderHyperlinkTitle ");
- sr.append(" name=\"");
- sr.append(modelFormField.getModelForm().getName());
- sr.append("\" title=\"");
- sr.append(MacroCommonRenderer.escapeFtlString(title));
- sr.append("\" />");
- executeMacro(writer, sr.toString());
+ String hyperlinkTitle = sr.toString().replace("\"", "\'");
+ writeFtlElement(writer,
renderableFtlFormElementsBuilder.hyperlinkTitle(modelFormField.getModelForm().getName(),
+ hyperlinkTitle, false));
} else if (modelFormField.isSortField()) {
- renderSortField(writer, context, modelFormField,
titleText);
+ renderSortField(writer, context, modelFormField,
encodedTitleText);
} else if (modelFormField.isRowSubmit()) {
- StringWriter sr = new StringWriter();
- sr.append("<@renderHyperlinkTitle ");
- sr.append(" name=\"");
- sr.append(modelFormField.getModelForm().getName());
- sr.append("\" title=\"");
- sr.append(titleText);
- sr.append("\" showSelectAll=\"Y\"/>");
- executeMacro(writer, sr.toString());
+ writeFtlElement(writer,
renderableFtlFormElementsBuilder.hyperlinkTitle(modelFormField.getModelForm().getName(),
+ encodedTitleText, true));
} else {
- sb.append(titleText);
+ title = encodedTitleText;
}
}
}
- if (!sb.toString().isEmpty()) {
+ if (!title.isEmpty()) {
//check for required field style on single forms
if (shouldApplyRequiredField(modelFormField)) {
String requiredStyle = modelFormField.getRequiredFieldStyle();
@@ -676,10 +380,7 @@ public final class MacroFormRenderer implements
FormStringRenderer {
style = requiredStyle;
}
}
- StringWriter sr = new StringWriter();
- sr.append("<@renderFieldTitle ");
- sr.append(" style=\"");
- sr.append(style);
+ String fieldHelpText = null;
String displayHelpText = UtilProperties.getPropertyValue("widget",
"widget.form.displayhelpText");
if ("Y".equals(displayHelpText)) {
Delegator delegator = WidgetWorker.getDelegator(context);
@@ -687,22 +388,9 @@ public final class MacroFormRenderer implements
FormStringRenderer {
String entityName = modelFormField.getEntityName();
String fieldName = modelFormField.getFieldName();
String helpText =
UtilHelpText.getEntityFieldDescription(entityName, fieldName, delegator,
locale);
-
- sr.append("\" fieldHelpText=\"");
- sr.append(MacroCommonRenderer.escapeFtlString(helpText));
- }
- sr.append("\" title=\"");
- sr.append(sb.toString());
- if (UtilValidate.isNotEmpty(id)) {
- sr.append("\" id=\"");
- sr.append(id);
- sr.append("_title");
- // Render "for"
- sr.append("\" for=\"");
- sr.append(id);
+ fieldHelpText = helpText == null ? "" : helpText;
}
- sr.append("\" />");
- executeMacro(writer, sr.toString());
+ writeFtlElement(writer,
renderableFtlFormElementsBuilder.fieldTitle(style, title, id, fieldHelpText));
}
}
@@ -2157,22 +1845,8 @@ public final class MacroFormRenderer implements
FormStringRenderer {
linkUrl = rh.makeLink(this.request, this.response,
urlPath.concat(UtilCodec.encodeUrl(newQueryString, context)));
}
}
- StringWriter sr = new StringWriter();
- sr.append("<@renderSortField ");
- sr.append(" style=\"");
- sr.append(sortFieldStyle);
- sr.append("\" title=\"");
- sr.append(titleText);
- sr.append("\" linkUrl=\"");
- sr.append(linkUrl);
- sr.append("\" ajaxEnabled=");
- sr.append(Boolean.toString(ajaxEnabled));
String tooltip = modelFormField.getSortFieldHelpText(context);
- if (!tooltip.isEmpty()) {
- sr.append(" tooltip=\"").append(tooltip).append("\"");
- }
- sr.append(" />");
- executeMacro(writer, sr.toString());
+ writeFtlElement(writer,
renderableFtlFormElementsBuilder.sortField(sortFieldStyle, titleText, linkUrl,
ajaxEnabled, tooltip));
}
private void appendTooltip(Appendable writer, Map<String, Object> context,
ModelFormField modelFormField) {
diff --git
a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilder.java
b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilder.java
index 1afb043407..d5171cf636 100644
---
a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilder.java
+++
b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilder.java
@@ -53,6 +53,7 @@ import
org.apache.ofbiz.base.util.string.FlexibleStringExpander;
import org.apache.ofbiz.webapp.control.RequestHandler;
import org.apache.ofbiz.widget.WidgetWorker;
import org.apache.ofbiz.widget.content.StaticContentUrlProvider;
+import org.apache.ofbiz.widget.model.CommonWidgetModels;
import org.apache.ofbiz.widget.model.ModelForm;
import org.apache.ofbiz.widget.model.ModelFormField;
import org.apache.ofbiz.widget.model.ModelFormField.ContainerField;
@@ -85,8 +86,6 @@ public final class RenderableFtlFormElementsBuilder {
private final StaticContentUrlProvider staticContentUrlProvider;
- private final UtilCodec.SimpleEncoder internalEncoder;
-
public RenderableFtlFormElementsBuilder(final VisualTheme visualTheme,
final RequestHandler requestHandler,
final HttpServletRequest request,
final HttpServletResponse response,
final StaticContentUrlProvider
staticContentUrlProvider) {
@@ -95,7 +94,6 @@ public final class RenderableFtlFormElementsBuilder {
this.request = request;
this.response = response;
this.staticContentUrlProvider = staticContentUrlProvider;
- this.internalEncoder = UtilCodec.getEncoder("string");
}
public RenderableFtl tooltip(final Map<String, Object> context, final
ModelFormField modelFormField) {
@@ -1277,8 +1275,6 @@ public final class RenderableFtlFormElementsBuilder {
UtilCodec.SimpleEncoder encoder = (UtilCodec.SimpleEncoder)
context.get("simpleEncoder");
if (modelFormField.getEncodeOutput() && encoder != null) {
value = encoder.encode(value);
- } else {
- value = internalEncoder.encode(value);
}
return value;
}
@@ -1296,6 +1292,280 @@ public final class RenderableFtlFormElementsBuilder {
.orElse(value);
}
+ /**
+ * Creates the macro call that renders the check boxes of a check field.
+ * @param context the context
+ * @param checkField the check field
+ * @return the RenderableFtl
+ */
+ public RenderableFtl checkField(final Map<String, Object> context, final
ModelFormField.CheckField checkField) {
+ final ModelFormField modelFormField = checkField.getModelFormField();
+ final String currentValue = modelFormField.getEntry(context);
+ final Boolean allChecked = checkField.isAllChecked(context);
+ final String checkBox = modelFormField.getAttributeName();
+
+ List<String> checkedByDefault = Collections.emptyList();
+ final Object checkBoxValue = context.get(checkBox);
+ if (checkBoxValue != null &&
!checkBoxValue.getClass().equals(String.class)) {
+ checkedByDefault = StringUtil.toList(checkBoxValue.toString());
+ }
+
+ List<String> currentValueList = null;
+ if (UtilValidate.isNotEmpty(currentValue)) {
+ currentValueList = currentValue.startsWith("[") ?
StringUtil.toList(currentValue) : UtilMisc.toList(currentValue);
+ }
+
+ final List<Map<String, String>> items = new ArrayList<>();
+ for (final ModelFormField.OptionValue optionValue :
checkField.getAllOptionValues(context, WidgetWorker.getDelegator(context))) {
+ final boolean checked;
+ if (UtilValidate.isNotEmpty(currentValueList)) {
+ checked = currentValueList.contains(optionValue.getKey());
+ } else if (UtilValidate.isNotEmpty(checkedByDefault)) {
+ checked = checkedByDefault.contains(optionValue.getKey());
+ } else {
+ checked = allChecked;
+ }
+ items.add(Map.of(
+ "value", nonNull(optionValue.getKey()),
+ "description",
nonNull(encode(optionValue.getDescription(), modelFormField, context)),
+ "checked", String.valueOf(checked)));
+ }
+
+ final var builder =
RenderableFtlMacroCall.builder().name("renderCheckField");
+ applyWidgetStyleAndAlert(modelFormField, context, builder);
+ return builder
+ .objectParameter("items", items)
+ .stringParameter("id",
nonNull(modelFormField.getCurrentContainerId(context)))
+ .stringParameter("conditionGroup",
nonNull(modelFormField.getConditionGroup()))
+ .stringParameter("currentValue", nonNull(currentValue))
+ .stringParameter("name",
nonNull(modelFormField.getParameterName(context)))
+ .stringParameter("event", nonNull(modelFormField.getEvent()))
+ .stringParameter("action",
nonNull(modelFormField.getAction(context)))
+ .stringParameter("tabindex",
nonNull(modelFormField.getTabindex()))
+ .booleanParameter("disabled",
modelFormField.getDisabled(context))
+ .build();
+ }
+
+ /**
+ * Creates the macro call that renders the radio buttons of a radio field.
+ * @param context the context
+ * @param radioField the radio field
+ * @return the RenderableFtl
+ */
+ public RenderableFtl radioField(final Map<String, Object> context, final
ModelFormField.RadioField radioField) {
+ final ModelFormField modelFormField = radioField.getModelFormField();
+
+ final List<Map<String, String>> items = new ArrayList<>();
+ for (final ModelFormField.OptionValue optionValue :
radioField.getAllOptionValues(context, WidgetWorker.getDelegator(context))) {
+ items.add(Map.of(
+ "key", nonNull(optionValue.getKey()),
+ "description",
nonNull(encode(optionValue.getDescription(), modelFormField, context))));
+ }
+
+ final var builder =
RenderableFtlMacroCall.builder().name("renderRadioField");
+ applyWidgetStyleAndAlert(modelFormField, context, builder);
+ return builder
+ .objectParameter("items", items)
+ .stringParameter("currentValue",
nonNull(modelFormField.getEntry(context)))
+ .stringParameter("noCurrentSelectedKey",
nonNull(radioField.getNoCurrentSelectedKey(context)))
+ .stringParameter("name",
nonNull(modelFormField.getParameterName(context)))
+ .stringParameter("event", nonNull(modelFormField.getEvent()))
+ .stringParameter("action",
nonNull(modelFormField.getAction(context)))
+ .stringParameter("conditionGroup",
nonNull(modelFormField.getConditionGroup()))
+ .stringParameter("tabindex",
nonNull(modelFormField.getTabindex()))
+ .booleanParameter("disabled",
modelFormField.getDisabled(context))
+ .build();
+ }
+
+ /**
+ * Creates the macro call that renders a submit button.
+ * @param context the context
+ * @param submitField the submit field
+ * @param javaScriptEnabled whether JavaScript is enabled in the browser
of the user
+ * @return the RenderableFtl
+ */
+ public RenderableFtl submitField(final Map<String, Object> context, final
ModelFormField.SubmitField submitField,
+ final boolean javaScriptEnabled) {
+ final ModelFormField modelFormField = submitField.getModelFormField();
+ final ModelForm modelForm = modelFormField.getModelForm();
+ final String formId = FormRenderer.getCurrentContainerId(modelForm,
context);
+
+ List<ModelForm.UpdateArea> updateAreas = new ArrayList<>();
+ final List<ModelForm.UpdateArea> onSubmitUpdateAreas =
modelForm.getOnSubmitUpdateAreas();
+ if (UtilValidate.isNotEmpty(onSubmitUpdateAreas)) {
+ updateAreas.addAll(onSubmitUpdateAreas);
+ }
+
+ // Retrieve on click event for submit field
+ final List<ModelForm.UpdateArea> onClickUpdateAreas =
modelFormField.getOnClickUpdateAreas();
+ if (UtilValidate.isNotEmpty(onClickUpdateAreas)) {
+ updateAreas.addAll(onClickUpdateAreas);
+ }
+
+ // This is here for backwards compatibility. Use on-event-update-area
elements instead.
+ final String backgroundSubmitRefreshTarget =
submitField.getBackgroundSubmitRefreshTarget(context);
+ final ModelForm.UpdateArea jwtCallback =
ModelForm.UpdateArea.fromJwtToken(context);
+ if (UtilValidate.isNotEmpty(backgroundSubmitRefreshTarget)) {
+ updateAreas.add(ModelForm.UpdateArea.literal("submit", formId,
backgroundSubmitRefreshTarget));
+ }
+
+ // In context a callback is present and no other update area to call
after the submit, so trigger it.
+ if (UtilValidate.isEmpty(updateAreas) && jwtCallback != null &&
!submitField.getPropagateCallback()) {
+ updateAreas = UtilMisc.toList(jwtCallback);
+ }
+ final boolean ajaxEnabled = UtilValidate.isNotEmpty(updateAreas) &&
javaScriptEnabled;
+ String ajaxUrl = "";
+ if (ajaxEnabled) {
+ final Map<String, Object> extraParams =
CommonWidgetModels.propagateCallbackInParameterMap(context,
+ submitField.getPropagateCallback(), jwtCallback);
+ ajaxUrl =
MacroCommonRenderer.createAjaxParamsFromUpdateAreas(updateAreas, extraParams,
modelForm, "", context);
+ }
+
+ final var builder =
RenderableFtlMacroCall.builder().name("renderSubmitField");
+ applyWidgetStyleAndAlert(modelFormField, context, builder);
+ return builder
+ .stringParameter("buttonType",
nonNull(submitField.getButtonType()))
+ .stringParameter("formName",
nonNull(FormRenderer.getCurrentFormName(modelForm, context)))
+ .stringParameter("title",
nonNull(encode(modelFormField.getTitle(context), modelFormField, context)))
+ .stringParameter("name",
nonNull(modelFormField.getParameterName(context)))
+ .stringParameter("id",
nonNull(modelFormField.getCurrentContainerId(context)))
+ .stringParameter("event", nonNull(modelFormField.getEvent()))
+ .stringParameter("action",
nonNull(modelFormField.getAction(context)))
+ .stringParameter("imgSrc",
nonNull(submitField.getImageLocation(context)))
+ .stringParameter("containerId", ajaxEnabled ? nonNull(formId)
: "")
+ .stringParameter("confirmation",
nonNull(submitField.getConfirmation(context)))
+ .stringParameter("ajaxUrl", ajaxEnabled ? nonNull(ajaxUrl) :
"")
+ .stringParameter("tabindex",
nonNull(modelFormField.getTabindex()))
+ .booleanParameter("disabled",
modelFormField.getDisabled(context))
+ .stringParameter("closeOnSubmit",
String.valueOf(!submitField.getPropagateCallback()))
+ .build();
+ }
+
+ /**
+ * Creates the macro call that renders a reset button.
+ * @param context the context
+ * @param resetField the reset field
+ * @return the RenderableFtl
+ */
+ public RenderableFtl resetField(final Map<String, Object> context, final
ModelFormField.ResetField resetField) {
+ final ModelFormField modelFormField = resetField.getModelFormField();
+ final var builder =
RenderableFtlMacroCall.builder().name("renderResetField");
+ applyWidgetStyleAndAlert(modelFormField, context, builder);
+ return builder
+ .stringParameter("name",
nonNull(modelFormField.getParameterName(context)))
+ .stringParameter("title",
nonNull(modelFormField.getTitle(context)))
+ .build();
+ }
+
+ /**
+ * Creates the macro call that renders a hidden field.
+ * @param context the context
+ * @param modelFormField the form field
+ * @param value the value of the field, which may contain the quotes
escaped for a FreeMarker string literal
+ * @return the RenderableFtl
+ */
+ public RenderableFtl hiddenField(final Map<String, Object> context, final
ModelFormField modelFormField, final String value) {
+ return RenderableFtlMacroCall.builder()
+ .name("renderHiddenField")
+ .stringParameter("name",
nonNull(modelFormField.getParameterName(context)))
+ .stringParameter("conditionGroup",
nonNull(modelFormField.getConditionGroup()))
+ // the form fields escape the double quotes with a backslash
because the value was a FreeMarker string literal
+ .stringParameter("value", nonNull(value).replace("\\\"", "\""))
+ .stringParameter("id",
nonNull(modelFormField.getCurrentContainerId(context)))
+ .stringParameter("event", nonNull(modelFormField.getEvent()))
+ .stringParameter("action",
nonNull(modelFormField.getAction(context)))
+ .booleanParameter("disabled",
modelFormField.getDisabled(context))
+ .build();
+ }
+
+ /**
+ * Creates the macro call that renders an empty field title.
+ * @return the RenderableFtl
+ */
+ public RenderableFtl formatEmptySpace() {
+ return
RenderableFtlMacroCall.builder().name("renderFormatEmptySpace").build();
+ }
+
+ /**
+ * Creates the macro call that renders a field title made of a link or of
a select all check box.
+ * @param formName the name of the form
+ * @param title the title, which can contain HTML
+ * @param showSelectAll true to show the select all check box
+ * @return the RenderableFtl
+ */
+ public RenderableFtl hyperlinkTitle(final String formName, final String
title, final boolean showSelectAll) {
+ final var builder = RenderableFtlMacroCall.builder()
+ .name("renderHyperlinkTitle")
+ .stringParameter("name", nonNull(formName))
+ .stringParameter("title", nonNull(title));
+ if (showSelectAll) {
+ builder.stringParameter("showSelectAll", "Y");
+ }
+ return builder.build();
+ }
+
+ /**
+ * Creates the macro call that renders a field title.
+ * @param style the style of the title
+ * @param title the title
+ * @param id the id of the field, or empty if the title has no id and does
not refer to a field
+ * @param fieldHelpText the help text of the field, or null if there is
none to show
+ * @return the RenderableFtl
+ */
+ public RenderableFtl fieldTitle(final String style, final String title,
final String id, final String fieldHelpText) {
+ final var builder = RenderableFtlMacroCall.builder()
+ .name("renderFieldTitle")
+ .stringParameter("style", nonNull(style))
+ .stringParameter("title", nonNull(title));
+ if (fieldHelpText != null) {
+ builder.stringParameter("fieldHelpText", fieldHelpText);
+ }
+ if (UtilValidate.isNotEmpty(id)) {
+ builder.stringParameter("id", id +
"_title").stringParameter("for", id);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Creates the macro call that renders a field title which sorts the list
when clicked.
+ * @param style the style of the link
+ * @param title the title
+ * @param linkUrl the url of the link
+ * @param ajaxEnabled true if the link updates areas of the page
+ * @param tooltip the tooltip, or empty if there is none
+ * @return the RenderableFtl
+ */
+ public RenderableFtl sortField(final String style, final String title,
final String linkUrl, final boolean ajaxEnabled,
+ final String tooltip) {
+ final var builder = RenderableFtlMacroCall.builder()
+ .name("renderSortField")
+ .stringParameter("style", nonNull(style))
+ .stringParameter("title", nonNull(title))
+ .stringParameter("linkUrl", nonNull(linkUrl))
+ .booleanParameter("ajaxEnabled", ajaxEnabled);
+ if (UtilValidate.isNotEmpty(tooltip)) {
+ builder.stringParameter("tooltip", tooltip);
+ }
+ return builder.build();
+ }
+
+ private static String nonNull(final String value) {
+ return value == null ? "" : value;
+ }
+
+ private static void applyWidgetStyleAndAlert(final ModelFormField
modelFormField, final Map<String, Object> context,
+ final
RenderableFtlMacroCallBuilder builder) {
+ String className = "";
+ String alert = "false";
+ if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
+ className = modelFormField.getWidgetStyle();
+ if (modelFormField.shouldBeRed(context)) {
+ alert = "true";
+ }
+ }
+ builder.stringParameter("className",
className).stringParameter("alert", alert);
+ }
+
private static void applyCommonStyling(final ModelFormField
modelFormField, final Map<String, Object> context,
final RenderableFtlMacroCallBuilder
builder) {
final var classNames = new ArrayList<String>();
diff --git
a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
index 40097f106c..ab1574b133 100644
---
a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
+++
b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
@@ -42,7 +42,6 @@ import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.StringWriter;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -74,7 +73,6 @@ import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.MockedStatic;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import freemarker.core.Environment;
@@ -265,92 +263,49 @@ public final class MacroFormRendererTest {
@Test
public void checkFieldMacroRendered() throws IOException {
final ModelFormField.CheckField checkField =
mock(ModelFormField.CheckField.class);
- when(checkField.getModelFormField()).thenReturn(modelFormField);
- final List<ModelFormField.OptionValue> optionValues = ImmutableList.of(
- new ModelFormField.OptionValue("KEY1", "DESC1"),
- new ModelFormField.OptionValue("KEY2", "DESC2"),
- new ModelFormField.OptionValue("KEY3", "DESC3"),
- new ModelFormField.OptionValue("KEY4", "DESC4"));
-
- when(modelFormField.getEntry(notNull())).thenReturn("KEY2");
- when(checkField.getAllOptionValues(notNull(),
any())).thenReturn(optionValues);
+ when(renderableFtlFormElementsBuilder.checkField(notNull(),
eq(checkField))).thenReturn(genericMacroCall);
+ genericTooltipRenderedExpectation(checkField);
macroFormRenderer.renderCheckField(appendable, ImmutableMap.of(),
checkField);
- assertAndGetMacroString("renderCheckField", ImmutableMap.of(
- "currentValue", "KEY2",
- "items", ImmutableList.of(
- "{'value':'KEY1', 'description':'DESC1',
'checked':'false'}",
- "{'value':'KEY2', 'description':'DESC2',
'checked':'true'}",
- "{'value':'KEY3', 'description':'DESC3',
'checked':'false'}",
- "{'value':'KEY4', 'description':'DESC4',
'checked':'false'}")));
-
- when(modelFormField.getEntry(notNull())).thenReturn("");
-
when(checkField.getModelFormField().getAttributeName()).thenReturn("FieldName");
-
- StringWriter writer = new StringWriter();
- Map<String, Object> context = new HashMap<>();
- List<String> fieldName = new ArrayList<>();
- fieldName.add("KEY1");
- fieldName.add("KEY3");
- context.put("FieldName", fieldName);
-
- try {
- macroFormRenderer.renderCheckField(writer, context, checkField);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- assertAndGetMacroString("renderCheckField", ImmutableMap.of(
- "items", ImmutableList.of(
- "{'value':'KEY1', 'description':'DESC1',
'checked':'true'}",
- "{'value':'KEY2', 'description':'DESC2',
'checked':'false'}",
- "{'value':'KEY3', 'description':'DESC3',
'checked':'true'}",
- "{'value':'KEY4', 'description':'DESC4',
'checked':'false'}")));
+ genericSingleMacroRenderedVerification();
+ genericTooltipRenderedVerification();
}
@Test
public void radioFieldMacroRendered() throws IOException {
final ModelFormField.RadioField radioField =
mock(ModelFormField.RadioField.class);
- when(radioField.getModelFormField()).thenReturn(modelFormField);
- final List<ModelFormField.OptionValue> optionValues = ImmutableList.of(
- new ModelFormField.OptionValue("KEY1", "DESC1"),
- new ModelFormField.OptionValue("KEY2", "DESC2"));
-
- when(modelFormField.getEntry(notNull())).thenReturn("KEY2");
- when(radioField.getAllOptionValues(notNull(),
any())).thenReturn(optionValues);
+ when(renderableFtlFormElementsBuilder.radioField(notNull(),
eq(radioField))).thenReturn(genericMacroCall);
+ genericTooltipRenderedExpectation(radioField);
macroFormRenderer.renderRadioField(appendable, ImmutableMap.of(),
radioField);
- assertAndGetMacroString("renderRadioField", ImmutableMap.of(
- "currentValue", "KEY2",
- "items", ImmutableList.of("{'key':'KEY1',
'description':'DESC1'}",
- "{'key':'KEY2', 'description':'DESC2'}")));
+
+ genericSingleMacroRenderedVerification();
+ genericTooltipRenderedVerification();
}
@Test
public void submitFieldMacroRendered() throws IOException {
final ModelFormField.SubmitField submitField =
mock(ModelFormField.SubmitField.class);
- when(submitField.getModelFormField()).thenReturn(modelFormField);
- when(modelFormField.getTitle(notNull())).thenReturn("BUTTONTITLE");
- // renderSubmitField() does
updateAreas.addAll(modelForm.getOnSubmitUpdateAreas()) unconditionally
- // once the isNotEmpty() guard passes. JMockit's cascading defaults an
unstubbed array-returning
- // call to an empty array; Mockito's deep-stub default is null, and
AbstractCollection.addAll()
- // dereferences Collection.toArray() without a null-check - needs an
explicit non-null list here.
-
when(modelFormField.getModelForm().getOnSubmitUpdateAreas()).thenReturn(new
ArrayList<>());
- when(modelFormField.getOnClickUpdateAreas()).thenReturn(new
ArrayList<>());
+ when(renderableFtlFormElementsBuilder.submitField(notNull(),
eq(submitField), anyBoolean())).thenReturn(genericMacroCall);
+ genericTooltipRenderedExpectation(submitField);
macroFormRenderer.renderSubmitField(appendable, ImmutableMap.of(),
submitField);
- assertAndGetMacroString("renderSubmitField", ImmutableMap.of("title",
"BUTTONTITLE"));
+
+ genericSingleMacroRenderedVerification();
+ genericTooltipRenderedVerification();
}
@Test
public void resetFieldMacroRendered() throws IOException {
final ModelFormField.ResetField resetField =
mock(ModelFormField.ResetField.class);
- when(resetField.getModelFormField()).thenReturn(modelFormField);
- when(modelFormField.getTitle(notNull())).thenReturn("BUTTONTITLE");
+ when(renderableFtlFormElementsBuilder.resetField(notNull(),
eq(resetField))).thenReturn(genericMacroCall);
+ genericTooltipRenderedExpectation(resetField);
macroFormRenderer.renderResetField(appendable, ImmutableMap.of(),
resetField);
- assertAndGetMacroString("renderResetField", ImmutableMap.of("title",
"BUTTONTITLE"));
+
+ genericSingleMacroRenderedVerification();
+ genericTooltipRenderedVerification();
}
@Test
@@ -358,25 +313,44 @@ public final class MacroFormRendererTest {
final ModelFormField.HiddenField hiddenField =
mock(ModelFormField.HiddenField.class);
when(hiddenField.getModelFormField()).thenReturn(modelFormField);
when(hiddenField.getValue(notNull())).thenReturn("HIDDENVALUE");
+ when(renderableFtlFormElementsBuilder.hiddenField(notNull(),
eq(modelFormField), eq("HIDDENVALUE"))).thenReturn(genericMacroCall);
macroFormRenderer.renderHiddenField(appendable, ImmutableMap.of(),
hiddenField);
- assertAndGetMacroString("renderHiddenField", ImmutableMap.of("value",
"HIDDENVALUE"));
+
+ genericSingleMacroRenderedVerification();
}
@Test
public void emptyFieldTitleMacroRendered() throws IOException {
when(modelFormField.getTitle(notNull())).thenReturn(" ");
+
when(renderableFtlFormElementsBuilder.formatEmptySpace()).thenReturn(genericMacroCall);
macroFormRenderer.renderFieldTitle(appendable, ImmutableMap.of(),
modelFormField);
- assertAndGetMacroString("renderFormatEmptySpace");
+
+ genericSingleMacroRenderedVerification();
}
@Test
public void fieldTitleMacroRendered() throws IOException {
when(modelFormField.getTitle(notNull())).thenReturn("FIELDTITLE");
+
when(renderableFtlFormElementsBuilder.fieldTitle(nullable(String.class),
eq("FIELDTITLE"), nullable(String.class),
+ nullable(String.class))).thenReturn(genericMacroCall);
+
+ macroFormRenderer.renderFieldTitle(appendable, ImmutableMap.of(),
modelFormField);
+
+ genericSingleMacroRenderedVerification();
+ }
+
+ @Test
+ public void rowSubmitFieldTitleMacroRendered() throws IOException {
+ when(modelFormField.getTitle(notNull())).thenReturn("FIELDTITLE");
+ when(modelFormField.isRowSubmit()).thenReturn(true);
+ when(modelFormField.getModelForm().getName()).thenReturn("FORMNAME");
+ when(renderableFtlFormElementsBuilder.hyperlinkTitle("FORMNAME",
"FIELDTITLE", true)).thenReturn(genericMacroCall);
macroFormRenderer.renderFieldTitle(appendable, ImmutableMap.of(),
modelFormField);
- assertAndGetMacroString("renderFieldTitle", ImmutableMap.of("title",
"FIELDTITLE"));
+
+ genericSingleMacroRenderedVerification();
}
@Test
@@ -635,11 +609,13 @@ public final class MacroFormRendererTest {
when(modelFormField.getModelForm()).thenReturn(modelForm);
when(modelForm.getPaginateTarget(notNull())).thenReturn(paginateTarget);
when(modelFormField.getSortFieldHelpText(notNull())).thenReturn("HELPTEXT");
+
when(renderableFtlFormElementsBuilder.sortField(nullable(String.class),
eq("TITLE"), nullable(String.class), eq(false),
+ eq("HELPTEXT"))).thenReturn(genericMacroCall);
final Map<String, Object> context = new HashMap<>();
macroFormRenderer.renderSortField(appendable, context, modelFormField,
"TITLE");
- assertAndGetMacroString("renderSortField", ImmutableMap.of("title",
"TITLE"));
+ genericSingleMacroRenderedVerification();
}
@Test
@@ -704,14 +680,15 @@ public final class MacroFormRendererTest {
when(modelForm.getPaginateTarget(notNull())).thenReturn(paginateTarget);
when(requestHandler.makeLink(notNull(), notNull(),
contains(qbeString))).thenReturn(linkFromQbeString);
when(modelFormField.getSortFieldHelpText(notNull())).thenReturn("HELPTEXT");
+
when(renderableFtlFormElementsBuilder.sortField(nullable(String.class), eq(""),
eq(linkFromQbeString), eq(false),
+ eq("HELPTEXT"))).thenReturn(genericMacroCall);
final Map<String, Object> context = new HashMap<>();
context.put("_QBESTRING_", qbeString);
context.put("listSize", 100);
macroFormRenderer.renderSortField(appendable, context, modelFormField,
"");
- assertAndGetMacroString("renderSortField", ImmutableMap.of(
- "linkUrl", new FreemarkerRawString(linkFromQbeString)));
+ genericSingleMacroRenderedVerification();
}
@Test
diff --git
a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilderTest.java
b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilderTest.java
index 35b3213e96..0bbb861ba3 100644
---
a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilderTest.java
+++
b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/RenderableFtlFormElementsBuilderTest.java
@@ -36,6 +36,7 @@ import org.junit.jupiter.api.Test;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -43,6 +44,9 @@ import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.hasKey;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@@ -537,4 +541,181 @@ public final class RenderableFtlFormElementsBuilderTest {
assertThat(renderableFtl,
MacroCallMatcher.hasParameters(MacroCallParameterMatcher.hasNameAndStringValue("timePickerIncrement",
"5")));
assertThat(renderableFtl,
MacroCallMatcher.hasParameters(MacroCallParameterMatcher.hasNameAndBooleanValue("timePickerSeconds",
true)));
}
+
+ private static List<ModelFormField.OptionValue> threeOptions() {
+ final List<ModelFormField.OptionValue> optionValues = new
ArrayList<>();
+ optionValues.add(new ModelFormField.OptionValue("KEY1", "DESC1"));
+ optionValues.add(new ModelFormField.OptionValue("KEY2", "DESC2"));
+ optionValues.add(new ModelFormField.OptionValue("KEY3", "DESC3"));
+ return optionValues;
+ }
+
+ private static Map<String, String> checkItem(final String key, final
String description, final boolean checked) {
+ return Map.of("value", key, "description", description, "checked",
Boolean.toString(checked));
+ }
+
+ @Test
+ public void checkFieldChecksTheCurrentValue() {
+ final ModelFormField.CheckField checkField =
mock(ModelFormField.CheckField.class);
+ when(checkField.getModelFormField()).thenReturn(modelFormField);
+ when(checkField.isAllChecked(notNull())).thenReturn(false);
+ when(checkField.getAllOptionValues(notNull(),
any())).thenReturn(threeOptions());
+ when(modelFormField.getEntry(notNull())).thenReturn("KEY2");
+
+ final RenderableFtlMacroCall macroCall = (RenderableFtlMacroCall)
renderableFtlFormElementsBuilder.checkField(new HashMap<>(), checkField);
+ assertThat(macroCall,
MacroCallMatcher.hasNameAndParameters("renderCheckField",
+
MacroCallParameterMatcher.hasNameAndStringValue("currentValue", "KEY2")));
+ assertThat(macroCall.getParameters().get("items"), equalTo(List.of(
+ checkItem("KEY1", "DESC1", false), checkItem("KEY2", "DESC2",
true), checkItem("KEY3", "DESC3", false))));
+ }
+
+ @Test
+ public void
checkFieldChecksTheValuesOfTheContextWhenThereIsNoCurrentValue() {
+ final ModelFormField.CheckField checkField =
mock(ModelFormField.CheckField.class);
+ when(checkField.getModelFormField()).thenReturn(modelFormField);
+ when(checkField.isAllChecked(notNull())).thenReturn(false);
+ when(checkField.getAllOptionValues(notNull(),
any())).thenReturn(threeOptions());
+ when(modelFormField.getEntry(notNull())).thenReturn("");
+ when(modelFormField.getAttributeName()).thenReturn("FieldName");
+
+ final Map<String, Object> context = new HashMap<>();
+ context.put("FieldName", List.of("KEY1", "KEY3"));
+
+ final RenderableFtlMacroCall macroCall = (RenderableFtlMacroCall)
renderableFtlFormElementsBuilder.checkField(context, checkField);
+ assertThat(macroCall.getParameters().get("items"), equalTo(List.of(
+ checkItem("KEY1", "DESC1", true), checkItem("KEY2", "DESC2",
false), checkItem("KEY3", "DESC3", true))));
+ }
+
+ @Test
+ public void checkFieldPassesKeysAndDescriptionsAsTheyAre() {
+ final ModelFormField.CheckField checkField =
mock(ModelFormField.CheckField.class);
+ when(checkField.getModelFormField()).thenReturn(modelFormField);
+ when(checkField.isAllChecked(notNull())).thenReturn(false);
+ final List<ModelFormField.OptionValue> optionValues = new
ArrayList<>();
+ optionValues.add(new ModelFormField.OptionValue("it's ${1+1}", "say
\"hi\" \\ #{2}"));
+ when(checkField.getAllOptionValues(notNull(),
any())).thenReturn(optionValues);
+ when(modelFormField.getEntry(notNull())).thenReturn("");
+
+ final RenderableFtlMacroCall macroCall = (RenderableFtlMacroCall)
renderableFtlFormElementsBuilder.checkField(new HashMap<>(), checkField);
+ assertThat(macroCall.getParameters().get("items"), equalTo(List.of(
+ checkItem("it's ${1+1}", "say \"hi\" \\ #{2}", false))));
+ }
+
+ @Test
+ public void radioFieldSetsItemsCurrentValueAndNoCurrentSelectedKey() {
+ final ModelFormField.RadioField radioField =
mock(ModelFormField.RadioField.class);
+ when(radioField.getModelFormField()).thenReturn(modelFormField);
+ when(radioField.getAllOptionValues(notNull(),
any())).thenReturn(threeOptions());
+
when(radioField.getNoCurrentSelectedKey(notNull())).thenReturn("NOKEY");
+ when(modelFormField.getEntry(notNull())).thenReturn("KEY2");
+
+ final RenderableFtlMacroCall macroCall = (RenderableFtlMacroCall)
renderableFtlFormElementsBuilder.radioField(new HashMap<>(), radioField);
+ assertThat(macroCall,
MacroCallMatcher.hasNameAndParameters("renderRadioField",
+
MacroCallParameterMatcher.hasNameAndStringValue("currentValue", "KEY2"),
+
MacroCallParameterMatcher.hasNameAndStringValue("noCurrentSelectedKey",
"NOKEY")));
+ assertThat(macroCall.getParameters().get("items"), equalTo(List.of(
+ Map.of("key", "KEY1", "description", "DESC1"),
+ Map.of("key", "KEY2", "description", "DESC2"),
+ Map.of("key", "KEY3", "description", "DESC3"))));
+ }
+
+ @Test
+ public void submitFieldSetsTitleAndDoesNotUseAjaxWithoutUpdateAreas() {
+ final ModelFormField.SubmitField submitField =
mock(ModelFormField.SubmitField.class);
+ when(submitField.getModelFormField()).thenReturn(modelFormField);
+ when(modelFormField.getTitle(notNull())).thenReturn("BUTTONTITLE");
+
when(modelFormField.getModelForm().getOnSubmitUpdateAreas()).thenReturn(new
ArrayList<>());
+ when(modelFormField.getOnClickUpdateAreas()).thenReturn(new
ArrayList<>());
+
+ final RenderableFtl renderableFtl =
renderableFtlFormElementsBuilder.submitField(new HashMap<>(), submitField,
true);
+ assertThat(renderableFtl,
MacroCallMatcher.hasNameAndParameters("renderSubmitField",
+ MacroCallParameterMatcher.hasNameAndStringValue("title",
"BUTTONTITLE"),
+ MacroCallParameterMatcher.hasNameAndStringValue("containerId",
""),
+ MacroCallParameterMatcher.hasNameAndStringValue("ajaxUrl", ""),
+
MacroCallParameterMatcher.hasNameAndStringValue("closeOnSubmit", "true")));
+ }
+
+ @Test
+ public void resetFieldSetsTitleAndName() {
+ final ModelFormField.ResetField resetField =
mock(ModelFormField.ResetField.class);
+ when(resetField.getModelFormField()).thenReturn(modelFormField);
+ when(modelFormField.getTitle(notNull())).thenReturn("BUTTONTITLE");
+
when(modelFormField.getParameterName(notNull())).thenReturn("PARAMNAME");
+
+ final RenderableFtl renderableFtl =
renderableFtlFormElementsBuilder.resetField(new HashMap<>(), resetField);
+ assertThat(renderableFtl,
MacroCallMatcher.hasNameAndParameters("renderResetField",
+ MacroCallParameterMatcher.hasNameAndStringValue("title",
"BUTTONTITLE"),
+ MacroCallParameterMatcher.hasNameAndStringValue("name",
"PARAMNAME")));
+ }
+
+ @Test
+ public void hiddenFieldSetsTheValue() {
+
when(modelFormField.getParameterName(notNull())).thenReturn("PARAMNAME");
+
+ final RenderableFtl renderableFtl =
renderableFtlFormElementsBuilder.hiddenField(new HashMap<>(), modelFormField,
"HIDDENVALUE");
+ assertThat(renderableFtl,
MacroCallMatcher.hasNameAndParameters("renderHiddenField",
+ MacroCallParameterMatcher.hasNameAndStringValue("name",
"PARAMNAME"),
+ MacroCallParameterMatcher.hasNameAndStringValue("value",
"HIDDENVALUE")));
+ }
+
+ @Test
+ public void hiddenFieldRemovesTheBackslashOfTheEscapedQuotes() {
+ final RenderableFtl renderableFtl =
renderableFtlFormElementsBuilder.hiddenField(new HashMap<>(), modelFormField,
"say \\\"hi\\\"");
+ assertThat(renderableFtl,
MacroCallMatcher.hasNameAndParameters("renderHiddenField",
+ MacroCallParameterMatcher.hasNameAndStringValue("value", "say
\"hi\"")));
+ }
+
+ @Test
+ public void formatEmptySpaceHasNoParameters() {
+ final RenderableFtlMacroCall macroCall = (RenderableFtlMacroCall)
renderableFtlFormElementsBuilder.formatEmptySpace();
+ assertThat(macroCall.getName(), equalTo("renderFormatEmptySpace"));
+ assertThat(macroCall.getParameters().isEmpty(), equalTo(true));
+ }
+
+ @Test
+ public void hyperlinkTitleShowsTheSelectAllOnlyWhenAsked() {
+ final RenderableFtlMacroCall withSelectAll = (RenderableFtlMacroCall)
renderableFtlFormElementsBuilder.hyperlinkTitle("FORM", "TITLE", true);
+ assertThat(withSelectAll,
MacroCallMatcher.hasNameAndParameters("renderHyperlinkTitle",
+ MacroCallParameterMatcher.hasNameAndStringValue("name",
"FORM"),
+ MacroCallParameterMatcher.hasNameAndStringValue("title",
"TITLE"),
+
MacroCallParameterMatcher.hasNameAndStringValue("showSelectAll", "Y")));
+
+ final RenderableFtlMacroCall withoutSelectAll =
+ (RenderableFtlMacroCall)
renderableFtlFormElementsBuilder.hyperlinkTitle("FORM", "TITLE", false);
+ assertThat(withoutSelectAll.getParameters(),
not(hasKey("showSelectAll")));
+ }
+
+ @Test
+ public void fieldTitleSetsIdAndForOnlyWithAnId() {
+ final RenderableFtlMacroCall withId = (RenderableFtlMacroCall)
renderableFtlFormElementsBuilder.fieldTitle("STYLE", "TITLE", "FIELDID", null);
+ assertThat(withId,
MacroCallMatcher.hasNameAndParameters("renderFieldTitle",
+ MacroCallParameterMatcher.hasNameAndStringValue("style",
"STYLE"),
+ MacroCallParameterMatcher.hasNameAndStringValue("title",
"TITLE"),
+ MacroCallParameterMatcher.hasNameAndStringValue("id",
"FIELDID_title"),
+ MacroCallParameterMatcher.hasNameAndStringValue("for",
"FIELDID")));
+ assertThat(withId.getParameters(), not(hasKey("fieldHelpText")));
+
+ final RenderableFtlMacroCall withoutId = (RenderableFtlMacroCall)
renderableFtlFormElementsBuilder.fieldTitle("STYLE", "TITLE", "", "HELP");
+ assertThat(withoutId.getParameters(), not(hasKey("id")));
+ assertThat(withoutId.getParameters(), not(hasKey("for")));
+ assertThat(withoutId,
MacroCallMatcher.hasNameAndParameters("renderFieldTitle",
+
MacroCallParameterMatcher.hasNameAndStringValue("fieldHelpText", "HELP")));
+ }
+
+ @Test
+ public void sortFieldSetsTheLinkAndOmitsAnEmptyTooltip() {
+ final RenderableFtlMacroCall macroCall =
+ (RenderableFtlMacroCall)
renderableFtlFormElementsBuilder.sortField("STYLE", "TITLE", "/target?x=1",
true, "");
+ assertThat(macroCall,
MacroCallMatcher.hasNameAndParameters("renderSortField",
+ MacroCallParameterMatcher.hasNameAndStringValue("style",
"STYLE"),
+ MacroCallParameterMatcher.hasNameAndStringValue("title",
"TITLE"),
+ MacroCallParameterMatcher.hasNameAndStringValue("linkUrl",
"/target?x=1"),
+
MacroCallParameterMatcher.hasNameAndBooleanValue("ajaxEnabled", true)));
+ assertThat(macroCall.getParameters(), not(hasKey("tooltip")));
+
+ final RenderableFtlMacroCall withTooltip =
+ (RenderableFtlMacroCall)
renderableFtlFormElementsBuilder.sortField("STYLE", "TITLE", "/target", false,
"TIP");
+ assertThat(withTooltip,
MacroCallMatcher.hasNameAndParameters("renderSortField",
+ MacroCallParameterMatcher.hasNameAndStringValue("tooltip",
"TIP")));
+ }
}