Skip to content

Commit d462fc8

Browse files
committed
Improved: Automatic callback element propagation inside a modal tunnel
process (OFBIZ-12664)
1 parent c61c6de commit d462fc8

File tree

9 files changed

+108
-47
lines changed

9 files changed

+108
-47
lines changed

framework/widget/dtd/widget-form.xsd

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,6 +1448,14 @@ under the License.
14481448
<xs:documentation>The message displayed in confirmation box</xs:documentation>
14491449
</xs:annotation>
14501450
</xs:attribute>
1451+
<xs:attribute name="propagate-callback" type="xs:boolean" default="false">
1452+
<xs:annotation>
1453+
<xs:documentation>If you are on an edition process with different steps and you want to wait the end of the complete action before using the callback,
1454+
use propagate-callback="true". The submit will understand that you want to continue your process and will not close the modal to refresh the screen.
1455+
The callback action will be kept within the different steps
1456+
</xs:documentation>
1457+
</xs:annotation>
1458+
</xs:attribute>
14511459
</xs:complexType>
14521460
</xs:element>
14531461
<xs:element name="text" substitutionGroup="AllFields">

framework/widget/src/main/java/org/apache/ofbiz/widget/WidgetWorker.java

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.apache.ofbiz.webapp.control.ConfigXMLReader;
3636
import org.apache.ofbiz.webapp.control.RequestHandler;
3737
import org.apache.ofbiz.webapp.taglib.ContentUrlTag;
38+
import org.apache.ofbiz.widget.model.CommonWidgetModels;
3839
import org.apache.ofbiz.widget.model.ModelForm;
3940
import org.apache.ofbiz.widget.model.ModelFormField;
4041
import org.apache.ofbiz.widget.renderer.ScreenRenderer;
@@ -100,17 +101,18 @@ public static URI buildHyperlinkUri(String target, String targetType, Map<String
100101
throw new RuntimeException(msg, e);
101102
}
102103

103-
final String tokenValue = CsrfUtil.generateTokenForNonAjax(request, target);
104-
if (isNotEmpty(tokenValue)) {
105-
additionalParameters.put(CsrfUtil.getTokenNameNonAjax(), tokenValue);
106-
}
107-
108-
if (UtilValidate.isNotEmpty(parameterMap)) {
109-
parameterMap.forEach(uriBuilder::addParameter);
110-
}
104+
if (!"plain".equals(targetType)) {
105+
final String tokenValue = CsrfUtil.generateTokenForNonAjax(request, target);
106+
if (isNotEmpty(tokenValue)) {
107+
additionalParameters.put(CsrfUtil.getTokenNameNonAjax(), tokenValue);
108+
}
111109

112-
additionalParameters.forEach(uriBuilder::addParameter);
110+
if (UtilValidate.isNotEmpty(parameterMap)) {
111+
parameterMap.forEach(uriBuilder::addParameter);
112+
}
113113

114+
additionalParameters.forEach(uriBuilder::addParameter);
115+
}
114116
try {
115117
return uriBuilder.build();
116118
} catch (URISyntaxException e) {
@@ -285,6 +287,19 @@ public static ScreenRenderer.ScreenStack getScreenStack(Map<String, Object> cont
285287
return (ScreenRenderer.ScreenStack) context.get("screenStack");
286288
}
287289

290+
/**
291+
* Returns the jwt callback id if present on the context.
292+
* @param context
293+
* @return
294+
*/
295+
public static String getJwtCallback(Map<String, Object> context) {
296+
String jwtCallback = (String) context.get(CommonWidgetModels.JWT_CALLBACK);
297+
if (UtilValidate.isEmpty(jwtCallback) && context.containsKey("parameters")) {
298+
jwtCallback = (String) ((Map) context.get("parameters")).get(CommonWidgetModels.JWT_CALLBACK);
299+
}
300+
return jwtCallback;
301+
}
302+
288303
public static int getPaginatorNumber(Map<String, Object> context) {
289304
int paginatorNumber = 0;
290305
if (context != null) {

framework/widget/src/main/java/org/apache/ofbiz/widget/model/CommonWidgetModels.java

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import org.apache.ofbiz.service.LocalDispatcher;
4949
import org.apache.ofbiz.service.ModelParam;
5050
import org.apache.ofbiz.service.ModelService;
51+
import org.apache.ofbiz.widget.WidgetWorker;
5152
import org.w3c.dom.Element;
5253
import org.w3c.dom.Node;
5354

@@ -574,26 +575,10 @@ public Map<String, String> getParameterMap(Map<String, Object> context,
574575
if (autoEntityParameters != null) {
575576
fullParameterMap.putAll(autoEntityParameters.getParametersMap(context, defaultEntityName));
576577
}
577-
propagateCallbackInParameterMap(context, propagateMyCallback, fullParameterMap);
578+
fullParameterMap.putAll(UtilGenerics.cast(propagateCallbackInParameterMap(context, propagateMyCallback, getCallback())));
578579
return fullParameterMap;
579580
}
580581

581-
// If a call back is present on link or present on context, adding it to the parameters list
582-
private void propagateCallbackInParameterMap(Map<String, Object> context, boolean propagateMyCallback, Map<String, String> fullParameterMap) {
583-
if (getCallback() != null && propagateMyCallback) {
584-
fullParameterMap.put(JWT_CALLBACK, getCallback().toJwtToken(context));
585-
} else if (context.containsKey(JWT_CALLBACK)) {
586-
fullParameterMap.put(JWT_CALLBACK, (String) context.get(JWT_CALLBACK));
587-
} else {
588-
if (context.containsKey("parameters")) {
589-
Map<String, Object> parameters = UtilGenerics.cast(context.get("parameters"));
590-
if (parameters.containsKey(JWT_CALLBACK)) {
591-
fullParameterMap.put(JWT_CALLBACK, (String) parameters.get(JWT_CALLBACK));
592-
}
593-
}
594-
}
595-
}
596-
597582
public Map<String, String> getParameterMap(Map<String, Object> context) {
598583
return getParameterMap(context, null, null, true);
599584
}
@@ -796,4 +781,22 @@ public static Parameter create(Map.Entry<String, Object> entry) {
796781
}
797782
}
798783
}
784+
785+
// If a call back is present on link or present on context, adding it to the parameters list
786+
public static Map<String, Object> propagateCallbackInParameterMap(Map<String, Object> context, boolean propagateMyCallback,
787+
ModelForm.UpdateArea callBack) {
788+
Map<String, Object> fullParameterMap = new HashMap<String, Object>();
789+
790+
// If the parameter contains the map, the call back will be automatically manage by the form
791+
if (fullParameterMap.containsKey("_FORM_NAME_")) return fullParameterMap;
792+
793+
String currentJwtCallback = WidgetWorker.getJwtCallback(context);
794+
if (callBack != null && propagateMyCallback) {
795+
fullParameterMap.put(JWT_CALLBACK, callBack.toJwtToken(context));
796+
} else if (UtilValidate.isNotEmpty(currentJwtCallback)) {
797+
fullParameterMap.put(JWT_CALLBACK, currentJwtCallback);
798+
}
799+
return fullParameterMap;
800+
}
801+
799802
}

framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelForm.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2511,12 +2511,8 @@ public String toJwtToken(Map<String, Object> context) {
25112511
public static ModelForm.UpdateArea fromJwtToken(Map<String, Object> context) {
25122512
Delegator delegator = (Delegator) context.get("delegator");
25132513

2514-
String jwtToken = (String) context.get(CommonWidgetModels.JWT_CALLBACK);
2515-
if (jwtToken == null && context.containsKey("parameters")) {
2516-
Map<String, Object> parameters = UtilGenerics.cast(context.get("parameters"));
2517-
jwtToken = (String) parameters.get(CommonWidgetModels.JWT_CALLBACK);
2518-
}
2519-
if (jwtToken == null) return null;
2514+
String jwtToken = WidgetWorker.getJwtCallback(context);
2515+
if (UtilValidate.isEmpty(jwtToken)) return null;
25202516

25212517
Map<String, Object> claims = JWTManager.validateToken(jwtToken, JWTManager.getJWTKey(delegator));
25222518
if (claims.containsKey(ModelService.ERROR_MESSAGE)) {

framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelFormField.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4913,6 +4913,7 @@ public boolean shouldIgnore(Map<String, Object> context) {
49134913
public static class SubmitField extends FieldInfo {
49144914
private final FlexibleStringExpander backgroundSubmitRefreshTargetExdr;
49154915
private final String buttonType;
4916+
private final boolean propagateCallback;
49164917
private final FlexibleStringExpander confirmationMsgExdr;
49174918
private final FlexibleStringExpander imageLocation;
49184919
private final boolean requestConfirmation;
@@ -4925,6 +4926,7 @@ public SubmitField(Element element, ModelFormField modelFormField) {
49254926
this.confirmationMsgExdr = FlexibleStringExpander.getInstance(element.getAttribute("confirmation-message"));
49264927
this.imageLocation = FlexibleStringExpander.getInstance(element.getAttribute("image-location"));
49274928
this.requestConfirmation = "true".equals(element.getAttribute("request-confirmation"));
4929+
this.propagateCallback = "true".equals(element.getAttribute("propagate-callback"));
49284930
}
49294931

49304932
public SubmitField(int fieldInfo, ModelFormField modelFormField) {
@@ -4934,6 +4936,7 @@ public SubmitField(int fieldInfo, ModelFormField modelFormField) {
49344936
this.confirmationMsgExdr = FlexibleStringExpander.getInstance("");
49354937
this.imageLocation = FlexibleStringExpander.getInstance("");
49364938
this.requestConfirmation = false;
4939+
this.propagateCallback = false;
49374940
}
49384941

49394942
public SubmitField(ModelFormField modelFormField) {
@@ -4947,6 +4950,7 @@ private SubmitField(SubmitField original, ModelFormField modelFormField) {
49474950
this.backgroundSubmitRefreshTargetExdr = original.backgroundSubmitRefreshTargetExdr;
49484951
this.requestConfirmation = original.requestConfirmation;
49494952
this.confirmationMsgExdr = original.confirmationMsgExdr;
4953+
this.propagateCallback = original.propagateCallback;
49504954
}
49514955

49524956
@Override
@@ -5043,6 +5047,14 @@ public boolean getRequestConfirmation() {
50435047
return this.requestConfirmation;
50445048
}
50455049

5050+
/**
5051+
* Gets keep callback.
5052+
* @return
5053+
*/
5054+
public boolean getPropagateCallback() {
5055+
return this.propagateCallback;
5056+
}
5057+
50465058
@Override
50475059
public void renderFieldString(Appendable writer, Map<String, Object> context, FormStringRenderer formStringRenderer)
50485060
throws IOException {

framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/FormRenderer.java

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*******************************************************************************/
1919
package org.apache.ofbiz.widget.renderer;
2020

21+
import org.apache.ofbiz.widget.model.CommonWidgetModels;
2122
import static org.apache.ofbiz.widget.model.ModelFormField.usedFields;
2223

2324
import java.io.IOException;
@@ -56,6 +57,7 @@
5657
import org.apache.ofbiz.widget.model.ModelForm.FieldGroup;
5758
import org.apache.ofbiz.widget.model.ModelForm.FieldGroupBase;
5859
import org.apache.ofbiz.widget.model.ModelFormField;
60+
import org.apache.ofbiz.widget.model.ModelFormFieldBuilder;
5961
import org.apache.ofbiz.widget.model.ModelGrid;
6062
import org.apache.ofbiz.widget.model.ModelWidget;
6163
import org.apache.ofbiz.widget.renderer.html.HtmlWidgetRenderer;
@@ -174,12 +176,30 @@ private static Predicate<ModelFormField> filteringIgnoredFields(Map<String, Obje
174176
}
175177

176178
private static List<ModelFormField> getHiddenIgnoredFields(Map<String, Object> context, Set<String> alreadyRendered,
177-
List<ModelFormField> fields, int position) {
178-
return fields.stream()
179+
List<ModelFormField> fields, ModelForm modelForm, int position) {
180+
List<ModelFormField> hiddenIgnoredFields = fields.stream()
179181
// with position == -1 then gets all the hidden fields
180182
.filter(modelFormField -> position == -1 || modelFormField.getPosition() == position)
181183
.filter(filteringIgnoredFields(context, alreadyRendered))
182184
.collect(Collectors.toList());
185+
ModelFormField jwtCallbackField = addJwtTokenHiddenField(context, modelForm);
186+
if (jwtCallbackField != null) {
187+
hiddenIgnoredFields.add(jwtCallbackField);
188+
}
189+
return hiddenIgnoredFields;
190+
}
191+
192+
private static ModelFormField addJwtTokenHiddenField(Map<String, Object> context, ModelForm modelForm) {
193+
if (UtilValidate.isNotEmpty(WidgetWorker.getJwtCallback(context))) {
194+
ModelFormFieldBuilder builder = new ModelFormFieldBuilder();
195+
builder.setModelForm(modelForm);
196+
builder.setName(CommonWidgetModels.JWT_CALLBACK);
197+
builder.setFieldName(CommonWidgetModels.JWT_CALLBACK);
198+
ModelFormField.HiddenField hiddenField = new ModelFormField.HiddenField(FieldInfo.SOURCE_EXPLICIT, null);
199+
builder.setFieldInfo(hiddenField);
200+
return ModelFormField.from(builder);
201+
}
202+
return null;
183203
}
184204

185205
private List<FieldGroupBase> getInbetweenList(FieldGroup startFieldGroup, FieldGroup endFieldGroup) {
@@ -869,8 +889,8 @@ private void renderItemRows(Appendable writer, Map<String, Object> context, Form
869889
innerDisplayHyperlinkFieldsEnd.add(modelFormField);
870890
currentPosition = modelFormField.getPosition();
871891
}
872-
List<ModelFormField> hiddenIgnoredFieldList = getHiddenIgnoredFields(localContext, null, tempFieldList,
873-
currentPosition);
892+
List<ModelFormField> hiddenIgnoredFieldList = getHiddenIgnoredFields(localContext, null,
893+
tempFieldList, modelForm, currentPosition);
874894

875895
// Rendering:
876896
// the fields in the three lists created in the preprocessing phase
@@ -984,7 +1004,7 @@ private void renderSingleFormString(Appendable writer, Map<String, Object> conte
9841004
}
9851005

9861006
// render all hidden & ignored fields
987-
List<ModelFormField> hiddenIgnoredFieldList = getHiddenIgnoredFields(context, alreadyRendered, tempFieldList, -1);
1007+
List<ModelFormField> hiddenIgnoredFieldList = getHiddenIgnoredFields(context, alreadyRendered, tempFieldList, modelForm, -1);
9881008
renderHiddenIgnoredFields(writer, context, formStringRenderer, hiddenIgnoredFieldList);
9891009

9901010
// render formatting wrapper open

framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRenderer.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,9 @@ public void renderSubmitField(Appendable writer, Map<String, Object> context, Su
703703
boolean ajaxEnabled = UtilValidate.isNotEmpty(updateAreas) && this.javaScriptEnabled;
704704
String ajaxUrl = "";
705705
if (ajaxEnabled) {
706-
ajaxUrl = MacroCommonRenderer.createAjaxParamsFromUpdateAreas(updateAreas, null, modelForm, "", context);
706+
Map<String, Object> extraParams = CommonWidgetModels.propagateCallbackInParameterMap(context,
707+
submitField.getPropagateCallback(), jwtCallback);
708+
ajaxUrl = MacroCommonRenderer.createAjaxParamsFromUpdateAreas(updateAreas, extraParams, modelForm, "", context);
707709
}
708710
String tabindex = modelFormField.getTabindex();
709711
boolean disabled = modelFormField.getDisabled(context);
@@ -747,7 +749,9 @@ public void renderSubmitField(Appendable writer, Map<String, Object> context, Su
747749
sr.append(tabindex);
748750
sr.append("\" disabled=");
749751
sr.append(Boolean.toString(disabled));
750-
sr.append(" />");
752+
sr.append(" closeOnSubmit=\"");
753+
sr.append(String.valueOf(!submitField.getPropagateCallback()));
754+
sr.append("\" />");
751755
executeMacro(writer, sr.toString());
752756
this.appendTooltip(writer, context, modelFormField);
753757
}

themes/common-theme/template/macro/HtmlFormMacroLibrary.ftl

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ under the License.
228228
</#list>
229229
</#macro>
230230

231-
<#macro renderSubmitField buttonType className alert formName action imgSrc ajaxUrl id title="" name="" event="" confirmation="" containerId="" tabindex="" disabled=false>
231+
<#macro renderSubmitField buttonType className alert formName action imgSrc ajaxUrl id title="" name="" event="" confirmation="" containerId="" tabindex="" disabled=false closeOnSubmit="true">
232232
<#if buttonType=="text-link">
233233
<a <@renderClass className alert /> href="javascript:document.${formName}.submit()" <#if confirmation?has_content>onclick="return confirm('${confirmation?js_string}');"</#if>><#if title?has_content>${title}</#if> </a>
234234
<#elseif buttonType=="image">
@@ -253,14 +253,15 @@ under the License.
253253
e.preventDefault();
254254
e.stopPropagation();
255255
if ($(this).valid()) {
256-
<#if confirmation?has_content>if (confirm('${confirmation?js_string}')) </#if>ajaxSubmitFormUpdateAreas('${formName}', '${ajaxUrl}');
256+
<#if confirmation?has_content>if (confirm('${confirmation?js_string}')) </#if>ajaxSubmitFormUpdateAreas('${formName}', '${ajaxUrl}', '${closeOnSubmit}');
257257
}
258258
})
259259
.keypress(function(e) {
260-
if (e.which === 13 && ! $(e.target).is('textarea')) {
261-
e.preventDefault();
262-
$("#${id!}").click();
263-
}});
260+
if (e.which === 13 && ! $(e.target).is('textarea')) {
261+
e.preventDefault();
262+
$("#${id!}").click();
263+
}
264+
});
264265
</script>
265266
</#if>
266267
</#if>

themes/common-theme/webapp/common-theme/js/util/OfbizUtil.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,7 @@ function errorRetrievingResponseFromServer(xhr, status, exception) {
834834
* @param areaCsvString The area CSV string. The CSV string is a flat array in the
835835
* form of: areaId, target, target parameters [, areaId, target, target parameters...].
836836
*/
837-
function ajaxSubmitFormUpdateAreas(formName, areaCsvString) {
837+
function ajaxSubmitFormUpdateAreas(formName, areaCsvString, close) {
838838
waitSpinnerShow();
839839

840840
var $form = jQuery("form[name='" + formName + "']");
@@ -864,7 +864,9 @@ function ajaxSubmitFormUpdateAreas(formName, areaCsvString) {
864864
areaCsvString += data[variableName] + endString.substring(endString.indexOf("_") + 1)
865865
}
866866
ajaxUpdateAreas(areaCsvString);
867-
$form.trigger("closeCurrentModalAfterAjaxSubmitFormUpdateAreasInSuccess");
867+
if (close === undefined || close == 'true') {
868+
$form.trigger('closeCurrentModalAfterAjaxSubmitFormUpdateAreasInSuccess');
869+
}
868870
}
869871
}
870872
}

0 commit comments

Comments
 (0)