diff --git a/webfx-kit/webfx-kit-javafxweb-peers-gwt-j2cl/pom.xml b/webfx-kit/webfx-kit-javafxweb-peers-gwt-j2cl/pom.xml
index f75a51e75..74e13e2ab 100644
--- a/webfx-kit/webfx-kit-javafxweb-peers-gwt-j2cl/pom.xml
+++ b/webfx-kit/webfx-kit-javafxweb-peers-gwt-j2cl/pom.xml
@@ -21,6 +21,12 @@
0.1.0-SNAPSHOT
+
+ dev.webfx
+ webfx-kit-javafxgraphics-emul
+ 0.1.0-SNAPSHOT
+
+
dev.webfx
webfx-kit-javafxweb-emul
@@ -44,12 +50,30 @@
0.1.0-SNAPSHOT
+
+ dev.webfx
+ webfx-kit-javafxweb-enginepeer
+ 0.1.0-SNAPSHOT
+
+
dev.webfx
webfx-kit-javafxweb-peers-base
0.1.0-SNAPSHOT
+
+ dev.webfx
+ webfx-platform-scheduler
+ 0.1.0-SNAPSHOT
+
+
+
+ dev.webfx
+ webfx-platform-uischeduler
+ 0.1.0-SNAPSHOT
+
+
dev.webfx
webfx-platform-util
diff --git a/webfx-kit/webfx-kit-javafxweb-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxweb/spi/gwt/HtmlWebViewPeer.java b/webfx-kit/webfx-kit-javafxweb-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxweb/spi/gwt/HtmlWebViewPeer.java
index 22b21d44a..98d1b2a7f 100644
--- a/webfx-kit/webfx-kit-javafxweb-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxweb/spi/gwt/HtmlWebViewPeer.java
+++ b/webfx-kit/webfx-kit-javafxweb-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxweb/spi/gwt/HtmlWebViewPeer.java
@@ -4,12 +4,14 @@
import dev.webfx.kit.mapper.peers.javafxgraphics.gwtj2cl.html.HtmlNodePeer;
import dev.webfx.kit.mapper.peers.javafxgraphics.gwtj2cl.util.HtmlPaints;
import dev.webfx.kit.mapper.peers.javafxgraphics.gwtj2cl.util.HtmlUtil;
+import dev.webfx.kit.mapper.peers.javafxweb.engine.WorkerImpl;
+import dev.webfx.platform.scheduler.Scheduled;
+import dev.webfx.platform.uischeduler.UiScheduler;
import dev.webfx.platform.util.Strings;
-import elemental2.dom.CSSProperties;
-import elemental2.dom.DomGlobal;
-import elemental2.dom.HTMLElement;
-import elemental2.dom.HTMLIFrameElement;
+import elemental2.dom.*;
+import javafx.concurrent.Worker;
import javafx.event.EventHandler;
+import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.web.WebErrorEvent;
import javafx.scene.web.WebView;
@@ -36,8 +38,8 @@ public HtmlWebViewPeer(NB base, HTMLElement webViewElement) {
HtmlUtil.setStyleAttribute(iFrame, "width", "100%"); // 100% of
HtmlUtil.setStyleAttribute(iFrame, "height", "100%"); // 100% of
// Allowing fullscreen and autoplay for videos
- HtmlUtil.setAttribute(iFrame, "allowfullscreen", "true");
- iFrame.allow = "fullscreen; autoplay";
+ iFrame.allow = "fullscreen; autoplay"; // new way
+ HtmlUtil.setAttribute(iFrame, "allowfullscreen", "true"); // old way (must be executed second otherwise warning)
// Error management. Actually this listener is never called by the browser for an unknown reason. So if it's
// important for the application code to be aware of errors (ex: network errors), webfx provides an alternative
// iFrame loading mode called prefetch which is able to report such errors (see updateUrl()).
@@ -51,15 +53,18 @@ public HtmlWebViewPeer(NB base, HTMLElement webViewElement) {
if (DomGlobal.document.activeElement == iFrame) { // and the active element should be the iFrame.
// Then, we set the WebView as the new focus owner in JavaFX
N webView = getNode();
- webView.getScene().focusOwnerProperty().setValue(webView);
+ Scene scene = webView == null ? null : webView.getScene();
+ if (scene != null)
+ scene.focusOwnerProperty().setValue(webView);
}
});
// 2) Detecting when the iFrame lost focus
DomGlobal.window.addEventListener("focus", e -> { // when iFrame lost focus, the parent window gained focus
// If the WebView is still the focus owner in JavaFX, we clear that focus to report the WebView lost focus
N webView = getNode();
- if (webView.getScene().getFocusOwner() == webView) {
- webView.getScene().focusOwnerProperty().setValue(null);
+ Scene scene = webView == null ? null : webView.getScene();
+ if (scene != null && scene.getFocusOwner() == webView) {
+ scene.focusOwnerProperty().setValue(null);
}
});
}
@@ -90,6 +95,8 @@ public void updateUrl(String url) {
if (!Strings.isEmpty(iFrame.src))
iFrame.src = "";
} else {
+ WorkerImpl worker = (WorkerImpl) getNode().getEngine().getLoadWorker();
+ worker.setState(Worker.State.SCHEDULED);
// WebFX proposes different loading mode for the iFrame:
Object webfxLoadingMode = getNode().getProperties().get("webfx-loadingMode");
if ("prefetch".equals(webfxLoadingMode)) { // prefetch mode
@@ -98,14 +105,18 @@ public void updateUrl(String url) {
iFrame.contentWindow.fetch(url)
.then(response -> {
response.text().then(text -> {
+ worker.setState(Worker.State.RUNNING);
updateLoadContent(text);
+ worker.setState(Worker.State.SUCCEEDED);
return null;
}).catch_(error -> {
+ worker.setState(Worker.State.FAILED);
reportError();
return null;
});
return null;
}).catch_(error -> {
+ worker.setState(Worker.State.FAILED);
reportError();
return null;
});
@@ -115,7 +126,47 @@ public void updateUrl(String url) {
// in all situations (ex: embed YouTube videos are not loading in this mode).
iFrame.contentWindow.location.replace(url);
} else { // Standard loading mode
+ Scheduled iFrameStateChecker = UiScheduler.schedulePeriodic(100, scheduled -> {
+ // Note: iFrame.contentDocument can be inaccessible (returns null) with cross-origin
+ Document contentDocument = iFrame.contentDocument;
+ if (contentDocument != null) {
+ String readyState = contentDocument.readyState.toLowerCase();
+ //DomGlobal.console.log("iFrame readyState = " + readyState);
+ switch (readyState) {
+ case "uninitialized":
+ worker.setState(Worker.State.READY);
+ break;
+ case "loading":
+ worker.setState(Worker.State.SCHEDULED);
+ break;
+ case "loaded":
+ case "interactive":
+ worker.setState(Worker.State.RUNNING);
+ break;
+ case "complete":
+ DomGlobal.console.log("iFrame readyState = " + readyState);
+ worker.setState(Worker.State.SUCCEEDED);
+ scheduled.cancel();
+ break;
+ }
+ }
+ });
+ iFrame.onload = e -> {
+ worker.setState(Worker.State.SUCCEEDED);
+ iFrameStateChecker.cancel();
+ };
+ iFrame.onerror = e -> {
+ worker.setState(Worker.State.FAILED);
+ iFrameStateChecker.cancel();
+ return null;
+ };
+ iFrame.onabort = e -> {
+ worker.setState(Worker.State.CANCELLED);
+ iFrameStateChecker.cancel();
+ return null;
+ };
iFrame.src = url; // Standard way to load an iFrame
+
// But it has 2 downsides (which is why webfx proposes alternative loading modes):
// 1) it doesn't report any network errors (iFrame.onerror not called). Issue addressed by the webfx
// "prefetch" mode
diff --git a/webfx-kit/webfx-kit-javafxweb-registry-gwt-j2cl/pom.xml b/webfx-kit/webfx-kit-javafxweb-registry-gwt-j2cl/pom.xml
index 2df4695b2..1316d6848 100644
--- a/webfx-kit/webfx-kit-javafxweb-registry-gwt-j2cl/pom.xml
+++ b/webfx-kit/webfx-kit-javafxweb-registry-gwt-j2cl/pom.xml
@@ -21,12 +21,6 @@
0.1.0-SNAPSHOT
-
- dev.webfx
- webfx-kit-javafxgraphics-emul
- 0.1.0-SNAPSHOT
-
-
dev.webfx
webfx-kit-javafxweb-emul
@@ -68,7 +62,7 @@
dev.webfx
- webfx-kit-util
+ webfx-platform-console
0.1.0-SNAPSHOT
@@ -80,12 +74,6 @@
true
-
- dev.webfx
- webfx-platform-scheduler
- 0.1.0-SNAPSHOT
-
-
dev.webfx
webfx-platform-util
diff --git a/webfx-kit/webfx-kit-javafxweb-registry-gwt-j2cl/src/main/java/dev/webfx/kit/registry/javafxweb/GwtJSObject.java b/webfx-kit/webfx-kit-javafxweb-registry-gwt-j2cl/src/main/java/dev/webfx/kit/registry/javafxweb/GwtJSObject.java
index bb02cbb98..10e64be6c 100644
--- a/webfx-kit/webfx-kit-javafxweb-registry-gwt-j2cl/src/main/java/dev/webfx/kit/registry/javafxweb/GwtJSObject.java
+++ b/webfx-kit/webfx-kit-javafxweb-registry-gwt-j2cl/src/main/java/dev/webfx/kit/registry/javafxweb/GwtJSObject.java
@@ -61,7 +61,7 @@ private static void bindCallbackMethods(Object javaInstance) {
WebToJavaCallbacks.bindCallbackMethods(javaInstance);
}
- private static Object wrapJSObject(Object o) {
+ public static Object wrapJSObject(Object o) {
if ("object".equals(Js.typeof(o)))
o = new GwtJSObject(o);
return o;
diff --git a/webfx-kit/webfx-kit-javafxweb-registry-gwt-j2cl/src/main/java/dev/webfx/kit/registry/javafxweb/GwtWebEnginePeer.java b/webfx-kit/webfx-kit-javafxweb-registry-gwt-j2cl/src/main/java/dev/webfx/kit/registry/javafxweb/GwtWebEnginePeer.java
index 733a6517d..68fa108f2 100644
--- a/webfx-kit/webfx-kit-javafxweb-registry-gwt-j2cl/src/main/java/dev/webfx/kit/registry/javafxweb/GwtWebEnginePeer.java
+++ b/webfx-kit/webfx-kit-javafxweb-registry-gwt-j2cl/src/main/java/dev/webfx/kit/registry/javafxweb/GwtWebEnginePeer.java
@@ -2,10 +2,11 @@
import dev.webfx.kit.mapper.peers.javafxweb.engine.WebEnginePeerBase;
import dev.webfx.kit.mapper.peers.javafxweb.spi.gwt.HtmlWebViewPeer;
-import dev.webfx.kit.util.properties.FXProperties;
-import dev.webfx.platform.scheduler.Scheduler;
-import elemental2.dom.*;
-import javafx.concurrent.Worker;
+import dev.webfx.platform.console.Console;
+import elemental2.dom.Document;
+import elemental2.dom.DomGlobal;
+import elemental2.dom.HTMLIFrameElement;
+import elemental2.dom.Window;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
@@ -14,12 +15,11 @@
*/
final class GwtWebEnginePeer extends WebEnginePeerBase {
+ // Note - WebFX convention: if webEngine.getWebView() is null, it's a webEngine that applies to the global window
private final WebEngine webEngine;
public GwtWebEnginePeer(WebEngine webEngine) {
this.webEngine = webEngine;
- WebView webView = webEngine.getWebView();
- FXProperties.runNowAndOnPropertiesChange(e -> updateState(), webView == null ? null : webView.sceneProperty());
}
private HTMLIFrameElement getIFrame() {
@@ -32,8 +32,11 @@ private HTMLIFrameElement getIFrame() {
private Window getScriptWindow() {
HTMLIFrameElement iFrame = getIFrame();
+ // contentWindow is set only once the iFrame is inserted to the DOM, before that it is null
Window iFrameWindow = iFrame == null ? null : iFrame.contentWindow;
- return iFrameWindow != null ? iFrameWindow : DomGlobal.window;
+ if (iFrameWindow == null && webEngine.getWebView() == null)
+ iFrameWindow = DomGlobal.window;
+ return iFrameWindow;
}
private Document getDocument() {
@@ -42,20 +45,16 @@ private Document getDocument() {
return iFrameDocument != null ? iFrameDocument : DomGlobal.document;
}
- private void updateState() {
- Window scriptWindow = getScriptWindow();
- if (scriptWindow != null)
- worker.setState(Worker.State.READY);
- else {
- worker.setState(Worker.State.SCHEDULED);
- if (webEngine.getWebView().getScene() != null)
- Scheduler.scheduleDelay(100, this::updateState);
- }
- }
-
@Override
public Object executeScript(String script) {
- return GwtJSObject.eval(getScriptWindow(), script);
+ Window scriptWindow = getScriptWindow();
+ if (scriptWindow != null) {
+ if ("window".equals(script))
+ return GwtJSObject.wrapJSObject(scriptWindow);
+ return GwtJSObject.eval(scriptWindow, script);
+ }
+ Console.log("⚠️ Couldn't execute script because the webEngine window is not ready (" + (getIFrame() == null ? "iFrame is null)" : getIFrame().contentWindow == null ? "iFrame.contentWindow is null)" : "???)"));
+ return null;
}
@Override