[ofbiz-framework] branch trunk updated: Improved: multi-block attribute for html-template tag (OFBIZ-11686)

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

[ofbiz-framework] branch trunk updated: Improved: multi-block attribute for html-template tag (OFBIZ-11686)

James Yong-2
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 4612e49  Improved: multi-block attribute for html-template tag (OFBIZ-11686)
4612e49 is described below

commit 4612e49fa6af21a1a68180c8b079546ff94485bb
Author: James Yong <[hidden email]>
AuthorDate: Sun Aug 23 21:55:09 2020 +0800

    Improved: multi-block attribute for html-template tag (OFBIZ-11686)
   
    Remove support to headerize script and css links from html-template
    as importLibrary js function is a more simple solution.
---
 framework/widget/dtd/widget-screen.xsd             |   4 +-
 .../org/apache/ofbiz/widget/model/HtmlWidget.java  |  34 ---
 .../ofbiz/widget/model/ModelScreenWidget.java      |  10 +-
 .../widget/model/MultiBlockHtmlTemplateUtil.java   | 301 +--------------------
 4 files changed, 3 insertions(+), 346 deletions(-)

diff --git a/framework/widget/dtd/widget-screen.xsd b/framework/widget/dtd/widget-screen.xsd
index 3bf4f1b..99f32b1 100644
--- a/framework/widget/dtd/widget-screen.xsd
+++ b/framework/widget/dtd/widget-screen.xsd
@@ -522,9 +522,7 @@ under the License.
         <xs:attribute type="xs:boolean" name="multi-block" use="optional" default="false">
             <xs:annotation>
                 <xs:documentation>
-                    Multi-block processing of template targeted for the html body.
-                    Inline script will be rendered as external script after html body tag.
-                    External script tag with attribute data-import='head' will be rendered within html head tag.
+                    Inline script will be rendered as external script at bottom of body tag.
                 </xs:documentation>
             </xs:annotation>
         </xs:attribute>
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 e1ee228..1a160ad 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
@@ -232,12 +232,6 @@ public class HtmlWidget extends ModelScreenWidget {
                         scripts.append(script.data());
                         script.remove();
                     }
-                } else {
-                    String dataImport = script.attr("data-import");
-                    if ("head".equals(dataImport)) {
-                        // remove external script in the template that is meant to be imported in the html header
-                        script.remove();
-                    }
                 }
             }
 
@@ -263,17 +257,6 @@ public class HtmlWidget extends ModelScreenWidget {
                 MultiBlockHtmlTemplateUtil.addScriptLinkForFoot(request, url);
             }
         }
-        // extract css link tags
-        Elements csslinkElements = doc.select("link");
-        if (csslinkElements != null && csslinkElements.size() > 0) {
-            for (org.jsoup.nodes.Element link : csslinkElements) {
-                String src = link.attr("href");
-                if (UtilValidate.isNotEmpty(src)) {
-                    // remove external style sheet in the template that will be added to the html header
-                    link.remove();
-                }
-            }
-        }
 
         // the 'template' block
         String body = doc.body().html();
@@ -296,23 +279,6 @@ public class HtmlWidget extends ModelScreenWidget {
             super(modelScreen, htmlTemplateElement);
             this.locationExdr = FlexibleStringExpander.getInstance(htmlTemplateElement.getAttribute("location"));
             this.multiBlock = !"false".equals(htmlTemplateElement.getAttribute("multi-block"));
-
-            if (this.isMultiBlock()) {
-                String origLoc = this.locationExdr.getOriginal();
-                Set<String> urls = null;
-                if (origLoc.contains("${")) {
-                    urls = new LinkedHashSet<>();
-                    urls.add(origLoc);
-                } else {
-                    try {
-                        urls = MultiBlockHtmlTemplateUtil.extractHtmlLinksFromRawHtmlTemplate(origLoc);
-                    } catch (IOException e) {
-                        String errMsg = "Error getting html imports from template at location [" + origLoc + "]: " + e.toString();
-                        Debug.logError(e, errMsg, MODULE);
-                    }
-                }
-                MultiBlockHtmlTemplateUtil.addHtmlLinksToHtmlLinksForScreenCache(modelScreen.getSourceLocation(), modelScreen.getName(), urls);
-            }
         }
 
         public String getLocation(Map<String, Object> context) {
diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelScreenWidget.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelScreenWidget.java
index 7867197..6a6f54a 100644
--- a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelScreenWidget.java
+++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/ModelScreenWidget.java
@@ -268,11 +268,7 @@ public abstract class ModelScreenWidget extends ModelWidget {
 
         @Override
         public void renderWidgetString(Appendable writer, Map<String, Object> context,
-                                       ScreenStringRenderer screenStringRenderer) throws GeneralException, IOException {
-
-            String location = getModelScreen().getSourceLocation();
-            String name = getModelScreen().getName();
-            MultiBlockHtmlTemplateUtil.storeScreenLocationName(context, location, name);
+                                       ScreenStringRenderer screenStringRenderer) throws GeneralException {
 
             // check the condition, if there is one
             boolean condTrue = true;
@@ -288,8 +284,6 @@ public abstract class ModelScreenWidget extends ModelWidget {
                 AbstractModelAction.runSubActions(this.actions, context);
 
                 try {
-                    MultiBlockHtmlTemplateUtil.addLinksToLayoutSettingsWhenConditionsAreRight(context);
-
                     // section by definition do not themselves do anything, so this method will generally do nothing, but we'll call it anyway
                     screenStringRenderer.renderSectionBegin(writer, context, this);
 
@@ -777,7 +771,6 @@ public abstract class ModelScreenWidget extends ModelWidget {
             this.nameExdr = FlexibleStringExpander.getInstance(includeScreenElement.getAttribute("name"));
             this.locationExdr = FlexibleStringExpander.getInstance(includeScreenElement.getAttribute("location"));
             this.shareScopeExdr = FlexibleStringExpander.getInstance(includeScreenElement.getAttribute("share-scope"));
-            MultiBlockHtmlTemplateUtil.addChildScreen(modelScreen, this.locationExdr.getOriginal(), this.nameExdr.getOriginal());
         }
 
         @Override
@@ -873,7 +866,6 @@ public abstract class ModelScreenWidget extends ModelWidget {
                 sectionMap.put(decoratorSection.getName(), decoratorSection);
             }
             this.sectionMap = Collections.unmodifiableMap(sectionMap);
-            MultiBlockHtmlTemplateUtil.addChildScreen(modelScreen, this.locationExdr.getOriginal(), this.nameExdr.getOriginal());
         }
 
         @Override
diff --git a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/MultiBlockHtmlTemplateUtil.java b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/MultiBlockHtmlTemplateUtil.java
index abbc57f..9da9124 100644
--- a/framework/widget/src/main/java/org/apache/ofbiz/widget/model/MultiBlockHtmlTemplateUtil.java
+++ b/framework/widget/src/main/java/org/apache/ofbiz/widget/model/MultiBlockHtmlTemplateUtil.java
@@ -42,13 +42,7 @@ import org.jsoup.select.Elements;
 
 /**
  * Utility to support different handling of code blocks in an html template:
- * 1. external script tags with data-import="head" are removed from the rendered template and merged with
- *    layoutSetting.javaScripts. This helps to keep page-specific external script tags to the html-template that needs it.
- *    In future when the javascript library allows, we can use import module functionality of the browser instead of
- *    special handling at the server side.
- * 2. link tags are removed from the rendered template and merged with layoutSetting.styleSheets.
- *    This helps to keep page-specific link tags to the html-template that needs it.
- * 3. Inline javascript tags are turned into external javascript tags for better compliance of Content Security Policy.
+ * 1. Inline javascript tags are turned into external javascript tags for better compliance of Content Security Policy.
  *    These external javascript tags are placed at the bottom of the html page. The scripts are retrieved via the getJs
  *    request handler.
  */
@@ -56,12 +50,10 @@ public final class MultiBlockHtmlTemplateUtil {
 
     private static final String MODULE = MultiBlockHtmlTemplateUtil.class.getName();
     public static final String MULTI_BLOCK_WRITER = "multiBlockWriter";
-    private static final String HTML_LINKS_FOR_HEAD = "htmlLinksForHead";
     private static final String SCRIPT_LINKS_FOR_FOOT = "ScriptLinksForFoot";
     private static int maxScriptCacheSizePerUserSession = 10;
     private static int estimatedConcurrentUserSessions = 250;
     private static int estimatedScreensWithMultiBlockHtmlTemplate = 200;
-    private static int estimatedScreensWithChildScreen = 200;
     /**
      * Store inline script extracted from freemarker template for a user session.
      * Number of inline scripts for a user session will be constraint by {@link MultiBlockHtmlTemplateUtil#maxScriptCacheSizePerUserSession}
@@ -86,301 +78,10 @@ public final class MultiBlockHtmlTemplateUtil {
                     return size() > estimatedScreensWithMultiBlockHtmlTemplate;
                 }
             };
-    /**
-     * Store set of dependent screens info, in form of screen location + hash + name, of a given parent screen.
-     * The set may contain entry of an expression of the dependent screen location and will need to be expanded before use.
-     */
-    private static LinkedHashMap<String, Set<String>> childScreenCache =
-            new LinkedHashMap<String, Set<String>>() {
-                private static final long serialVersionUID = 1L;
-                protected boolean removeEldestEntry(Map.Entry<String, Set<String>> eldest) {
-                    return size() > estimatedScreensWithChildScreen;
-                }
-            };
 
     private MultiBlockHtmlTemplateUtil() { }
 
     /**
-     * Allow unit testing to check results
-     * @return
-     */
-    public static Map<String, Set<String>> getChildScreenCache() {
-        return Collections.unmodifiableMap(childScreenCache);
-    }
-
-    /**
-     * Add child screen info to {@link MultiBlockHtmlTemplateUtil#childScreenCache}.
-     * @param parentModelScreen parent screen.
-     * @param location screen location. Expression is allowed.
-     * @param name screen name. Expression is allowed.
-     */
-    public static void addChildScreen(ModelScreen parentModelScreen, String location, String name) {
-        String key = parentModelScreen.getSourceLocation() + "#" + parentModelScreen.getName();
-        Set<String> childList = childScreenCache.get(key);
-        if (childList == null) {
-            childList = new LinkedHashSet<>();
-            childScreenCache.put(key, childList);
-        }
-        if (UtilValidate.isNotEmpty(location)) {
-            childList.add(location + "#" + name);
-        } else {
-            childList.add(parentModelScreen.getSourceLocation() + "#" + name);
-        }
-    }
-
-    /**
-     * Add Html Imports to {@link MultiBlockHtmlTemplateUtil#htmlLinksForScreenCache}.
-     * @param location screen location. Expression is not allowed.
-     * @param name screen name. Expression is not allowed.
-     * @param urls Set of html links associated with the screen. May contain expression to html-template location.
-     */
-    public static void addHtmlLinksToHtmlLinksForScreenCache(String location, String name, Set<String> urls) {
-        if (UtilValidate.isEmpty(urls)) {
-            return;
-        }
-        String locHashName = location + "#" + name;
-        Set<String> htmlLinks = htmlLinksForScreenCache.get(locHashName);
-        if (htmlLinks == null) {
-            htmlLinks = new LinkedHashSet<>();
-            htmlLinksForScreenCache.put(locHashName, htmlLinks);
-        }
-        htmlLinks.addAll(urls);
-    }
-
-    /**
-     * Get locations for external css link and external script from raw html template
-     * @param fileLocation Location to html template. Expression is not allowed.
-     * @return
-     */
-    public static Set<String> extractHtmlLinksFromRawHtmlTemplate(String fileLocation) throws IOException {
-        Set<String> imports = new LinkedHashSet<>();
-        String template = FileUtil.readString("UTF-8", FileUtil.getFile(fileLocation));
-        Document doc = Jsoup.parseBodyFragment(template);
-        Elements scriptElements = doc.select("script");
-        if (scriptElements != null && scriptElements.size() > 0) {
-            for (org.jsoup.nodes.Element script : scriptElements) {
-                String src = script.attr("src");
-                if (UtilValidate.isNotEmpty(src)) {
-                    String dataImport = script.attr("data-import");
-                    if ("head".equals(dataImport)) {
-                        imports.add("script:" + src);
-                    }
-                }
-            }
-        }
-        Elements csslinkElements = doc.select("link");
-        if (csslinkElements != null && csslinkElements.size() > 0) {
-            for (org.jsoup.nodes.Element link : csslinkElements) {
-                String src = link.attr("href");
-                if (UtilValidate.isNotEmpty(src)) {
-                    imports.add("link:" + src);
-                }
-            }
-        }
-        return imports;
-    }
-
-    /**
-     * Store the 1st screen called by request.
-     * Request attribute HTML_LINKS_FOR_HEAD will be set to a string containing the initial screen location + hash + name
-     * @param context
-     * @param location screen location. Expression is not allowed.
-     * @param name screen name. Expression is not allowed.
-     */
-    public static void storeScreenLocationName(final Map<String, Object> context, String location, String name) {
-        HttpServletRequest request = (HttpServletRequest) context.get("request");
-        if (request == null) {
-            return;
-        }
-        if (request.getAttribute(HTML_LINKS_FOR_HEAD) == null) {
-            String currentLocationHashName = location + "#" + name;
-            request.setAttribute(HTML_LINKS_FOR_HEAD, currentLocationHashName);
-        }
-    }
-
-    /**
-     * Add html links to the header.
-     * Request attribute HTML_LINKS_FOR_HEAD will be set to boolean when all html links are added to the 'layoutSettings'.
-     * Request attribute HTML_LINKS_FOR_HEAD will be set to Object[] when there are expressions for screen location or
-     * template location that need to be expanded, in order to read the content of screen or template.
-     * @param context
-     * @throws IOException
-     */
-    public static void addLinksToLayoutSettingsWhenConditionsAreRight(final Map<String, Object> context) throws IOException {
-        HttpServletRequest request = (HttpServletRequest) context.get("request");
-        if (request == null) {
-            return;
-        }
-        // check "layoutSettings.javaScripts" is not empty
-        Map<String, Object> layoutSettings = UtilGenerics.cast(context.get("layoutSettings"));
-        if (UtilValidate.isEmpty(layoutSettings)) {
-            return;
-        }
-        List<String> layoutSettingsJavaScripts = UtilGenerics.cast(layoutSettings.get("javaScripts"));
-        if (UtilValidate.isEmpty(layoutSettingsJavaScripts)) {
-            return;
-        }
-        List<String> layoutSettingsStyleSheets = UtilGenerics.cast(layoutSettings.get("styleSheets"));
-        if (UtilValidate.isEmpty(layoutSettingsStyleSheets)) {
-            layoutSettingsStyleSheets = UtilGenerics.cast(layoutSettings.get("VT_STYLESHEET"));
-            if (UtilValidate.isEmpty(layoutSettingsStyleSheets)) {
-                return;
-            }
-        }
-        // ensure initTheme.groovy has run.
-        Map<String, String> commonScreenLocations = UtilGenerics.cast(context.get("commonScreenLocations"));
-        if (UtilValidate.isEmpty(commonScreenLocations)) {
-            return;
-        }
-        Locale locale = (Locale) context.get("locale");
-        Object objValue = request.getAttribute(HTML_LINKS_FOR_HEAD);
-        if (objValue instanceof String) {
-            // store expressions for Template Location that is not expanded correctly, for retry.
-            Set<String> retryTemplateLocationExpressions = new LinkedHashSet<>();
-            // store expressions for Screen Location + Hash + Name that is not expanded correctly, for retry.
-            Set<String> retryScreenLocHashNameExpressions = new LinkedHashSet<>();
-            String currentLocationHashName = (String) request.getAttribute(HTML_LINKS_FOR_HEAD);
-            // store the html links that will be added to 'layoutSettings'
-            Set<String> htmlLinks = new LinkedHashSet<>();
-            Set<String> locHashNameList = getRelatedScreenLocationHashName(currentLocationHashName, context);
-            for (String locHashName:locHashNameList) {
-                if (locHashName.contains("${")) {
-                    // as getRelatedScreenLocationHashName method has already tried to expand the expression;
-                    // just add to the retry variable for the next loop.
-                    retryScreenLocHashNameExpressions.add(locHashName);
-                    continue;
-                }
-                // check for any html links associated with the screen
-                Set<String> urls = htmlLinksForScreenCache.get(locHashName);
-                if (UtilValidate.isNotEmpty(urls)) {
-                    for (String url : urls) {
-                        // if an expression is found, treat it like template location location, instead of html link
-                        if (url.contains("${")) {
-                            String expandUrl = FlexibleStringExpander.expandString(url, context);
-                            if (UtilValidate.isNotEmpty(expandUrl)) {
-                                htmlLinks.addAll(extractHtmlLinksFromRawHtmlTemplate(expandUrl));
-                            } else {
-                                retryTemplateLocationExpressions.add(url);
-                            }
-                        } else {
-                            if (!htmlLinks.contains(url)) {
-                                htmlLinks.add(url);
-                            }
-                        }
-                    }
-                }
-            }
-            if (UtilValidate.isNotEmpty(htmlLinks)) {
-                addLinksToLayoutSettings(htmlLinks, layoutSettingsJavaScripts, layoutSettingsStyleSheets, locale);
-            }
-            if (UtilValidate.isEmpty(retryScreenLocHashNameExpressions) && UtilValidate.isEmpty(retryTemplateLocationExpressions)) {
-                request.setAttribute(HTML_LINKS_FOR_HEAD, true);
-            } else {
-                Object[] retry = new Object[2];
-                retry[0] = retryScreenLocHashNameExpressions;
-                retry[1] = retryTemplateLocationExpressions;
-                request.setAttribute(HTML_LINKS_FOR_HEAD, retry);
-            }
-        } else if (objValue instanceof Object[]) {
-            Object[] retry = UtilGenerics.cast(request.getAttribute(HTML_LINKS_FOR_HEAD));
-            Set<String> retryScreenLocHashNameExpressions = UtilGenerics.cast(retry[0]);
-            Set<String> retryTemplateLocationExpressions = UtilGenerics.cast(retry[1]);
-            Set<String> htmlLinks = new HashSet<>();
-            if (UtilValidate.isNotEmpty(retryScreenLocHashNameExpressions)) {
-                for (Iterator<String> it = retryScreenLocHashNameExpressions.iterator(); it.hasNext();) {
-                    String locHashName = it.next();
-                    String expandLocHashName = FlexibleStringExpander.expandString(locHashName, context);
-                    if (!expandLocHashName.startsWith("#") && !expandLocHashName.endsWith("#")) {
-                        Set<String> urls = htmlLinksForScreenCache.get(expandLocHashName);
-                        if (UtilValidate.isNotEmpty(urls)) {
-                            for (String url : urls) {
-                                if (url.contains("${")) {
-                                    retryTemplateLocationExpressions.add(url);
-                                } else {
-                                    if (!htmlLinks.contains(url)) {
-                                        htmlLinks.add(url);
-                                    }
-                                }
-                            }
-                        }
-                        it.remove();
-                    }
-                }
-            }
-
-            if (UtilValidate.isNotEmpty(retryTemplateLocationExpressions)) {
-                for (Iterator<String> it = retryTemplateLocationExpressions.iterator(); it.hasNext();) {
-                    String url = it.next();
-                    // we know url contains "${", so we expand the url
-                    String expandUrl = FlexibleStringExpander.expandString(url, context);
-                    if (UtilValidate.isNotEmpty(expandUrl)) {
-                        htmlLinks.addAll(extractHtmlLinksFromRawHtmlTemplate(expandUrl));
-                        it.remove();
-                    }
-
-                }
-            }
-            if (UtilValidate.isNotEmpty(htmlLinks)) {
-                addLinksToLayoutSettings(htmlLinks, layoutSettingsJavaScripts, layoutSettingsStyleSheets, locale);
-            }
-            if (UtilValidate.isEmpty(retryScreenLocHashNameExpressions) && UtilValidate.isEmpty(retryTemplateLocationExpressions)) {
-                request.setAttribute(HTML_LINKS_FOR_HEAD, true);
-            } else {
-                Object[] retry2 = new Object[2];
-                retry2[0] = retryScreenLocHashNameExpressions;
-                retry2[1] = retryTemplateLocationExpressions;
-                request.setAttribute(HTML_LINKS_FOR_HEAD, retry2);
-            }
-        }
-    }
-
-    private static void addLinksToLayoutSettings(Set<String> htmlLinks,
-                                                 List<String> layoutSettingsJavaScripts,
-                                                 List<String> layoutSettingsStyleSheets, Locale locale) {
-        for (String link : htmlLinks) {
-            if (link.startsWith("script:")) {
-                String url = link.substring(7);
-                // check url is not already in layoutSettings.javaScripts
-                if (!layoutSettingsJavaScripts.contains(url)) {
-                    layoutSettingsJavaScripts.add(url);
-                }
-            } else if (link.startsWith("link:")) {
-                String url = link.substring(5);
-                // check url is not already in layoutSettings.styleSheets
-                if (!layoutSettingsStyleSheets.contains(url)) {
-                    layoutSettingsStyleSheets.add(url);
-                }
-            }
-        }
-    }
-
-    /**
-     * Get all the child screens including itself
-     * @param locationHashName
-     * @return
-     */
-    private static Set<String> getRelatedScreenLocationHashName(String locationHashName, final Map<String, Object> context) {
-        Set<String> resultList = new HashSet<>();
-        resultList.add(locationHashName);
-        Set<String> locHashNameList = childScreenCache.get(locationHashName);
-        if (locHashNameList != null) {
-            for (String locHashName : locHashNameList) {
-                String exLocHashName = "";
-                if (locHashName.contains("${")) {
-                    exLocHashName = FlexibleStringExpander.expandString(locHashName, context);
-                    if (exLocHashName.startsWith("#") || exLocHashName.endsWith("#")) {
-                        exLocHashName = locHashName;
-                    }
-                } else {
-                    exLocHashName = locHashName;
-                }
-                resultList.addAll(getRelatedScreenLocationHashName(exLocHashName, context));
-            }
-        }
-        return resultList;
-    }
-
-    /**
      * add script link for page footer.
      * @param request
      * @param filePath