webbrowser — u_pbt_webbrowser #
← Référence des composants · Sommaire du guide
Navigateur web intégré à votre fenêtre : affichage d'une page, barre d'adresse, historique Précédent / Suivant, menu contextuel de navigation.
▶ Le voir en vrai — Application de démonstration, tuile Web browser : l'aperçu, le code qui le produit et cette page, côte à côte.
En bref #
| Userobject | u_pbt_webbrowser |
| Classe d'items | — (composant sans items) |
| Sert à | Afficher une page web, un portail interne, une documentation en ligne ou un contenu HTML généré, sans quitter l'application |
Démarrage rapide #
// event open de la fenetre
uo_browser.ib_address_bar = true // barre d'adresse + boutons de navigation
uo_browser.is_address = "https://fr.wikipedia.org/wiki/PowerBuilder"
Poser is_address est l'acte de navigation : chaque affectation ouvre la page demandée. Une adresse sans protocole ("exemple.com") reçoit automatiquement https://. Un chemin disque (C:\dossier\page.html, \\serveur\partage\page.html) devient une adresse file:///. Des mots qui ne sont pas une adresse ("facture 2026") partent vers le moteur de recherche de is_search_url ; sans moteur, ils sont refusés et ue_error le dit. Un nom de serveur d'un seul mot suivi de /, ? ou # (office/, intranet/home) est une adresse, comme une adresse IPv6 entre crochets ([::1]/x) ; le mot seul (intranet) reste un texte libre. Un serveur sans HTTPS s'écrit avec http:// explicite.
Propriétés #
| Propriété | Type | Défaut | Rôle |
|---|---|---|---|
is_address | string | "" | Adresse affichée. Affecter cette propriété déclenche la navigation. La relire donne la page réellement affichée : si l'utilisateur suit un lien ou revient en arrière, elle suit aussi (ue_load_completed vous prévient). Schémas acceptés : http(s):, file: (un chemin disque aussi), about:, data:, mailto:, tel: ; javascript: est refusé. Une page affichée par of_show_html (une page data:) n'a pas d'adresse à elle : elle se relit vide |
ib_address_bar | boolean | false | Affiche la barre d'adresse intégrée : champ URL, boutons Précédent / Suivant / Recharger — qui devient Arrêter pendant le chargement d'une page |
ib_context_menu | boolean | false | Active le menu contextuel au clic droit : Précédent, Suivant, Recharger, plus Copier sur une sélection, Ouvrir le lien et Copier l'adresse du lien sur un lien, Copier l'image sur une image. Ouvert au clavier (Maj+F10), il se pose sur l'élément. Dans un champ de saisie, le menu Couper / Copier / Coller reste |
is_search_url | string | "" | Moteur de recherche des mots qui ne sont pas une adresse, %s = le texte encodé (ex. https://www.bing.com/search?q=%s). Vide par défaut : un tel texte est refusé et ue_error est levé — une application métier n'envoie pas la frappe de ses utilisateurs à un moteur qu'elle n'a pas choisi. Seule une adresse http(s) contenant %s est acceptée : toute autre lève ue_error et le moteur en place reste |
ib_veto_new_window | boolean | false | Demande à ue_new_window avant d'ouvrir une nouvelle fenêtre dans la vue ; renvoyer false y laisse la page courante |
ib_veto_downloads | boolean | false | Demande à ue_download_starting avant chaque téléchargement ; renvoyer false l'annule |
ib_veto_navigation | boolean | false | Demande à ue_navigating avant que la page parte vers une autre : un lien, un formulaire ou un script du site, ou un geste de l'utilisateur (une adresse tapée dans la barre, Ouvrir le lien, une nouvelle fenêtre) ; renvoyer false y laisse la page courante. Jamais pour une adresse posée par votre code, ni pour une redirection du serveur : pour garder l'application sur ses serveurs, voir is_allowed_hosts. Une page autorisée est rouverte à l'adresse demandée : un formulaire envoyé en POST y perd ses données |
ib_private | boolean | false | Navigation privée : cookies, stockage et cache des sites ne sont jamais écrits sur le disque et disparaissent avec la vue. À poser avant is_address : le changer rouvre la vue vide (ni page, ni historique) ; le reposer à true ouvre une session privée neuve |
is_title | string | "" | Titre de la page affichée, lu en direct (ue_title_changed prévient quand il change). En lecture seule : l'écrire ne change rien. Vide pour une page sans titre à elle |
is_allowed_hosts | string | "" | Les hôtes que la page peut montrer, joints par | : "intranet.example.com|*.example.com" (*. = tout sous-domaine, pas le domaine lui-même). Toute page d'une adresse http(s) hors de la liste est refusée, d'où que vienne la demande — votre code, un lien, l'utilisateur dans la barre, une redirection du serveur — et ue_navigation_blocked le dit ; la page affichée reste. Un fichier local, une page d'of_show_html et about:blank ne sont pas concernés. Une entrée qui n'est pas un nom d'hôte lève ue_error et la liste en vigueur reste. Vide par défaut : tout hôte |
ii_zoom | integer | 100 | Zoom du site en pour cent, de 25 à 500 (la barre d'adresse ne zoome jamais) ; une valeur hors bornes y est ramenée. Lu en direct : Ctrl+molette dans le site le change aussi. Gardé d'une page à l'autre et à travers ib_private |
ib_certificate_questions | boolean | false | Demande à ue_certificate_error quand le certificat d'un serveur n'est pas valide (un intranet à certificat interne ou expiré), au lieu de le refuser aussitôt. La réponse ne vaut que pour cette navigation, et une question restée sans réponse est un non. Désactivé par défaut : la page est refusée et ue_load_failed donne un statut LOADSTATUS_CERT_* |
ib_web_messages | boolean | false | Ouvre le pont entre le site et l'application : la page envoie une valeur par chrome.webview.postMessage(value) et ue_web_message la reçoit ; of_post_message en envoie une à la page. Seulement pour les origines de is_message_origins : sans origine, le pont reste fermé. Un message de plus de 64 Ko est ignoré. Désactivé par défaut : aucun site n'atteint l'application |
is_message_origins | string | "" | Les origines autorisées à parler avec l'application (voir ib_web_messages), jointes par | : "https://portal.example.com|https://erp.example.com" — un schéma, un hôte, un port s'il n'est pas celui par défaut ; le chemin est ignoré. Exactes : un sous-domaine est une autre origine. file:/// désigne les pages du poste. Une entrée sans schéma lève ue_error et la liste en vigueur reste |
is_theme_style | string | "" | Style visuel du composant (constantes THEME_STYLE_*) ; vide = celui de l'application, suivi à chaque changement |
is_theme_mode | string | "" | Variante claire ou sombre (constantes THEME_MODE_*) ; vide = celle de l'application, suivie à chaque changement |
il_theme_accent | long | -1 | Couleur d'accent de ce composant (-1 = l'accent de l'application, ou celui du thème) |
Méthodes #
| Méthode | Rôle |
|---|---|
of_refresh ( ) | Recharge la page courante. Renvoie 0 une fois demandé, -4 si aucune page n'est affichée (is_address vide), -2 si le composant n'est pas créé |
of_go_back ( ) → long | Revient à la page précédente. Suit l'ordre de votre code : is_address puis of_go_back() jouent dans cet ordre. Renvoie 0 une fois demandé, -2 si le composant n'est pas créé |
of_go_forward ( ) → long | Avance à la page suivante. Renvoie 0 une fois demandé, -2 si le composant n'est pas créé |
of_can_go_back ( ) → boolean | true si une page précédente existe — pour activer ou griser votre bouton Précédent. Lu en direct sur la page ; à lire après un chargement (ue_load_completed) |
of_can_go_forward ( ) → boolean | true si une page suivante existe |
of_stop ( ) → long | Interrompt le chargement en cours et abandonne les pages encore en attente ; le chargement interrompu lève ue_load_failed. Renvoie 0 une fois demandé, -2 si le composant n'est pas créé |
of_execute_javascript (string as_script) | Exécute un script dans la page affichée et renvoie sa valeur en JSON : un texte revient entre guillemets, un nombre non (42), un script qui lève une erreur ou ne renvoie rien donne null. Une réponse longue revient entière. Une seule condition, et elle est structurelle : la page doit être chargée, donc appelez-la depuis ue_load_completed, jamais juste après avoir posé is_address. Renvoie une chaîne vide s'il n'y a pas encore de page ou sans réponse en 5 secondes : of_get_last_error() dit pourquoi |
of_show_html (string as_html) → long | Affiche une page construite par l'application (facture, courrier). La page est encodée : une couleur #c00, une ancre, un % ou un accent s'affichent tels qu'écrits. 2 Mo au plus une fois encodée : au-delà, ue_error et rien ne change. Renvoie 0 une fois envoyé, -2 si le composant n'est pas créé |
of_clear_browsing_data ( ) → long | Efface ce que les sites ont retenu : cookies (une session ouverte), stockage local, cache, permissions accordées. L'effacement prend sa place après les adresses déjà posées : la page suivante s'ouvre vierge. Tous les webbrowser de l'application partagent ces données. Renvoie 0 une fois envoyé, -2 si le composant n'est pas créé |
of_is_loading ( ) → boolean | true tant qu'une page se charge : de ue_load_started à ue_load_completed ou ue_load_failed — pour un sablier ou un bouton Arrêter. Lu en direct ; false avant toute page |
of_post_message (string as_json) → long | Envoie une valeur à la page affichée, écrite en JSON (un objet, un texte entre guillemets, un nombre) ; la page la reçoit par l'événement message de chrome.webview. Seulement avec ib_web_messages, vers une page d'une origine de is_message_origins : toute autre page lève ue_error et ne reçoit rien. Renvoie 0 une fois envoyé, -5 si le texte est vide ou n'est pas du JSON (of_get_last_error dit pourquoi), -2 si le composant n'est pas créé |
of_reset ( ) | Remet le composant à neuf : page vidée, historique de navigation effacé, barre d'adresse masquée, menu contextuel désactivé, moteur de recherche vidé, demandes (ib_veto_*) désactivées, navigation privée coupée. Les cookies et sessions des sites restent : c'est of_clear_browsing_data. Renvoie 0 une fois appliqué, -2 si le composant n'est pas créé. Il vide aussi is_allowed_hosts, remet ii_zoom à 100, ferme le pont des messages (ib_web_messages, is_message_origins) et éteint ib_certificate_questions |
of_save_as_png (string) · of_save_as_jpg (string) | Exporte le site affiché en image. Renvoie 0 une fois l'image écrite, -4 si l'écriture échoue, -2 si le composant n'est pas créé |
Événements #
| Événement | Déclenché quand |
|---|---|
ue_load_completed (string as_url) | Une page a fini de se charger (la vôtre, un lien, Précédent, of_refresh) ; as_url est l'adresse effectivement atteinte, redirections comprises. Pas levé pour une adresse vide (about:blank) ni pour un chargement en échec. Pour une page d'of_show_html, as_url est vide |
ue_load_failed (string as_url, long al_status) | Une page n'a pas pu être chargée : hôte inconnu, pas de réseau, certificat, ou chargement annulé par of_stop ou par une adresse plus récente. al_status dit pourquoi : voir Pourquoi une page n'a pas chargé |
ue_error (string as_message) | Un texte posé dans is_address (ou tapé dans la barre) n'est pas une adresse et aucun is_search_url n'est posé, une adresse n'a pas pu être ouverte du tout, ou le processus de la page s'est arrêté. Rien d'autre n'est retenu : l'adresse suivante se charge normalement |
ue_new_window (string as_url) → boolean | La page demande une nouvelle fenêtre après un clic (lien target=_blank, window.open) : elle s'ouvre dans cette vue. Annulable si ib_veto_new_window = true : renvoyer false garde la page courante. Une fenêtre ouverte par un script seul, sans clic, est ignorée. Seules les adresses http et https s'ouvrent : un site qui demande un fichier, une page data: ou un lien de courrier obtient ue_error. Un lien file: dans une page web (http, https, data:) est refusé par le moteur lui-même, avant le composant : rien ne s'ouvre et aucun événement n'est levé |
ue_download_starting (string as_url, string as_path) → boolean | Un téléchargement commence : as_url est ce qui est téléchargé, as_path le fichier qui sera écrit. Annulable si ib_veto_downloads = true : renvoyer false l'annule ; sinon il continue comme dans Edge |
ue_navigating (string as_url) → boolean | La page part vers une autre : un lien, un formulaire ou un script du site, ou un geste de l'utilisateur (adresse tapée dans la barre, Ouvrir le lien, nouvelle fenêtre) — jamais pour une adresse posée par votre application, ni pour une redirection du serveur. Annulable si ib_veto_navigation = true : renvoyer false garde la page courante |
ue_title_changed (string as_title) | Le titre de la page affichée a changé (is_title le relit à tout moment) |
ue_permission_requested (string as_url, string as_kind) → boolean | Le site demande la caméra, le micro, la position… (as_kind = une constante PERMISSION_*). Refusé sauf si l'événement renvoie true : la seule question de la bibliothèque où le silence vaut NON |
ue_load_started (string as_url) | Une page commence à se charger — une adresse de votre code, un lien, un geste de l'utilisateur. as_url est vide pour une page d'of_show_html. of_is_loading() rend true jusqu'à ue_load_completed ou ue_load_failed |
ue_navigation_blocked (string as_url) | is_allowed_hosts a refusé une page : une adresse, un lien ou une redirection vers un hôte hors de la liste. Rien n'a été chargé, la page affichée reste |
ue_certificate_error (string as_url, long al_status) → boolean | Le certificat d'un serveur n'est pas valide (al_status = une constante LOADSTATUS_CERT_*). Levé seulement si ib_certificate_questions = true. Refusé sauf si l'événement renvoie true : accepter un certificat est une décision de sécurité, jamais le défaut. La réponse ne vaut que pour cette navigation |
ue_web_message (string as_origin, string as_json) | Le site a envoyé une valeur (chrome.webview.postMessage) : as_json est cette valeur en JSON (à lire avec n_pbt_json), as_origin l'origine de la page qui l'a envoyée. Seulement avec ib_web_messages et depuis une origine de is_message_origins |
ue_ready ( ) | Le composant a fini de charger ; tout ce qui a été envoyé avant a été rejoué |
ue_runtime_missing ( ) | Le runtime WebView2 est absent : le composant reste vide |
ue_bg_color (long al_color) | Le composant a calculé sa couleur de fond de thème ; l'userobject l'a déjà adoptée (backcolor) |
ue_script_error (string as_message, string as_stack) | Une erreur JavaScript s'est produite dans la barre d'adresse du composant (jamais dans le site affiché) |
Naviguer #
La barre d'adresse intégrée #
C'est la solution la plus rapide : une propriété, et l'utilisateur dispose d'un champ URL et des boutons Précédent / Suivant / Recharger, thémés comme le reste de l'application.
// La barre d'adresse, puis la page a ouvrir
uo_browser.ib_address_bar = true
uo_browser.is_address = "https://fr.wikipedia.org/wiki/PowerBuilder"
Les boutons se grisent tout seuls quand il n'y a nulle part où aller. Dans le champ d'adresse, F5 (ou Ctrl+R) recharge, Alt+← / Alt+→ reviennent et avancent (inversés en écriture de droite à gauche), Échap rend l'adresse courante après une frappe abandonnée, et le premier clic sélectionne toute l'adresse. Un texte qui n'est pas une adresse est signalé : le champ se borde de rouge, avec une infobulle, jusqu'à la frappe suivante. Entrée sur un champ vide ne fait rien : la page reste.
Vos propres boutons #
Si vous préférez piloter la navigation depuis votre propre barre d'outils, masquez la barre intégrée et utilisez les méthodes :
// Boutons Precedent / Suivant de votre fenetre
uo_browser.of_go_back()
uo_browser.of_go_forward()
// event ue_load_completed de uo_browser : (string as_url)
// Mettre a jour l'etat de vos boutons apres chaque page
uo_toolbar.of_item(/*keys*/ "main/back").ib_enabled = uo_browser.of_can_go_back()
uo_toolbar.of_item(/*keys*/ "main/forward").ib_enabled = uo_browser.of_can_go_forward()
// Et refleter l'adresse reelle (redirections comprises)
sle_url.text = as_url
Le menu contextuel de navigation #
ib_context_menu ajoute au clic droit un petit menu Précédent / Suivant / Recharger, thémé et rendu par l'application. Il suit ce qui est sous la souris : Copier sur un texte sélectionné, Ouvrir le lien et Copier l'adresse du lien sur un lien, Copier l'image sur une image. Ouvert au clavier (Maj+F10, touche Menu), il se pose sur l'élément. Il partage exactement le même historique que la barre d'adresse : les deux restent donc toujours cohérents.
// A small menu on a right click : back, forward, refresh
uo_browser.ib_context_menu = true
Arrêter un chargement #
// Bouton Stop : interrompt une page qui tarde
uo_browser.of_stop()
Des mots plutôt qu'une adresse #
Par défaut, un texte qui n'est pas une adresse est refusé (ue_error), sans rien bloquer : l'adresse suivante se charge normalement. Pour en faire une recherche, choisissez le moteur :
// Words typed in the address bar go to this engine (%s = the text)
uo_browser.is_search_url = "https://www.bing.com/search?q=%s"
uo_browser.is_address = "PowerBuilder WebView2"
Nouvelles fenêtres et téléchargements #
Un lien « ouvrir dans un nouvel onglet » ou une fenêtre de connexion ouverte après un clic s'affiche dans la vue, et ue_new_window vous le dit. Un téléchargement continue comme dans Edge, et ue_download_starting vous donne l'adresse et le fichier. Les deux se changent en question quand vous le demandez :
// Ask before each download
uo_browser.ib_veto_downloads = true
// ue_download_starting event of uo_browser : (string as_url, string as_path)
// Only PDF files may be downloaded
return Lower(Right(as_path, 4)) = ".pdf"
Une fenêtre de connexion qui dialogue avec la page qui l'a ouverte (une connexion OAuth ou Microsoft en fenêtre surgissante) perd ce lien une fois affichée dans la vue, et la connexion n'aboutit pas : ouvrez une telle connexion dans la page elle-même (mode redirection).
Rester sur ses serveurs #
Pour garder une application métier sur ses serveurs, listez-les dans is_allowed_hosts : toute page d'un autre hôte est refusée, d'où que vienne la demande — votre code, un lien, une adresse tapée dans la barre, une redirection du serveur —, et ue_navigation_blocked le dit. La page affichée reste.
// Only the company servers : any other host is refused, redirections included
uo_browser.is_allowed_hosts = "intranet.example.com|*.example.com"
// ue_navigation_blocked event of uo_browser : (string as_url)
st_message.text = "This site is not allowed : " + as_url
ue_navigating, lui, est levé chaque fois que la page part vers une autre — un lien, un formulaire ou un script du site, une adresse tapée par l'utilisateur, Ouvrir le lien, une nouvelle fenêtre —, jamais pour une adresse posée par votre code ni pour une redirection. Avec ib_veto_navigation, c'est une question : renvoyer false y laisse la page courante. Une page autorisée est rouverte à l'adresse demandée ; un formulaire envoyé en POST y perd ses données. Comparez l'hôte de l'adresse, jamais un morceau de l'adresse entière : https://evil.test/?next=://intranet.example.com/ contient le nom de votre serveur.
// Ask before the site leaves for another page
uo_browser.ib_veto_navigation = true
// ue_navigating event of uo_browser : (string as_url)
// Local variables
string ls_host
long ll_cut
// The host of the address : after "://", up to the first "/", "?", "#" or ":"
ls_host = Lower(Mid(as_url, Pos(as_url, "://") + 3))
for ll_cut = 1 to Len(ls_host)
if Pos("/?#:", Mid(ls_host, ll_cut, 1)) > 0 then exit
next
ls_host = Left(ls_host, ll_cut - 1)
// Only the company server may be opened : the host must be EXACTLY it
return ls_host = "intranet.example.com"
Caméra, micro, position #
Quand un site demande la caméra, le micro, la position, les notifications ou la lecture du presse-papiers, c'est ue_permission_requested qui décide, et la réponse par défaut est non : un site n'allume pas une caméra par une invite que l'utilisateur ne comprend pas. C'est la seule question de la bibliothèque où le silence vaut refus. Rien n'est retenu : la question revient à chaque demande.
// ue_permission_requested event of uo_browser : (string as_url, string as_kind)
// The video-call page of the company may use the camera and the microphone
if Pos(Lower(as_url), "://visio.example.com/") = 0 then return false
return as_kind = uo_browser.PERMISSION_CAMERA or as_kind = uo_browser.PERMISSION_MICROPHONE
Valeurs de as_kind : PERMISSION_CAMERA, PERMISSION_MICROPHONE, PERMISSION_GEOLOCATION, PERMISSION_NOTIFICATIONS, PERMISSION_CLIPBOARD, PERMISSION_SENSORS, PERMISSION_DOWNLOADS (plusieurs téléchargements d'affilée), PERMISSION_FILES, PERMISSION_AUTOPLAY, PERMISSION_FONTS, PERMISSION_MIDI, PERMISSION_WINDOWS, PERMISSION_UNKNOWN.
Pourquoi une page n'a pas chargé #
al_status de ue_load_failed se compare aux constantes LOADSTATUS_* du composant :
| Constante | Signifie |
|---|---|
LOADSTATUS_HOST_NOT_RESOLVED | Hôte inconnu (nom mal écrit, DNS) |
LOADSTATUS_DISCONNECTED · LOADSTATUS_CANNOT_CONNECT · LOADSTATUS_SERVER_UNREACHABLE | Pas de réseau, serveur injoignable |
LOADSTATUS_TIMEOUT | Le serveur n'a pas répondu à temps |
LOADSTATUS_CERT_INVALID · LOADSTATUS_CERT_EXPIRED · LOADSTATUS_CERT_NAME_INCORRECT · LOADSTATUS_CERT_REVOKED · LOADSTATUS_CLIENT_CERT_ERROR | Certificat refusé |
LOADSTATUS_CANCELED | Chargement annulé par of_stop ou par une adresse plus récente |
LOADSTATUS_AUTH_REQUIRED · LOADSTATUS_PROXY_AUTH_REQUIRED | Identification demandée (serveur, proxy) |
LOADSTATUS_CONNECTION_ABORTED · LOADSTATUS_CONNECTION_RESET · LOADSTATUS_INVALID_RESPONSE · LOADSTATUS_REDIRECT_FAILED · LOADSTATUS_UNEXPECTED_ERROR · LOADSTATUS_UNKNOWN | Autres échecs de connexion ou de réponse |
// ue_load_failed event of uo_browser : (string as_url, long al_status)
if al_status = uo_browser.LOADSTATUS_HOST_NOT_RESOLVED then
st_message.text = "Unknown address : " + as_url
end if
Exécuter un script dans la page #
of_execute_javascript lit ou modifie la page affichée (son titre, un champ, un compteur). Il n'est pas bridé par la licence, y compris sur une page about:blank ou data: : exécuter un script dans la page est le métier d'un navigateur, et le composant est gratuit.
// ue_load_completed event of uo_browser : (string as_url)
// The page title, as JSON : "PowerBuilder - Wikipedia" (quotes included)
sle_title.text = uo_browser.of_execute_javascript(/*script*/ "document.title")
Indicateur de chargement #
ue_load_started est levé quand une page commence à se charger — une adresse de votre code, un lien, un geste de l'utilisateur —, et of_is_loading() rend true jusqu'à ue_load_completed ou ue_load_failed : de quoi montrer un sablier ou activer votre bouton Arrêter.
// ue_load_started event of uo_browser : (string as_url)
// The Stop button works while the page loads
cb_stop.enabled = true
// ue_load_completed event of uo_browser : (string as_url)
// Loaded : nothing left to stop
cb_stop.enabled = uo_browser.of_is_loading()
Zoom #
ii_zoom agrandit ou réduit le site (la barre d'adresse garde sa taille), de 25 à 500 %. Il se relit en direct : Ctrl+molette dans le site le change aussi, et votre code le voit.
// A screen read from a distance : the site one and a half times larger
uo_browser.ii_zoom = 150
Le certificat d'un intranet #
Un serveur dont le certificat n'est pas valide (certificat interne, expiré) est refusé, et ue_load_failed donne un statut LOADSTATUS_CERT_*. Avec ib_certificate_questions, ue_certificate_error décide — et sa réponse par défaut est non, comme pour une permission : accepter un certificat est une décision de sécurité. Une réponse ne vaut que pour la navigation en cours ; rien n'est retenu.
// Ask about certificates instead of refusing them at once
uo_browser.ib_certificate_questions = true
// ue_certificate_error event of uo_browser : (string as_url, long al_status)
// Only the test server of the company, whose certificate is internal
return Left(Lower(as_url), 34) = "https://test-intranet.example.com/"
Des messages entre la page et l'application #
Un portail interne peut prévenir l'application (« dossier enregistré », « ligne choisie ») : ouvrez le pont avec ib_web_messages, et listez dans is_message_origins les origines qui ont le droit de parler. Sans origine listée, le pont reste fermé : aucun site du Web ne peut atteindre votre application. La page envoie une valeur JSON, ue_web_message la reçoit telle quelle ; of_post_message répond à la page.
// The company portal may talk with the application
uo_browser.ib_web_messages = true
uo_browser.is_message_origins = "https://portal.example.com"
uo_browser.is_address = "https://portal.example.com/orders"
// In a page of the portal : send a value to the application, and listen to its answers
chrome.webview.postMessage({ order: 4152, action: "open" });
chrome.webview.addEventListener("message", function (e) { console.log(e.data); });
// ue_web_message event of uo_browser : (string as_origin, string as_json)
// Local variables
n_pbt_json lnv_json
// Read the value the page sent, then answer it
lnv_json.of_load(/*json*/ as_json)
if lnv_json.of_get_string(/*path*/ "action") = "open" then
st_message.text = "Order " + String(lnv_json.of_get_number(/*path*/ "order"))
uo_browser.of_post_message(/*json*/ '{"opened":true}')
end if
Une origine s'écrit schéma, hôte et port s'il n'est pas celui par défaut (https://portal.example.com:8443) ; un sous-domaine est une autre origine, et file:/// désigne les pages du poste. Un message de plus de 64 Ko est ignoré. of_post_message vers une page d'une autre origine lève ue_error et n'envoie rien.
Sites qui refusent l'affichage intégré #
Certains sites — Google, la plupart des banques, beaucoup d'applications SaaS — envoient des en-têtes de sécurité qui interdisent leur affichage à l'intérieur d'une autre page. Le composant n'est pas concerné : il n'affiche jamais un site dans un cadre. La page est ouverte comme document principal, exactement comme le fait votre navigateur, et ces en-têtes ne s'appliquent alors plus.
Il n'y a donc rien à régler, et aucun cas particulier à prévoir dans votre code.
// Un site qui refuse d'etre integre dans une page : rien de special a faire
uo_browser.ib_address_bar = true
uo_browser.is_address = "https://www.google.com"
En contrepartie, la page occupe toute la surface du composant sous la barre d'adresse : les habillages posés par-dessus (bandeaux, superpositions thémées) ne sont pas visibles pendant la navigation.
Contenu HTML sans réseau #
of_show_html affiche une page HTML construite par votre application : un aperçu de courrier, un ticket, une facture ou un rapport, sans aucun appel réseau ni fichier temporaire. La page est encodée pour vous : une couleur #c00, une ancre, un % ou un accent s'affichent tels qu'écrits (2 Mo au plus).
// Local variables
string ls_html
// An order summary built by the application : the colour and the "%" come out as written
ls_html = "<html><body>" &
+ "<h1 style='color:#1f6feb'>Order #4152</h1>" &
+ "<p>Discount : 10%</p>" &
+ "</body></html>"
uo_browser.of_show_html(/*html*/ ls_html)
Posée directement dans is_address, une adresse data:text/html, n'est pas encodée : un # y coupe la page (tout ce qui suit passe pour une ancre) et un % la brouille. Préférez of_show_html, ou encodez vous-même (# → %23, % → %25).
Une telle page n'a pas d'adresse à elle : is_address se relit vide, la barre d'adresse aussi, et ue_load_completed reçoit une adresse vide. Sans <title>, son titre est vide. Une image du disque (file:///) n'y est pas affichée : le moteur ne laisse pas une page data: lire les fichiers du poste ; écrivez l'image dans la page (<img src="data:image/png;base64,…">).
Un fichier local s'ouvre de la même façon avec file:///C:/temp/rapport.html, ou simplement son chemin C:\temp\rapport.html.
Repartir de zéro #
of_reset() ne se contente pas de vider la page : il efface aussi l'historique de navigation. Un utilisateur ne peut donc pas revenir, par le bouton Précédent, sur une page consultée par l'utilisateur précédent ou dans un autre dossier. Il ne touche pas à ce que les sites ont retenu : cookies, sessions ouvertes, stockage local, permissions. Sur un poste partagé, l'utilisateur suivant arriverait connecté sous le compte du précédent — c'est of_clear_browsing_data() qui l'efface. Les sites vivent dans un profil de navigation à part, séparé des composants de l'application.
// Local variables
string ls_folder_url
// L'adresse du dossier que l'utilisateur vient d'ouvrir
ls_folder_url = "https://intranet.example.com/files/4152"
// Changement de dossier : on repart d'un navigateur vierge, sans historique
uo_browser.of_reset()
// Puis le dossier, avec sa barre d'adresse
uo_browser.ib_address_bar = true
uo_browser.is_address = ls_folder_url
// The user of the workstation changes : no page, no history, no signed-in session left
uo_browser.of_reset()
uo_browser.of_clear_browsing_data()
Pour que rien ne soit jamais écrit sur le disque, posez ib_private = true avant la première adresse : cookies et stockage disparaissent avec la vue.
C'est le réflexe à avoir chaque fois qu'un même composant sert à afficher des contenus de contextes différents.
Exemple complet #
// event open de la fenetre : page d'accueil du portail interne
uo_browser.of_reset() // repartir propre (historique compris)
// Les outils de navigation, puis la page d'accueil
uo_browser.ib_address_bar = true // champ URL + Precedent / Suivant / Recharger
uo_browser.ib_context_menu = true // meme navigation au clic droit
uo_browser.is_address = "https://intranet.example.com/home"
// event ue_load_completed de uo_browser : (string as_url)
uo_status.of_panel(/*key*/ "main").is_text = "Page chargee : " + as_url
Bonnes pratiques #
- Affectez
is_address, n'appelez pas de méthode de navigation : c'est la propriété qui déclenche l'ouverture de la page. - Activez
ib_address_bardès que l'utilisateur peut naviguer librement ; réservez le pilotage par vos propres boutons aux parcours contraints. - Fiez-vous à
of_can_go_back()/of_can_go_forward()pour l'état de vos boutons plutôt que de compter les pages vous-même : les redirections fausseraient votre compte. - Rien à prévoir pour les sites qui refusent l'affichage intégré : la page est toujours ouverte comme document principal, ces en-têtes ne s'appliquent pas.
- Appelez
of_reset()en changeant de contexte : c'est le seul moyen de garantir qu'aucune page précédente n'est accessible par le bouton Précédent. Quand l'utilisateur du poste change, ajoutezof_clear_browsing_data(): sans lui, cookies et sessions des sites restent. - Le composant a besoin du runtime web installé sur le poste : traitez
ue_runtime_missingcomme pour tout autre composant (Installation). - Un site peut jouer du son sans geste de l'utilisateur : la lecture automatique sonore est permise dans tout l'environnement WebView2 de l'application (le lecteur vidéo et le lecteur de sons en ont besoin, une page cachée n'a pas de geste). Une page qui lance une vidéo sonore à l'ouverture la jouera ; si c'est gênant, ouvrez des adresses que vous connaissez.
- Pour garder l'application sur ses serveurs, listez-les dans
is_allowed_hosts: il arrête aussi les redirections, queue_navigatingne voit pas.
Hérité du socle commun #
Ces membres existent sur tous les composants visuels — ils ne sont pas propres à celui-ci. Ils sont détaillés une seule fois, dans les chapitres transverses ; cette table dit seulement où les lire.
| Membres | Rôle | Détaillé dans |
|---|---|---|
of_reset | Remettre le composant à zéro | 3.6 Remettre un composant à zéro : of_reset() |
of_register_shortcut · of_clear_shortcuts | Raccourcis clavier du composant | 3.5 Les raccourcis clavier |
of_is_created · of_is_ready · of_get_last_error | S'il est né, s'il est prêt, ce qui a échoué | 3.7 Diagnostic |
of_save_as_png · of_save_as_jpg | Exporter le rendu en image | 3.8 Exporter le rendu en image |
of_set_redraw | Grouper les modifications en un seul repaint | 3.10 Bonnes pratiques |
of_preload_icons | Icônes affichées sans délai | Affichage instantané : of_icon |
of_set_translation | Traduire un libellé du composant | 5.2 Adapter un libellé : of_set_translation |
of_focus_webview | Donner le focus au composant | 6.4 Clavier et focus |
of_print · of_print_to_pdf | Imprimer, ou écrire un PDF | 6.9 Imprimer |
of_set_property · of_get_property · of_component_name | Piloter une propriété par son nom | 3.1 Le moteur de propriétés |
is_accessible_name · is_accessible_description | Le nom et la description que dit un lecteur d'écran | 3.4 Propriétés et events optionnels |
Deux aides ne sont pas héritées : of_icon et of_escape_markup vivent sur n_pbt_utils. Déclarez-en une — n_pbt_utils lnv_utils, rien à créer — et appelez-les dessus.