diff --git a/vaadin-touchkit-agpl/pom.xml b/vaadin-touchkit-agpl/pom.xml index fa00a56f..12ac0c55 100644 --- a/vaadin-touchkit-agpl/pom.xml +++ b/vaadin-touchkit-agpl/pom.xml @@ -157,8 +157,8 @@ agpl 3.0 - [7.6.0.beta1,7.99.9999] - 7.7.26 + 7.7.28 + 7.7.28 empty.properties true http://oss.sonatype.org/content/repositories/vaadin-snapshots/ diff --git a/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/annotations/CacheManifestEnabled.java b/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/annotations/CacheManifestEnabled.java index 7662fd56..6b6a0d3e 100644 --- a/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/annotations/CacheManifestEnabled.java +++ b/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/annotations/CacheManifestEnabled.java @@ -22,10 +22,12 @@ import java.lang.annotation.Target; /** - * Disables o enable the manifest cache. + * This annotation is no longer needed as service worker and local storage is + * being used by Safari, Chrome and Firefox for now on. */ +@Deprecated @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface CacheManifestEnabled { - boolean value() default true; + boolean value() default true; } diff --git a/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/gwt/client/offlinemode/CacheManifestStatusIndicator.java b/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/gwt/client/offlinemode/CacheManifestStatusIndicator.java index a08fcf80..e98f54c7 100644 --- a/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/gwt/client/offlinemode/CacheManifestStatusIndicator.java +++ b/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/gwt/client/offlinemode/CacheManifestStatusIndicator.java @@ -35,7 +35,8 @@ public class CacheManifestStatusIndicator implements EntryPoint { // TODO(manolo): should be configurable via offline connector private int updateCheckInterval = 1800000; - private static final Logger logger = Logger.getLogger(CacheManifestStatusIndicator.class.getName()); + private static final Logger logger = Logger + .getLogger(CacheManifestStatusIndicator.class.getName()); private static boolean confirmationRequired = true; @@ -48,8 +49,8 @@ public void onModuleLoad() { } /** - * Let the indicator ask the user to reload the application - * when a new version of the app has been downloaded. + * Let the indicator ask the user to reload the application when a new + * version of the app has been downloaded. */ public static void setConfirmationRequired(boolean b) { confirmationRequired = b; @@ -59,7 +60,8 @@ public static void setConfirmationRequired(boolean b) { * return true if we are downloading a new version of the app. */ public static boolean isUpdating() { - return updating || getStatus() == CHECKING || getStatus() == DOWNLOADING; + return updating || getStatus() == CHECKING + || getStatus() == DOWNLOADING; } /** @@ -67,7 +69,6 @@ public static boolean isUpdating() { */ public void init() { loadSettingsFromLocalStorage(); - hookAllListeners(this); scheduleUpdateChecker(); if (getStatus() == CHECKING || getStatus() == DOWNLOADING) { showProgress(); @@ -79,8 +80,8 @@ public void init() { private void pollForStatusOnAndroid() { if (BrowserInfo.get().isAndroid()) { - Scheduler.get().scheduleFixedPeriod( - new Scheduler.RepeatingCommand() { + Scheduler.get() + .scheduleFixedPeriod(new Scheduler.RepeatingCommand() { @Override public boolean execute() { if (updating) { @@ -121,7 +122,8 @@ private void loadSettingsFromLocalStorage() { && !updateCheckIntervalStr.isEmpty()) { // The value in local storage is in seconds, but we need // milliseconds. - updateCheckInterval = Integer.valueOf(updateCheckIntervalStr) * 1000; + updateCheckInterval = Integer.valueOf(updateCheckIntervalStr) + * 1000; } } } @@ -135,9 +137,8 @@ private void scheduleUpdateChecker() { public boolean execute() { // Don't try to update cache if already updating or app is // paused - if (!isUpdating() - && OfflineModeEntrypoint.get().getNetworkStatus() - .isAppRunning()) { + if (!isUpdating() && OfflineModeEntrypoint.get() + .getNetworkStatus().isAppRunning()) { updateCache(); } return true; @@ -210,7 +211,8 @@ protected void hideProgress() { * true to force reloading the site without asking the user. */ private void requestUpdate() { - logger.info("Application cache updated, confirmationRequired=" + confirmationRequired); + logger.info("Application cache updated, confirmationRequired=" + + confirmationRequired); if (!confirmationRequired || Window.confirm(updateNowMessage)) { Window.Location.reload(); } @@ -219,48 +221,28 @@ private void requestUpdate() { /** * Hooks all listeners to the specified instance. * + * @deprecated This is NOP as Safari, Chrome and Firefox do not need this + * anymore. + * * @param instance * the instance to hook the listeners to. */ + @Deprecated protected final native void hookAllListeners( CacheManifestStatusIndicator instance) /*-{ - $wnd.applicationCache.addEventListener('cached', - function(event) { - instance.@com.vaadin.addon.touchkit.gwt.client.offlinemode.CacheManifestStatusIndicator::onCacheEvent(Lcom/google/gwt/user/client/Event;)(event); - }, false); - $wnd.applicationCache.addEventListener('checking', - function(event) { - instance.@com.vaadin.addon.touchkit.gwt.client.offlinemode.CacheManifestStatusIndicator::onCacheEvent(Lcom/google/gwt/user/client/Event;)(event); - }, false); - $wnd.applicationCache.addEventListener('downloading', - function(event) { - instance.@com.vaadin.addon.touchkit.gwt.client.offlinemode.CacheManifestStatusIndicator::onCacheEvent(Lcom/google/gwt/user/client/Event;)(event); - }, false); - $wnd.applicationCache.addEventListener('noupdate', - function(event) { - instance.@com.vaadin.addon.touchkit.gwt.client.offlinemode.CacheManifestStatusIndicator::onCacheEvent(Lcom/google/gwt/user/client/Event;)(event); - }, false); - $wnd.applicationCache.addEventListener('updateready', - function(event) { - instance.@com.vaadin.addon.touchkit.gwt.client.offlinemode.CacheManifestStatusIndicator::onCacheEvent(Lcom/google/gwt/user/client/Event;)(event); - }, false); - $wnd.applicationCache.addEventListener('error', - function(event) { - instance.@com.vaadin.addon.touchkit.gwt.client.offlinemode.CacheManifestStatusIndicator::onError(Lcom/google/gwt/user/client/Event;)(event); - }, false); }-*/; /** * @return The status of the application cache. See the constants in this - * class for possible values. Return 99 if application cache does + * class for possible values. Return 99 if application cache does * not exist. */ private static native int getStatus() /*-{ - if($wnd.applicationCache) { + if($wnd.applicationCache) { return $wnd.applicationCache.status; - } + } return 99; }-*/; diff --git a/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/settings/ApplicationCacheSettings.java b/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/settings/ApplicationCacheSettings.java index 132488c9..5951dddc 100644 --- a/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/settings/ApplicationCacheSettings.java +++ b/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/settings/ApplicationCacheSettings.java @@ -20,7 +20,7 @@ @SuppressWarnings("serial") public class ApplicationCacheSettings implements BootstrapListener { - private boolean cacheManifestEnabled = true; + private boolean cacheManifestEnabled = false; private boolean offlineModeEnabled = true; @Override @@ -38,8 +38,7 @@ public void modifyBootstrapPage(BootstrapPageResponse response) { final VaadinService service = response.getSession().getService(); final VaadinRequest request = response.getRequest(); - final String staticFilePath = service - .getStaticFileLocation(request); + final String staticFilePath = service.getStaticFileLocation(request); // VAADIN folder location final String vaadinDir = staticFilePath + "/VAADIN/"; // Figure out widgetset @@ -47,8 +46,7 @@ public void modifyBootstrapPage(BootstrapPageResponse response) { response.getUiClass()); String widgetset = response.getUIProvider().getWidgetset(event); if (widgetset == null) { - widgetset = request.getService() - .getConfiguredWidgetset(request); + widgetset = request.getService().getConfiguredWidgetset(request); } // Url for the widgetset final String widgetsetUrl = String.format( @@ -67,8 +65,7 @@ public void modifyBootstrapPage(BootstrapPageResponse response) { if (isCacheManifestEnabled()) { // Add cache manifest attribute to html tag - document.getElementsByTag("html").attr( - "manifest", + document.getElementsByTag("html").attr("manifest", vaadinDir + "widgetsets/" + widgetset + "/" + generateManifestFileName(response)); } @@ -113,21 +110,28 @@ protected String generateManifestFileName(BootstrapPageResponse response) { } /** + * @deprecated Safari, Chrome and Firefox use serviceworkerd and + * localstorage, so this is allways false with them. + * * @return true if the cache manifest (and thus application cache) is * enabled. */ + @Deprecated public boolean isCacheManifestEnabled() { - return cacheManifestEnabled && !TouchKitSettings.supportsGooglePWA(); + return false; } /** * Enable or disable the cache manifest (and thus application cache). * + * @deprecated Safari, Chrome and Firefox use serviceworkerd and + * localstorage, so this is allways false with them. + * * @param cacheManifestEnabled * true to enable. */ + @Deprecated public void setCacheManifestEnabled(boolean cacheManifestEnabled) { - this.cacheManifestEnabled = cacheManifestEnabled; } /** @@ -152,8 +156,8 @@ public void setOfflineModeEnabled(boolean offlineModeEnabled) { * cache (== new version of the widget set). * * @param message - * The new message. The default is - * "There are updates ready to be installed. Would you like to restart now?" + * The new message. The default is "There are updates ready to be + * installed. Would you like to restart now?" */ public void setUpdateNowMessage(String message) { LocalStorage.get().put(CacheManifestStatusIndicator.UPDATE_NOW_MSG_KEY, diff --git a/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/settings/TouchKitSettings.java b/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/settings/TouchKitSettings.java index 755312cf..6e4826e0 100644 --- a/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/settings/TouchKitSettings.java +++ b/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/settings/TouchKitSettings.java @@ -17,7 +17,6 @@ import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; -import com.vaadin.addon.touchkit.annotations.CacheManifestEnabled; import com.vaadin.addon.touchkit.annotations.OfflineModeEnabled; import com.vaadin.addon.touchkit.server.TouchKitServlet; import com.vaadin.addon.touchkit.service.ApplicationIcon; @@ -47,8 +46,8 @@ * which is {@link TouchKitServlet} by default. */ @SuppressWarnings("serial") -public class TouchKitSettings implements BootstrapListener, - SessionInitListener, SystemMessagesProvider { +public class TouchKitSettings implements BootstrapListener, SessionInitListener, + SystemMessagesProvider { private List stronglyCachedResources; @@ -182,28 +181,22 @@ public void modifyBootstrapPage(BootstrapPageResponse response) { } if (getApplicationCacheSettings() != null) { OfflineModeEnabled offline = null; - CacheManifestEnabled manifest = null; Class clazz = response.getUiClass(); if (clazz != null) { offline = clazz.getAnnotation(OfflineModeEnabled.class); - manifest = clazz.getAnnotation(CacheManifestEnabled.class); } - if (response.getSession().getService() instanceof VaadinServletService) { + if (response.getSession() + .getService() instanceof VaadinServletService) { clazz = ((VaadinServletService) response.getSession() .getService()).getServlet().getClass(); if (offline == null) { offline = clazz.getAnnotation(OfflineModeEnabled.class); } - if (manifest == null) { - manifest = clazz.getAnnotation(CacheManifestEnabled.class); - } } - getApplicationCacheSettings().setCacheManifestEnabled( - manifest == null || manifest.value()); - getApplicationCacheSettings().setOfflineModeEnabled( - offline == null || offline.value()); + getApplicationCacheSettings() + .setOfflineModeEnabled(offline == null || offline.value()); getApplicationCacheSettings().modifyBootstrapPage(response); } @@ -218,7 +211,8 @@ public void modifyBootstrapPage(BootstrapPageResponse response) { element.attr("rel", "manifest"); element.attr("href", contextPath + "/manifest.json"); document.getElementsByTag("head").get(0).appendChild(element); - // This meta tag is for some weird reason needed for 100% google PWA ;-) + // This meta tag is for some weird reason needed for 100% google PWA + // ;-) element = document.createElement("meta"); element.attr("name", "theme-color"); element.attr("content", getWebAppSettings().getTheme_color()); @@ -228,27 +222,34 @@ public void modifyBootstrapPage(BootstrapPageResponse response) { // TODO make this somehow more stable and cleaner String text = document.body().toString().replaceAll("\n", ""); - Pattern p = Pattern.compile(".*widgetset\": \"([^\"]+)\"", Pattern.DOTALL); + Pattern p = Pattern.compile(".*widgetset\": \"([^\"]+)\"", + Pattern.DOTALL); Matcher matcher = p.matcher(text); boolean find = matcher.find(); String wsname = ""; if (find) { - wsname = matcher.group(1); + wsname = matcher.group(1); } else { - return; + return; } - - InputStream resourceAsStream = getClass().getResourceAsStream("/VAADIN/widgetsets/" + wsname + "/" + "safari.manifest"); + + InputStream resourceAsStream = getClass() + .getResourceAsStream("/VAADIN/widgetsets/" + wsname + + "/" + "safari.manifest"); // Might be null in case of for example fallback UI if (resourceAsStream != null) { List resources = new ArrayList(); try { - final URI base = new URI(contextPath + "/VAADIN/widgetsets/" + wsname + "/"); - // the safari permutation is used by most mobile web apps - // Read the cached files from the GWT generated manifest file for service workers as well - List readLines = IOUtils.readLines(resourceAsStream); + final URI base = new URI(contextPath + + "/VAADIN/widgetsets/" + wsname + "/"); + // the safari permutation is used by most mobile web + // apps + // Read the cached files from the GWT generated manifest + // file for service workers as well + List readLines = IOUtils + .readLines(resourceAsStream); boolean cachedFilesStarted = false; for (String readLine : readLines) { if (readLine.startsWith("CACHE:")) { @@ -263,43 +264,48 @@ public void modifyBootstrapPage(BootstrapPageResponse response) { if (cachedFilesStarted) { readLine = readLine.trim(); if (!readLine.isEmpty()) { - readLine = readLine.replace("\\", "/"); + readLine = readLine.replace("\\", "/"); URI resolved = base.resolve(readLine); resources.add(resolved.toString()); } } } } catch (IOException ex) { - Logger.getLogger(TouchKitSettings.class.getName()).log(Level.SEVERE, null, ex); + Logger.getLogger(TouchKitSettings.class.getName()) + .log(Level.SEVERE, null, ex); } catch (URISyntaxException ex) { - Logger.getLogger(TouchKitSettings.class.getName()).log(Level.SEVERE, null, ex); + Logger.getLogger(TouchKitSettings.class.getName()) + .log(Level.SEVERE, null, ex); } this.stronglyCachedResources = resources; } } - if (stronglyCachedResources != null && !stronglyCachedResources.isEmpty()) { - Element serviceworkerregistration = document.createElement("script"); + if (stronglyCachedResources != null + && !stronglyCachedResources.isEmpty()) { + Element serviceworkerregistration = document + .createElement("script"); serviceworkerregistration.attr("type", "text/javascript"); - serviceworkerregistration.appendText("if ('serviceWorker' in navigator) {\n" - + " navigator.serviceWorker.register('"+contextPath+"/service-worker.js', { scope: '"+contextPath+"/' }).then(function(reg) {\n" - + "\n" - + " if(reg.installing) {\n" - + " console.log('Service worker installing');\n" - + " } else if(reg.waiting) {\n" - + " console.log('Service worker installed');\n" - + " } else if(reg.active) {\n" - + " console.log('Service worker active');\n" - + " }\n" - + "\n" - + " }).catch(function(error) {\n" - + " console.log('Registration failed with ' + error);\n" - + " });\n" - + "}"); + serviceworkerregistration + .appendText("if ('serviceWorker' in navigator) {\n" + + " navigator.serviceWorker.register('" + + contextPath + + "/service-worker.js', { scope: '" + + contextPath + "/' }).then(function(reg) {\n" + + "\n" + " if(reg.installing) {\n" + + " console.log('Service worker installing');\n" + + " } else if(reg.waiting) {\n" + + " console.log('Service worker installed');\n" + + " } else if(reg.active) {\n" + + " console.log('Service worker active');\n" + + " }\n" + "\n" + + " }).catch(function(error) {\n" + + " console.log('Registration failed with ' + error);\n" + + " });\n" + "}"); document.body().appendChild(serviceworkerregistration); } - } + } } @Override @@ -307,26 +313,34 @@ public void sessionInit(SessionInitEvent event) throws ServiceException { event.getSession().addBootstrapListener(this); event.getSession().addRequestHandler(new RequestHandler() { @Override - public boolean handleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { + public boolean handleRequest(VaadinSession session, + VaadinRequest request, VaadinResponse response) + throws IOException { final String pathInfo = request.getPathInfo(); String contextPath = request.getContextPath(); // Skip the request if the pathInfo is null if (pathInfo == null) { - return false; + return false; } if (pathInfo.endsWith("manifest.json")) { // TODO write manifest.json using Jackson or similar PrintWriter writer = response.getWriter(); - writer.append("{\n" - + " \"short_name\": \"" + getWebAppSettings().getApplicationShortName() + "\",\n" - + " \"name\": \"" + getWebAppSettings().getApplicationName() + "\",\n" - + " \"display\": \"" + getWebAppSettings().getDisplay() + "\",\n" - + " \"start_url\": \"" + contextPath + getWebAppSettings().getStart_url() + "\",\n" - + " \"background_color\": \"" + getWebAppSettings().getBackground_color() + "\",\n" - + " \"theme_color\": \"" + getWebAppSettings().getTheme_color() + "\",\n" + writer.append("{\n" + " \"short_name\": \"" + + getWebAppSettings().getApplicationShortName() + + "\",\n" + " \"name\": \"" + + getWebAppSettings().getApplicationName() + "\",\n" + + " \"display\": \"" + + getWebAppSettings().getDisplay() + "\",\n" + + " \"start_url\": \"" + contextPath + + getWebAppSettings().getStart_url() + "\",\n" + + " \"background_color\": \"" + + getWebAppSettings().getBackground_color() + + "\",\n" + " \"theme_color\": \"" + + getWebAppSettings().getTheme_color() + "\",\n" + " \"icons\": [\n"); - final ApplicationIcon[] icons = getApplicationIcons().getApplicationIcons(); + final ApplicationIcon[] icons = getApplicationIcons() + .getApplicationIcons(); for (int i = 0; i < icons.length; i++) { ApplicationIcon icon = icons[i]; if (i > 0) { @@ -350,7 +364,8 @@ public boolean handleRequest(VaadinSession session, VaadinRequest request, Vaadi + " caches.open(\"tkcache\").then(c => {\n" + " return c.addAll([\n"); - // TODO consider using https://github.com/GoogleChromeLabs/sw-precache + // TODO consider using + // https://github.com/GoogleChromeLabs/sw-precache if (stronglyCachedResources != null) { for (String stronglyCachedResource : stronglyCachedResources) { writer.write("'"); @@ -358,32 +373,27 @@ public boolean handleRequest(VaadinSession session, VaadinRequest request, Vaadi writer.write("',\n"); } } else { - Logger.getLogger(TouchKitSettings.class.getName()).log(Level.SEVERE, "strongly cached resources could not be found"); + Logger.getLogger(TouchKitSettings.class.getName()).log( + Level.SEVERE, + "strongly cached resources could not be found"); } writer.write("" + " ]).then(() => self.skipWaiting());\n" - + " })\n" - + " );\n" - + "});\n" - + "\n" + + " })\n" + " );\n" + "});\n" + "\n" + "self.addEventListener('fetch', e => {\n" + " e.respondWith(\n" + " caches.open(\"tkcache\").then(c => {\n" + " return c.match(e.request).then(res => {\n" + " return res || fetch(e.request)\n" - + " });\n" - + " })\n" - + " );\n" - + "});"); + + " });\n" + " })\n" + " );\n" + "});"); return true; } return false; } - } - ); + }); } /** @@ -457,15 +467,20 @@ public SystemMessages getSystemMessages( } /** - * @return true if Google style service worker + json manifest style PWA - * should be used instead of original iOS style home screen web app thingies. + * @return true if Google style service worker + json manifest style PWA + * should be used instead of original iOS style home screen web app + * thingies. */ public static boolean supportsGooglePWA() { try { - VaadinRequest currentRequest = VaadinServletService.getCurrentRequest(); - String useragentheader = currentRequest.getHeader("User-Agent").toLowerCase(); + VaadinRequest currentRequest = VaadinServletService + .getCurrentRequest(); + String useragentheader = currentRequest.getHeader("User-Agent") + .toLowerCase(); // Simply expect all chromes to support - if (useragentheader.contains("chrome") || useragentheader.contains("firefox")) { + if (useragentheader.contains("chrome") + || useragentheader.contains("firefox") + || useragentheader.contains("safari")) { return true; } } catch (Exception e) {