Pop-ups
This page describes how to work with pop-ups, display or suppress them.
Overview
Any web page can display pop-up windows using one of the following ways:
Using the
window.open()
JavaScript function. For example:window.open("https://www.google.com", "_blank", "resizable=yes, top=500, left=500, width=400, height=400");
Through a link with the
target
attribute:<a href="https://www.google.com" target="_blank">Open Google</a>
By default all pop-ups are suppressed.
Opening pop-ups
In order to change the default behavior and take control over creation of pop-ups use the CreatePopupCallback
and OpenPopupCallback
callbacks.
The CreatePopupCallback
callback is invoked when the engine wants to know whether pop-up can be created or not. The following code shows how to allow creating a pop-up:
browser.set(CreatePopupCallback.class, (params) -> CreatePopupCallback.Response.create());
browser.register(CreatePopupCallback {
CreatePopupCallback.Response.create()
})
If the CreatePopupCallback
callback allows to create a pop-up, the OpenPopupCallback
callback will be invoked. In this callback you can access the created pop-up and display it if necessary. For example:
browser.set(OpenPopupCallback.class, (params) -> {
// Access the created popup.
var popup = params.popupBrowser();
return OpenPopupCallback.Response.proceed();
});
browser.register(OpenPopupCallback { params ->
// Access the created popup.
val popup = params.popupBrowser()
OpenPopupCallback.Response.proceed()
})
The popup
instance in the sample above does not have any web page loaded at the time the callback is invoked. The web page will be loaded later. At this moment you can register all required event listeners and callbacks, but you cannot access DOM or JavaScript, because the popup
does not have a Frame
yet.
Suppressing pop-ups
To suppress pop-ups use the following approach:
browser.set(CreatePopupCallback.class, params -> CreatePopupCallback.Response.suppress());
browser.register(CreatePopupCallback {
CreatePopupCallback.Response.suppress()
})
Displaying pop-ups
When you create a Swing or JavaFX BrowserView
, it automatically configures the given Browser
instance with the default implementation of the CreatePopupCallback
and OpenPopupCallback
callbacks.
The default implementation of the CreatePopupCallback
allows creating all pop-ups:
browser.set(CreatePopupCallback.class, params -> CreatePopupCallback.Response.create());
browser.register(CreatePopupCallback {
CreatePopupCallback.Response.create()
})
The default implementation of the OpenPopupCallback
callback for both Swing and JavaFX you can find below.
Swing
The default implementation for Swing BrowserView
is the following:
import com.teamdev.jxbrowser.browser.callback.OpenPopupCallback;
import com.teamdev.jxbrowser.browser.event.BrowserClosed;
import com.teamdev.jxbrowser.browser.event.TitleChanged;
import com.teamdev.jxbrowser.browser.event.UpdateBoundsRequested;
import com.teamdev.jxbrowser.ui.Rect;
import com.teamdev.jxbrowser.ui.Size;
import com.teamdev.jxbrowser.view.swing.BrowserView;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import static javax.swing.SwingUtilities.invokeLater;
/**
* The default {@link OpenPopupCallback} implementation for the Swing UI toolkit
* that creates and shows a new window with the embedded popup browser.
*/
public final class DefaultOpenPopupCallbackSwing implements OpenPopupCallback {
private static final int DEFAULT_POPUP_WIDTH = 800;
private static final int DEFAULT_POPUP_HEIGHT = 600;
@Override
public Response on(Params params) {
var browser = params.popupBrowser();
invokeLater(() -> {
var view = BrowserView.newInstance(browser);
var frame = new JFrame();
frame.add(view, BorderLayout.CENTER);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
invokeLater(browser::close);
}
});
updateBounds(frame, params.initialBounds());
browser.on(TitleChanged.class, event -> invokeLater(() ->
frame.setTitle(event.title())
));
browser.on(BrowserClosed.class, event -> invokeLater(() -> {
frame.setVisible(false);
frame.dispose();
}));
browser.on(UpdateBoundsRequested.class, event -> invokeLater(() ->
updateBounds(frame, event.bounds())
));
frame.setVisible(true);
});
return Response.proceed();
}
private static void updateBounds(JFrame frame, Rect bounds) {
if (bounds.size().isEmpty()) {
frame.setLocationByPlatform(true);
frame.setSize(DEFAULT_POPUP_WIDTH, DEFAULT_POPUP_HEIGHT);
} else {
frame.setLocation(toPoint(bounds.origin()));
frame.getContentPane().setPreferredSize(toDimension(bounds.size()));
frame.pack();
}
}
private static Dimension toDimension(Size size) {
return new Dimension(size.width(), size.height());
}
private static Point toPoint(com.teamdev.jxbrowser.ui.Point point) {
return new Point(point.x(), point.y());
}
}
import com.teamdev.jxbrowser.browser.callback.OpenPopupCallback
import com.teamdev.jxbrowser.browser.event.BrowserClosed
import com.teamdev.jxbrowser.browser.event.TitleChanged
import com.teamdev.jxbrowser.browser.event.UpdateBoundsRequested
import com.teamdev.jxbrowser.dsl.subscribe
import com.teamdev.jxbrowser.ui.Point
import com.teamdev.jxbrowser.ui.Rect
import com.teamdev.jxbrowser.ui.Size
import com.teamdev.jxbrowser.view.swing.BrowserView
import java.awt.BorderLayout
import java.awt.Dimension
import java.awt.event.WindowAdapter
import java.awt.event.WindowEvent
import javax.swing.JFrame
import javax.swing.SwingUtilities.invokeLater
/**
* The default [OpenPopupCallback] implementation for the Swing UI toolkit
* that creates and shows a new window with the embedded popup browser.
*/
class DefaultOpenPopupCallbackSwing : OpenPopupCallback {
override fun on(params: OpenPopupCallback.Params): OpenPopupCallback.Response {
val browser = params.popupBrowser()
invokeLater {
val view = BrowserView.newInstance(browser)
val frame = JFrame()
frame.add(view, BorderLayout.CENTER)
frame.addWindowListener(object: WindowAdapter() {
override fun windowClosing(e: WindowEvent) {
invokeLater { browser.close() }
}
})
updateBounds(frame, params.initialBounds())
browser.subscribe<TitleChanged> { event ->
invokeLater { frame.title = event.title() }
}
browser.subscribe<BrowserClosed> {
invokeLater {
frame.isVisible = false
frame.dispose()
}
}
browser.subscribe<UpdateBoundsRequested> { event ->
invokeLater { updateBounds(frame, event.bounds()) }
}
frame.isVisible = true
}
return OpenPopupCallback.Response.proceed()
}
companion object {
private const val DEFAULT_POPUP_WIDTH = 800
private const val DEFAULT_POPUP_HEIGHT = 600
private fun updateBounds(frame: JFrame, bounds: Rect) {
if (bounds.size().isEmpty) {
frame.isLocationByPlatform = true
frame.setSize(DEFAULT_POPUP_WIDTH, DEFAULT_POPUP_HEIGHT)
} else {
frame.location = toPoint(bounds.origin())
frame.contentPane.preferredSize = toDimension(bounds.size())
frame.pack()
}
}
private fun toDimension(size: Size): Dimension {
return Dimension(size.width(), size.height())
}
private fun toPoint(point: Point): java.awt.Point {
return java.awt.Point(point.x(), point.y())
}
}
}
JavaFX
The default implementation for JavaFX BrowserView
is the following:
import static javafx.application.Platform.runLater;
import com.teamdev.jxbrowser.browser.callback.OpenPopupCallback;
import com.teamdev.jxbrowser.browser.event.BrowserClosed;
import com.teamdev.jxbrowser.browser.event.TitleChanged;
import com.teamdev.jxbrowser.browser.event.UpdateBoundsRequested;
import com.teamdev.jxbrowser.ui.Rect;
import com.teamdev.jxbrowser.view.javafx.BrowserView;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
* The default {@link OpenPopupCallback} implementation for the JavaFX UI toolkit
* that creates and shows a new window with the embedded popup browser.
*/
public final class DefaultOpenPopupCallbackJavaFx implements OpenPopupCallback {
private static final int DEFAULT_POPUP_WIDTH = 800;
private static final int DEFAULT_POPUP_HEIGHT = 600;
@Override
public Response on(Params params) {
var browser = params.popupBrowser();
runLater(() -> {
var view = BrowserView.newInstance(browser);
var stage = new Stage();
var root = new StackPane();
var scene = new Scene(root);
root.getChildren().add(view);
stage.setScene(scene);
updateBounds(stage, params.initialBounds());
stage.setOnCloseRequest(event -> browser.close());
browser.on(TitleChanged.class, event ->
runLater(() -> stage.setTitle(event.title()))
);
browser.on(BrowserClosed.class, event ->
runLater(stage::close)
);
browser.on(UpdateBoundsRequested.class, event ->
runLater(() -> updateBounds(stage, event.bounds()))
);
stage.show();
});
return Response.proceed();
}
private static void updateBounds(Stage stage, Rect bounds) {
if (bounds.size().isEmpty()) {
stage.setWidth(DEFAULT_POPUP_WIDTH);
stage.setHeight(DEFAULT_POPUP_HEIGHT);
} else {
stage.setX(bounds.origin().x());
stage.setY(bounds.origin().y());
stage.setWidth(bounds.size().width());
stage.setHeight(bounds.size().height());
}
}
}
import com.teamdev.jxbrowser.browser.callback.OpenPopupCallback
import com.teamdev.jxbrowser.browser.event.BrowserClosed
import com.teamdev.jxbrowser.browser.event.TitleChanged
import com.teamdev.jxbrowser.browser.event.UpdateBoundsRequested
import com.teamdev.jxbrowser.dsl.subscribe
import com.teamdev.jxbrowser.ui.Rect
import com.teamdev.jxbrowser.view.javafx.BrowserView
import javafx.application.Platform.runLater
import javafx.event.EventHandler
import javafx.scene.Scene
import javafx.scene.layout.StackPane
import javafx.stage.Stage
/**
* The default [OpenPopupCallback] implementation for the JavaFX UI toolkit
* that creates and shows a new window with the embedded popup browser.
*/
class DefaultOpenPopupCallbackJavaFx : OpenPopupCallback {
override fun on(params: OpenPopupCallback.Params): OpenPopupCallback.Response {
val browser = params.popupBrowser()
runLater {
val view = BrowserView.newInstance(browser)
val stage = Stage()
val root = StackPane()
val scene = Scene(root)
root.children.add(view)
stage.scene = scene
updateBounds(stage, params.initialBounds())
stage.onCloseRequest = EventHandler { browser.close() }
browser.subscribe<TitleChanged> { event ->
runLater { stage.title = event.title() }
}
browser.subscribe<BrowserClosed> {
runLater { stage.close() }
}
browser.subscribe<UpdateBoundsRequested> { event ->
runLater { updateBounds(stage, event.bounds()) }
}
stage.show()
}
return OpenPopupCallback.Response.proceed()
}
companion object {
private const val DEFAULT_POPUP_WIDTH = 800
private const val DEFAULT_POPUP_HEIGHT = 600
private fun updateBounds(stage: Stage, bounds: Rect) {
if (bounds.size().isEmpty) {
stage.width = DEFAULT_POPUP_WIDTH.toDouble()
stage.height = DEFAULT_POPUP_HEIGHT.toDouble()
} else {
stage.x = bounds.origin().x().toDouble()
stage.y = bounds.origin().y().toDouble()
stage.width = bounds.size().width().toDouble()
stage.height = bounds.size().height().toDouble()
}
}
}
}
SWT
The default implementation for SWT BrowserView
is the following:
import com.teamdev.jxbrowser.browser.callback.OpenPopupCallback;
import com.teamdev.jxbrowser.browser.event.BrowserClosed;
import com.teamdev.jxbrowser.browser.event.TitleChanged;
import com.teamdev.jxbrowser.browser.event.UpdateBoundsRequested;
import com.teamdev.jxbrowser.ui.Rect;
import com.teamdev.jxbrowser.view.swt.BrowserView;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Widget;
/**
* The default {@link OpenPopupCallback} implementation for the SWT UI toolkit
* that creates and shows a new window with the embedded popup browser.
*/
public final class DefaultOpenPopupCallbackSwt implements OpenPopupCallback {
private static final int DEFAULT_POPUP_WIDTH = 800;
private static final int DEFAULT_POPUP_HEIGHT = 600;
@Override
public Response on(Params params) {
var browser = params.popupBrowser();
try {
var display = Display.getDefault();
display.asyncExec(() -> {
var shell = new Shell(display);
shell.setLayout(new FillLayout());
var view = BrowserView.newInstance(shell, browser);
updateBounds(shell, view, params.initialBounds());
shell.addDisposeListener(event -> {
if (!browser.isClosed()) {
asyncExec(shell, browser::close);
}
});
browser.on(TitleChanged.class, event ->
asyncExec(shell, () -> shell.setText(event.title())));
browser.on(BrowserClosed.class, event ->
asyncExec(shell, shell::dispose));
browser.on(UpdateBoundsRequested.class, event ->
asyncExec(shell, () -> updateBounds(shell, view, event.bounds())));
view.setVisible(true);
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
});
} catch (SWTException ignore) {
Response.proceed();
}
return Response.proceed();
}
private static void updateBounds(Shell shell, BrowserView view, Rect bounds) {
shell.setLocation(bounds.x(), bounds.y());
if (bounds.size().isEmpty()) {
view.setSize(DEFAULT_POPUP_WIDTH, DEFAULT_POPUP_HEIGHT);
} else {
view.setSize(bounds.width(), bounds.height());
}
}
private static void asyncExec(Widget widget, Runnable doRun) {
widget.getDisplay().asyncExec(() -> {
if (!widget.isDisposed()) {
doRun.run();
}
});
}
}
import com.teamdev.jxbrowser.browser.Browser
import com.teamdev.jxbrowser.browser.callback.OpenPopupCallback
import com.teamdev.jxbrowser.browser.event.BrowserClosed
import com.teamdev.jxbrowser.browser.event.TitleChanged
import com.teamdev.jxbrowser.browser.event.UpdateBoundsRequested
import com.teamdev.jxbrowser.dsl.subscribe
import com.teamdev.jxbrowser.ui.Rect
import com.teamdev.jxbrowser.view.swt.BrowserView
import org.eclipse.swt.SWTException
import org.eclipse.swt.layout.FillLayout
import org.eclipse.swt.widgets.Display
import org.eclipse.swt.widgets.Shell
import org.eclipse.swt.widgets.Widget
/**
* The default [OpenPopupCallback] implementation for the SWT UI toolkit
* that creates and shows a new window with the embedded popup browser.
*/
class DefaultOpenPopupCallbackSwt : OpenPopupCallback {
override fun on(params: OpenPopupCallback.Params): OpenPopupCallback.Response {
val browser: Browser = params.popupBrowser()
try {
val display: Display = Display.getDefault()
display.asyncExec {
val shell = Shell(display)
shell.layout = FillLayout()
val view = BrowserView.newInstance(shell, browser)
updateBounds(shell, view, params.initialBounds())
shell.addDisposeListener {
if (!browser.isClosed) {
asyncExec(shell) { browser.close() }
}
}
browser.subscribe<TitleChanged> { event ->
asyncExec(shell) { shell.text = event.title() }
}
browser.subscribe<BrowserClosed> {
asyncExec(shell, shell::dispose)
}
browser.subscribe<UpdateBoundsRequested> { event ->
asyncExec(shell) { updateBounds(shell, view, event.bounds()) }
}
view.isVisible = true
shell.pack()
shell.open()
while (!shell.isDisposed) {
if (!display.readAndDispatch()) {
display.sleep()
}
}
}
} catch (ignore: SWTException) {
OpenPopupCallback.Response.proceed()
}
return OpenPopupCallback.Response.proceed()
}
companion object {
private const val DEFAULT_POPUP_WIDTH = 800
private const val DEFAULT_POPUP_HEIGHT = 600
private fun updateBounds(shell: Shell, view: BrowserView, bounds: Rect) {
shell.setLocation(bounds.x(), bounds.y())
if (bounds.size().isEmpty) {
view.setSize(DEFAULT_POPUP_WIDTH, DEFAULT_POPUP_HEIGHT)
} else {
view.setSize(bounds.width(), bounds.height())
}
}
private fun asyncExec(widget: Widget, doRun: Runnable) {
widget.display.asyncExec {
if (!widget.isDisposed) {
doRun.run()
}
}
}
}
}
Closing pop-ups
The opened pop-up can be closed via the Browser.close()
method, or via window.close()
from JavaScript. In both cases the BrowserClosed
event is fired.
We recommend you to always register the BrowserClosed
event listener to get notifications when pop-up is closed. This will allow you to hide the pop-up window if you have it displayed.
popup.on(BrowserClosed.class, event -> {
// Hide the pop-up window.
});
popup.on(BrowserClosed::class.java) { event ->
// Hide the pop-up window.
}