/*
* 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.tdi;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.formio.AbstractFormElement;
import net.formio.FormElement;
import net.formio.render.FormRenderer;
import net.formio.render.RenderUtils;
/**
* Builder of TDI response.
* @author Radek Beran
*/
public class TdiResponseBuilder {
private final FormRenderer renderer;
private final List<String> instructions;
public TdiResponseBuilder(FormRenderer renderer) {
this.renderer = renderer;
this.instructions = new ArrayList<String>();
}
public TdiResponseBuilder() {
this(null);
}
/**
* Adds instruction to AJAX response: Status.
* The default value is OK. At this time, this is the only value recognised as success by TDI.
* Any other value is treated as an error and is displayed using alert() function.
* @param status
* @return
*/
public TdiResponseBuilder status(String status) {
instructions.add(getStatus(status));
return this;
}
/**
* Adds instruction to AJAX response: Script.
* @param script inline Javascript code - it is invoked in the window scope
* @param src URL of the external Javascript
* @param id ID of the script - if there is another script on the page with the same name,
* the script will not be downloaded more than once
* @return
*/
public TdiResponseBuilder script(String script, String src, String id) {
instructions.add(getScript(script, src, id));
return this;
}
/**
* Adds instruction to AJAX response: Script.
* @param script inline Javascript code - it is invoked in the window scope
* @param src URL of the external Javascript
* @return
*/
public TdiResponseBuilder script(String script, String src) {
return script(script, src, null);
}
/**
* Adds instruction to AJAX response: Script.
* @param script inline Javascript code - it is invoked in the window scope
* @return
*/
public TdiResponseBuilder script(String script) {
return script(script, null);
}
/**
* Adds instruction to AJAX response: Set focus to element with given name.
* @param elementName
* @return
*/
public TdiResponseBuilder focusForName(String elementName) {
return script("$(\"#" + RenderUtils.getElementIdForName(elementName) + "\").focus();");
}
/**
* Adds instruction to AJAX response: Set focus to element with given id.
* @param elementId
* @return
*/
public TdiResponseBuilder focusForId(String elementId) {
return script("$(\"#" + elementId + "\").focus();");
}
/**
* Adds instruction to AJAX response: Insertion of form element in given position (before/after)
* given target element id.
* @param position
* @param targetElementId
* @param element
* @return
*/
public <T> TdiResponseBuilder insert(InsertionPosition position, String targetElementId, FormElement<T> element) {
if (element == null) {
throw new IllegalArgumentException("inserted element cannot be null");
}
// Render all element, including element placeholder tag
return insert(position, targetElementId, renderElement(element));
}
/**
* Adds instruction to AJAX response: Insertion of content markup in given position (before/after)
* given target element id.
* @param position
* @param targetElementId
* @param contentMarkup
* @return
*/
public TdiResponseBuilder insert(InsertionPosition position, String targetElementId, String contentMarkup) {
if (position == null) {
throw new IllegalArgumentException("insertion position cannot be null");
}
if (targetElementId == null || targetElementId.isEmpty()) {
throw new IllegalArgumentException("targetElementId must be specified");
}
String str = renderInsertBeginTag(position, targetElementId) +
renderCDataBegin() +
contentMarkup +
renderCDataEnd() +
renderInsertEndTag();
instructions.add(str);
return this;
}
/**
* Adds instruction to AJAX response: Update of form element.
* @param element
* @return
*/
public <T> TdiResponseBuilder update(FormElement<T> element) {
if (element == null) {
throw new IllegalArgumentException("updated element cannot be null");
}
return update(AbstractFormElement.getElementPlaceholderId(element.getName(), element.getConfig().getPathSeparator()), renderElementMarkup(element));
}
/**
* Adds instruction to AJAX response: Update of form element.
* @param elementId
* @param elementMarkup
* @return
*/
public TdiResponseBuilder update(String elementId, String elementMarkup) {
String str = renderUpdateBeginTag(elementId) +
renderCDataBegin() +
elementMarkup +
renderCDataEnd() +
renderUpdateEndTag();
instructions.add(str);
return this;
}
/**
* Adds instructions to AJAX response: Updates of form elements.
* @param elements
* @return
*/
public TdiResponseBuilder update(List<FormElement<?>> elements) {
if (elements != null) {
for (FormElement<?> el : elements) {
update(el);
}
}
return this;
}
/**
* Adds instructions to AJAX response: Updates of form elements.
* @param elements
* @return
*/
public TdiResponseBuilder update(FormElement<?>[] elements) {
return update(elements == null ? new ArrayList<FormElement<?>>() : Arrays.asList(elements));
}
/**
* Adds reload page instruction to AJAX response.
* This instruction should be the last in the response. No further instruction will be performed.
* @return
*/
public TdiResponseBuilder reload() {
instructions.add("<reload></reload>" + newLine());
return this;
}
/**
* Adds redirect instruction to AJAX response.
* This instruction should be the last in the response. No further instruction will be performed.
* @param url
* @return
*/
public TdiResponseBuilder redirect(String url) {
instructions.add("<redirect href=\"" + url + "\"></redirect>" + newLine());
return this;
}
/**
* Returns AJAX response in form of a string.
* @return
*/
public String asString() {
StringBuilder sb = new StringBuilder();
sb.append(renderXmlDeclaration()).append(renderResponseBeginTag());
boolean statusFound = false;
for (String i : instructions) {
if (i.contains("<" + getStatusTagName())) {
statusFound = true;
break;
}
}
List<String> completeInstructions = new ArrayList<String>();
if (!statusFound) {
completeInstructions.add(getStatus("OK"));
}
completeInstructions.addAll(instructions);
for (String i : completeInstructions) {
sb.append(i);
}
sb.append(renderResponseEndTag());
return sb.toString();
}
protected String renderXmlDeclaration() {
return "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + newLine();
}
protected String renderResponseBeginTag() {
return "<response>" + newLine();
}
protected String renderResponseEndTag() {
return "</response>" + newLine();
}
protected String renderUpdateBeginTag(String id) {
return "<update target=\"" + id + "\" class-remove=\"hidden\">" + newLine();
}
protected String renderInsertBeginTag(InsertionPosition position, String targetElementId) {
if (position == null) {
throw new IllegalArgumentException("position cannot be null");
}
return "<insert target=\"" + targetElementId + "\" position=\"" + position.getPositionValue() + "\">" + newLine();
}
protected String renderInsertEndTag() {
return "</insert>" + newLine();
}
protected String renderUpdateEndTag() {
return "</update>" + newLine();
}
protected String renderCDataBegin() {
return "<![CDATA[" + newLine();
}
protected String renderCDataEnd() {
return "]]>" + newLine();
}
protected FormRenderer getRenderer() {
return renderer;
}
protected List<String> getInstructions() {
return instructions;
}
protected <T> String renderElementMarkup(FormElement<T> element) {
if (getRenderer() == null) return "";
return getRenderer().renderElementMarkup(element);
}
protected <T> String renderElement(FormElement<T> element) {
if (getRenderer() == null) return "";
return getRenderer().renderElement(element);
}
private String newLine() {
return System.getProperty("line.separator");
}
private String getStatus(String statusText) {
return "<" + getStatusTagName() + ">" + statusText + "</" + getStatusTagName() + ">" + newLine();
}
private String getScript(String script, String src, String id) {
StringBuilder sb = new StringBuilder();
sb.append("<script");
if (src != null && !src.isEmpty()) {
sb.append(" src=\"").append(src).append("\"");
}
if (id != null && !id.isEmpty()) {
sb.append(" id=\"").append(id).append("\"");
}
sb.append(">").append(newLine());
if (script != null && !script.isEmpty()) {
sb.append(script).append(newLine());
}
sb.append("</script>").append(newLine());
return sb.toString();
}
private String getStatusTagName() {
return "status";
}
}