Pop-ups

Esta página descreve como trabalhar com pop-ups, apresentá-los ou suprimi-los.

Visão Geral

Qualquer página Web pode apresentar janelas pop-up utilizando uma das seguintes formas:

  1. Utilizando a função JavaScript window.open(). Por exemplo:

    window.open("https://www.google.com", "_blank", "resizable=yes,
        top=500, left=500, width=400, height=400");
    
  2. Através de um link com o atributo target:

    <a href="https://www.google.com" target="_blank">Open Google</a>
    

Por padrão, todos os pop-ups são suprimidos.

Abrindo Pop-ups

Para alterar o comportamento padrão e ter controle sobre a criação de pop-ups, utilize as chamadas de retorno CreatePopupCallback e OpenPopupCallback.

A chamada de retorno CreatePopupCallback é invocada quando o motor quer saber se o pop-up pode ser criado ou não. O código seguinte mostra como permitir a criação de um pop-up:

browser.set(CreatePopupCallback.class, (params) -> Response.create());
browser.set(CreatePopupCallback::class.java, CreatePopupCallback { Response.create() })

Se a chamada de retorno CreatePopupCallback permitir a criação de um pop-up, a chamada de retorno OpenPopupCallback será invocada. Nesta chamada de retorno, você pode acessar a janela pop-up criada e apresentá-la, se necessário. Por exemplo:

browser.set(OpenPopupCallback.class, (params) -> {
    // Acessar o popup criado.
    Browser popup = params.popupBrowser();
    return Response.proceed();
});
browser.set(OpenPopupCallback::class.java, OpenPopupCallback { params -> 
    // Acessar o popup criado.
    val popup = params.popupBrowser()
    Response.proceed()
})

A instância popup no exemplo acima não tem nenhuma página da Web carregada no momento em que o retorno de chamada é chamado. A página Web será carregada mais tarde. Neste momento, é possível registrar todos os ouvintes de eventos e chamadas de retorno necessários, mas não é possível acessar o DOM ou o JavaScript, porque o popup ainda não tem um Frame.

Supressão de pop-ups

Para suprimir os pop-ups, utilize a seguinte abordagem:

browser.set(CreatePopupCallback.class, params -> Response.suppress());
browser.set(CreatePopupCallback::class.java,  CreatePopupCallback { Response.suppress() })

Exibindo pop-ups

Quando você cria um Swing ou JavaFX BrowserView, ele configura automaticamente a instância Browser com a implementação padrão das chamadas de retorno CreatePopupCallback e OpenPopupCallback.

A implementação padrão do CreatePopupCallback permite criar todos os pop-ups:

browser.set(CreatePopupCallback.class, params -> Response.create());
browser.set(CreatePopupCallback::class.java,  CreatePopupCallback { Response.create() })

A implementação padrão do callback OpenPopupCallback para Swing e JavaFX pode ser encontrada abaixo.

Swing

A implementação padrão para o Swing BrowserView é a seguinte:

import static javax.swing.SwingUtilities.invokeLater;

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.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;

/**
 * A implementação {@link OpenPopupCallback} padrão para o conjunto de ferramentas Swing UI
 * que cria e mostra uma nova janela com o navegador popup incorporado.
 */
public final class DefaultOpenPopupCallback implements OpenPopupCallback {

    private static final int DEFAULT_POPUP_WIDTH = 800;
    private static final int DEFAULT_POPUP_HEIGHT = 600;

    @Override
    public Response on(Params params) {
        Browser browser = params.popupBrowser();
        invokeLater(() -> {
            BrowserView view = BrowserView.newInstance(browser);
            JFrame 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.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

/**
 * A implementação padrão [OpenPopupCallback] para o conjunto de ferramentas de IU do Swing
 * que cria e mostra uma nova janela com o navegador popup incorporado.
 */
class DefaultOpenPopupCallback : 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.on(TitleChanged::class.java) { event ->
                invokeLater { frame.title = event.title() }
            }
            browser.on(BrowserClosed::class.java) {
                invokeLater {
                    frame.isVisible = false
                    frame.dispose()
                }
            }
            browser.on(UpdateBoundsRequested::class.java) { 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

A implementação padrão para JavaFX BrowserView é a seguinte:

import static javafx.application.Platform.runLater;

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.ui.Rect;
import com.teamdev.jxbrowser.view.javafx.BrowserView;

import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 * A implementação {@link OpenPopupCallback} padrão para o conjunto de ferramentas de IU JavaFX
 * que cria e mostra uma nova janela com o navegador popup incorporado.
 */
public final class DefaultOpenPopupCallback implements OpenPopupCallback {

    private static final int DEFAULT_POPUP_WIDTH = 800;
    private static final int DEFAULT_POPUP_HEIGHT = 600;

    @Override
    public Response on(Params params) {
        Browser browser = params.popupBrowser();
        runLater(() -> {
            BrowserView view = BrowserView.newInstance(browser);
            Stage stage = new Stage();
            StackPane root = new StackPane();
            Scene 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.ui.Rect
import com.teamdev.jxbrowser.view.javafx.BrowserView
import javafx.application.Platform
import javafx.application.Platform.runLater
import javafx.event.EventHandler
import javafx.scene.Scene
import javafx.scene.layout.StackPane
import javafx.stage.Stage
import javafx.stage.WindowEvent

/**
 * A implementação padrão [OpenPopupCallback] para o conjunto de ferramentas de IU JavaFX
 * que cria e mostra uma nova janela com o navegador popup incorporado.
 */
class DefaultOpenPopupCallback : 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.on(TitleChanged::class.java) { event -> 
                runLater { stage.title = event.title() } 
            }
            browser.on(BrowserClosed::class.java) {
                runLater { stage.close() }
            }
            browser.on(UpdateBoundsRequested::class.java) { 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

A implementação padrão para o SWT BrowserView é a seguinte:

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.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;

/**
 * A implementação {@link OpenPopupCallback} padrão para o conjunto de ferramentas SWT UI
 * que cria e mostra uma nova janela com o navegador pop-up incorporado.
 */
public final class DefaultOpenPopupCallback implements OpenPopupCallback {

    private static final int DEFAULT_POPUP_WIDTH = 800;
    private static final int DEFAULT_POPUP_HEIGHT = 600;

    @Override
    public Response on(Params params) {
        Browser browser = params.popupBrowser();
        try {
            Display display = Display.getDefault();
            display.asyncExec(() -> {
                Shell shell = new Shell(display);
                shell.setLayout(new FillLayout());
                BrowserView 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.event.Observer
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

/**
 * A implementação padrão [OpenPopupCallback] para o conjunto de ferramentas SWT UI
 * que cria e mostra uma nova janela com o navegador popup incorporado.
 */
class DefaultOpenPopupCallback : 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.setLayout(FillLayout())
                val view = BrowserView.newInstance(shell, browser)
                updateBounds(shell, view, params.initialBounds())
                shell.addDisposeListener { event ->
                    if (!browser.isClosed) {
                        asyncExec(shell) { browser.close() }
                    }
                }
                browser.on(TitleChanged::class.java) { event -> 
                    asyncExec(shell) { shell.setText(event.title()) } 
                }
                browser.on(BrowserClosed::class.java) { 
                    asyncExec(shell, shell::dispose)
                }
                browser.on(UpdateBoundsRequested::class.java) { event ->
                    asyncExec(shell) { updateBounds(shell, view, event.bounds()) }
                }
                view.setVisible(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.getDisplay().asyncExec {
                if (!widget.isDisposed()) {
                    doRun.run()
                }
            }
        }
    }
}

Fechando pop-ups

O pop-up aberto pode ser fechado através do método Browser.close(), ou através de window.close() do JavaScript. Em ambos os casos, o evento BrowserClosed é disparado.

Recomendamos que registre sempre o ouvinte do evento BrowserClosed para receber notificações quando o pop-up é fechado. Isto lhe permitirá ocultar a janela de contexto, caso a tenha apresentado.

popup.on(BrowserClosed.class, event -> {
    // Esconde a janela pop-up.
});
popup.on(BrowserClosed::class.java) { event ->
    // Hide the pop-up window.
}
Go Top