CT WEBBROWSER: Difference between revisions
mNo edit summary |
(Trick to redirect links to game files) |
||
(6 intermediate revisions by 2 users not shown) | |||
Line 11: | Line 11: | ||
{{CT|abc start}} | {{CT|abc start}} | ||
=== A === | |||
{{CT|attribute | |||
|name=allowExternalURL | |||
|type1=Boolean | |||
|value1=1 | |||
|description=Whether this browser will allow external URLs, as opposed to local content. | |||
}} | |||
=== U === | === U === | ||
Line 18: | Line 28: | ||
|type1=String | |type1=String | ||
|value1="https://arma3.com" | |value1="https://arma3.com" | ||
|description=URL to be opened | |description= if allowExternalURL==1 then URL to be opened else path to a local file to load. Local files are subject to allowedHTMLloadExtensions (#TODO link) | ||
}} | }} | ||
Line 26: | Line 36: | ||
=== ctrlWebBrowserAction === | === ctrlWebBrowserAction === | ||
{{RV|type=command | {{RV|type=command | ||
Line 44: | Line 56: | ||
{{!}} None | {{!}} None | ||
{{!}} [[Nothing]] | {{!}} [[Nothing]] | ||
{{!}} Opens a Chrome Developer console for this browser, in a external window. | {{!}} Opens a Chrome Developer console for this browser, in a external window. (Only available if -debug start parameter is set) | ||
{{!}}- | {{!}}- | ||
{{!}} ExecJS | {{!}} ExecJS | ||
Line 51: | Line 63: | ||
{{!}} Executes Javascript code inside the currently loaded page. | {{!}} Executes Javascript code inside the currently loaded page. | ||
{{!}}- | {{!}}- | ||
{{!}} | {{!}} JSDialogResponse | ||
{{!}} [[Boolean]] | {{!}} [[Boolean]] | ||
{{!}} [[Nothing]] | {{!}} [[Nothing]] | ||
Line 60: | Line 72: | ||
{{!}} [[Nothing]] | {{!}} [[Nothing]] | ||
{{!}} Displays provided data in browser. This can be used to load HTML from a file and display it in the Browser window. | {{!}} Displays provided data in browser. This can be used to load HTML from a file and display it in the Browser window. | ||
{{!}}- | |||
{{!}} LoadFile | |||
{{!}} [[String]] | |||
{{!}} [[Nothing]] | |||
{{!}} Loads file into browser (Equivalent to ["OpenDataAsURL", loadFile "filePathHere"])<br> | |||
_ctrl ctrlWebBrowserAction ["LoadFile", "z\mod\file.html"] is equivalent to _ctrl [[ctrlSetURL]] "file://z/mod/file.html" | |||
{{!}}- | |||
{{!}} ToBase64 | |||
{{!}} [[String]] | |||
{{!}} [[String]] | |||
{{!}} Encodes the input string into Base64 (This also works with [[controlNull]]) | |||
{{!}}- | |||
{{!}} FromBase64 | |||
{{!}} [[String]] | |||
{{!}} [[String]] | |||
{{!}} Decodes the input Base64 string (This also works with [[controlNull]]) | |||
{{!}}- | |||
{{!}} Deflate | |||
{{!}} [[String]] | |||
{{!}} [[String]] | |||
{{!}} Compresses the input and returns a Base64 Deflate compressed output with ZLib header (This also works with [[controlNull]]) | |||
{{!}}- | |||
{{!}} Inflate | |||
{{!}} [[String]] | |||
{{!}} [[String]] | |||
{{!}} Takes Base64 encoded, Deflate compressed input data and returns the decompressed output (This also works with [[controlNull]]). Output is limited to 1Megabyte. Equivalent Javascript code: | |||
is https://gist.github.com/asidko/9c7064027039411a11323eaf7d8ea2a4#file-gzip-js-L12 but replace 'gzip' with 'deflate' | |||
{{!}}- | |||
{{!}} StopBrowser | |||
{{!}} | |||
{{!}} | |||
{{!}} Freezes the currently displayed image (the same image will keep being displayed). Closes the browser and free's all resources of it. This is useful if the Browser is only used to generate a static element and it doesn't need to keep updating it. It saves CPU and Memory resources. | |||
{{!}}- | |||
{{!}} ResumeBrowser | |||
{{!}} | |||
{{!}} | |||
{{!}} Unfreezes the browser, and loads the currently set URL (Either that was set before StopBrowser, or which has been set while the browser was paused). Note that when unfreezing, the browser may show one or two black frames while the page is loading. For seemless transition from Paused/Resumed state, you can use a ui2texture and not send any displayUpdate's to it until you consider the resumed browser to be ready. | |||
</syntaxhighlight> | |||
{{!}}} | {{!}}} | ||
Line 73: | Line 124: | ||
|seealso= [[ctrlURL]] [[menuSetURL]] | |seealso= [[ctrlURL]] [[menuSetURL]] | ||
}} | }} | ||
<pre> | |||
</pre> | |||
=== Control EventHandler === | |||
This eventhandler can only be added to WebBrowser controls | This eventhandler can only be added to WebBrowser controls | ||
Line 84: | Line 137: | ||
* '''Use on:''' Control ([[CT_WEBBROWSER]]) | * '''Use on:''' Control ([[CT_WEBBROWSER]]) | ||
* '''Fired on:''' Fires when Javascript triggers a alert() or confirm() dialog. | * '''Fired on:''' Fires when Javascript triggers a alert() or confirm() dialog. | ||
<sqf>params ["_control", "_isConfirmDialog", "_message"];</sqf> | <sqf>params ["_control", "_isConfirmDialog", "_message"];</sqf> | ||
The code handling this event can return a [[Boolean]] true/false. Which will stop the next Eventhandlers from being triggered, and will be interpreted as a reply to the dialog.<br> | The code handling this event can return a [[Boolean]] true/false. Which will stop the next Eventhandlers from being triggered, and will be interpreted as a reply to the dialog.<br> | ||
If the code does not immediately provide a reply, it should return [[Nothing]].<br> | If the code does not immediately provide a reply, it should return [[Nothing]].<br> | ||
If the code does not return bool, then the script must call [[ctrlWebBrowserAction]] with the "JSDialog" action to reply to the dialog, the WebBrowser will be unresponsive until a reply has been sent. | If the code does not return bool, then the script must call [[ctrlWebBrowserAction]] with the "JSDialog" action to reply to the dialog, the WebBrowser will be unresponsive until a reply has been sent. | ||
==== Draw ==== | |||
* '''Use on:''' Control ([[CT_WEBBROWSER]]) | |||
* '''Fired on:''' Fires when the WebBrowser has drawn a new frame (NOT when the game control displays a new frame) | |||
<sqf>params ["_control"];</sqf> | |||
==== PageLoaded ==== | |||
* '''Use on:''' Control ([[CT_WEBBROWSER]]) | |||
* '''Fired on:''' Fires when the current page has finished loading. This only contains the main page, the page may contain content (scripts, images) that will load asynchronously and may not be ready. This fires multiple times, when the current page (url) was changed or when the browser is Resumed. | |||
<sqf>params ["_control"];</sqf> | |||
Once PageLoaded is triggered, it is safe to execute javascript on the page. Before PageLoaded, the page might not be ready to receive javascript and may drop ExecJS requests. | |||
{{ConfigPage|end}} | {{ConfigPage|end}} | ||
Line 96: | Line 160: | ||
=== RscWebBrowser === | === RscWebBrowser === | ||
Baseline | Baseline RscWebBrowser example | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
class | class RscWebBrowser | ||
{ | { | ||
type = CT_WEBBROWSER; // 106 | type = CT_WEBBROWSER; // 106 | ||
Line 108: | Line 172: | ||
w = 0.3; | w = 0.3; | ||
h = 0.3; | h = 0.3; | ||
url= "https://arma3.com"; | allowExternalURL = 1; | ||
url = "https://arma3.com"; | |||
}; | }; | ||
</syntaxhighlight> | |||
== Browser Content == | |||
The Browser is separated into two modes. | |||
- Remote Content (Loading external websites by a URL) which can be enabled with the allowExternalContent attribute. | |||
- Local Content (Loading local html files from within a pbo/mission). | |||
=== Remote Content === | |||
Remote content is considered unsafe. Any browser that uses "allowExternalURL" will prompt the player to allow it being opened. | |||
URL's are limited by the allowedHTMLLoadURIs server/mod configuration (#TODO link to it) | |||
=== Local Content === | |||
Loading Local Content, forces the browser into a "sandbox" mode.<br> | |||
Players will not receive a permission popup for Local Content.<br> | |||
Local Content offers a Javascript API to interact with the game without having to go through SQF.<br> | |||
Local files are subject to allowedHTMLloadExtensions (#TODO link).<br> | |||
==== Sandbox ==== | |||
The content is loaded into a [https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox sandboxed] iframe with a [https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP Content Security Policy].<br> | |||
<br> | |||
Any external communication via [https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API fetch] or [https://developer.mozilla.org/de/docs/Web/API/XMLHttpRequest XMLHttpRequest] is unavailable.<br> | |||
Access to [https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage Local Storage], [https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API IndexedDB] are unvailable.<br> | |||
[https://developer.mozilla.org/en-US/docs/Web/API/Window/alert alert()] and [https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm confirm()] are not directly accessible, but the Javascript API provides a wrapper. | |||
Content like Images, Styles, Font's, Scripts, Media, can only be specified inline (for Scripts and Styles) or via [https://developer.mozilla.org/en-US/docs/Web/URI/Schemes/data Data URLs].<br> | |||
==== Javascript API ==== | |||
This API is injected into every local content page automatically. | |||
API offers the following functions (Here expressed as typescript to clarify argument and return types) | |||
<syntaxhighlight lang="javascript"> | |||
class A3API | |||
{ | |||
/** | |||
* Loads file from game filesystem. | |||
* | |||
* @param filePath - Path in game filesystem, without leading backslash | |||
* @param maxSize - maximum texture width (used to select Mip) | |||
* @returns The image as a data-url | |||
*/ | |||
static RequestTexture(texturePath: string, maxSize: number): Promise<string>; | |||
/** | |||
* Loads file from game filesystem. | |||
* | |||
* @param filePath - same as loadFile SQF command | |||
* @returns The file content | |||
*/ | |||
static RequestFile(filePath: string): Promise<string>; | |||
/** | |||
* Loads and preprocesses file from game filesystem. | |||
* | |||
* @param filePath - same as preprocessFile SQF command | |||
* @returns The file content | |||
*/ | |||
static RequestPreprocessedFile(filePath: string): Promise<string>; | |||
// Triggers a alert() (Needs to be piped due to https://chromestatus.com/feature/5148698084376576) | |||
static SendAlert(content: string): void; | |||
static SendConfirm(content: string): Promise<string>; | |||
} | |||
</syntaxhighlight> | |||
Example, this is how to load a image out of the game, into Javascript, and insert it into the page | |||
<syntaxhighlight lang="javascript"> | |||
const eWeaponImage = document.createElement('img'); | |||
A3API.RequestTexture("A3\\weapons_F\\Rifles\\MX\\data\\UI\\gear_mx_rifle_X_CA.paa", 512).then(imageContent => eWeaponImage.src = imageContent); | |||
document.body.appendChild(eWeaponImage); | |||
</syntaxhighlight> | |||
==== Example HUD ==== | |||
Here is an example of how to create a basic WebBrowser based HUD overlay purely inside a mission file. | |||
Create a basic mission, and place the following files next to the mission.sqm | |||
description.ext: | |||
<syntaxhighlight lang="cpp"> | |||
import RscText; | |||
class RscTitles | |||
{ | |||
class HudOverlayUI | |||
{ | |||
idd = 13371337; | |||
fadein = 0; // Required parameters for RscTitles | |||
fadeout = 0; | |||
duration = 1e+011; | |||
onLoad = "GHUDOverlay = _this"; // Store our Display in a variable so we can access it from script | |||
class controls | |||
{ | |||
class Texture: RscText | |||
{ | |||
type = 106; // CT_WEBBROWSER | |||
idc = 1337; | |||
x = safeZoneX; // Full screen from corner to corner | |||
y = safeZoneY; | |||
w = safeZoneW; | |||
h = safeZoneH; | |||
url = "file://hudOverlay.html"; // Reference to a file inside our mission | |||
}; | |||
}; | |||
}; | |||
}; | |||
</syntaxhighlight> | |||
init.sqf | |||
<sqf> | |||
("MyHudLayer" call BIS_fnc_rscLayer) cutRsc ["HudOverlayUI", "PLAIN"]; // Add our Display to the HUD | |||
private _ctrl = ((GHUDOverlay#0) displayCtrl 1337); | |||
_ctrl ctrlAddEventHandler ["JSDialog", { | |||
params ["_control", "_isConfirmDialog", "_message"]; | |||
// Insert message as text into the page, by assembling Javascript code to insert a new element and set its text. | |||
_control ctrlWebBrowserAction ["ExecJS", format ["const eSpan = document.createElement('span'); eSpan.textContent = 'Script says %1!'; document.body.appendChild(eSpan);", _message]]; | |||
true; // We need to tell it that we handled the "dialog", by returning true or false. | |||
}]; | |||
//_ctrl ctrlWebBrowserAction ["OpenDevConsole"]; // Can open developer console here | |||
//_ctrl ctrlWebBrowserAction ["LoadFile", "hudOverlay.html"]; // Instead of using url= in description.ext, we could also load the file here, that way we can open dev console before the page is loaded | |||
</sqf> | |||
hudOverlay.html | |||
<syntaxhighlight lang="html"> | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<body> | |||
<script> | |||
// Load the MX Rifle inventory image and add it to the page | |||
const eWeaponImage = document.createElement('img'); | |||
A3API.RequestTexture("A3\\weapons_F\\Rifles\\MX\\data\\UI\\gear_mx_rifle_X_CA.paa", 512).then(imageContent => eWeaponImage.src = imageContent); | |||
document.body.appendChild(eWeaponImage); | |||
// Send a message to script | |||
A3API.SendAlert("Javascript is sending an alert"); // This alert will trigger a JSDialog (Alert Dialog) eventhandler | |||
</script> | |||
</body> | |||
</html> | |||
</syntaxhighlight> | |||
==== Seamless Stop/Resume ==== | |||
When you stop a browser, and resume it again, the browser will have to reload the last page which might take a couple frames. During the reload, the browser might display a few empty. | |||
Inside a ui2texture containing a browser, it is possible to skip/hide these empty frames by also pausing the ui2texture updates. | |||
This code assumes that the displayUpdate calls on the ui2texture, are done with a EachFrame Mission EH. | |||
And also the WebBrowser control is directly inside the ui2texture display. | |||
<sqf> | |||
_ctrl ctrlWebBrowserAction ["StopBrowser"]; | |||
// Remove the EachFrame handler doing displayUpdate. So our ui2tex will also be frozen | |||
removeMissionEventHandler ["EachFrame", (ctrlParent _ctrl) getVariable "displayUpdateHandler"]; | |||
</sqf> | |||
<sqf> | |||
// Resume the browser, it will now start loading the page | |||
private _display = ctrlParent _ctrl; | |||
_ctrl ctrlWebBrowserAction ["ResumeBrowser"]; | |||
// Remember when the last browser draw happened, so we can wait for it to become stable (once it stops drawing for a while) | |||
_ctrl setVariable ["lastDraw", diag_frameNo]; | |||
private _drawHandlerIndex = _ctrl ctrlAddEventHandler ["Draw", { | |||
params ["_ctrl"]; | |||
_ctrl setVariable ["lastDraw", diag_frameNo]; // Remember when the last draw happened | |||
}]; | |||
waitUntil {((_ctrl getVariable "lastDraw") + 60) < diag_frameNo}; // Note that this will not serialize into savegames, and will probably cause errors if Save/Load is involved. | |||
//#TODO handle the control becoming null because the UI was closed | |||
// No draw for 60 frames, its probably stable, so we resume updating the ui2tex | |||
private _handlerID = addMissionEventHandler ["EachFrame", {displayUpdate (_thisArgs#0)}, [_display]]; // Note that this will not serialize into savegames, and will probably cause errors if Save/Load is involved. | |||
_display setVariable ["displayUpdateHandler", _handlerID]; | |||
_ctrl ctrlRemoveEventHandler ["Draw", _drawHandlerIndex]; // Stop listening for draw events | |||
</sqf> | |||
==== Redirecting links into Arma files ==== | |||
You can build a "normal" web page, with "normal" <a href=".."> links on it. And have the links navigate to files that are inside Arma. | |||
This javascript, will redirect all links, to the A3API which will make it load the file from the game filesystem. | |||
Just like using "LoadFile" ctrlWebBrowserAction. | |||
<syntaxhighlight lang="html"> | |||
<script> | |||
document.addEventListener("DOMContentLoaded", () => { | |||
var allLinks = document.getElementsByTagName("a"); | |||
[...allLinks].forEach((link) => { | |||
link.onclick = function (e) { | |||
e.preventDefault(); | |||
var targetUrl = e.currentTarget.getAttribute('href'); | |||
A3API.NavigateTo(targetUrl); | |||
}; | |||
}); | |||
}); | |||
</script> | |||
<body> | |||
<a href="arma://MissionSubFolder/index.html">Click me to get to page</a> | |||
</body> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
[[Category: Control Types]] | [[Category: Control Types]] |
Latest revision as of 14:27, 24 January 2025
Control Types / MACRO (TYPE VALUE) | |
---|---|
Text/Image/Video |
CT_STATIC (0) | CT_EDIT (2) | CT_HTML (9) | CT_STRUCTURED_TEXT (13) |
Buttons |
CT_BUTTON (1) | CT_ACTIVETEXT (11) | CT_SHORTCUTBUTTON (16) | CT_CHECKBOX (77) | CT_XBUTTON (41) |
Lists |
CT_COMBO (4) | CT_TOOLBOX (6) | CT_CHECKBOXES (7) | CT_TREE (12) | CT_CONTROLS_TABLE (19) | CT_XCOMBO (44) | CT_LISTBOX (5) | CT_LISTNBOX (102) | CT_LISTNBOX_CHECKABLE (104) | CT_XLISTBOX (45) |
3D Objects |
CT_OBJECT (80) | CT_OBJECT_ZOOM (81) | CT_OBJECT_CONTAINER (82) | CT_OBJECT_CONT_ANIM (83) |
Maps |
CT_MAP (100) | CT_MAP_MAIN (101) |
Meta |
CT_SLIDER (3) | CT_XSLIDER (43) | CT_PROGRESS (8) | CT_CONTROLS_GROUP (15) | CT_WEBBROWSER (106) | CT_EXTENSION (107) |
Menu |
CT_CONTEXT_MENU (14) | CT_MENU (46) | CT_MENU_STRIP (47) |
Unknown |
CT_STATIC_SKEW (10) | CT_HITZONES (17) | CT_VEHICLETOGGLES (18) | CT_XKEYDESC (40) | CT_ANIMATED_TEXTURE (45) | CT_LINEBREAK (98) | CT_USER (99) | CT_ITEMSLOT (103) | CT_VEHICLE_DIRECTION (105) |
Introduction
WebBrowser control features an embedded Chromium window.
The URL is subject to allowedHTMLLoadURIs[] whitelisting in CfgCommands config.
ctrlSetURL Can be used to change the URL after creation of the control.
Related commands & functions
Related User Interface Eventhandlers
Alphabetical Order
#define CT_WEBBROWSER 106
A
allowExternalURL
- Type
- Boolean
- Description
- Whether this browser will allow external URLs, as opposed to local content.
allowExternalURL = 1;
U
url
- Type
- String
- Description
- if allowExternalURL==1 then URL to be opened else path to a local file to load. Local files are subject to allowedHTMLloadExtensions (#TODO link)
url = "https://arma3.com";
Scripting
ctrlWebBrowserAction
Warning: Display title "CT WEBBROWSER" overrides earlier display title "CT_WEBBROWSER".
Description
- Description:
- Executes an action on a WebBrowser control. The type of parameters depends on the action type. Possible Actions are:
Action Parameter Result Description OpenDevConsole None Nothing Opens a Chrome Developer console for this browser, in a external window. (Only available if -debug start parameter is set) ExecJS String Nothing Executes Javascript code inside the currently loaded page. JSDialogResponse Boolean Nothing Respond to a Javascript alert() or confirm(), after triggered by "JSDialog" Eventhandler OpenDataAsURL String Nothing Displays provided data in browser. This can be used to load HTML from a file and display it in the Browser window. LoadFile String Nothing Loads file into browser (Equivalent to ["OpenDataAsURL", loadFile "filePathHere"])
_ctrl ctrlWebBrowserAction ["LoadFile", "z\mod\file.html"] is equivalent to _ctrl ctrlSetURL "file://z/mod/file.html"
ToBase64 String String Encodes the input string into Base64 (This also works with controlNull) FromBase64 String String Decodes the input Base64 string (This also works with controlNull) Deflate String String Compresses the input and returns a Base64 Deflate compressed output with ZLib header (This also works with controlNull) Inflate String String Takes Base64 encoded, Deflate compressed input data and returns the decompressed output (This also works with controlNull). Output is limited to 1Megabyte. Equivalent Javascript code: is https://gist.github.com/asidko/9c7064027039411a11323eaf7d8ea2a4#file-gzip-js-L12 but replace 'gzip' with 'deflate'
StopBrowser Freezes the currently displayed image (the same image will keep being displayed). Closes the browser and free's all resources of it. This is useful if the Browser is only used to generate a static element and it doesn't need to keep updating it. It saves CPU and Memory resources. ResumeBrowser Unfreezes the browser, and loads the currently set URL (Either that was set before StopBrowser, or which has been set while the browser was paused). Note that when unfreezing, the browser may show one or two black frames while the page is loading. For seemless transition from Paused/Resumed state, you can use a ui2texture and not send any displayUpdate's to it until you consider the resumed browser to be ready. </syntaxhighlight>
- Groups:
- GUI Control
Syntax
- Syntax:
- control ctrlWebBrowserAction [Action, ...]
- Parameters:
- control: Control
- Action: String
- Return Value:
- Nothing
Examples
- Example 1:
Additional Information
- See also:
- ctrlURL menuSetURL
Notes
-
Report bugs on the Feedback Tracker and/or discuss them on the Arma Discord or on the Forums.
Only post proven facts here! Add Note
[[Category:Introduced with arma3dev version 2.20]][[ Category: arma3dev: New Scripting Commands | CT WEBBROWSER]][[ Category: arma3dev: Scripting Commands | CT WEBBROWSER]]
Control EventHandler
This eventhandler can only be added to WebBrowser controls
JSDialog
- Use on: Control (CT_WEBBROWSER)
- Fired on: Fires when Javascript triggers a alert() or confirm() dialog.
If the code does not immediately provide a reply, it should return Nothing.
If the code does not return bool, then the script must call ctrlWebBrowserAction with the "JSDialog" action to reply to the dialog, the WebBrowser will be unresponsive until a reply has been sent.
Draw
- Use on: Control (CT_WEBBROWSER)
- Fired on: Fires when the WebBrowser has drawn a new frame (NOT when the game control displays a new frame)
PageLoaded
- Use on: Control (CT_WEBBROWSER)
- Fired on: Fires when the current page has finished loading. This only contains the main page, the page may contain content (scripts, images) that will load asynchronously and may not be ready. This fires multiple times, when the current page (url) was changed or when the browser is Resumed.
Default Classes
RscWebBrowser
Baseline RscWebBrowser example
class RscWebBrowser
{
type = CT_WEBBROWSER; // 106
idc = -1;
deletable = 0;
style = 0;
x = 0;
y = 0;
w = 0.3;
h = 0.3;
allowExternalURL = 1;
url = "https://arma3.com";
};
Browser Content
The Browser is separated into two modes. - Remote Content (Loading external websites by a URL) which can be enabled with the allowExternalContent attribute. - Local Content (Loading local html files from within a pbo/mission).
Remote Content
Remote content is considered unsafe. Any browser that uses "allowExternalURL" will prompt the player to allow it being opened. URL's are limited by the allowedHTMLLoadURIs server/mod configuration (#TODO link to it)
Local Content
Loading Local Content, forces the browser into a "sandbox" mode.
Players will not receive a permission popup for Local Content.
Local Content offers a Javascript API to interact with the game without having to go through SQF.
Local files are subject to allowedHTMLloadExtensions (#TODO link).
Sandbox
The content is loaded into a sandboxed iframe with a Content Security Policy.
Any external communication via fetch or XMLHttpRequest is unavailable.
Access to Local Storage, IndexedDB are unvailable.
alert() and confirm() are not directly accessible, but the Javascript API provides a wrapper.
Content like Images, Styles, Font's, Scripts, Media, can only be specified inline (for Scripts and Styles) or via Data URLs.
Javascript API
This API is injected into every local content page automatically.
API offers the following functions (Here expressed as typescript to clarify argument and return types)
class A3API
{
/**
* Loads file from game filesystem.
*
* @param filePath - Path in game filesystem, without leading backslash
* @param maxSize - maximum texture width (used to select Mip)
* @returns The image as a data-url
*/
static RequestTexture(texturePath: string, maxSize: number): Promise<string>;
/**
* Loads file from game filesystem.
*
* @param filePath - same as loadFile SQF command
* @returns The file content
*/
static RequestFile(filePath: string): Promise<string>;
/**
* Loads and preprocesses file from game filesystem.
*
* @param filePath - same as preprocessFile SQF command
* @returns The file content
*/
static RequestPreprocessedFile(filePath: string): Promise<string>;
// Triggers a alert() (Needs to be piped due to https://chromestatus.com/feature/5148698084376576)
static SendAlert(content: string): void;
static SendConfirm(content: string): Promise<string>;
}
Example, this is how to load a image out of the game, into Javascript, and insert it into the page
const eWeaponImage = document.createElement('img');
A3API.RequestTexture("A3\\weapons_F\\Rifles\\MX\\data\\UI\\gear_mx_rifle_X_CA.paa", 512).then(imageContent => eWeaponImage.src = imageContent);
document.body.appendChild(eWeaponImage);
Example HUD
Here is an example of how to create a basic WebBrowser based HUD overlay purely inside a mission file.
Create a basic mission, and place the following files next to the mission.sqm
description.ext:
import RscText;
class RscTitles
{
class HudOverlayUI
{
idd = 13371337;
fadein = 0; // Required parameters for RscTitles
fadeout = 0;
duration = 1e+011;
onLoad = "GHUDOverlay = _this"; // Store our Display in a variable so we can access it from script
class controls
{
class Texture: RscText
{
type = 106; // CT_WEBBROWSER
idc = 1337;
x = safeZoneX; // Full screen from corner to corner
y = safeZoneY;
w = safeZoneW;
h = safeZoneH;
url = "file://hudOverlay.html"; // Reference to a file inside our mission
};
};
};
};
init.sqf
hudOverlay.html
<!DOCTYPE html>
<html lang="en">
<body>
<script>
// Load the MX Rifle inventory image and add it to the page
const eWeaponImage = document.createElement('img');
A3API.RequestTexture("A3\\weapons_F\\Rifles\\MX\\data\\UI\\gear_mx_rifle_X_CA.paa", 512).then(imageContent => eWeaponImage.src = imageContent);
document.body.appendChild(eWeaponImage);
// Send a message to script
A3API.SendAlert("Javascript is sending an alert"); // This alert will trigger a JSDialog (Alert Dialog) eventhandler
</script>
</body>
</html>
Seamless Stop/Resume
When you stop a browser, and resume it again, the browser will have to reload the last page which might take a couple frames. During the reload, the browser might display a few empty. Inside a ui2texture containing a browser, it is possible to skip/hide these empty frames by also pausing the ui2texture updates.
This code assumes that the displayUpdate calls on the ui2texture, are done with a EachFrame Mission EH. And also the WebBrowser control is directly inside the ui2texture display.
Redirecting links into Arma files
You can build a "normal" web page, with "normal" <a href=".."> links on it. And have the links navigate to files that are inside Arma. This javascript, will redirect all links, to the A3API which will make it load the file from the game filesystem. Just like using "LoadFile" ctrlWebBrowserAction.
<script>
document.addEventListener("DOMContentLoaded", () => {
var allLinks = document.getElementsByTagName("a");
[...allLinks].forEach((link) => {
link.onclick = function (e) {
e.preventDefault();
var targetUrl = e.currentTarget.getAttribute('href');
A3API.NavigateTo(targetUrl);
};
});
});
</script>
<body>
<a href="arma://MissionSubFolder/index.html">Click me to get to page</a>
</body>