FTL not work after: commit branch trunk updated: Improved: <script-template> widget tag (OFBIZ-11686)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

FTL not work after: commit branch trunk updated: Improved: <script-template> widget tag (OFBIZ-11686)

Olivier.heintz
Hi James,

In HR, on main page, on tree company organization, with a Right Click, there is a menu with
as last item "Remove Internal Organization" which call RemoveInternalOrg.ftl

before your commit this function works
now nothing is done

after remove multi-block="true"  in the line
 <platform-specific><html><html-template location="component://humanres/template/internalorg/RemoveInternalOrg.ftl"/></html></platform-specific>
it works again

Can you have a look at this problem
Thank you



Le 15/05/2020 à 05:17, [hidden email] a écrit :

> This is an automated email from the ASF dual-hosted git repository.
>
> jamesyong 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 60c78d2  Improved: <script-template> widget tag (OFBIZ-11686)
> 60c78d2 is described below
>
> commit 60c78d24be4ab2b4f8aa2f6603968863c12b9b92
> Author: James Yong <[hidden email]>
> AuthorDate: Fri May 15 11:16:15 2020 +0800
>
>     Improved: <script-template> widget tag (OFBIZ-11686)
>    
>     Removed script-template tag.
>     Use multi-block=true on html-template tag instead.
> ---
>  applications/order/template/order/FindOrders.ftl   |  72 +++++++++++-
>  .../order/template/order/FindOrders.js.ftl         |  86 --------------
>  .../order/widget/ordermgr/OrderViewScreens.xml     |   3 +-
>  .../webapp/ftl/ScriptTemplateListTransform.java    |   5 +-
>  framework/widget/dtd/widget-screen.xsd             |   9 +-
>  .../widget/artifact/ArtifactInfoGatherer.java      |   5 -
>  .../org/apache/ofbiz/widget/model/HtmlWidget.java  | 124 +++++++++------------
>  .../ofbiz/widget/model/ModelWidgetVisitor.java     |   2 -
>  .../ofbiz/widget/model/ScriptTemplateUtil.java     |  43 ++++---
>  .../ofbiz/widget/model/XmlWidgetVisitor.java       |  10 +-
>  .../ofbiz/widget/renderer/ScreenRenderer.java      |   7 +-
>  11 files changed, 160 insertions(+), 206 deletions(-)
>
> diff --git a/applications/order/template/order/FindOrders.ftl b/applications/order/template/order/FindOrders.ftl
> index 0d1923d..6eaff5b 100644
> --- a/applications/order/template/order/FindOrders.ftl
> +++ b/applications/order/template/order/FindOrders.ftl
> @@ -17,6 +17,76 @@ specific language governing permissions and limitations
>  under the License.
>  -->
>  
> +<script>
> +function lookupOrders(click) {
> +    orderIdValue = document.lookuporder.orderId.value;
> +    if (orderIdValue.length > 1) {
> +        document.lookuporder.action = "<@ofbizUrl>orderview</@ofbizUrl>";
> +        document.lookuporder.method = "get";
> +    } else {
> +        document.lookuporder.action = "<@ofbizUrl>searchorders</@ofbizUrl>";
> +    }
> +
> +    if (click) {
> +        document.lookuporder.submit();
> +    }
> +    return true;
> +}
> +function toggleOrderId(master) {
> +    var form = document.massOrderChangeForm;
> +    var orders = form.elements.length;
> +    for (var i = 0; i < orders; i++) {
> +        var element = form.elements[i];
> +        if ("orderIdList" == element.name) {
> +            element.checked = master.checked;
> +        }
> +    }
> +    toggleOrderIdList();
> +}
> +function setServiceName(selection) {
> +    document.massOrderChangeForm.action = selection.value;
> +}
> +function runAction() {
> +    var form = document.massOrderChangeForm;
> +    form.submit();
> +}
> +
> +function toggleOrderIdList() {
> +    var form = document.massOrderChangeForm;
> +    var orders = form.elements.length;
> +    var isAllSelected = true;
> +    var isSingle = true;
> +    for (var i = 0; i < orders; i++) {
> +        var element = form.elements[i];
> +        if ("orderIdList" == element.name) {
> +            if (element.checked) {
> +                isSingle = false;
> +            } else {
> +                isAllSelected = false;
> +            }
> +        }
> +    }
> +    if (isAllSelected) {
> +        jQuery('#checkAllOrders').attr('checked', true);
> +    } else {
> +        jQuery('#checkAllOrders').attr('checked', false);
> +    }
> +    jQuery('#checkAllOrders').attr("checked", isAllSelected);
> +    if (!isSingle && jQuery('#serviceName').val() != "") {
> +        jQuery('#submitButton').removeAttr("disabled");
> +    } else {
> +        jQuery('#submitButton').attr('disabled', true);
> +    }
> +}
> +
> +function paginateOrderList(viewSize, viewIndex, hideFields) {
> +    document.paginationForm.viewSize.value = viewSize;
> +    document.paginationForm.viewIndex.value = viewIndex;
> +    document.paginationForm.hideFields.value = hideFields;
> +    document.paginationForm.submit();
> +}
> +</script>
> +
>  <#if security.hasEntityPermission("ORDERMGR", "_VIEW", session)>
>  <#if parameters.hideFields?has_content>
>  <form name='lookupandhidefields${requestParameters.hideFields?default("Y")}' method="post" action="<@ofbizUrl>searchorders</@ofbizUrl>">
> @@ -404,9 +474,7 @@ under the License.
>  </form>
>  <#if requestParameters.hideFields?default("N") != "Y">
>  <script type="application/javascript">
> -<!--//
>  document.lookuporder.orderId.focus();
> -//-->
>  </script>
>  </#if>
>  
> diff --git a/applications/order/template/order/FindOrders.js.ftl b/applications/order/template/order/FindOrders.js.ftl
> deleted file mode 100644
> index 0b98270..0000000
> --- a/applications/order/template/order/FindOrders.js.ftl
> +++ /dev/null
> @@ -1,86 +0,0 @@
> -/***********************************************
> -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.
> -***********************************************/
> -
> -function lookupOrders(click) {
> -    orderIdValue = document.lookuporder.orderId.value;
> -    if (orderIdValue.length > 1) {
> -        document.lookuporder.action = "<@ofbizUrl>orderview</@ofbizUrl>";
> -        document.lookuporder.method = "get";
> -    } else {
> -        document.lookuporder.action = "<@ofbizUrl>searchorders</@ofbizUrl>";
> -    }
> -
> -    if (click) {
> -        document.lookuporder.submit();
> -    }
> -    return true;
> -}
> -function toggleOrderId(master) {
> -    var form = document.massOrderChangeForm;
> -    var orders = form.elements.length;
> -    for (var i = 0; i < orders; i++) {
> -        var element = form.elements[i];
> -        if ("orderIdList" == element.name) {
> -            element.checked = master.checked;
> -        }
> -    }
> -    toggleOrderIdList();
> -}
> -function setServiceName(selection) {
> -    document.massOrderChangeForm.action = selection.value;
> -}
> -function runAction() {
> -    var form = document.massOrderChangeForm;
> -    form.submit();
> -}
> -
> -function toggleOrderIdList() {
> -    var form = document.massOrderChangeForm;
> -    var orders = form.elements.length;
> -    var isAllSelected = true;
> -    var isSingle = true;
> -    for (var i = 0; i < orders; i++) {
> -        var element = form.elements[i];
> -        if ("orderIdList" == element.name) {
> -            if (element.checked) {
> -                isSingle = false;
> -            } else {
> -                isAllSelected = false;
> -            }
> -        }
> -    }
> -    if (isAllSelected) {
> -        jQuery('#checkAllOrders').attr('checked', true);
> -    } else {
> -        jQuery('#checkAllOrders').attr('checked', false);
> -    }
> -    jQuery('#checkAllOrders').attr("checked", isAllSelected);
> -    if (!isSingle && jQuery('#serviceName').val() != "") {
> -        jQuery('#submitButton').removeAttr("disabled");
> -    } else {
> -        jQuery('#submitButton').attr('disabled', true);
> -    }
> -}
> -
> -function paginateOrderList(viewSize, viewIndex, hideFields) {
> -    document.paginationForm.viewSize.value = viewSize;
> -    document.paginationForm.viewIndex.value = viewIndex;
> -    document.paginationForm.hideFields.value = hideFields;
> -    document.paginationForm.submit();
> -}
> \ No newline at end of file
> diff --git a/applications/order/widget/ordermgr/OrderViewScreens.xml b/applications/order/widget/ordermgr/OrderViewScreens.xml
> index 7d0667c..04b84ce 100644
> --- a/applications/order/widget/ordermgr/OrderViewScreens.xml
> +++ b/applications/order/widget/ordermgr/OrderViewScreens.xml
> @@ -267,8 +267,7 @@ under the License.
>                          <platform-specific><html><html-template location="component://common-theme/template/includes/SetMultipleSelectJs.ftl"/></html></platform-specific>
>                          <platform-specific>
>                              <html>
> -                                <script-template location="component://order/template/order/FindOrders.js.ftl"/>
> -                                <html-template location="component://order/template/order/FindOrders.ftl"/>
> +                                <html-template multi-block="true" location="component://order/template/order/FindOrders.ftl"/>
>                              </html>
>                          </platform-specific>
>                      </decorator-section>
> diff --git a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/ScriptTemplateListTransform.java b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/ScriptTemplateListTransform.java
> index 6b3f385..7c9bf4d 100644
> --- a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/ScriptTemplateListTransform.java
> +++ b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/ScriptTemplateListTransform.java
> @@ -22,7 +22,6 @@ import java.io.IOException;
>  import java.io.Writer;
>  import java.util.Map;
>  import java.util.Set;
> -
>  import javax.servlet.http.HttpServletRequest;
>  
>  import org.apache.ofbiz.widget.model.ScriptTemplateUtil;
> @@ -53,7 +52,7 @@ public class ScriptTemplateListTransform implements TemplateTransformModel {
>                      if (req != null) {
>                          HttpServletRequest request = (HttpServletRequest) req.getWrappedObject();
>                          Set<String> scriptSrcSet = ScriptTemplateUtil.getScriptSrcLinksFromRequest(request);
> -                        if (scriptSrcSet!=null) {
> +                        if (scriptSrcSet != null) {
>                              String srcList = "";
>                              for (String scriptSrc : scriptSrcSet) {
>                                  srcList += ("<script src=\"" + scriptSrc + "\" type=\"application/javascript\"></script>\n");
> @@ -73,7 +72,7 @@ public class ScriptTemplateListTransform implements TemplateTransformModel {
>              }
>  
>              @Override
> -            public void write(char cbuf[], int off, int len) {
> +            public void write(char[] cbuf, int off, int len) {
>              }
>          };
>  
> diff --git a/framework/widget/dtd/widget-screen.xsd b/framework/widget/dtd/widget-screen.xsd
> index 62ffc03..087809b 100644
> --- a/framework/widget/dtd/widget-screen.xsd
> +++ b/framework/widget/dtd/widget-screen.xsd
> @@ -519,6 +519,7 @@ under the License.
>      </xs:element>
>      <xs:attributeGroup name="attlist.html-template">
>          <xs:attribute type="xs:string" name="location" use="required" />
> +        <xs:attribute type="xs:boolean" name="multi-block" use="optional" default="false" />
>      </xs:attributeGroup>
>      <xs:element name="html-template-decorator" substitutionGroup="HtmlWidgets">
>          <xs:annotation>
> @@ -544,14 +545,6 @@ under the License.
>              <xs:attribute type="xs:string" name="name" use="required" />
>          </xs:complexType>
>      </xs:element>
> -    <xs:element name="script-template" substitutionGroup="HtmlWidgets">
> -        <xs:complexType>
> -            <xs:attributeGroup ref="attlist.script-template" />
> -        </xs:complexType>
> -    </xs:element>
> -    <xs:attributeGroup name="attlist.script-template">
> -        <xs:attribute type="xs:string" name="location" use="required" />
> -    </xs:attributeGroup>
>      <!-- ============== Swing Specific Elements =============== -->
>      <xs:element name="swing">
>          <xs:complexType />
> diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/artifact/ArtifactInfoGatherer.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/artifact/ArtifactInfoGatherer.java
> index 3c96f1e..0ea3393 100644
> --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/artifact/ArtifactInfoGatherer.java
> +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/artifact/ArtifactInfoGatherer.java
> @@ -38,7 +38,6 @@ import org.apache.ofbiz.widget.model.HtmlWidget;
>  import org.apache.ofbiz.widget.model.HtmlWidget.HtmlTemplate;
>  import org.apache.ofbiz.widget.model.HtmlWidget.HtmlTemplateDecorator;
>  import org.apache.ofbiz.widget.model.HtmlWidget.HtmlTemplateDecoratorSection;
> -import org.apache.ofbiz.widget.model.HtmlWidget.ScriptTemplate;
>  import org.apache.ofbiz.widget.model.IterateSectionWidget;
>  import org.apache.ofbiz.widget.model.ModelAction;
>  import org.apache.ofbiz.widget.model.ModelActionVisitor;
> @@ -357,10 +356,6 @@ public final class ArtifactInfoGatherer implements ModelWidgetVisitor, ModelActi
>      }
>  
>      @Override
> -    public void visit(ScriptTemplate scriptTemplate) throws Exception {
> -    }
> -
> -    @Override
>      public void visit(Section section) throws Exception {
>          for (ModelAction action : section.getActions()) {
>              action.accept(this);
> diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/HtmlWidget.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/HtmlWidget.java
> index b5afc68..acb850c 100644
> --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/HtmlWidget.java
> +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/HtmlWidget.java
> @@ -40,6 +40,9 @@ import org.apache.ofbiz.base.util.template.FreeMarkerWorker;
>  import org.apache.ofbiz.widget.renderer.ScreenRenderer;
>  import org.apache.ofbiz.widget.renderer.ScreenStringRenderer;
>  import org.apache.ofbiz.widget.renderer.html.HtmlWidgetRenderer;
> +import org.jsoup.Jsoup;
> +import org.jsoup.nodes.Document;
> +import org.jsoup.select.Elements;
>  import org.w3c.dom.Element;
>  
>  import freemarker.ext.beans.BeansWrapper;
> @@ -121,8 +124,6 @@ public class HtmlWidget extends ModelScreenWidget {
>                      subWidgets.add(new HtmlTemplate(modelScreen, childElement));
>                  } else if ("html-template-decorator".equals(childElement.getNodeName())) {
>                      subWidgets.add(new HtmlTemplateDecorator(modelScreen, childElement));
> -                } else if ("script-template".equals(childElement.getNodeName())) {
> -                    subWidgets.add(new ScriptTemplate(modelScreen, childElement));
>                  } else {
>                      throw new IllegalArgumentException("Tag not supported under the platform-specific -> html tag with name: "
>                              + childElement.getNodeName());
> @@ -178,36 +179,6 @@ public class HtmlWidget extends ModelScreenWidget {
>          }
>      }
>  
> -    public static void renderScriptTemplate(Appendable writer, FlexibleStringExpander locationExdr, Map<String, Object> context) {
> -        String location = locationExdr.expandString(context);
> -
> -        if (UtilValidate.isEmpty(location)) {
> -            throw new IllegalArgumentException("Template location is empty with search string location " + locationExdr.getOriginal());
> -        }
> -
> -        if (location.endsWith(".ftl")) {
> -            try {
> -                boolean insertWidgetBoundaryComments = ModelWidget.widgetBoundaryCommentsEnabled(context);
> -                if (insertWidgetBoundaryComments) {
> -                    writer.append(HtmlWidgetRenderer.formatBoundaryJsComment("Begin", "Template", location));
> -                }
> -
> -                Template template = FreeMarkerWorker.getTemplate(location, specialTemplateCache, specialConfig);
> -                FreeMarkerWorker.renderTemplate(template, context, writer);
> -
> -                if (insertWidgetBoundaryComments) {
> -                    writer.append(HtmlWidgetRenderer.formatBoundaryJsComment("End", "Template", location));
> -                }
> -            } catch (IllegalArgumentException | TemplateException | IOException e) {
> -                String errMsg = "Error rendering included template at location [" + location + "]: " + e.toString();
> -                Debug.logError(e, errMsg, MODULE);
> -                writeError(writer, errMsg);
> -            }
> -        } else {
> -            throw new IllegalArgumentException("Rendering not yet supported for the template at location: " + location);
> -        }
> -    }
> -
>      // TODO: We can make this more fancy, but for now this is very functional
>      public static void writeError(Appendable writer, String message) {
>          try {
> @@ -218,19 +189,65 @@ public class HtmlWidget extends ModelScreenWidget {
>  
>      public static class HtmlTemplate extends ModelScreenWidget {
>          protected FlexibleStringExpander locationExdr;
> +        protected boolean multiBlock;
>  
>          public HtmlTemplate(ModelScreen modelScreen, Element htmlTemplateElement) {
>              super(modelScreen, htmlTemplateElement);
>              this.locationExdr = FlexibleStringExpander.getInstance(htmlTemplateElement.getAttribute("location"));
> +            this.multiBlock = !"false".equals(htmlTemplateElement.getAttribute("multi-block"));
>          }
>  
>          public String getLocation(Map<String, Object> context) {
>              return locationExdr.expandString(context);
>          }
>  
> +        public boolean isMultiBlock() {
> +            return this.multiBlock;
> +        }
> +
>          @Override
> -        public void renderWidgetString(Appendable writer, Map<String, Object> context, ScreenStringRenderer screenStringRenderer) {
> -            renderHtmlTemplate(writer, this.locationExdr, context);
> +        public void renderWidgetString(Appendable writer, Map<String, Object> context, ScreenStringRenderer screenStringRenderer) throws IOException {
> +
> +            if (isMultiBlock()) {
> +
> +                StringWriter stringWriter = new StringWriter();
> +                context.put("MultiBlockWriter", stringWriter);
> +                renderHtmlTemplate(stringWriter, this.locationExdr, context);
> +                context.remove("MultiBlockWriter");
> +                String data = stringWriter.toString();
> +                stringWriter.close();
> +
> +                Document doc = Jsoup.parse(data);
> +
> +                // extract scripts
> +                Elements scriptElements = doc.select("script").remove();
> +                if (scriptElements != null) {
> +                    StringBuilder scripts = new StringBuilder();
> +
> +                    for (org.jsoup.nodes.Element script : scriptElements) {
> +                        scripts.append(script.data());
> +                    }
> +
> +                    // store script for retrieval by the browser
> +                    String fileName = this.getLocation(context);
> +                    fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
> +                    if (fileName.endsWith(".ftl")) {
> +                        fileName = fileName.substring(0, fileName.length() - 4);
> +                    }
> +                    ScriptTemplateUtil.putScriptInSession(context, fileName, scripts.toString());
> +
> +                    // store value to be used by ScriptTemplateList freemarker macro
> +                    String webappName = (String) context.get("webappName");
> +                    ScriptTemplateUtil.addScriptSrcToRequest(context, "/" + webappName + "/control/getJs?name="
> +                            + fileName);
> +                }
> +
> +                // the 'template' block
> +                String body = doc.body().html();
> +                writer.append(body);
> +            } else {
> +                renderHtmlTemplate(writer, this.locationExdr, context);
> +            }
>          }
>  
>          @Override
> @@ -321,45 +338,6 @@ public class HtmlWidget extends ModelScreenWidget {
>          }
>      }
>  
> -    public static class ScriptTemplate extends ModelScreenWidget {
> -        protected FlexibleStringExpander locationExdr;
> -
> -        public ScriptTemplate(ModelScreen modelScreen, Element htmlTemplateElement) {
> -            super(modelScreen, htmlTemplateElement);
> -            this.locationExdr = FlexibleStringExpander.getInstance(htmlTemplateElement.getAttribute("location"));
> -        }
> -
> -        public String getLocation(Map<String, Object> context) {
> -            return locationExdr.expandString(context);
> -        }
> -
> -        @Override
> -        public void renderWidgetString(Appendable writer, Map<String, Object> context, ScreenStringRenderer screenStringRenderer) throws IOException {
> -            StringWriter stringWriter = new StringWriter();
> -            renderScriptTemplate(stringWriter, this.locationExdr, context);
> -            String data = stringWriter.toString();
> -            stringWriter.close();
> -
> -            String fileName = this.getLocation(context);
> -            fileName = fileName.substring(fileName.lastIndexOf("/")+1);
> -            // remove ".ftl"
> -            fileName = fileName.substring(0, fileName.length()-4);
> -            ScriptTemplateUtil.putScriptInSession(context, fileName, data);
> -
> -            String webappName = (String)context.get("webappName");
> -            ScriptTemplateUtil.addScriptSrcToRequest(context, "/"+webappName+"/control/getJs?name="+fileName);
> -        }
> -
> -        @Override
> -        public void accept(ModelWidgetVisitor visitor) throws Exception {
> -            visitor.visit(this);
> -        }
> -
> -        public FlexibleStringExpander getLocationExdr() {
> -            return locationExdr;
> -        }
> -    }
> -
>      @Override
>      public void accept(ModelWidgetVisitor visitor) throws Exception {
>          visitor.visit(this);
> diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelWidgetVisitor.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelWidgetVisitor.java
> index a1f89bb..f081f98 100644
> --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelWidgetVisitor.java
> +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelWidgetVisitor.java
> @@ -32,8 +32,6 @@ public interface ModelWidgetVisitor {
>  
>      void visit(HtmlWidget.HtmlTemplateDecoratorSection htmlTemplateDecoratorSection) throws Exception;
>  
> -    void visit(HtmlWidget.ScriptTemplate scriptTemplate) throws Exception;
> -
>      void visit(IterateSectionWidget iterateSectionWidget) throws Exception;
>  
>      void visit(ModelSingleForm modelForm) throws Exception;
> diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ScriptTemplateUtil.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ScriptTemplateUtil.java
> index 9d3417c..7bce317 100644
> --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ScriptTemplateUtil.java
> +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ScriptTemplateUtil.java
> @@ -27,7 +27,6 @@ import javax.servlet.http.HttpServletRequest;
>  import javax.servlet.http.HttpSession;
>  
>  import org.apache.ofbiz.base.util.UtilGenerics;
> -import org.apache.ofbiz.webapp.ftl.ScriptTemplateListTransform;
>  
>  public class ScriptTemplateUtil {
>  
> @@ -35,15 +34,17 @@ public class ScriptTemplateUtil {
>      private static String requestKey = "ScriptTemplateList";
>      private static int maxNumOfScriptInCache = 10;
>  
> +    private ScriptTemplateUtil() { }
> +
>      /**
> -     * add script src link for use by @see {@link ScriptTemplateListTransform}
> +     * add script src link for use by @see {@link org.apache.ofbiz.webapp.ftl.ScriptTemplateListTransform}
>       * @param context
>       * @param filePath
>       */
> -    public static void addScriptSrcToRequest(Map<String, Object> context, String filePath){
> -        HttpServletRequest request = (HttpServletRequest)context.get("request");
> +    public static void addScriptSrcToRequest(final Map<String, Object> context, final String filePath) {
> +        HttpServletRequest request = (HttpServletRequest) context.get("request");
>          Set<String> scriptTemplates = UtilGenerics.cast(request.getAttribute(requestKey));
> -        if (scriptTemplates==null){
> +        if (scriptTemplates == null) {
>              // use of LinkedHashSet to maintain insertion order
>              scriptTemplates = new LinkedHashSet<String>();
>              request.setAttribute(requestKey, scriptTemplates);
> @@ -52,22 +53,28 @@ public class ScriptTemplateUtil {
>      }
>  
>      /**
> -     * get the script src links collected from the "script-template" tags
> +     * get the script src links collected from the html-template tags where multi-block=true.
>       * @param request
>       * @return
>       */
> -    public static Set<String> getScriptSrcLinksFromRequest(HttpServletRequest request){
> +    public static Set<String> getScriptSrcLinksFromRequest(HttpServletRequest request) {
>          Set<String> scriptTemplates = UtilGenerics.cast(request.getAttribute(requestKey));
>          return scriptTemplates;
>      }
>  
> -    public static void putScriptInSession(Map<String, Object> context, String fileName, String fileContent){
> -        HttpSession session = (HttpSession)context.get("session");
> -        Map<String,String> scriptTemplateMap = UtilGenerics.cast(session.getAttribute(sessionKey));
> -        if (scriptTemplateMap==null){
> +    /**
> +     * put script in user session for retrieval by the browser
> +     * @param context
> +     * @param fileName
> +     * @param fileContent
> +     */
> +    public static void putScriptInSession(Map<String, Object> context, String fileName, String fileContent) {
> +        HttpSession session = (HttpSession) context.get("session");
> +        Map<String, String> scriptTemplateMap = UtilGenerics.cast(session.getAttribute(sessionKey));
> +        if (scriptTemplateMap == null) {
>              synchronized (session) {
>                  scriptTemplateMap = UtilGenerics.cast(session.getAttribute(sessionKey));
> -                if (scriptTemplateMap==null){
> +                if (scriptTemplateMap == null) {
>                      // use of LinkedHashMap to limit size of the map
>                      scriptTemplateMap = new LinkedHashMap<String, String>() {
>                          private static final long serialVersionUID = 1L;
> @@ -82,9 +89,15 @@ public class ScriptTemplateUtil {
>          scriptTemplateMap.put(fileName, fileContent);
>      }
>  
> -    public static String getScriptFromSession(HttpSession session, String fileName){
> -        Map<String,String> scriptTemplateMap = UtilGenerics.cast(session.getAttribute(sessionKey));
> -        if (scriptTemplateMap!=null){
> +    /**
> +     * Get the script stored in user session.
> +     * @param session
> +     * @param fileName
> +     * @return script to be sent back to browser
> +     */
> +    public static String getScriptFromSession(HttpSession session, final String fileName) {
> +        Map<String, String> scriptTemplateMap = UtilGenerics.cast(session.getAttribute(sessionKey));
> +        if (scriptTemplateMap != null) {
>              return scriptTemplateMap.get(fileName);
>          }
>          return null;
> diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/XmlWidgetVisitor.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/XmlWidgetVisitor.java
> index 737ced1..0777a70 100644
> --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/XmlWidgetVisitor.java
> +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/XmlWidgetVisitor.java
> @@ -24,7 +24,6 @@ import java.util.Map;
>  import org.apache.ofbiz.widget.model.HtmlWidget.HtmlTemplate;
>  import org.apache.ofbiz.widget.model.HtmlWidget.HtmlTemplateDecorator;
>  import org.apache.ofbiz.widget.model.HtmlWidget.HtmlTemplateDecoratorSection;
> -import org.apache.ofbiz.widget.model.HtmlWidget.ScriptTemplate;
>  import org.apache.ofbiz.widget.model.ModelScreenWidget.Column;
>  import org.apache.ofbiz.widget.model.ModelScreenWidget.ColumnContainer;
>  import org.apache.ofbiz.widget.model.ModelScreenWidget.Container;
> @@ -167,6 +166,7 @@ public class XmlWidgetVisitor extends XmlAbstractWidgetVisitor implements ModelW
>          writer.append("<html-template");
>          visitModelWidget(htmlTemplate);
>          visitAttribute("location", htmlTemplate.getLocationExdr());
> +        visitAttribute("multi-block", htmlTemplate.isMultiBlock());
>          writer.append("/>");
>      }
>  
> @@ -406,14 +406,6 @@ public class XmlWidgetVisitor extends XmlAbstractWidgetVisitor implements ModelW
>      }
>  
>      @Override
> -    public void visit(ScriptTemplate scriptTemplate) throws Exception {
> -        writer.append("<script-template");
> -        visitModelWidget(scriptTemplate);
> -        visitAttribute("location", scriptTemplate.getLocationExdr());
> -        writer.append("/>");
> -    }
> -
> -    @Override
>      public void visit(ModelScreen modelScreen) throws Exception {
>          writer.append("<screen");
>          visitModelWidget(modelScreen);
> diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/ScreenRenderer.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/ScreenRenderer.java
> index 888d123..ccf1ea1 100644
> --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/ScreenRenderer.java
> +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/ScreenRenderer.java
> @@ -137,7 +137,12 @@ public class ScreenRenderer {
>              }
>          } else {
>              context.put("renderFormSeqNumber", String.valueOf(renderFormSeqNumber));
> -            modelScreen.renderScreenString(writer, context, screenStringRenderer);
> +            if (context.get("MultiBlockWriter") != null) {
> +                StringWriter stringWriter = (StringWriter) context.get("MultiBlockWriter");
> +                modelScreen.renderScreenString(stringWriter, context, screenStringRenderer);
> +            } else {
> +                modelScreen.renderScreenString(writer, context, screenStringRenderer);
> +            }
>          }
>          return "";
>      }
>
Reply | Threaded
Open this post in threaded view
|

Re: FTL not work after: commit branch trunk updated: Improved: &lt;script-template> widget tag (OFBIZ-11686)

James Yong-2
Hi Olivier,

Thanks for the detailed reporting.

Confirmed multi-block="true" is not needed as there is no CSP error.
So the html-template attribute is removed for RemoveInternalOrg.ftl,
instead of introducing more fix.

Regards,
James

On 2020/05/18 08:04:09, Olivier Heintz <[hidden email]> wrote:

> Hi James,
>
> In HR, on main page, on tree company organization, with a Right Click, there is a menu with
> as last item "Remove Internal Organization" which call RemoveInternalOrg.ftl
>
> before your commit this function works
> now nothing is done
>
> after remove multi-block="true"  in the line
>  <platform-specific><html><html-template location="component://humanres/template/internalorg/RemoveInternalOrg.ftl"/></html></platform-specific>
> it works again
>
> Can you have a look at this problem
> Thank you
>
>
>
> Le 15/05/2020 à 05:17, [hidden email] a écrit :
> > This is an automated email from the ASF dual-hosted git repository.
> >
> > jamesyong 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 60c78d2  Improved: <script-template> widget tag (OFBIZ-11686)
> > 60c78d2 is described below
> >
> > commit 60c78d24be4ab2b4f8aa2f6603968863c12b9b92
> > Author: James Yong <[hidden email]>
> > AuthorDate: Fri May 15 11:16:15 2020 +0800
> >
> >     Improved: <script-template> widget tag (OFBIZ-11686)
> >    
> >     Removed script-template tag.
> >     Use multi-block=true on html-template tag instead.
> > ---
> >  applications/order/template/order/FindOrders.ftl   |  72 +++++++++++-
> >  .../order/template/order/FindOrders.js.ftl         |  86 --------------
> >  .../order/widget/ordermgr/OrderViewScreens.xml     |   3 +-
> >  .../webapp/ftl/ScriptTemplateListTransform.java    |   5 +-
> >  framework/widget/dtd/widget-screen.xsd             |   9 +-
> >  .../widget/artifact/ArtifactInfoGatherer.java      |   5 -
> >  .../org/apache/ofbiz/widget/model/HtmlWidget.java  | 124 +++++++++------------
> >  .../ofbiz/widget/model/ModelWidgetVisitor.java     |   2 -
> >  .../ofbiz/widget/model/ScriptTemplateUtil.java     |  43 ++++---
> >  .../ofbiz/widget/model/XmlWidgetVisitor.java       |  10 +-
> >  .../ofbiz/widget/renderer/ScreenRenderer.java      |   7 +-
> >  11 files changed, 160 insertions(+), 206 deletions(-)
> >
> > diff --git a/applications/order/template/order/FindOrders.ftl b/applications/order/template/order/FindOrders.ftl
> > index 0d1923d..6eaff5b 100644
> > --- a/applications/order/template/order/FindOrders.ftl
> > +++ b/applications/order/template/order/FindOrders.ftl
> > @@ -17,6 +17,76 @@ specific language governing permissions and limitations
> >  under the License.
> >  -->
> >  
> > +<script>
> > +function lookupOrders(click) {
> > +    orderIdValue = document.lookuporder.orderId.value;
> > +    if (orderIdValue.length > 1) {
> > +        document.lookuporder.action = "<@ofbizUrl>orderview</@ofbizUrl>";
> > +        document.lookuporder.method = "get";
> > +    } else {
> > +        document.lookuporder.action = "<@ofbizUrl>searchorders</@ofbizUrl>";
> > +    }
> > +
> > +    if (click) {
> > +        document.lookuporder.submit();
> > +    }
> > +    return true;
> > +}
> > +function toggleOrderId(master) {
> > +    var form = document.massOrderChangeForm;
> > +    var orders = form.elements.length;
> > +    for (var i = 0; i < orders; i++) {
> > +        var element = form.elements[i];
> > +        if ("orderIdList" == element.name) {
> > +            element.checked = master.checked;
> > +        }
> > +    }
> > +    toggleOrderIdList();
> > +}
> > +function setServiceName(selection) {
> > +    document.massOrderChangeForm.action = selection.value;
> > +}
> > +function runAction() {
> > +    var form = document.massOrderChangeForm;
> > +    form.submit();
> > +}
> > +
> > +function toggleOrderIdList() {
> > +    var form = document.massOrderChangeForm;
> > +    var orders = form.elements.length;
> > +    var isAllSelected = true;
> > +    var isSingle = true;
> > +    for (var i = 0; i < orders; i++) {
> > +        var element = form.elements[i];
> > +        if ("orderIdList" == element.name) {
> > +            if (element.checked) {
> > +                isSingle = false;
> > +            } else {
> > +                isAllSelected = false;
> > +            }
> > +        }
> > +    }
> > +    if (isAllSelected) {
> > +        jQuery('#checkAllOrders').attr('checked', true);
> > +    } else {
> > +        jQuery('#checkAllOrders').attr('checked', false);
> > +    }
> > +    jQuery('#checkAllOrders').attr("checked", isAllSelected);
> > +    if (!isSingle && jQuery('#serviceName').val() != "") {
> > +        jQuery('#submitButton').removeAttr("disabled");
> > +    } else {
> > +        jQuery('#submitButton').attr('disabled', true);
> > +    }
> > +}
> > +
> > +function paginateOrderList(viewSize, viewIndex, hideFields) {
> > +    document.paginationForm.viewSize.value = viewSize;
> > +    document.paginationForm.viewIndex.value = viewIndex;
> > +    document.paginationForm.hideFields.value = hideFields;
> > +    document.paginationForm.submit();
> > +}
> > +</script>
> > +
> >  <#if security.hasEntityPermission("ORDERMGR", "_VIEW", session)>
> >  <#if parameters.hideFields?has_content>
> >  <form name='lookupandhidefields${requestParameters.hideFields?default("Y")}' method="post" action="<@ofbizUrl>searchorders</@ofbizUrl>">
> > @@ -404,9 +474,7 @@ under the License.
> >  </form>
> >  <#if requestParameters.hideFields?default("N") != "Y">
> >  <script type="application/javascript">
> > -<!--//
> >  document.lookuporder.orderId.focus();
> > -//-->
> >  </script>
> >  </#if>
> >  
> > diff --git a/applications/order/template/order/FindOrders.js.ftl b/applications/order/template/order/FindOrders.js.ftl
> > deleted file mode 100644
> > index 0b98270..0000000
> > --- a/applications/order/template/order/FindOrders.js.ftl
> > +++ /dev/null
> > @@ -1,86 +0,0 @@
> > -/***********************************************
> > -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.
> > -***********************************************/
> > -
> > -function lookupOrders(click) {
> > -    orderIdValue = document.lookuporder.orderId.value;
> > -    if (orderIdValue.length > 1) {
> > -        document.lookuporder.action = "<@ofbizUrl>orderview</@ofbizUrl>";
> > -        document.lookuporder.method = "get";
> > -    } else {
> > -        document.lookuporder.action = "<@ofbizUrl>searchorders</@ofbizUrl>";
> > -    }
> > -
> > -    if (click) {
> > -        document.lookuporder.submit();
> > -    }
> > -    return true;
> > -}
> > -function toggleOrderId(master) {
> > -    var form = document.massOrderChangeForm;
> > -    var orders = form.elements.length;
> > -    for (var i = 0; i < orders; i++) {
> > -        var element = form.elements[i];
> > -        if ("orderIdList" == element.name) {
> > -            element.checked = master.checked;
> > -        }
> > -    }
> > -    toggleOrderIdList();
> > -}
> > -function setServiceName(selection) {
> > -    document.massOrderChangeForm.action = selection.value;
> > -}
> > -function runAction() {
> > -    var form = document.massOrderChangeForm;
> > -    form.submit();
> > -}
> > -
> > -function toggleOrderIdList() {
> > -    var form = document.massOrderChangeForm;
> > -    var orders = form.elements.length;
> > -    var isAllSelected = true;
> > -    var isSingle = true;
> > -    for (var i = 0; i < orders; i++) {
> > -        var element = form.elements[i];
> > -        if ("orderIdList" == element.name) {
> > -            if (element.checked) {
> > -                isSingle = false;
> > -            } else {
> > -                isAllSelected = false;
> > -            }
> > -        }
> > -    }
> > -    if (isAllSelected) {
> > -        jQuery('#checkAllOrders').attr('checked', true);
> > -    } else {
> > -        jQuery('#checkAllOrders').attr('checked', false);
> > -    }
> > -    jQuery('#checkAllOrders').attr("checked", isAllSelected);
> > -    if (!isSingle && jQuery('#serviceName').val() != "") {
> > -        jQuery('#submitButton').removeAttr("disabled");
> > -    } else {
> > -        jQuery('#submitButton').attr('disabled', true);
> > -    }
> > -}
> > -
> > -function paginateOrderList(viewSize, viewIndex, hideFields) {
> > -    document.paginationForm.viewSize.value = viewSize;
> > -    document.paginationForm.viewIndex.value = viewIndex;
> > -    document.paginationForm.hideFields.value = hideFields;
> > -    document.paginationForm.submit();
> > -}
> > \ No newline at end of file
> > diff --git a/applications/order/widget/ordermgr/OrderViewScreens.xml b/applications/order/widget/ordermgr/OrderViewScreens.xml
> > index 7d0667c..04b84ce 100644
> > --- a/applications/order/widget/ordermgr/OrderViewScreens.xml
> > +++ b/applications/order/widget/ordermgr/OrderViewScreens.xml
> > @@ -267,8 +267,7 @@ under the License.
> >                          <platform-specific><html><html-template location="component://common-theme/template/includes/SetMultipleSelectJs.ftl"/></html></platform-specific>
> >                          <platform-specific>
> >                              <html>
> > -                                <script-template location="component://order/template/order/FindOrders.js.ftl"/>
> > -                                <html-template location="component://order/template/order/FindOrders.ftl"/>
> > +                                <html-template multi-block="true" location="component://order/template/order/FindOrders.ftl"/>
> >                              </html>
> >                          </platform-specific>
> >                      </decorator-section>
> > diff --git a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/ScriptTemplateListTransform.java b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/ScriptTemplateListTransform.java
> > index 6b3f385..7c9bf4d 100644
> > --- a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/ScriptTemplateListTransform.java
> > +++ b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/ScriptTemplateListTransform.java
> > @@ -22,7 +22,6 @@ import java.io.IOException;
> >  import java.io.Writer;
> >  import java.util.Map;
> >  import java.util.Set;
> > -
> >  import javax.servlet.http.HttpServletRequest;
> >  
> >  import org.apache.ofbiz.widget.model.ScriptTemplateUtil;
> > @@ -53,7 +52,7 @@ public class ScriptTemplateListTransform implements TemplateTransformModel {
> >                      if (req != null) {
> >                          HttpServletRequest request = (HttpServletRequest) req.getWrappedObject();
> >                          Set<String> scriptSrcSet = ScriptTemplateUtil.getScriptSrcLinksFromRequest(request);
> > -                        if (scriptSrcSet!=null) {
> > +                        if (scriptSrcSet != null) {
> >                              String srcList = "";
> >                              for (String scriptSrc : scriptSrcSet) {
> >                                  srcList += ("<script src=\"" + scriptSrc + "\" type=\"application/javascript\"></script>\n");
> > @@ -73,7 +72,7 @@ public class ScriptTemplateListTransform implements TemplateTransformModel {
> >              }
> >  
> >              @Override
> > -            public void write(char cbuf[], int off, int len) {
> > +            public void write(char[] cbuf, int off, int len) {
> >              }
> >          };
> >  
> > diff --git a/framework/widget/dtd/widget-screen.xsd b/framework/widget/dtd/widget-screen.xsd
> > index 62ffc03..087809b 100644
> > --- a/framework/widget/dtd/widget-screen.xsd
> > +++ b/framework/widget/dtd/widget-screen.xsd
> > @@ -519,6 +519,7 @@ under the License.
> >      </xs:element>
> >      <xs:attributeGroup name="attlist.html-template">
> >          <xs:attribute type="xs:string" name="location" use="required" />
> > +        <xs:attribute type="xs:boolean" name="multi-block" use="optional" default="false" />
> >      </xs:attributeGroup>
> >      <xs:element name="html-template-decorator" substitutionGroup="HtmlWidgets">
> >          <xs:annotation>
> > @@ -544,14 +545,6 @@ under the License.
> >              <xs:attribute type="xs:string" name="name" use="required" />
> >          </xs:complexType>
> >      </xs:element>
> > -    <xs:element name="script-template" substitutionGroup="HtmlWidgets">
> > -        <xs:complexType>
> > -            <xs:attributeGroup ref="attlist.script-template" />
> > -        </xs:complexType>
> > -    </xs:element>
> > -    <xs:attributeGroup name="attlist.script-template">
> > -        <xs:attribute type="xs:string" name="location" use="required" />
> > -    </xs:attributeGroup>
> >      <!-- ============== Swing Specific Elements =============== -->
> >      <xs:element name="swing">
> >          <xs:complexType />
> > diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/artifact/ArtifactInfoGatherer.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/artifact/ArtifactInfoGatherer.java
> > index 3c96f1e..0ea3393 100644
> > --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/artifact/ArtifactInfoGatherer.java
> > +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/artifact/ArtifactInfoGatherer.java
> > @@ -38,7 +38,6 @@ import org.apache.ofbiz.widget.model.HtmlWidget;
> >  import org.apache.ofbiz.widget.model.HtmlWidget.HtmlTemplate;
> >  import org.apache.ofbiz.widget.model.HtmlWidget.HtmlTemplateDecorator;
> >  import org.apache.ofbiz.widget.model.HtmlWidget.HtmlTemplateDecoratorSection;
> > -import org.apache.ofbiz.widget.model.HtmlWidget.ScriptTemplate;
> >  import org.apache.ofbiz.widget.model.IterateSectionWidget;
> >  import org.apache.ofbiz.widget.model.ModelAction;
> >  import org.apache.ofbiz.widget.model.ModelActionVisitor;
> > @@ -357,10 +356,6 @@ public final class ArtifactInfoGatherer implements ModelWidgetVisitor, ModelActi
> >      }
> >  
> >      @Override
> > -    public void visit(ScriptTemplate scriptTemplate) throws Exception {
> > -    }
> > -
> > -    @Override
> >      public void visit(Section section) throws Exception {
> >          for (ModelAction action : section.getActions()) {
> >              action.accept(this);
> > diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/HtmlWidget.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/HtmlWidget.java
> > index b5afc68..acb850c 100644
> > --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/HtmlWidget.java
> > +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/HtmlWidget.java
> > @@ -40,6 +40,9 @@ import org.apache.ofbiz.base.util.template.FreeMarkerWorker;
> >  import org.apache.ofbiz.widget.renderer.ScreenRenderer;
> >  import org.apache.ofbiz.widget.renderer.ScreenStringRenderer;
> >  import org.apache.ofbiz.widget.renderer.html.HtmlWidgetRenderer;
> > +import org.jsoup.Jsoup;
> > +import org.jsoup.nodes.Document;
> > +import org.jsoup.select.Elements;
> >  import org.w3c.dom.Element;
> >  
> >  import freemarker.ext.beans.BeansWrapper;
> > @@ -121,8 +124,6 @@ public class HtmlWidget extends ModelScreenWidget {
> >                      subWidgets.add(new HtmlTemplate(modelScreen, childElement));
> >                  } else if ("html-template-decorator".equals(childElement.getNodeName())) {
> >                      subWidgets.add(new HtmlTemplateDecorator(modelScreen, childElement));
> > -                } else if ("script-template".equals(childElement.getNodeName())) {
> > -                    subWidgets.add(new ScriptTemplate(modelScreen, childElement));
> >                  } else {
> >                      throw new IllegalArgumentException("Tag not supported under the platform-specific -> html tag with name: "
> >                              + childElement.getNodeName());
> > @@ -178,36 +179,6 @@ public class HtmlWidget extends ModelScreenWidget {
> >          }
> >      }
> >  
> > -    public static void renderScriptTemplate(Appendable writer, FlexibleStringExpander locationExdr, Map<String, Object> context) {
> > -        String location = locationExdr.expandString(context);
> > -
> > -        if (UtilValidate.isEmpty(location)) {
> > -            throw new IllegalArgumentException("Template location is empty with search string location " + locationExdr.getOriginal());
> > -        }
> > -
> > -        if (location.endsWith(".ftl")) {
> > -            try {
> > -                boolean insertWidgetBoundaryComments = ModelWidget.widgetBoundaryCommentsEnabled(context);
> > -                if (insertWidgetBoundaryComments) {
> > -                    writer.append(HtmlWidgetRenderer.formatBoundaryJsComment("Begin", "Template", location));
> > -                }
> > -
> > -                Template template = FreeMarkerWorker.getTemplate(location, specialTemplateCache, specialConfig);
> > -                FreeMarkerWorker.renderTemplate(template, context, writer);
> > -
> > -                if (insertWidgetBoundaryComments) {
> > -                    writer.append(HtmlWidgetRenderer.formatBoundaryJsComment("End", "Template", location));
> > -                }
> > -            } catch (IllegalArgumentException | TemplateException | IOException e) {
> > -                String errMsg = "Error rendering included template at location [" + location + "]: " + e.toString();
> > -                Debug.logError(e, errMsg, MODULE);
> > -                writeError(writer, errMsg);
> > -            }
> > -        } else {
> > -            throw new IllegalArgumentException("Rendering not yet supported for the template at location: " + location);
> > -        }
> > -    }
> > -
> >      // TODO: We can make this more fancy, but for now this is very functional
> >      public static void writeError(Appendable writer, String message) {
> >          try {
> > @@ -218,19 +189,65 @@ public class HtmlWidget extends ModelScreenWidget {
> >  
> >      public static class HtmlTemplate extends ModelScreenWidget {
> >          protected FlexibleStringExpander locationExdr;
> > +        protected boolean multiBlock;
> >  
> >          public HtmlTemplate(ModelScreen modelScreen, Element htmlTemplateElement) {
> >              super(modelScreen, htmlTemplateElement);
> >              this.locationExdr = FlexibleStringExpander.getInstance(htmlTemplateElement.getAttribute("location"));
> > +            this.multiBlock = !"false".equals(htmlTemplateElement.getAttribute("multi-block"));
> >          }
> >  
> >          public String getLocation(Map<String, Object> context) {
> >              return locationExdr.expandString(context);
> >          }
> >  
> > +        public boolean isMultiBlock() {
> > +            return this.multiBlock;
> > +        }
> > +
> >          @Override
> > -        public void renderWidgetString(Appendable writer, Map<String, Object> context, ScreenStringRenderer screenStringRenderer) {
> > -            renderHtmlTemplate(writer, this.locationExdr, context);
> > +        public void renderWidgetString(Appendable writer, Map<String, Object> context, ScreenStringRenderer screenStringRenderer) throws IOException {
> > +
> > +            if (isMultiBlock()) {
> > +
> > +                StringWriter stringWriter = new StringWriter();
> > +                context.put("MultiBlockWriter", stringWriter);
> > +                renderHtmlTemplate(stringWriter, this.locationExdr, context);
> > +                context.remove("MultiBlockWriter");
> > +                String data = stringWriter.toString();
> > +                stringWriter.close();
> > +
> > +                Document doc = Jsoup.parse(data);
> > +
> > +                // extract scripts
> > +                Elements scriptElements = doc.select("script").remove();
> > +                if (scriptElements != null) {
> > +                    StringBuilder scripts = new StringBuilder();
> > +
> > +                    for (org.jsoup.nodes.Element script : scriptElements) {
> > +                        scripts.append(script.data());
> > +                    }
> > +
> > +                    // store script for retrieval by the browser
> > +                    String fileName = this.getLocation(context);
> > +                    fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
> > +                    if (fileName.endsWith(".ftl")) {
> > +                        fileName = fileName.substring(0, fileName.length() - 4);
> > +                    }
> > +                    ScriptTemplateUtil.putScriptInSession(context, fileName, scripts.toString());
> > +
> > +                    // store value to be used by ScriptTemplateList freemarker macro
> > +                    String webappName = (String) context.get("webappName");
> > +                    ScriptTemplateUtil.addScriptSrcToRequest(context, "/" + webappName + "/control/getJs?name="
> > +                            + fileName);
> > +                }
> > +
> > +                // the 'template' block
> > +                String body = doc.body().html();
> > +                writer.append(body);
> > +            } else {
> > +                renderHtmlTemplate(writer, this.locationExdr, context);
> > +            }
> >          }
> >  
> >          @Override
> > @@ -321,45 +338,6 @@ public class HtmlWidget extends ModelScreenWidget {
> >          }
> >      }
> >  
> > -    public static class ScriptTemplate extends ModelScreenWidget {
> > -        protected FlexibleStringExpander locationExdr;
> > -
> > -        public ScriptTemplate(ModelScreen modelScreen, Element htmlTemplateElement) {
> > -            super(modelScreen, htmlTemplateElement);
> > -            this.locationExdr = FlexibleStringExpander.getInstance(htmlTemplateElement.getAttribute("location"));
> > -        }
> > -
> > -        public String getLocation(Map<String, Object> context) {
> > -            return locationExdr.expandString(context);
> > -        }
> > -
> > -        @Override
> > -        public void renderWidgetString(Appendable writer, Map<String, Object> context, ScreenStringRenderer screenStringRenderer) throws IOException {
> > -            StringWriter stringWriter = new StringWriter();
> > -            renderScriptTemplate(stringWriter, this.locationExdr, context);
> > -            String data = stringWriter.toString();
> > -            stringWriter.close();
> > -
> > -            String fileName = this.getLocation(context);
> > -            fileName = fileName.substring(fileName.lastIndexOf("/")+1);
> > -            // remove ".ftl"
> > -            fileName = fileName.substring(0, fileName.length()-4);
> > -            ScriptTemplateUtil.putScriptInSession(context, fileName, data);
> > -
> > -            String webappName = (String)context.get("webappName");
> > -            ScriptTemplateUtil.addScriptSrcToRequest(context, "/"+webappName+"/control/getJs?name="+fileName);
> > -        }
> > -
> > -        @Override
> > -        public void accept(ModelWidgetVisitor visitor) throws Exception {
> > -            visitor.visit(this);
> > -        }
> > -
> > -        public FlexibleStringExpander getLocationExdr() {
> > -            return locationExdr;
> > -        }
> > -    }
> > -
> >      @Override
> >      public void accept(ModelWidgetVisitor visitor) throws Exception {
> >          visitor.visit(this);
> > diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelWidgetVisitor.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelWidgetVisitor.java
> > index a1f89bb..f081f98 100644
> > --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelWidgetVisitor.java
> > +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelWidgetVisitor.java
> > @@ -32,8 +32,6 @@ public interface ModelWidgetVisitor {
> >  
> >      void visit(HtmlWidget.HtmlTemplateDecoratorSection htmlTemplateDecoratorSection) throws Exception;
> >  
> > -    void visit(HtmlWidget.ScriptTemplate scriptTemplate) throws Exception;
> > -
> >      void visit(IterateSectionWidget iterateSectionWidget) throws Exception;
> >  
> >      void visit(ModelSingleForm modelForm) throws Exception;
> > diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ScriptTemplateUtil.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ScriptTemplateUtil.java
> > index 9d3417c..7bce317 100644
> > --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ScriptTemplateUtil.java
> > +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ScriptTemplateUtil.java
> > @@ -27,7 +27,6 @@ import javax.servlet.http.HttpServletRequest;
> >  import javax.servlet.http.HttpSession;
> >  
> >  import org.apache.ofbiz.base.util.UtilGenerics;
> > -import org.apache.ofbiz.webapp.ftl.ScriptTemplateListTransform;
> >  
> >  public class ScriptTemplateUtil {
> >  
> > @@ -35,15 +34,17 @@ public class ScriptTemplateUtil {
> >      private static String requestKey = "ScriptTemplateList";
> >      private static int maxNumOfScriptInCache = 10;
> >  
> > +    private ScriptTemplateUtil() { }
> > +
> >      /**
> > -     * add script src link for use by @see {@link ScriptTemplateListTransform}
> > +     * add script src link for use by @see {@link org.apache.ofbiz.webapp.ftl.ScriptTemplateListTransform}
> >       * @param context
> >       * @param filePath
> >       */
> > -    public static void addScriptSrcToRequest(Map<String, Object> context, String filePath){
> > -        HttpServletRequest request = (HttpServletRequest)context.get("request");
> > +    public static void addScriptSrcToRequest(final Map<String, Object> context, final String filePath) {
> > +        HttpServletRequest request = (HttpServletRequest) context.get("request");
> >          Set<String> scriptTemplates = UtilGenerics.cast(request.getAttribute(requestKey));
> > -        if (scriptTemplates==null){
> > +        if (scriptTemplates == null) {
> >              // use of LinkedHashSet to maintain insertion order
> >              scriptTemplates = new LinkedHashSet<String>();
> >              request.setAttribute(requestKey, scriptTemplates);
> > @@ -52,22 +53,28 @@ public class ScriptTemplateUtil {
> >      }
> >  
> >      /**
> > -     * get the script src links collected from the "script-template" tags
> > +     * get the script src links collected from the html-template tags where multi-block=true.
> >       * @param request
> >       * @return
> >       */
> > -    public static Set<String> getScriptSrcLinksFromRequest(HttpServletRequest request){
> > +    public static Set<String> getScriptSrcLinksFromRequest(HttpServletRequest request) {
> >          Set<String> scriptTemplates = UtilGenerics.cast(request.getAttribute(requestKey));
> >          return scriptTemplates;
> >      }
> >  
> > -    public static void putScriptInSession(Map<String, Object> context, String fileName, String fileContent){
> > -        HttpSession session = (HttpSession)context.get("session");
> > -        Map<String,String> scriptTemplateMap = UtilGenerics.cast(session.getAttribute(sessionKey));
> > -        if (scriptTemplateMap==null){
> > +    /**
> > +     * put script in user session for retrieval by the browser
> > +     * @param context
> > +     * @param fileName
> > +     * @param fileContent
> > +     */
> > +    public static void putScriptInSession(Map<String, Object> context, String fileName, String fileContent) {
> > +        HttpSession session = (HttpSession) context.get("session");
> > +        Map<String, String> scriptTemplateMap = UtilGenerics.cast(session.getAttribute(sessionKey));
> > +        if (scriptTemplateMap == null) {
> >              synchronized (session) {
> >                  scriptTemplateMap = UtilGenerics.cast(session.getAttribute(sessionKey));
> > -                if (scriptTemplateMap==null){
> > +                if (scriptTemplateMap == null) {
> >                      // use of LinkedHashMap to limit size of the map
> >                      scriptTemplateMap = new LinkedHashMap<String, String>() {
> >                          private static final long serialVersionUID = 1L;
> > @@ -82,9 +89,15 @@ public class ScriptTemplateUtil {
> >          scriptTemplateMap.put(fileName, fileContent);
> >      }
> >  
> > -    public static String getScriptFromSession(HttpSession session, String fileName){
> > -        Map<String,String> scriptTemplateMap = UtilGenerics.cast(session.getAttribute(sessionKey));
> > -        if (scriptTemplateMap!=null){
> > +    /**
> > +     * Get the script stored in user session.
> > +     * @param session
> > +     * @param fileName
> > +     * @return script to be sent back to browser
> > +     */
> > +    public static String getScriptFromSession(HttpSession session, final String fileName) {
> > +        Map<String, String> scriptTemplateMap = UtilGenerics.cast(session.getAttribute(sessionKey));
> > +        if (scriptTemplateMap != null) {
> >              return scriptTemplateMap.get(fileName);
> >          }
> >          return null;
> > diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/XmlWidgetVisitor.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/XmlWidgetVisitor.java
> > index 737ced1..0777a70 100644
> > --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/XmlWidgetVisitor.java
> > +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/XmlWidgetVisitor.java
> > @@ -24,7 +24,6 @@ import java.util.Map;
> >  import org.apache.ofbiz.widget.model.HtmlWidget.HtmlTemplate;
> >  import org.apache.ofbiz.widget.model.HtmlWidget.HtmlTemplateDecorator;
> >  import org.apache.ofbiz.widget.model.HtmlWidget.HtmlTemplateDecoratorSection;
> > -import org.apache.ofbiz.widget.model.HtmlWidget.ScriptTemplate;
> >  import org.apache.ofbiz.widget.model.ModelScreenWidget.Column;
> >  import org.apache.ofbiz.widget.model.ModelScreenWidget.ColumnContainer;
> >  import org.apache.ofbiz.widget.model.ModelScreenWidget.Container;
> > @@ -167,6 +166,7 @@ public class XmlWidgetVisitor extends XmlAbstractWidgetVisitor implements ModelW
> >          writer.append("<html-template");
> >          visitModelWidget(htmlTemplate);
> >          visitAttribute("location", htmlTemplate.getLocationExdr());
> > +        visitAttribute("multi-block", htmlTemplate.isMultiBlock());
> >          writer.append("/>");
> >      }
> >  
> > @@ -406,14 +406,6 @@ public class XmlWidgetVisitor extends XmlAbstractWidgetVisitor implements ModelW
> >      }
> >  
> >      @Override
> > -    public void visit(ScriptTemplate scriptTemplate) throws Exception {
> > -        writer.append("<script-template");
> > -        visitModelWidget(scriptTemplate);
> > -        visitAttribute("location", scriptTemplate.getLocationExdr());
> > -        writer.append("/>");
> > -    }
> > -
> > -    @Override
> >      public void visit(ModelScreen modelScreen) throws Exception {
> >          writer.append("<screen");
> >          visitModelWidget(modelScreen);
> > diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/ScreenRenderer.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/ScreenRenderer.java
> > index 888d123..ccf1ea1 100644
> > --- a/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/ScreenRenderer.java
> > +++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/ScreenRenderer.java
> > @@ -137,7 +137,12 @@ public class ScreenRenderer {
> >              }
> >          } else {
> >              context.put("renderFormSeqNumber", String.valueOf(renderFormSeqNumber));
> > -            modelScreen.renderScreenString(writer, context, screenStringRenderer);
> > +            if (context.get("MultiBlockWriter") != null) {
> > +                StringWriter stringWriter = (StringWriter) context.get("MultiBlockWriter");
> > +                modelScreen.renderScreenString(stringWriter, context, screenStringRenderer);
> > +            } else {
> > +                modelScreen.renderScreenString(writer, context, screenStringRenderer);
> > +            }
> >          }
> >          return "";
> >      }
> >
>