31 мая 2021

Встраиваем Microsoft Edge. Управление всплывающими окнами

    В интернет-браузере клик по ссылке с атрибутом "target="_blank"", или клик по ссылке левой кнопкой мыши с нажатой на клавиатуре клавишей ctrl или shift инициируют создание в интернет-браузере новой вкладки или нового окна. В WebView2 нет встроенной поддержки вкладок, поэтому в этой ситуации всегда открывается новое окно браузера. Например, в программе на Delphi первый клик по ссылке в TEdgeBrowser откроет окно браузера, второй клик в этом окне откроет второе окно и так до бесконечности. Самое плохое то, что эти новые окна мы уже не контролируем. Они живут своей жизнью даже после закрытия программы.
TEdgeBrowser/WebView2 NewWindowRequested
На скриншоте в логе программы видно, что открытие первой ссылки программа перехватила, а открытие второй ссылки, которое инициировано в окне браузера, программа не видит.
    Помочь в решении этой проблемы у TEdgeBrowser может обработчик события OnNewWindowRequested. Это событие вызывается, когда WebView2 для перехода по ссылке запрашивает открытие нового окна. Свое решение на этот запрос программа может сообщить через параметр "Args" типа TNewWindowRequestedEventArgs, который реализует интерфейс ICoreWebView2NewWindowRequestedEventArgs:
ICoreWebView2NewWindowRequestedEventArgs = interface(IUnknown)
  ['{9EDC7F5F-C6EA-4F3C-827B-A8880794C0A9}']
  function Get_uri(out uri: PWideChar): HResult; stdcall;
  function Set_NewWindow(const NewWindow: ICoreWebView2): HResult; stdcall;
  function Get_NewWindow(out NewWindow: ICoreWebView2): HResult; stdcall;
  function Set_Handled(Handled: Integer): HResult; stdcall;
  function Get_Handled(out Handled: Integer): HResult; stdcall;
  function Get_IsUserInitiated(out IsUserInitiated: Integer): HResult; stdcall;
  function GetDeferral(out deferral: ICoreWebView2Deferral): HResult; stdcall;
end;
    Итак, что мы можем сделать в обработчике OnNewWindowRequested?
    Для начала, посмотреть, какую ссылку WebView2 пытается открыть:
procedure TEdgeMain.EdgeBrowserNewWindowRequested(Sender: TCustomEdgeBrowser;
                                                  Args: TNewWindowRequestedEventArgs);
var
  wcUri: PWideChar;
begin
  mLog.Lines.Add(Sender.Name + ' NewWindowRequested');
  Args.ArgsInterface.Get_uri(wcUri);
  mLog.Lines.Add(wcUri);
  CoTaskMemFree(wcUri);
end;
А дальше принять решение, что делать с этой ссылкой:
  1. Запретить переход по ссылке. Для этого просто сообщим WebView2, что мы уже обработали его запрос на открытие нового окна:
    procedure TEdgeMain.EdgeBrowserNewWindowRequested(Sender: TCustomEdgeBrowser;
                                                      Args: TNewWindowRequestedEventArgs);
    begin
      Args.ArgsInterface.Set_Handled(1);
    end;
  2. Открыть ссылку в текущем WebView2:
    procedure TEdgeMain.EdgeBrowserNewWindowRequested(Sender: TCustomEdgeBrowser;
                                                      Args: TNewWindowRequestedEventArgs);
    begin
      Args.ArgsInterface.Set_NewWindow(Sender.DefaultInterface);
    end;
    
  3. Открыть ссылку в другом WebView2 (новой вкладке):
    procedure TEdgeMain.EdgeBrowserNewWindowRequested(Sender: TCustomEdgeBrowser;
                                                      Args: TNewWindowRequestedEventArgs);
    begin
      // тут должен быть код создания новой вкладки с новым TEdgeBrowser
      pcEdgeBrowser.ActivePageIndex := 1;
      Args.ArgsInterface.Set_NewWindow(EdgeBrowser1.DefaultInterface);
    end;
К сожаленью, вызов Set_NewWindow полон сюрпризов. Например, клик по ссылке с "target="_blank"" у меня в TEdgeBrowser всегда открывает новое окно. Этого и других сюрпризов я избежал топорно – просто вызвал Navigate с заданной ссылкой и сообщил WebView2, что его запрос обработан:
procedure TEdgeMain.EdgeBrowserNewWindowRequested(Sender: TCustomEdgeBrowser;
                                                  Args: TNewWindowRequestedEventArgs);
var
  wcUri: PWideChar;
begin
  Args.ArgsInterface.Get_uri(wcUri);

  // тут должен быть код создания новой вкладки с новым TEdgeBrowser
  pcEdgeBrowser.ActivePageIndex := 1;
  EdgeBrowser1.Navigate(wcUri);
  CoTaskMemFree(wcUri);
  
  Args.ArgsInterface.Set_Handled(1);
end;

Комментариев нет:

Отправить комментарий