From 7cd33123f07e2415ad968dfd7f71e82f15d775db Mon Sep 17 00:00:00 2001 From: tatulund Date: Wed, 20 Oct 2021 16:57:33 +0300 Subject: [PATCH 1/4] Fix for Vaadin 7.7.28 and new Jsoup version --- .../addon/touchkit/settings/ApplicationCacheSettings.java | 2 +- .../com/vaadin/addon/touchkit/settings/ViewPortSettings.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 5055c04c..132488c9 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 @@ -63,7 +63,7 @@ public void modifyBootstrapPage(BootstrapPageResponse response) { script = script.replace("});", ",\"widgetsetUrl\":\"" + widgetsetUrl + "\",\"offlineEnabled\":" + isOfflineModeEnabled() + "});"); - scriptTag.appendChild(new DataNode(script, scriptTag.baseUri())); + scriptTag.appendChild(new DataNode(script)); if (isCacheManifestEnabled()) { // Add cache manifest attribute to html tag diff --git a/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/settings/ViewPortSettings.java b/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/settings/ViewPortSettings.java index 2c1fa832..5209b9e5 100644 --- a/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/settings/ViewPortSettings.java +++ b/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/settings/ViewPortSettings.java @@ -136,7 +136,7 @@ public void modifyBootstrapPage(BootstrapPageResponse response) { Element head = document.getElementsByTag("head").get(0); DocumentType doctype = (DocumentType) html.previousSibling(); - DocumentType html5doc = new DocumentType("html", "", "", ""); + DocumentType html5doc = new DocumentType("html", "", ""); doctype.replaceWith(html5doc); Element element = document.createElement("meta"); From f35f6c159c80fa27f64b43b1848605f1643e9e66 Mon Sep 17 00:00:00 2001 From: tatulund Date: Thu, 6 Oct 2022 18:45:23 +0300 Subject: [PATCH 2/4] Chnage Safari to use PWA approach, deprecate and inactive application cache manifest functionality as incompatible with modern browsers --- vaadin-touchkit-agpl/pom.xml | 4 +- .../annotations/CacheManifestEnabled.java | 6 +- .../CacheManifestStatusIndicator.java | 478 +++++++++--------- .../settings/ApplicationCacheSettings.java | 13 +- .../touchkit/settings/TouchKitSettings.java | 10 +- 5 files changed, 242 insertions(+), 269 deletions(-) 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..c964c3d6 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 @@ -17,265 +17,237 @@ * offline mode is ready to be used. */ public class CacheManifestStatusIndicator implements EntryPoint { - public static final String UPDATE_NOW_MSG_KEY = "updateNowMessage"; - public static final String UPDATE_CHECK_INTERVAL_KEY = "updateCheckInterval"; + public static final String UPDATE_NOW_MSG_KEY = "updateNowMessage"; + public static final String UPDATE_CHECK_INTERVAL_KEY = "updateCheckInterval"; - private static final int UNCACHED = 0; - private static final int IDLE = 1; - private static final int CHECKING = 2; - private static final int DOWNLOADING = 3; - private static final int UPDATEREADY = 4; - private static final int OBSOLETE = 5; + private static final int UNCACHED = 0; + private static final int IDLE = 1; + private static final int CHECKING = 2; + private static final int DOWNLOADING = 3; + private static final int UPDATEREADY = 4; + private static final int OBSOLETE = 5; - private Element progressElement; - private String updateNowMessage = "There are updates ready to be installed. Would you like to restart now?"; - private static boolean updating; + private Element progressElement; + private String updateNowMessage = "There are updates ready to be installed. Would you like to restart now?"; + private static boolean updating; - // Check for updates once every 30 min by default. - // TODO(manolo): should be configurable via offline connector - private int updateCheckInterval = 1800000; + // Check for updates once every 30 min by default. + // 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; + private static boolean confirmationRequired = true; - @Override - public void onModuleLoad() { - // Do nothing if document has no manifest. - if (hasManifest()) { - init(); - } - } - - /** - * 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; - } - - /** - * return true if we are downloading a new version of the app. - */ - public static boolean isUpdating() { - return updating || getStatus() == CHECKING || getStatus() == DOWNLOADING; - } - - /** - * Initializes and starts the monitoring. - */ - public void init() { - loadSettingsFromLocalStorage(); - hookAllListeners(this); - scheduleUpdateChecker(); - if (getStatus() == CHECKING || getStatus() == DOWNLOADING) { - showProgress(); - } - // Sometimes android leaves the status indicator spinning and spinning - // and spinning... - pollForStatusOnAndroid(); - } - - private void pollForStatusOnAndroid() { - if (BrowserInfo.get().isAndroid()) { - Scheduler.get().scheduleFixedPeriod( - new Scheduler.RepeatingCommand() { - @Override - public boolean execute() { - if (updating) { - // The normal listeners are working correctly - return false; - } - switch (getStatus()) { - case IDLE: - hideProgress(); - return false; - case UPDATEREADY: - requestUpdate(); - return false; - default: - return true; - } - } - }, 500); - } - } - - /** - * Loads the configurable settings from localstorage. The settings are - * "updateNowMessage" for specifying the message to show when a new version - * of the cache is ready, and "updateCheckInterval" for specifying how often - * to check for new versions. - */ - private void loadSettingsFromLocalStorage() { - Storage localStorage = Storage.getLocalStorageIfSupported(); - if (localStorage != null) { - String newMessage = localStorage.getItem(UPDATE_NOW_MSG_KEY); - if (newMessage != null && !newMessage.isEmpty()) { - updateNowMessage = newMessage; - } - String updateCheckIntervalStr = localStorage - .getItem(UPDATE_CHECK_INTERVAL_KEY); - if (updateCheckIntervalStr != null - && !updateCheckIntervalStr.isEmpty()) { - // The value in local storage is in seconds, but we need - // milliseconds. - updateCheckInterval = Integer.valueOf(updateCheckIntervalStr) * 1000; - } - } - } - - /** - * Check for updates to the application cache every 30 minutes - */ - private void scheduleUpdateChecker() { - Scheduler.get().scheduleFixedPeriod(new Scheduler.RepeatingCommand() { - @Override - public boolean execute() { - // Don't try to update cache if already updating or app is - // paused - if (!isUpdating() - && OfflineModeEntrypoint.get().getNetworkStatus() - .isAppRunning()) { - updateCache(); - } - return true; - } - }, updateCheckInterval); - } - - /** - * Called when a cache event is triggered. All events except for error - * events are handled here. - * - * @param event - * The event. - */ - protected void onCacheEvent(Event event) { - // consoleLog(event.getType()); - if ("cached".equals(event.getType())) { - hideProgress(); - } else if ("checking".equals(event.getType())) { - showProgress(); - } else if ("downloading".equals(event.getType())) { - updating = true; - showProgress(); - } else if ("noupdate".equals(event.getType())) { - hideProgress(); - } else if ("updateready".equals(event.getType())) { - hideProgress(); - requestUpdate(); - updating = false; - } - } - - /** - * Called when an error event is triggered. - * - * @param event - * The error event. - */ - protected void onError(Event event) { - logger.severe("An error occurred"); - } - - /** - * Shows the progress element, which, by default, is styled to be a small - * animated spinner in the top right corner of the screen. - */ - protected void showProgress() { - if (progressElement == null) { - progressElement = Document.get().createDivElement(); - progressElement.addClassName("v-cache-loading-indicator"); - } - RootPanel.getBodyElement().appendChild(progressElement); - } - - /** - * Hides the progress element. - */ - protected void hideProgress() { - if (progressElement != null) { - progressElement.removeFromParent(); - } - } - - /** - * Called when a new version of the application cache (i.e. the widgetset) - * has been detected. The default implementation asks the user if we should - * update now unless forced. - * - * @param force - * true to force reloading the site without asking the user. - */ - private void requestUpdate() { - logger.info("Application cache updated, confirmationRequired=" + confirmationRequired); - if (!confirmationRequired || Window.confirm(updateNowMessage)) { - Window.Location.reload(); - } - } - - /** - * Hooks all listeners to the specified instance. - * - * @param instance - * the instance to hook the listeners to. - */ - 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 - * not exist. - */ - private static native int getStatus() - /*-{ + @Override + public void onModuleLoad() { + // Do nothing if document has no manifest. + if (hasManifest()) { + init(); + } + } + + /** + * 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; + } + + /** + * return true if we are downloading a new version of the app. + */ + public static boolean isUpdating() { + return updating || getStatus() == CHECKING || getStatus() == DOWNLOADING; + } + + /** + * Initializes and starts the monitoring. + */ + public void init() { + loadSettingsFromLocalStorage(); + scheduleUpdateChecker(); + if (getStatus() == CHECKING || getStatus() == DOWNLOADING) { + showProgress(); + } + // Sometimes android leaves the status indicator spinning and spinning + // and spinning... + pollForStatusOnAndroid(); + } + + private void pollForStatusOnAndroid() { + if (BrowserInfo.get().isAndroid()) { + Scheduler.get().scheduleFixedPeriod(new Scheduler.RepeatingCommand() { + @Override + public boolean execute() { + if (updating) { + // The normal listeners are working correctly + return false; + } + switch (getStatus()) { + case IDLE: + hideProgress(); + return false; + case UPDATEREADY: + requestUpdate(); + return false; + default: + return true; + } + } + }, 500); + } + } + + /** + * Loads the configurable settings from localstorage. The settings are + * "updateNowMessage" for specifying the message to show when a new version of + * the cache is ready, and "updateCheckInterval" for specifying how often to + * check for new versions. + */ + private void loadSettingsFromLocalStorage() { + Storage localStorage = Storage.getLocalStorageIfSupported(); + if (localStorage != null) { + String newMessage = localStorage.getItem(UPDATE_NOW_MSG_KEY); + if (newMessage != null && !newMessage.isEmpty()) { + updateNowMessage = newMessage; + } + String updateCheckIntervalStr = localStorage.getItem(UPDATE_CHECK_INTERVAL_KEY); + if (updateCheckIntervalStr != null && !updateCheckIntervalStr.isEmpty()) { + // The value in local storage is in seconds, but we need + // milliseconds. + updateCheckInterval = Integer.valueOf(updateCheckIntervalStr) * 1000; + } + } + } + + /** + * Check for updates to the application cache every 30 minutes + */ + private void scheduleUpdateChecker() { + Scheduler.get().scheduleFixedPeriod(new Scheduler.RepeatingCommand() { + @Override + public boolean execute() { + // Don't try to update cache if already updating or app is + // paused + if (!isUpdating() && OfflineModeEntrypoint.get().getNetworkStatus().isAppRunning()) { + updateCache(); + } + return true; + } + }, updateCheckInterval); + } + + /** + * Called when a cache event is triggered. All events except for error events + * are handled here. + * + * @param event + * The event. + */ + protected void onCacheEvent(Event event) { + // consoleLog(event.getType()); + if ("cached".equals(event.getType())) { + hideProgress(); + } else if ("checking".equals(event.getType())) { + showProgress(); + } else if ("downloading".equals(event.getType())) { + updating = true; + showProgress(); + } else if ("noupdate".equals(event.getType())) { + hideProgress(); + } else if ("updateready".equals(event.getType())) { + hideProgress(); + requestUpdate(); + updating = false; + } + } + + /** + * Called when an error event is triggered. + * + * @param event + * The error event. + */ + protected void onError(Event event) { + logger.severe("An error occurred"); + } + + /** + * Shows the progress element, which, by default, is styled to be a small + * animated spinner in the top right corner of the screen. + */ + protected void showProgress() { + if (progressElement == null) { + progressElement = Document.get().createDivElement(); + progressElement.addClassName("v-cache-loading-indicator"); + } + RootPanel.getBodyElement().appendChild(progressElement); + } + + /** + * Hides the progress element. + */ + protected void hideProgress() { + if (progressElement != null) { + progressElement.removeFromParent(); + } + } + + /** + * Called when a new version of the application cache (i.e. the widgetset) has + * been detected. The default implementation asks the user if we should update + * now unless forced. + * + * @param force + * true to force reloading the site without asking the user. + */ + private void requestUpdate() { + logger.info("Application cache updated, confirmationRequired=" + confirmationRequired); + if (!confirmationRequired || Window.confirm(updateNowMessage)) { + Window.Location.reload(); + } + } + + /** + * 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) + /*-{ + }-*/; + + /** + * @return The status of the application cache. See the constants in this class + * for possible values. Return 99 if application cache does not exist. + */ + private static native int getStatus() + /*-{ if($wnd.applicationCache) { - return $wnd.applicationCache.status; + return $wnd.applicationCache.status; } - return 99; - }-*/; - - /** - * Asks the application cache to update itself, i.e. visit the server and - * check if there's an update available. - */ - protected static native void updateCache() - /*-{ - return $wnd.applicationCache.update(); - }-*/; - - // Return true if the document has the manifest attribute - private static native boolean hasManifest() - /*-{ - return $doc.documentElement.hasAttribute('manifest'); - }-*/; + return 99; + }-*/; + + /** + * Asks the application cache to update itself, i.e. visit the server and check + * if there's an update available. + */ + protected static native void updateCache() + /*-{ + return $wnd.applicationCache.update(); + }-*/; + + // Return true if the document has the manifest attribute + private static native boolean hasManifest() + /*-{ + return $doc.documentElement.hasAttribute('manifest'); + }-*/; } 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..61cb1c5e 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 @@ -113,21 +113,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; } /** 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..175cb9b6 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; @@ -182,12 +181,10 @@ 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) { clazz = ((VaadinServletService) response.getSession() @@ -195,13 +192,8 @@ public void modifyBootstrapPage(BootstrapPageResponse response) { 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().modifyBootstrapPage(response); @@ -465,7 +457,7 @@ public static boolean supportsGooglePWA() { 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) { From ddb0d840de5e048155d82e5e01a896c72974a6d3 Mon Sep 17 00:00:00 2001 From: tatulund Date: Thu, 6 Oct 2022 18:52:20 +0300 Subject: [PATCH 3/4] Fix code formatting --- .../CacheManifestStatusIndicator.java | 476 +++++++++--------- .../settings/ApplicationCacheSettings.java | 23 +- .../touchkit/settings/TouchKitSettings.java | 149 +++--- 3 files changed, 339 insertions(+), 309 deletions(-) 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 c964c3d6..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 @@ -17,237 +17,247 @@ * offline mode is ready to be used. */ public class CacheManifestStatusIndicator implements EntryPoint { - public static final String UPDATE_NOW_MSG_KEY = "updateNowMessage"; - public static final String UPDATE_CHECK_INTERVAL_KEY = "updateCheckInterval"; - - private static final int UNCACHED = 0; - private static final int IDLE = 1; - private static final int CHECKING = 2; - private static final int DOWNLOADING = 3; - private static final int UPDATEREADY = 4; - private static final int OBSOLETE = 5; - - private Element progressElement; - private String updateNowMessage = "There are updates ready to be installed. Would you like to restart now?"; - private static boolean updating; - - // Check for updates once every 30 min by default. - // TODO(manolo): should be configurable via offline connector - private int updateCheckInterval = 1800000; - - private static final Logger logger = Logger.getLogger(CacheManifestStatusIndicator.class.getName()); - - private static boolean confirmationRequired = true; - - @Override - public void onModuleLoad() { - // Do nothing if document has no manifest. - if (hasManifest()) { - init(); - } - } - - /** - * 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; - } - - /** - * return true if we are downloading a new version of the app. - */ - public static boolean isUpdating() { - return updating || getStatus() == CHECKING || getStatus() == DOWNLOADING; - } - - /** - * Initializes and starts the monitoring. - */ - public void init() { - loadSettingsFromLocalStorage(); - scheduleUpdateChecker(); - if (getStatus() == CHECKING || getStatus() == DOWNLOADING) { - showProgress(); - } - // Sometimes android leaves the status indicator spinning and spinning - // and spinning... - pollForStatusOnAndroid(); - } - - private void pollForStatusOnAndroid() { - if (BrowserInfo.get().isAndroid()) { - Scheduler.get().scheduleFixedPeriod(new Scheduler.RepeatingCommand() { - @Override - public boolean execute() { - if (updating) { - // The normal listeners are working correctly - return false; - } - switch (getStatus()) { - case IDLE: - hideProgress(); - return false; - case UPDATEREADY: - requestUpdate(); - return false; - default: - return true; - } - } - }, 500); - } - } - - /** - * Loads the configurable settings from localstorage. The settings are - * "updateNowMessage" for specifying the message to show when a new version of - * the cache is ready, and "updateCheckInterval" for specifying how often to - * check for new versions. - */ - private void loadSettingsFromLocalStorage() { - Storage localStorage = Storage.getLocalStorageIfSupported(); - if (localStorage != null) { - String newMessage = localStorage.getItem(UPDATE_NOW_MSG_KEY); - if (newMessage != null && !newMessage.isEmpty()) { - updateNowMessage = newMessage; - } - String updateCheckIntervalStr = localStorage.getItem(UPDATE_CHECK_INTERVAL_KEY); - if (updateCheckIntervalStr != null && !updateCheckIntervalStr.isEmpty()) { - // The value in local storage is in seconds, but we need - // milliseconds. - updateCheckInterval = Integer.valueOf(updateCheckIntervalStr) * 1000; - } - } - } - - /** - * Check for updates to the application cache every 30 minutes - */ - private void scheduleUpdateChecker() { - Scheduler.get().scheduleFixedPeriod(new Scheduler.RepeatingCommand() { - @Override - public boolean execute() { - // Don't try to update cache if already updating or app is - // paused - if (!isUpdating() && OfflineModeEntrypoint.get().getNetworkStatus().isAppRunning()) { - updateCache(); - } - return true; - } - }, updateCheckInterval); - } - - /** - * Called when a cache event is triggered. All events except for error events - * are handled here. - * - * @param event - * The event. - */ - protected void onCacheEvent(Event event) { - // consoleLog(event.getType()); - if ("cached".equals(event.getType())) { - hideProgress(); - } else if ("checking".equals(event.getType())) { - showProgress(); - } else if ("downloading".equals(event.getType())) { - updating = true; - showProgress(); - } else if ("noupdate".equals(event.getType())) { - hideProgress(); - } else if ("updateready".equals(event.getType())) { - hideProgress(); - requestUpdate(); - updating = false; - } - } - - /** - * Called when an error event is triggered. - * - * @param event - * The error event. - */ - protected void onError(Event event) { - logger.severe("An error occurred"); - } - - /** - * Shows the progress element, which, by default, is styled to be a small - * animated spinner in the top right corner of the screen. - */ - protected void showProgress() { - if (progressElement == null) { - progressElement = Document.get().createDivElement(); - progressElement.addClassName("v-cache-loading-indicator"); - } - RootPanel.getBodyElement().appendChild(progressElement); - } - - /** - * Hides the progress element. - */ - protected void hideProgress() { - if (progressElement != null) { - progressElement.removeFromParent(); - } - } - - /** - * Called when a new version of the application cache (i.e. the widgetset) has - * been detected. The default implementation asks the user if we should update - * now unless forced. - * - * @param force - * true to force reloading the site without asking the user. - */ - private void requestUpdate() { - logger.info("Application cache updated, confirmationRequired=" + confirmationRequired); - if (!confirmationRequired || Window.confirm(updateNowMessage)) { - Window.Location.reload(); - } - } - - /** - * 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) - /*-{ - }-*/; - - /** - * @return The status of the application cache. See the constants in this class - * for possible values. Return 99 if application cache does not exist. - */ - private static native int getStatus() - /*-{ - if($wnd.applicationCache) { - return $wnd.applicationCache.status; - } - return 99; - }-*/; - - /** - * Asks the application cache to update itself, i.e. visit the server and check - * if there's an update available. - */ - protected static native void updateCache() - /*-{ - return $wnd.applicationCache.update(); - }-*/; - - // Return true if the document has the manifest attribute - private static native boolean hasManifest() - /*-{ - return $doc.documentElement.hasAttribute('manifest'); - }-*/; + public static final String UPDATE_NOW_MSG_KEY = "updateNowMessage"; + public static final String UPDATE_CHECK_INTERVAL_KEY = "updateCheckInterval"; + + private static final int UNCACHED = 0; + private static final int IDLE = 1; + private static final int CHECKING = 2; + private static final int DOWNLOADING = 3; + private static final int UPDATEREADY = 4; + private static final int OBSOLETE = 5; + + private Element progressElement; + private String updateNowMessage = "There are updates ready to be installed. Would you like to restart now?"; + private static boolean updating; + + // Check for updates once every 30 min by default. + // TODO(manolo): should be configurable via offline connector + private int updateCheckInterval = 1800000; + + private static final Logger logger = Logger + .getLogger(CacheManifestStatusIndicator.class.getName()); + + private static boolean confirmationRequired = true; + + @Override + public void onModuleLoad() { + // Do nothing if document has no manifest. + if (hasManifest()) { + init(); + } + } + + /** + * 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; + } + + /** + * return true if we are downloading a new version of the app. + */ + public static boolean isUpdating() { + return updating || getStatus() == CHECKING + || getStatus() == DOWNLOADING; + } + + /** + * Initializes and starts the monitoring. + */ + public void init() { + loadSettingsFromLocalStorage(); + scheduleUpdateChecker(); + if (getStatus() == CHECKING || getStatus() == DOWNLOADING) { + showProgress(); + } + // Sometimes android leaves the status indicator spinning and spinning + // and spinning... + pollForStatusOnAndroid(); + } + + private void pollForStatusOnAndroid() { + if (BrowserInfo.get().isAndroid()) { + Scheduler.get() + .scheduleFixedPeriod(new Scheduler.RepeatingCommand() { + @Override + public boolean execute() { + if (updating) { + // The normal listeners are working correctly + return false; + } + switch (getStatus()) { + case IDLE: + hideProgress(); + return false; + case UPDATEREADY: + requestUpdate(); + return false; + default: + return true; + } + } + }, 500); + } + } + + /** + * Loads the configurable settings from localstorage. The settings are + * "updateNowMessage" for specifying the message to show when a new version + * of the cache is ready, and "updateCheckInterval" for specifying how often + * to check for new versions. + */ + private void loadSettingsFromLocalStorage() { + Storage localStorage = Storage.getLocalStorageIfSupported(); + if (localStorage != null) { + String newMessage = localStorage.getItem(UPDATE_NOW_MSG_KEY); + if (newMessage != null && !newMessage.isEmpty()) { + updateNowMessage = newMessage; + } + String updateCheckIntervalStr = localStorage + .getItem(UPDATE_CHECK_INTERVAL_KEY); + if (updateCheckIntervalStr != null + && !updateCheckIntervalStr.isEmpty()) { + // The value in local storage is in seconds, but we need + // milliseconds. + updateCheckInterval = Integer.valueOf(updateCheckIntervalStr) + * 1000; + } + } + } + + /** + * Check for updates to the application cache every 30 minutes + */ + private void scheduleUpdateChecker() { + Scheduler.get().scheduleFixedPeriod(new Scheduler.RepeatingCommand() { + @Override + public boolean execute() { + // Don't try to update cache if already updating or app is + // paused + if (!isUpdating() && OfflineModeEntrypoint.get() + .getNetworkStatus().isAppRunning()) { + updateCache(); + } + return true; + } + }, updateCheckInterval); + } + + /** + * Called when a cache event is triggered. All events except for error + * events are handled here. + * + * @param event + * The event. + */ + protected void onCacheEvent(Event event) { + // consoleLog(event.getType()); + if ("cached".equals(event.getType())) { + hideProgress(); + } else if ("checking".equals(event.getType())) { + showProgress(); + } else if ("downloading".equals(event.getType())) { + updating = true; + showProgress(); + } else if ("noupdate".equals(event.getType())) { + hideProgress(); + } else if ("updateready".equals(event.getType())) { + hideProgress(); + requestUpdate(); + updating = false; + } + } + + /** + * Called when an error event is triggered. + * + * @param event + * The error event. + */ + protected void onError(Event event) { + logger.severe("An error occurred"); + } + + /** + * Shows the progress element, which, by default, is styled to be a small + * animated spinner in the top right corner of the screen. + */ + protected void showProgress() { + if (progressElement == null) { + progressElement = Document.get().createDivElement(); + progressElement.addClassName("v-cache-loading-indicator"); + } + RootPanel.getBodyElement().appendChild(progressElement); + } + + /** + * Hides the progress element. + */ + protected void hideProgress() { + if (progressElement != null) { + progressElement.removeFromParent(); + } + } + + /** + * Called when a new version of the application cache (i.e. the widgetset) + * has been detected. The default implementation asks the user if we should + * update now unless forced. + * + * @param force + * true to force reloading the site without asking the user. + */ + private void requestUpdate() { + logger.info("Application cache updated, confirmationRequired=" + + confirmationRequired); + if (!confirmationRequired || Window.confirm(updateNowMessage)) { + Window.Location.reload(); + } + } + + /** + * 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) + /*-{ + }-*/; + + /** + * @return The status of the application cache. See the constants in this + * class for possible values. Return 99 if application cache does + * not exist. + */ + private static native int getStatus() + /*-{ + if($wnd.applicationCache) { + return $wnd.applicationCache.status; + } + return 99; + }-*/; + + /** + * Asks the application cache to update itself, i.e. visit the server and + * check if there's an update available. + */ + protected static native void updateCache() + /*-{ + return $wnd.applicationCache.update(); + }-*/; + + // Return true if the document has the manifest attribute + private static native boolean hasManifest() + /*-{ + return $doc.documentElement.hasAttribute('manifest'); + }-*/; } 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 61cb1c5e..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 @@ -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,22 +110,22 @@ protected String generateManifestFileName(BootstrapPageResponse response) { } /** - * @deprecated Safari, Chrome and Firefox use serviceworkerd and localstorage, - * so this is allways false with them. + * @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 false; + 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. + * @deprecated Safari, Chrome and Firefox use serviceworkerd and + * localstorage, so this is allways false with them. * * @param cacheManifestEnabled * true to enable. @@ -159,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 175cb9b6..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 @@ -46,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; @@ -186,7 +186,8 @@ public void modifyBootstrapPage(BootstrapPageResponse response) { if (clazz != null) { offline = clazz.getAnnotation(OfflineModeEnabled.class); } - if (response.getSession().getService() instanceof VaadinServletService) { + if (response.getSession() + .getService() instanceof VaadinServletService) { clazz = ((VaadinServletService) response.getSession() .getService()).getServlet().getClass(); if (offline == null) { @@ -194,8 +195,8 @@ public void modifyBootstrapPage(BootstrapPageResponse response) { } } - getApplicationCacheSettings().setOfflineModeEnabled( - offline == null || offline.value()); + getApplicationCacheSettings() + .setOfflineModeEnabled(offline == null || offline.value()); getApplicationCacheSettings().modifyBootstrapPage(response); } @@ -210,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()); @@ -220,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:")) { @@ -255,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 @@ -299,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) { @@ -342,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("'"); @@ -350,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; } - } - ); + }); } /** @@ -449,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") || useragentheader.contains("safari")) { + if (useragentheader.contains("chrome") + || useragentheader.contains("firefox") + || useragentheader.contains("safari")) { return true; } } catch (Exception e) { From 5ebbbc59ba12636792be6d223a9614a745e7e9d5 Mon Sep 17 00:00:00 2001 From: tatulund Date: Fri, 7 Oct 2022 11:43:07 +0300 Subject: [PATCH 4/4] Fix datepicker double icon issue --- .../com/vaadin/addon/touchkit/gwt/client/theme/touchkit.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/gwt/client/theme/touchkit.css b/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/gwt/client/theme/touchkit.css index afdc7488..47256a46 100644 --- a/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/gwt/client/theme/touchkit.css +++ b/vaadin-touchkit-agpl/src/main/java/com/vaadin/addon/touchkit/gwt/client/theme/touchkit.css @@ -1797,6 +1797,10 @@ select.v-select-select::-ms-expand { width:100%; } +.v-touchkit-datepicker>input::-webkit-calendar-picker-indicator { + background: none !important; +} + .v-touchkit-datepicker:after, .v-select:after { content: fa-icon-chevron-down;