TChromium Events - обработка событий

Рассмотрим и потестируем некоторые события компонента TChromium.
На момент тестов (август 2016) автор использовал конфигурацию: Lazarus IDE v1.6.0, fpc 3.0.0, fpCEF3 3.2526, win7 64.
В сентябре 2016 автор сменил версию fpCEF3 на 3.2704, изменения дописываются (если они замечены).
В новых версиях fpCEF3 (например в 3.2924 - Chromium 56.0.2924.76), некоторые события удалены, новые добавлены.
Обработка событий позволяет отслеживать и контролировать работу веб-страницы.
Например, мы сможем отследить, когда пользователь наводит курсор мыши на URL-ссылку,
или можем вызвать диалог сохранения загружаемого файла, и т.д.
Все передаваемые в обработчики текстовые параметры имеют кодировку UTF-8 (ustring).
Если Вы заметили ошибку или неточность, просьба сообщить об ошибке.
Описание событий будет постепенно расширяться, как только руки автора дойдут до мелочей.
Создайте произвольное тестовое приложение, например как здесь: TChromium Options - опции в инспекторе объектов
(для проверки некоторых событий, потребуется загружать произвольную веб-страницу вместо локальной).
Для навигации по всем страницам этого раздела сайта используйте иконку меню или ссылку Навигация в строке навигации.
В таблице ниже перечислены события TChromium в инспекторе объектов, ещё ниже Подробное описание
Событие и локальная ссылка | Краткое описание и официальная ссылка |
---|---|
OnAddressChange | При смене URL-адреса. CefDisplayHandler |
OnAfterCreated | Сразу после создания объекта браузера. CefLifeSpanHandler |
OnBeforeBrowse | При попытке открыть любую веб-страницу. CefRequestHandler |
OnBeforeClose | Информирование о закрытии окна. CefLifeSpanHandler |
OnBeforeContextMenu | Перед показом контекстного меню. |
OnBeforeDownload | Перед попыткой загрузить файл. |
OnBeforePluginLoad | --- Удалено в новых версиях fpCEF3 --- |
OnBeforePopup | При попытке создать новый объект браузера (окно). CefLifeSpanHandler |
OnBeforeResourceLoad | CefRequestHandler |
OnBeforeUnloadDialog | Вывод подтверждающего диалога при попытке покинуть веб-страницу. |
OnCancelGeolocationPermission | CefGeolocationHandler. |
OnCertificateError | CefRequestHandler Prompt to choose client certificate |
OnClose | При попытке закрыть окно с объектом браузера. |
OnConsoleMessage | При выводе сообщения в консоль браузера. CefDisplayHandler |
OnContextMenuCommand | Выбор команды контекстного меню. |
OnContextMenuDismissed | Информирование о закрытии контекстного меню. |
OnDialogClosed | CefJSDialogHandler |
OnDownloadUpdated | Многократный вызов обработчика при загрузке файла. |
OnDragEnter | При перемещении объекта над веб-страницей. CefDragHandler |
OnDraggableRegionsChanged | CefDragHandler |
OnFaviconUrlchange | CefDisplayHandler |
OnFileDialog | Непосредственно перед открытием стандартного диалога сохранения файла. |
OnFindResult | CefFindHandler |
OnFullscreenModeChange | CefDisplayHandler |
OnGetAuthCredentials | CefRequestHandler |
OnGetCookieManager | --- Удалено в новых версиях fpCEF3 --- |
OnGetResourceHandler | CefRequestHandler |
OnGetResourceResponseFilter | --- Появилось в новых версиях fpCEF3 --- |
OnGotFocus | При получении фокуса объектом браузера. |
OnJsdialog | Попытка вывести диалог из JavaScript ( CefJSDialogHandler ) |
OnKeyEvent | Событие клавиатуры объекта браузера. CefKeyboardHandler |
OnLoadEnd | Завершение загрузки каждого фрейма веб-страницы. CefLoadHandler |
OnLoadError | Ошибка загрузки фрейма. CefLoadHandler |
OnLoadingStateChange | При начале и завершении загрузки. CefLoadHandler |
OnLoadStart | Начало загрузки каждого фрейма. CefLoadHandler |
OnOpenUrlFromTab | Клик по ссылке средней кнопкой мыши (или удерживая <Ctrl>). |
OnPluginCrashed | CefRequestHandler |
OnPreKeyEvent | Перед событием OnKeyEvent объекта браузера. |
OnProcessMessageReceived | CefRenderProcessHandler |
OnProtocolExecution | CefRequestHandler |
OnQuotaRequest | CefRequestHandler --- Обзор File API |
OnRenderProcessTerminated | CefRequestHandler |
OnRenderViewReady | CefRequestHandler |
OnRequestGeolocationPermission | CefGeolocationHandler |
OnResetDialogState | CefJSDialogHandler |
OnResourceLoadComplete | --- Появилось в новых версиях fpCEF3 --- |
OnResourceRedirect | CefRequestHandler |
OnResourceResponse | --- Появилось в новых версиях fpCEF3 --- |
OnRunContextMenu | CefContextMenuHandler |
OnRunModal | CefLifeSpanHandler --- Удалено в новых версиях fpCEF3 --- |
OnSelectClientCertificate | --- Появилось в новых версиях fpCEF3 --- |
OnSetFocus | CefFocusHandler |
OnStatusMessage | Информирование о выделении и отмены выделения URL - ссылок. CefDisplayHandler |
OnTakeFocus | CefFocusHandler |
OnTitleChange | Информирование о смене TITLE веб-страницы. CefDisplayHandler |
OnTooltip | Не работает. CefDisplayHandler --- CefRenderWidgetHostViewOSR :: SetTooltipText |
Подробное описание событий
Для изучения всех методов и свойств см. файлы cef3gui.pas и cef3intf.pas, а так же cef3own.pas
OnAddressChange
Событие генерируется при смене URL-адреса. Параметр url содержит новый URL в кодировке UTF-8.
Позволяет отслеживать текущий URL страницы или переход по локальным для веб-странице ссылкам-якорям.
В обработчике события OnBeforeBrowse можно запретить смену URL и загрузку другой страницы.
Текущий URL-адрес всегда можно получить через ICefFrame.Url или ICefFrame.GetUrl()
Отличить различные объекты браузера можно через ICefBrowser.GetIdentifier()
OnAfterCreated
Генерируется сразу после создания нового объекта браузера
Приложение может получить уникальный идентификатор объекта браузера ICefBrowser.GetIdentifier()
OnBeforeBrowse
Событие генерируется при попытке открыть любую веб-страницу (перед навигацией объекта браузера).
При установке Result:=false; веб-страница открывается, иначе остаётся текущая.
OnBeforeClose
Генерируется при закрытии окна с объектом браузера. Отменить уничтожение окна можно в OnClose.
Приложение может получить уникальный идентификатор уничтожаемого объекта браузера ICefBrowser.GetIdentifier()
OnBeforeContextMenu
Событие генерируется перед показом контекстного меню.
Дефолтное меню можно очистить через ICefMenuModel.Clear(),
можно добавлять необходимые пункты и разделители ( ICefMenuModel.AddItem() и ICefMenuModel.AddSeparator() )
Можно назначить клавишу быстрого выбора через амперсенд &, например model.AddItem( 131, Utf8Decode('&Print...') );
Автор нашёл в исходных файлах следующие коды операций для меню:
- 100 (Back)
- 101 (Forward)
- 102 (Reload)
- 103 (Reload NoCache)
- 104 (Stop load)
- 113 (Copy)
- 116 (Select all)
- 130 (Find)
- 131 (Print)
- 132 (View source)
- 220 (MENU_ID_CUSTOM_FIRST)
- 250 (MENU_ID_CUSTOM_LAST)
OnBeforeDownload
Генерируется перед началом загрузки файла (например, при клике по ссылке с получением HTTP-заголовков загрузки файла).
По умолчанию (без вызова обратной функции) загрузка будет отменена.
Для сохранения файла нужно вызвать ICefBeforeDownloadCallback.Cont(suggestedName, True);
При передаче True будет вызван диалог сохранения, при передаче False файл будет сохраняться без диалога.
procedure TFormMain.Chromium1BeforeDownload(Sender: TObject;
const Browser: ICefBrowser; const downloadItem: ICefDownloadItem;
const suggestedName: ustring; const callback: ICefBeforeDownloadCallback);
begin
{ Сохранимм файл без диалога как "D:\myfolder\file.txt" }
callback.Cont('D:\myfolder\file.txt', false);
end;
Отслеживать процесс загрузки файла можно в обработчике OnDownloadUpdated
Дополнительно см. OnFileDialog
OnBeforePopup
Событие генерируется при попытке создать новый объект браузера в окне. По-умолчанию объект и окно создаются
(инициировать создание нового окна с объектом браузера можно кликом по ссылке с атрибутом target="_blank").
Чтобы запретить создание нового объекта браузера, нужно выполнить Result:=True;
Параметр targetUrl содержит URL-адрес страницы, которую можно при желании открыть в любом их существующих объектов,
например так: ICefBrowser.MainFrame.LoadUrl(targetUrl); или ICefFrame.LoadUrl(targetUrl);
OnBeforeUnloadDialog
Генерируется при попытке покинуть веб-страницу, если на ней задан JS-обработчик window.onbeforeunload.
Если JS-обработчик не задан, или возвращает null / undefined, то события OnBeforeUnloadDialog нет и веб-страницу можно покинуть без проблем.
/* JavaScript-код на веб-странице */
window.onbeforeunload = function(e) {
/* alert(...) не сработает, важен return */
return null; /* return "Мы что-то не то сказали ???"; */
}
Если событие window.onbeforeunload на веб-странице обрабатывается и возвращается значение, отличное от null или undefined, то:
- будет выведен диалог подтверждения, если OnBeforeUnloadDialog не обрабатывается или Result:=False;
- диалога не будет и веб-страницу невозможно покинуть (а так же закрыть окно), если Result:=True;
Можно вызвать обработчик ICefJsDialogCallback.Cont(success: Boolean; const userInput: ustring);
в этом случае никакого подтверждающего окна не будет ни при каких вариантах, поведение зависит от параметра success
при вызове обработчика нельзя трогать Result - будет runtime error (у меня было именно так).
procedure TFormMain.Chromium1BeforeUnloadDialog(Sender: TObject;
const Browser: ICefBrowser; const messageText: ustring; isReload: Boolean;
const callback: ICefJsDialogCallback; out Result: Boolean);
begin
{ Код ниже разрешает перезагружать страницу }
callback.cont(isReload, '');
end;
Попытка закрыть отдельное независимое окно с объектом браузера может привести к генерации данного события.
OnClose
Генерируется при попытке закрыть окно с объектом браузера. Окно приложения по-умолчанию закрывается пользоветелем без подверждения.
Если обработчика этого события нет или Result:=False; то окно закрывается, иначе остаётся открытым.
Приложение может получить уникальный идентификатор уничтожаемого объекта браузера ICefBrowser.GetIdentifier()
Если необходимо лишь получать уведомления об уничтожении объектов браузера, то см. OnBeforeClose
OnConsoleMessage
Генерируется при выводе сообщения в консоль браузера. Параметр message содержит текст сообщения в кодировке UTF-8.
OnContextMenuCommand
Генерируется при выборе команды контекстного меню. Каманда НЕ выполняется при установке Result:=True;
См. описание ICefContextMenuParams в файле cef3intf.pas
См. описание TCefEventFlags в файле cef3types.pas
OnContextMenuDismissed
Информационное событие генерируется после отмены контекстного меню или после события OnContextMenuCommand
См. описание ICefBrowser и ICefFrame в файле cef3intf.pas
OnDownloadUpdated
Многократный вызов обработчика при загрузке файла.
procedure TFormMain.Chromium1DownloadUpdated(Sender: TObject;
const Browser: ICefBrowser; const downloadItem: ICefDownloadItem;
const callback: ICefDownloadItemCallback);
begin
{ callback.Cancel | callback.Pause | callback.Resume }
if (downloadItem.IsComplete) then ShowMessage('Download complete');
end;
В обработчике OnBeforeDownload можно показывать диалог сохранения файла или сразу указать путь.
Дополнительно см. OnFileDialog. См. описание ICefDownloadItem в файле cef3intf.pas
OnDragEnter
Генерируется при перемещении объекта над веб-страницей.
См. описание ICefDragData в файле cef3intf.pas
См. описание TCefDragOperationsMask в файле cef3types.pas
OnFileDialog
Генерируется непосредственно перед открытием стандартного диалога сохранения файла.
Можно отменить диалог, если установить Result:=True;
Можно вызвать произвольный диалог:
ICefFileDialogCallback.Cont(selectedAcceptFilter: Integer; filePaths: TStrings);
Дополнительно см. описание OnBeforeDownload
См. описание ICefFileDialogCallback в файле cef3intf.pas
См. описание TCefFileDialogMode в файле cef3types.pas
OnGotFocus
Генерируется при получении фокуса объектом браузера.
OnJsdialog
Генерируется при попытке вывести диалог из JavaScript (alert(), prompt(), confirm())
При установке Result:=true; или suppressMessage:=true; JS-диалог будет проигнорирован.
Можно обработать диалог из приложения, заменив стандартный браузерный диалог.
Поэкспериментируйте с кодом ниже (Pascal и JavaScript), чтобы лучше разобраться в работе обработчика события.
procedure TFormMain.Chromium1Jsdialog(Sender: TObject;
const Browser: ICefBrowser; const originUrl, acceptLang: ustring;
dialogType: TCefJsDialogType; const messageText, defaultPromptText: ustring;
callback: ICefJsDialogCallback;
out suppressMessage: Boolean; out Result: Boolean);
begin
case dialogType of
JSDIALOGTYPE_ALERT: //alert( messageText );
begin
ShowMessage('alert: ' + UTF8Encode(messageText)); // закомментировать для теста
//suppressMessage := true; Exit; // раскомментировать для теста
end;
JSDIALOGTYPE_CONFIRM: //result = confirm( messageText );
if (MessageDlg('confirm: ' + UTF8Encode(messageText), mtConfirmation, mbOKCancel, 0) = 1)
and (UTF8Encode( messageText ) = 'Продолжить?')
then callback.Cont(true, '')
else callback.Cont(false, '');
JSDIALOGTYPE_PROMPT: //result = prompt(messageText, defaultPromptText);
begin
if (UTF8Encode(messageText) = 'Введите текст') then
callback.Cont(true, defaultPromptText)
else
begin
Result:=false;
Exit;
end;
end;
end;
Result:=true;
end;
/* Локальный файл JavaScript для выполнения */
document.addEventListener("DOMContentLoaded", init, false);
function init() {
/* Здесь работа с веб-страницей */
alert( prompt("Введите текст",1) );
alert( confirm("Продолжить?") );
}
OnKeyEvent
События клавиатуры. В обработчике лучше сразу устанавливать по-умолчанию Result:=False; ,
иначе, когда фокус на объекте браузера, нам придётся самим обрабатывать все нажатия на клавиши.
Пример простой навигации по страницам через клавиши <F5>, <Alt + LeftArrow>, <Alt + RightArrow> :
procedure TFormMain.Chromium1KeyEvent(Sender: TObject;
const Browser: ICefBrowser; const event: PCefKeyEvent;
osEvent: TCefEventHandle; out Result: Boolean);
var KeyCode: Integer;
begin
Result:=False;
if (event^.kind <> KEYEVENT_KEYUP) then Exit;
KeyCode:=event^.windows_key_code;
if (KeyCode=116) then Browser.Reload();
{ ??? Перепутаны наименования флагов ??? }
if (EVENTFLAG_ALT_DOWN in event^.modifiers) then
begin
if (KeyCode=37) and Browser.CanGoBack() then Browser.GoBack();
if (KeyCode=39) and Browser.CanGoForward() then Browser.GoForward();
end;
end;
Примечание: под fpCEF3 3.2526 флаги определяются так:
EVENTFLAG_SHIFT_DOWN - левый и правый Ctrl
EVENTFLAG_CONTROL_DOWN - левый и парвый Alt
EVENTFLAG_ALT_DOWN - не определяется :)
Под fpCEF3 3.2704 флаги определяются правильно:
EVENTFLAG_SHIFT_DOWN - левый и правый Shift
EVENTFLAG_CONTROL_DOWN - левый и парвый Ctrl
EVENTFLAG_ALT_DOWN - левый и парвый Alt
Можно обрабатывать клавиатурные события ещё раньше - в обработчике события OnPreKeyEvent
OnLoadEnd
Завершение загрузки каждого фрейма веб-страницы (страница может содержать вложенные фреймы).
Проверить загрузку главного фрейма можно через ICefFrame.IsMain()
Событие OnLoadEnd соответствует событию веб-страницы «DomContentLoaded».
Важно! При обработке этого события DOM уже построен, поэтому можно выполнить собственный произвольный JavaScript-код. Таким образом, мы можем выполнять свои скрипты для любых или определённых веб-страниц. Это бывает удобно для автоматической авторизации на том или ином сайте/админке, удаления рекламы, изменения оформления, расширения функциональности... и прочих задач, насколько хватит нашей фантазии.
Пример автоматической подстановки логина и пароля для сайта www.sql.ru
procedure TFormMain.Chromium1LoadEnd(Sender: TObject;
const Browser: ICefBrowser; const Frame: ICefFrame;
httpStatusCode: Integer);
var s, url: String;
begin
if (not Frame.IsMain) or (httpStatusCode<>200) then Exit;
url := 'http://www.sql.ru/forum/login.aspx?action=login';
if (UTF8Encode(Browser.MainFrame.Url)=url) then
begin
s := 'var p=document.getElementById("login_form");';
s := s + 'p=p.getElementsByTagName("input");';
s := s + 'p[0].value="myLogin";';
s := s + 'p[1].value="myPassword";';
Frame.ExecuteJavaScript(Utf8Decode(s),'about:blank',0);
end;
end;
Намного удобнее при запуске приложения читать заранее заготовленный JavaScript-файл (в кодировке UTF-8) в переменную и выполнять его при готовности веб-страниц, так мы сможем гибко менять JS-код без перекомпиляции приложения, например:
/* Локальный файл JavaScript для выполнения */
(function() {
var p, url = window.location.href;
if (url == 'http://www.sql.ru/forum/login.aspx?action=login') {
p = document.getElementById('login_form');
p = p.getElementsByTagName('input');
p[0].value = 'myLogin';
p[1].value = 'myPassword';
}
...
/* прочие действия над любыми страницами */
...
})();
OnLoadError
Ошибка загрузки фрейма. Можно проверять главный фрейм через ICefFrame.IsMain(), и другими способами.
См. описание TCefErrorCode в файле cef3types.pas
OnLoadingStateChange
Генерируется при инициации и завершении загрузки. Пераметры:
isLoading - загрузка в процессе (true) или завершена (false)
canGoBack - возможность вернуться на предыдущую страницу (true/false)
canGoForward - возможность перейти на следующую страницу (true/false)
При загрузке файла по ссылке, это событие возникает дважды ДО начала процесса загрузки и/или вывода диалога сохранения.
Процесс скачивания файла не отслеживается этим событием.
OnLoadStart
Начало загрузки каждого фрейма (страница может содержать вложенные фреймы).
OnOpenUrlFromTab
Генерируется в случае, когда пользователь кликает по ссылке средней кнопкой мыши, или кликает, удерживая <Ctrl>
Это событие возникает перед событием OnBeforeBrowse
Дествие разрешено только при установке Result:=False;
OnPreKeyEvent
Генерируется перед событием OnKeyEvent объекта браузера.
Можно обработать или установить Result:=False; для продолжения текущей операции.
OnStatusMessage
Генерируется при наведении курсора мыши на любую URL-ссылку или в момент, когда курсор мыши покидает URL-ссылку.
Клавиша Tab так же позволяет обходить ссылки по порядку (если опция TabToLinks не установлена как STATE_DISABLED).
Параметр value содержит URL-адрес ссылки (возможного перехода) в кодировке UTF-8, или пустое значение (когда курсор покидает ссылку).
OnTitleChange
Смена TITLE веб-страницы (параметр title в кодировке UTF-8). Генерируется каждый раз при смене TITLE веб-страниц(ы).
