You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ofbiz.apache.org by James Yong <ja...@apache.org> on 2020/05/18 12:36:21 UTC

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

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 <ho...@ofbizextra.org> 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, jamesyong@apache.org 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 <ja...@apache.org>
> > 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 = "<@o...@ofbizUrl>";
> > +        document.lookuporder.method = "get";
> > +    } else {
> > +        document.lookuporder.action = "<@o...@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="<@o...@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 = "<@o...@ofbizUrl>";
> > -        document.lookuporder.method = "get";
> > -    } else {
> > -        document.lookuporder.action = "<@o...@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 "";
> >      }
> > 
>