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 |
Free forum by Nabble | Edit this page |