/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.formio.render;
import java.util.Arrays;
import java.util.List;
import net.formio.Field;
import net.formio.FormField;
import net.formio.ajax.AjaxParams;
import net.formio.ajax.JsEvent;
import net.formio.ajax.action.AjaxHandler;
import net.formio.internal.FormUtils;
/**
* Renders script for invoking AJAX events.
* @author Radek Beran
*/
class AjaxEventRenderer {
private final FormRenderer renderer;
AjaxEventRenderer(FormRenderer renderer) {
if (renderer == null) {
throw new IllegalArgumentException("renderer cannot be null");
}
this.renderer = renderer;
}
/**
* Returns AJAX URL for given link field.
* @param field
* @return
*/
protected <T> String getActionLinkUrl(FormField<T> field) {
String url = null;
if (Field.LINK.getType().equals(field.getType())) {
for (AjaxHandler<?> eventHandler : field.getProperties().getAjaxHandlers()) {
url = getActionUrl(field, eventHandler);
break;
}
}
return url;
}
/**
* Renders script for handling form field.
* @param field
* @param multipleInputs
* @return
*/
protected <T> String renderFieldScript(FormField<T> field, InputMultiplicity inputMultiplicity) {
StringBuilder sb = new StringBuilder();
List<AjaxHandler<?>> urlEvents = Arrays.asList(field.getProperties().getAjaxHandlers());
if (urlEvents.size() > 0) {
StringBuilder tdiSend = new StringBuilder();
if (inputMultiplicity == InputMultiplicity.MULTIPLE) {
if (field.getChoices() != null && field.getChoiceRenderer() != null) {
List<?> items = field.getChoices().getItems();
if (items != null) {
for (int i = 0; i < items.size(); i++) {
String itemId = field.getElementIdWithIndex(i);
tdiSend.append(renderTdiSend(field, itemId, urlEvents));
}
}
}
} else {
tdiSend.append(renderTdiSend(field, field.getElementId(), urlEvents));
}
if (tdiSend.length() > 0) {
sb.append("<script>").append(renderer.newLine()).append(tdiSend).append("</script>").append(renderer.newLine());
}
}
return sb.toString();
}
/**
* Composes JavaScript for given form field that initiates TDI AJAX request when
* some given event occurs - different JavaScript events can have different URL addresses
* for handling the AJAX request. The value of form field is part of the AJAX request
* (if some value is filled).
* @param formField
* @param inputId
* @param eventHandlers
* @return
*/
private <T> String renderTdiSend(FormField<T> formField, String inputId, List<AjaxHandler<?>> eventHandlers) {
StringBuilder sb = new StringBuilder("");
if (eventHandlers != null && eventHandlers.size() > 0) {
if (Field.LINK.getType().equals(formField.getType()) && (formField.getValue() == null || formField.getValue().isEmpty())) {
// nothing, AJAX URL is rendered directly in href attribute
} else {
boolean actionWithJsType = false;
for (AjaxHandler<?> handler : eventHandlers) {
if (handler.getEvent() != null) {
actionWithJsType = true;
}
}
if (actionWithJsType) {
String elm = "$(\"#" + inputId + "\")";
sb.append(elm).append(".on({").append(renderer.newLine());
for (int i = 0; i < eventHandlers.size(); i++) {
AjaxHandler<?> eventToUrl = eventHandlers.get(i);
JsEvent eventType = eventToUrl.getEvent();
if (eventType != null) {
String url = getActionUrl(formField, eventToUrl);
sb.append(eventType.getEventName()).append(": function(evt) {").append(renderer.newLine());
// Remember previous data-ajax-url (to revert it back) and set it temporarily to custom URL
sb.append("var prevUrl = ").append(elm).append(".attr(\"data-ajax-url\");").append(renderer.newLine());
sb.append(elm).append(".attr(\"data-ajax-url\", \"").append(url).append("\");").append(renderer.newLine());
sb.append("TDI.Ajax.send(").append(elm).append(");").append(renderer.newLine());
sb.append(elm).append(".attr(\"data-ajax-url\", prevUrl);").append(renderer.newLine());
sb.append("var prevUrl = null;").append(renderer.newLine());
sb.append("}");
if (i < eventHandlers.size() - 1) {
// not the last event handler
sb.append(",");
}
sb.append(renderer.newLine());
}
}
sb.append("});").append(renderer.newLine());
}
}
}
return sb.toString();
}
private <T> String getActionUrl(FormField<T> formField, AjaxHandler<?> eventHandler) {
String url = eventHandler.getHandlerUrl(formField.getParent().getConfig().getUrlBase(), formField);
if (url == null || url.isEmpty()) {
throw new IllegalArgumentException("No URL for AJAX request is specified");
}
url = FormUtils.urlWithAppendedParameter(url, AjaxParams.SRC_ELEMENT_NAME, formField.getName());
return url;
}
}