diff options
author | Artur <artur@vaadin.com> | 2017-01-25 11:27:49 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-25 11:27:49 +0200 |
commit | be694984fb35262b32c89be075e6d4a059931b62 (patch) | |
tree | d66a85f91404b5bb7f82d845a25b96ec9cebf350 /client | |
parent | e397ea01e5ddb0c977561c008b84c6ed7c0ef706 (diff) | |
download | vaadin-framework-be694984fb35262b32c89be075e6d4a059931b62.tar.gz vaadin-framework-be694984fb35262b32c89be075e6d4a059931b62.zip |
Support loading of HTML imports using @HtmlImport (#8301)
Note that not all browsers yet support HTML imports. If a polyfill
is needed to load HTML imports, it must be loaded before HTML Imports
can be loaded. There is no automatic loading of any polyfills.
Diffstat (limited to 'client')
-rw-r--r-- | client/src/main/java/com/vaadin/client/DependencyLoader.java | 113 | ||||
-rw-r--r-- | client/src/main/java/com/vaadin/client/ResourceLoader.java | 52 |
2 files changed, 96 insertions, 69 deletions
diff --git a/client/src/main/java/com/vaadin/client/DependencyLoader.java b/client/src/main/java/com/vaadin/client/DependencyLoader.java index d217c824b2..4a8e054a54 100644 --- a/client/src/main/java/com/vaadin/client/DependencyLoader.java +++ b/client/src/main/java/com/vaadin/client/DependencyLoader.java @@ -17,7 +17,7 @@ package com.vaadin.client; import java.util.logging.Logger; -import com.google.gwt.core.client.JsArrayString; +import com.google.gwt.core.client.JsArray; import com.google.gwt.user.client.Command; import com.vaadin.client.ResourceLoader.ResourceLoadEvent; import com.vaadin.client.ResourceLoader.ResourceLoadListener; @@ -34,10 +34,31 @@ import com.vaadin.client.ResourceLoader.ResourceLoadListener; */ public class DependencyLoader { - private static final String STYLE_DEPENDENCIES = "styleDependencies"; - private static final String SCRIPT_DEPENDENCIES = "scriptDependencies"; + private static final String DEPENDENCIES = "dependencies"; private ApplicationConnection connection = null; + private ResourceLoader loader = ResourceLoader.get(); + + private ResourceLoadListener dependencyLoadingTracker = new ResourceLoadListener() { + + @Override + public void onLoad(ResourceLoadEvent event) { + ApplicationConfiguration.endDependencyLoading(); + } + + @Override + public void onError(ResourceLoadEvent event) { + String error = event.getResourceUrl() + " could not be loaded."; + if (event.getResourceUrl().endsWith("css")) { + error += " or the load detection failed because the stylesheet is empty."; + } + getLogger().severe(error); + // The show must go on + onLoad(event); + } + + }; + /** * Sets the ApplicationConnection this instance is connected to. * @@ -61,83 +82,43 @@ public class DependencyLoader { /** * Loads the any dependencies present in the given json snippet. * - * Scans the key "{@literal scriptDependencies}" for JavaScripts and the key - * "{@literal styleDependencies}" for style sheets. + * Handles all dependencies found with the key "{@literal dependencies}". * - * Ensures that the given JavaScript dependencies are loaded in the given - * order. Does not ensure anything about stylesheet order. + * Ensures that + * <ul> + * <li>JavaScript dependencies are loaded in the given order. + * <li>HTML imports are loaded after all JavaScripts are loaded and + * executed. + * <li>Style sheets are loaded and evaluated in some undefined order + * </ul> * * @param json * the JSON containing the dependencies to load */ public void loadDependencies(ValueMap json) { - if (json.containsKey(SCRIPT_DEPENDENCIES)) { - loadScriptDependencies(json.getJSStringArray(SCRIPT_DEPENDENCIES)); - } - if (json.containsKey(STYLE_DEPENDENCIES)) { - loadStyleDependencies(json.getJSStringArray(STYLE_DEPENDENCIES)); - } - - } - - private void loadStyleDependencies(JsArrayString dependencies) { - // Assuming no reason to interpret in a defined order - ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { - @Override - public void onLoad(ResourceLoadEvent event) { - ApplicationConfiguration.endDependencyLoading(); - } - - @Override - public void onError(ResourceLoadEvent event) { - getLogger().severe(event.getResourceUrl() - + " could not be loaded, or the load detection failed because the stylesheet is empty."); - // The show must go on - onLoad(event); - } - }; - ResourceLoader loader = ResourceLoader.get(); - for (int i = 0; i < dependencies.length(); i++) { - String url = translateVaadinUri(dependencies.get(i)); - ApplicationConfiguration.startDependencyLoading(); - loader.loadStylesheet(url, resourceLoadListener); - } - } - - private void loadScriptDependencies(final JsArrayString dependencies) { - if (dependencies.length() == 0) { + if (!json.containsKey(DEPENDENCIES)) { return; } + JsArray<ValueMap> deps = json.getJSValueMapArray(DEPENDENCIES); - // Listener that loads the next when one is completed - ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { - @Override - public void onLoad(ResourceLoadEvent event) { - // Call start for next before calling end for current + for (int i = 0; i < deps.length(); i++) { + ValueMap dep = deps.get(i); + String type = dep.getAsString("type"); + String url = connection.translateVaadinUri(dep.getAsString("url")); + ApplicationConfiguration.startDependencyLoading(); + if (type.equals("STYLESHEET")) { + loader.loadStylesheet(url, dependencyLoadingTracker); + } else if (type.equals("JAVASCRIPT")) { + loader.loadScript(url, dependencyLoadingTracker); + } else if (type.equals("HTMLIMPORT")) { + loader.loadHtmlImport(url, dependencyLoadingTracker); + } else { ApplicationConfiguration.endDependencyLoading(); + throw new IllegalArgumentException("Unknown type: " + type); } - - @Override - public void onError(ResourceLoadEvent event) { - getLogger().severe( - event.getResourceUrl() + " could not be loaded."); - // The show must go on - onLoad(event); - } - }; - - ResourceLoader loader = ResourceLoader.get(); - for (int i = 0; i < dependencies.length(); i++) { - ApplicationConfiguration.startDependencyLoading(); - String preloadUrl = translateVaadinUri(dependencies.get(i)); - loader.loadScript(preloadUrl, resourceLoadListener); } } - private String translateVaadinUri(String url) { - return connection.translateVaadinUri(url); - } - private static Logger getLogger() { return Logger.getLogger(DependencyLoader.class.getName()); } diff --git a/client/src/main/java/com/vaadin/client/ResourceLoader.java b/client/src/main/java/com/vaadin/client/ResourceLoader.java index a20daced44..f58453ced5 100644 --- a/client/src/main/java/com/vaadin/client/ResourceLoader.java +++ b/client/src/main/java/com/vaadin/client/ResourceLoader.java @@ -135,7 +135,7 @@ public class ResourceLoader { Document document = Document.get(); head = document.getElementsByTagName("head").getItem(0); - // detect already loaded scripts and stylesheets + // detect already loaded scripts, html imports and stylesheets NodeList<Element> scripts = document.getElementsByTagName("script"); for (int i = 0; i < scripts.getLength(); i++) { ScriptElement element = ScriptElement.as(scripts.getItem(i)); @@ -154,6 +154,10 @@ public class ResourceLoader { && href.length() != 0) { loadedResources.add(href); } + if ("import".equalsIgnoreCase(rel) && href != null + && href.length() != 0) { + loadedResources.add(href); + } } } @@ -215,6 +219,48 @@ public class ResourceLoader { } /** + * Loads an HTML import and notify a listener when the HTML import is + * loaded. Calling this method when the HTML import is currently loading or + * already loaded doesn't cause the HTML import to be loaded again, but the + * listener will still be notified when appropriate. + * + * @param htmlUrl + * url of HTML import to load + * @param resourceLoadListener + * listener to notify when the HTML import is loaded + */ + public void loadHtmlImport(final String htmlUrl, + final ResourceLoadListener resourceLoadListener) { + final String url = WidgetUtil.getAbsoluteUrl(htmlUrl); + ResourceLoadEvent event = new ResourceLoadEvent(this, url); + if (loadedResources.contains(url)) { + if (resourceLoadListener != null) { + resourceLoadListener.onLoad(event); + } + return; + } + + if (addListener(url, resourceLoadListener, loadListeners)) { + LinkElement linkTag = Document.get().createLinkElement(); + linkTag.setAttribute("rel", "import"); + linkTag.setAttribute("href", url); + + addOnloadHandler(linkTag, new ResourceLoadListener() { + @Override + public void onLoad(ResourceLoadEvent event) { + fireLoad(event); + } + + @Override + public void onError(ResourceLoadEvent event) { + fireError(event); + } + }, event); + head.appendChild(linkTag); + } + } + + /** * Adds an onload listener to the given element, which should be a link or a * script tag. The listener is called whenever loading is complete or an * error occurred. @@ -355,12 +401,12 @@ public class ResourceLoader { if (rules === undefined) { rules = sheet.rules; } - + if (rules === null) { // Style sheet loaded, but can't access length because of XSS -> assume there's something there return 1; } - + // Return length so we can distinguish 0 (probably 404 error) from normal case. return rules.length; } catch (err) { |