Compare commits

...

8 commits

Author SHA1 Message Date
phosit
6ffc251114
Make timedconfirmation.js a module
Some checks failed
checkrefs / lfscheck (push) Has been cancelled
checkrefs / checkrefs (push) Has been cancelled
lint / cppcheck (push) Has been cancelled
lint / copyright (push) Has been cancelled
lint / jenkinsfiles (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Refs: #8081
2026-08-14 12:41:45 +02:00
phosit
0f939b8abf
Make termsdialog.js a module
Refs: #8081
2026-08-14 12:41:45 +02:00
phosit
bf0c3af75a
Make mod/gui/pregame/mainmenu.js a module
Refs: #8081
2026-08-14 12:41:45 +02:00
phosit
497efe5a99
Make msgbox.js a module
Refs: #8081
2026-08-14 12:41:45 +02:00
phosit
609efa7e32
Make modmod/help/help.js a module
Refs: #8081
2026-08-14 12:41:44 +02:00
phosit
9adb3e7889
Make modmod.js a module
Actions in xml files only has access to the global scope, not the module
scope. So define them in the js file.

Refs: #8081
2026-08-14 12:41:44 +02:00
phosit
2c4f7d85b6
Make modio.js a module
Actions in xml files only has access to the global scope, not the module
scope. So define them in the js file.

Refs: #8081
2026-08-14 12:41:44 +02:00
phosit
8918cfb0a7
Make incompatible_mods.js a module
Refs: #8081
2026-08-14 12:41:44 +02:00
18 changed files with 91 additions and 71 deletions

View file

@ -1,6 +1,8 @@
var g_IncompatibleModsFile = "gui/incompatible_mods/incompatible_mods.txt"; /* eslint-disable prefer-const -- Mods should be able to change it */
let g_IncompatibleModsFile = "gui/incompatible_mods/incompatible_mods.txt";
/* eslint-enable prefer-const */
function init(data) export function init(data)
{ {
Engine.GetGUIObjectByName("mainText").caption = Engine.TranslateLines(Engine.ReadFile(g_IncompatibleModsFile)); Engine.GetGUIObjectByName("mainText").caption = Engine.TranslateLines(Engine.ReadFile(g_IncompatibleModsFile));
return new Promise(closePageCallback => return new Promise(closePageCallback =>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<objects> <objects>
<script directory="gui/common/"/> <script directory="gui/common/"/>
<script directory="gui/incompatible_mods/"/> <script module="gui/incompatible_mods/incompatible_mods.js"/>
<!-- Add a translucent black background to fade out the menu page --> <!-- Add a translucent black background to fade out the menu page -->
<object type="image" sprite="ModernFade"/> <object type="image" sprite="ModernFade"/>

View file

@ -1,4 +1,4 @@
var g_ModsAvailableOnline = []; let g_ModsAvailableOnline = [];
/** /**
* Indicates if we have encountered an error in one of the network-interaction attempts. * Indicates if we have encountered an error in one of the network-interaction attempts.
@ -8,7 +8,7 @@ var g_ModsAvailableOnline = [];
* Set to `true` by showErrorMessageBox * Set to `true` by showErrorMessageBox
* Set to `false` by init, updateModList, downloadFile, and cancelRequest * Set to `false` by init, updateModList, downloadFile, and cancelRequest
*/ */
var g_Failure; let g_Failure;
/** /**
* Indicates if the user has cancelled a request. * Indicates if the user has cancelled a request.
@ -19,11 +19,11 @@ var g_Failure;
* Set to `true` by cancelRequest * Set to `true` by cancelRequest
* Set to `false` by updateModList, and downloadFile * Set to `false` by updateModList, and downloadFile
*/ */
var g_RequestCancelled; let g_RequestCancelled;
var g_RequestStartTime; let g_RequestStartTime;
var g_ModIOState = { const g_ModIOState = {
/** /**
* Finished status indicators * Finished status indicators
*/ */
@ -142,7 +142,7 @@ var g_ModIOState = {
} }
}; };
function init(data) export function init(data)
{ {
const promise = progressDialog( const promise = progressDialog(
translate("Initializing mod.io interface."), translate("Initializing mod.io interface."),
@ -153,6 +153,21 @@ function init(data)
g_Failure = false; g_Failure = false;
Engine.ModIoStartGetGameId(); Engine.ModIoStartGetGameId();
Object.assign(Engine.GetGUIObjectByName("modFilter"), {
"onPress": displayMods,
"onTextEdit": displayMods
});
Object.assign(Engine.GetGUIObjectByName("modsAvailableList"), {
"onSelectionChange": showModDescription,
"onSelectionColumnChange": displayMods,
"onMouseLeftDoubleClickItem": downloadMod
});
Engine.GetGUIObjectByName("compatibilityFilter").onPress = displayMods;
Engine.GetGUIObjectByName("refreshButton").onPress = updateModList;
Engine.GetGUIObjectByName("downloadButton").onPress = downloadMod;
return Promise.race([ return Promise.race([
promise, promise,
new Promise(closePageCallback => new Promise(closePageCallback =>

View file

@ -3,7 +3,7 @@
<objects> <objects>
<script directory="gui/common/"/> <script directory="gui/common/"/>
<script directory="gui/modio/"/> <script module="gui/modio/modio.js"/>
<object type="image" sprite="ModernFade"/> <object type="image" sprite="ModernFade"/>
@ -25,8 +25,6 @@
style="ModernInput" style="ModernInput"
size="16 0 200 24" size="16 0 200 24"
> >
<action on="Press">displayMods();</action>
<action on="TextEdit">displayMods();</action>
<translatableAttribute id="placeholder_text" context="placeholder text for input field to filter mods">Filter</translatableAttribute> <translatableAttribute id="placeholder_text" context="placeholder text for input field to filter mods">Filter</translatableAttribute>
</object> </object>
@ -39,10 +37,6 @@
selected_column_order="1" selected_column_order="1"
font="sans-stroke-13" font="sans-stroke-13"
> >
<action on="SelectionChange">showModDescription();</action>
<action on="SelectionColumnChange">displayMods();</action>
<action on="MouseLeftDoubleClickItem">downloadMod();</action>
<!-- List headers --> <!-- List headers -->
<!-- Keep in sync with mod property names --> <!-- Keep in sync with mod property names -->
<column id="name_id" textcolor="255 255 255" width="20%"> <column id="name_id" textcolor="255 255 255" width="20%">
@ -69,9 +63,7 @@
<!-- Right Panel: Compatibility Filter--> <!-- Right Panel: Compatibility Filter-->
<object name="rightPanel" size="100%-250 20 100%-10 40" > <object name="rightPanel" size="100%-250 20 100%-10 40" >
<!-- Compatibility Filter Checkbox --> <!-- Compatibility Filter Checkbox -->
<object name="compatibilityFilter" type="checkbox" checked="true" style="ModernTickBox" size="0 4 20 100%"> <object name="compatibilityFilter" type="checkbox" checked="true" style="ModernTickBox" size="0 4 20 100%" />
<action on="Press">displayMods();</action>
</object>
<!-- Compatibility Filter Label --> <!-- Compatibility Filter Label -->
<object type="text" size="20 2 100% 100%" text_align="left" textcolor="white"> <object type="text" size="20 2 100% 100%" text_align="left" textcolor="white">
<translatableAttribute id="caption">Filter valid mods</translatableAttribute> <translatableAttribute id="caption">Filter valid mods</translatableAttribute>
@ -85,12 +77,10 @@
<object name="refreshButton" type="button" style="ModernButtonRed" size="100%-368 100%-44 100%-188 100%-16" enabled="false"> <object name="refreshButton" type="button" style="ModernButtonRed" size="100%-368 100%-44 100%-188 100%-16" enabled="false">
<translatableAttribute id="caption">Refresh List</translatableAttribute> <translatableAttribute id="caption">Refresh List</translatableAttribute>
<action on="Press">updateModList();</action>
</object> </object>
<object name="downloadButton" type="button" style="ModernButtonRed" size="100%-184 100%-44 100%-16 100%-16" enabled="false"> <object name="downloadButton" type="button" style="ModernButtonRed" size="100%-184 100%-44 100%-16 100%-16" enabled="false">
<translatableAttribute id="caption">Download</translatableAttribute> <translatableAttribute id="caption">Download</translatableAttribute>
<action on="Press">downloadMod();</action>
</object> </object>
</object> </object>

View file

@ -1,4 +1,4 @@
function init(data) export function init(data)
{ {
Engine.GetGUIObjectByName("mainText").caption = Engine.TranslateLines(Engine.ReadFile("gui/modmod/help/help.txt")); Engine.GetGUIObjectByName("mainText").caption = Engine.TranslateLines(Engine.ReadFile("gui/modmod/help/help.txt"));
return new Promise(closePageCallback => return new Promise(closePageCallback =>

View file

@ -3,7 +3,7 @@
<objects> <objects>
<script directory="gui/common/"/> <script directory="gui/common/"/>
<script directory="gui/modmod/help/"/> <script module="gui/modmod/help/help.js"/>
<!-- Add a translucent black background to fade out the menu page --> <!-- Add a translucent black background to fade out the menu page -->
<object type="image" sprite="ModernFade"/> <object type="image" sprite="ModernFade"/>

View file

@ -19,33 +19,37 @@
* This allows mods to express upwards and downwards compatibility. * This allows mods to express upwards and downwards compatibility.
*/ */
import { downloadModsButton } from "gui/modmod/modmodio.js";
import { regExpComparisonOperator, validateMod } from "gui/modmod/validatemod.js";
/** /**
* Mod definitions loaded from the files, including invalid mods. * Mod definitions loaded from the files, including invalid mods.
*/ */
var g_Mods = {}; let g_Mods = {};
/** /**
* Folder names of all mods that are or can be launched. * Folder names of all mods that are or can be launched.
*/ */
var g_ModsEnabled = []; let g_ModsEnabled = [];
var g_ModsDisabled = []; let g_ModsDisabled = [];
var g_ModsEnabledFiltered = []; let g_ModsEnabledFiltered = [];
var g_ModsDisabledFiltered = []; let g_ModsDisabledFiltered = [];
/** /**
* Cache mod compatibility recomputed when some mod is enbaled/disabled. * Cache mod compatibility recomputed when some mod is enbaled/disabled.
*/ */
var g_ModsCompatibility = []; const g_ModsCompatibility = [];
/** /**
* Name of the mods installed by the ModInstaller. * Name of the mods installed by the ModInstaller.
*/ */
var g_InstalledMods; let g_InstalledMods;
var g_HasIncompatibleMods; let g_HasIncompatibleMods;
var g_FakeMod = { /* eslint-disable prefer-const -- Mods should be able to change them */
let g_FakeMod = {
"name": translate("This mod does not exist"), "name": translate("This mod does not exist"),
"version": "", "version": "",
"label": "", "label": "",
@ -54,12 +58,34 @@ var g_FakeMod = {
"dependencies": [] "dependencies": []
}; };
var g_ColorNoModSelected = "255 255 100"; let g_ColorNoModSelected = "255 255 100";
var g_ColorDependenciesMet = "100 255 100"; let g_ColorDependenciesMet = "100 255 100";
var g_ColorDependenciesNotMet = "255 100 100"; let g_ColorDependenciesNotMet = "255 100 100";
/* eslint-enable prefer-const */
function init(data, hotloadData) export function init(data, hotloadData)
{ {
Object.assign(Engine.GetGUIObjectByName("modsDisabledList"), {
"onSelectionChange": selectedMod.bind(undefined, "modsDisabledList"),
"onSelectionColumnChange": displayModLists,
"onMouseLeftDoubleClickItem": enableMod
});
Object.assign(Engine.GetGUIObjectByName("modsEnabledList"), {
"onSelectionChange": selectedMod.bind(undefined, "modsEnabledList"),
"onMouseLeftDoubleClickItem": disableMod
});
Engine.GetGUIObjectByName("enabledModUp").onPress =
moveCurrItem.bind(undefined, "modsEnabledList", true);
Engine.GetGUIObjectByName("enabledModDown").onPress =
moveCurrItem.bind(undefined, "modsEnabledList", false);
Engine.GetGUIObjectByName("visitWebButton").onPress = visitModWebsite;
Engine.GetGUIObjectByName("downloadButton").onPress = downloadModsButton.bind(undefined, initMods);
Engine.GetGUIObjectByName("saveConfigurationButton").onPress = saveMods;
Engine.GetGUIObjectByName("startButton").onPress = startMods;
g_InstalledMods = data && data.installedMods || hotloadData && hotloadData.installedMods || []; g_InstalledMods = data && data.installedMods || hotloadData && hotloadData.installedMods || [];
g_HasIncompatibleMods = Engine.HasIncompatibleMods(); g_HasIncompatibleMods = Engine.HasIncompatibleMods();
@ -354,7 +380,7 @@ function recomputeCompatibility(disabledAction = false)
*/ */
function isDependencyMet(dependency) function isDependencyMet(dependency)
{ {
const operator = dependency.match(g_RegExpComparisonOperator); const operator = dependency.match(regExpComparisonOperator);
const [name, version] = operator ? dependency.split(operator[0]) : [dependency, undefined]; const [name, version] = operator ? dependency.split(operator[0]) : [dependency, undefined];
return g_ModsEnabled.some(folder => return g_ModsEnabled.some(folder =>
@ -403,7 +429,7 @@ function sortEnabledMods()
{ {
const dependencies = {}; const dependencies = {};
for (const folder of g_ModsEnabled) for (const folder of g_ModsEnabled)
dependencies[folder] = getMod(folder).dependencies.map(d => d.split(g_RegExpComparisonOperator)[0]); dependencies[folder] = getMod(folder).dependencies.map(d => d.split(regExpComparisonOperator)[0]);
g_ModsEnabled.sort((folder1, folder2) => g_ModsEnabled.sort((folder1, folder2) =>
dependencies[folder1].indexOf(getMod(folder2).name) != -1 ? 1 : dependencies[folder1].indexOf(getMod(folder2).name) != -1 ? 1 :

View file

@ -3,7 +3,7 @@
<objects> <objects>
<script directory="gui/common/"/> <script directory="gui/common/"/>
<script directory="gui/modmod/"/> <script module="gui/modmod/modmod.js"/>
<object type="image" style="ModernWindow"> <object type="image" style="ModernWindow">
@ -80,10 +80,6 @@
font="sans-stroke-13" font="sans-stroke-13"
auto_scroll="true" auto_scroll="true"
> >
<action on="SelectionChange">selectedMod(this.name);</action>
<action on="SelectionColumnChange">displayModLists();</action>
<action on="MouseLeftDoubleClickItem">enableMod();</action>
<!-- List headers --> <!-- List headers -->
<!-- Keep the column names in sync with the property names of mods --> <!-- Keep the column names in sync with the property names of mods -->
<column id="name" textcolor="255 255 255" width="10%"> <column id="name" textcolor="255 255 255" width="10%">
@ -123,9 +119,6 @@
tooltip_style="pgToolTip" tooltip_style="pgToolTip"
auto_scroll="true" auto_scroll="true"
> >
<action on="SelectionChange">selectedMod(this.name);</action>
<action on="MouseLeftDoubleClickItem">disableMod();</action>
<!-- List headers --> <!-- List headers -->
<column id="name" textcolor="255 255 255" width="10%"> <column id="name" textcolor="255 255 255" width="10%">
<translatableAttribute id="heading">Name</translatableAttribute> <translatableAttribute id="heading">Name</translatableAttribute>
@ -159,7 +152,6 @@
sprite_disabled="ModernArrowUpGrey" sprite_disabled="ModernArrowUpGrey"
> >
<translatableAttribute id="tooltip">Change the order in which mods are launched. This should match the mods dependencies.</translatableAttribute> <translatableAttribute id="tooltip">Change the order in which mods are launched. This should match the mods dependencies.</translatableAttribute>
<action on="Press">moveCurrItem("modsEnabledList", true);</action>
</object> </object>
<object <object
name="enabledModDown" name="enabledModDown"
@ -173,7 +165,6 @@
sprite_disabled="ModernArrowDownGrey" sprite_disabled="ModernArrowDownGrey"
> >
<translatableAttribute id="tooltip">Change the order in which mods are launched. This should match the mods dependencies.</translatableAttribute> <translatableAttribute id="tooltip">Change the order in which mods are launched. This should match the mods dependencies.</translatableAttribute>
<action on="Press">moveCurrItem("modsEnabledList", false);</action>
</object> </object>
</object> </object>
@ -181,7 +172,6 @@
<object name="toggleModButton" type="button" style="ModernButtonRed" size="16 100%-80 196 100%-52" enabled="false"/> <object name="toggleModButton" type="button" style="ModernButtonRed" size="16 100%-80 196 100%-52" enabled="false"/>
<object name="visitWebButton" type="button" style="ModernButtonRed" size="200 100%-80 380 100%-52" enabled="false"> <object name="visitWebButton" type="button" style="ModernButtonRed" size="200 100%-80 380 100%-52" enabled="false">
<translatableAttribute id="caption">Visit Website</translatableAttribute> <translatableAttribute id="caption">Visit Website</translatableAttribute>
<action on="Press">visitModWebsite();</action>
</object> </object>
<!-- Message --> <!-- Message -->
@ -198,22 +188,19 @@
<object type="button" style="ModernButtonRed" size="100%-748 100%-44 100%-568 100%-16"> <object type="button" style="ModernButtonRed" size="100%-748 100%-44 100%-568 100%-16">
<translatableAttribute id="caption">Help</translatableAttribute> <translatableAttribute id="caption">Help</translatableAttribute>
<action on="Press">Engine.OpenChildPage("page_modhelp.xml");</action> <action on="Press">Engine.OpenChildPage("page_modhelp.xml");</action>
</object> </object>
<object type="button" style="ModernButtonRed" size="100%-564 100%-44 100%-384 100%-16"> <object name="downloadButton" type="button" style="ModernButtonRed" size="100%-564 100%-44 100%-384 100%-16">
<translatableAttribute id="caption">Download Mods</translatableAttribute> <translatableAttribute id="caption">Download Mods</translatableAttribute>
<action on="Press">downloadModsButton();</action>
</object> </object>
<object name="saveConfigurationButton" type="button" style="ModernButtonRed" size="100%-380 100%-44 100%-200 100%-16"> <object name="saveConfigurationButton" type="button" style="ModernButtonRed" size="100%-380 100%-44 100%-200 100%-16">
<translatableAttribute id="caption">Save Configuration</translatableAttribute> <translatableAttribute id="caption">Save Configuration</translatableAttribute>
<action on="Press">saveMods();</action>
</object> </object>
<object name="startButton" type="button" style="ModernButtonRed" size="100%-196 100%-44 100%-16 100%-16"> <object name="startButton" type="button" style="ModernButtonRed" size="100%-196 100%-44 100%-16 100%-16">
<translatableAttribute id="caption">Save and Restart</translatableAttribute> <translatableAttribute id="caption">Save and Restart</translatableAttribute>
<action on="Press">startMods();</action>
</object> </object>
</object> </object>
</objects> </objects>

View file

@ -1,4 +1,4 @@
function downloadModsButton() export function downloadModsButton(initMods)
{ {
initTerms({ initTerms({
"Disclaimer": { "Disclaimer": {
@ -6,7 +6,7 @@ function downloadModsButton()
"file": "gui/modio/Disclaimer.txt", "file": "gui/modio/Disclaimer.txt",
"config": "modio.disclaimer", "config": "modio.disclaimer",
"accepted": false, "accepted": false,
"callback": openModIo, "callback": openModIo.bind(undefined, initMods),
"urlButtons": [ "urlButtons": [
{ {
"caption": translate("mod.io Terms"), "caption": translate("mod.io Terms"),
@ -23,7 +23,7 @@ function downloadModsButton()
openTerms("Disclaimer"); openTerms("Disclaimer");
} }
async function openModIo(data) async function openModIo(initMods, data)
{ {
if (!data.accepted) if (!data.accepted)
return; return;

View file

@ -48,12 +48,12 @@ const g_RegExpVersion= /[0-9]+(\.[0-9]+){0,2}/;
/** /**
* Version checks in mod dependencies can use these operators. * Version checks in mod dependencies can use these operators.
*/ */
const g_RegExpComparisonOperator = /(<=|>=|<|>|=)/; export const regExpComparisonOperator = /(<=|>=|<|>|=)/;
/** /**
* Tests if a dependency compares a mod version against another, for instance "0ad<=0.0.16". * Tests if a dependency compares a mod version against another, for instance "0ad<=0.0.16".
*/ */
const g_RegExpComparison = globalRegExp(new RegExp(g_RegExpName.source + g_RegExpComparisonOperator.source + g_RegExpVersion.source)); const g_RegExpComparison = globalRegExp(new RegExp(g_RegExpName.source + regExpComparisonOperator.source + g_RegExpVersion.source));
/** /**
* The label may not be empty. * The label may not be empty.
@ -69,7 +69,7 @@ function globalRegExp(regexp)
* Returns whether the mod defines all required properties and whether all properties are valid. * Returns whether the mod defines all required properties and whether all properties are valid.
* Shows a notification if not. * Shows a notification if not.
*/ */
function validateMod(folder, modData, notify) export function validateMod(folder, modData, notify)
{ {
let valid = true; let valid = true;

View file

@ -2,7 +2,7 @@
* Currently limited to at most 3 buttons per message box. * Currently limited to at most 3 buttons per message box.
* The convention is to have "cancel" appear first. * The convention is to have "cancel" appear first.
*/ */
function init(data) export function init(data)
{ {
// Set title // Set title
Engine.GetGUIObjectByName("mbTitleBar").caption = data.title; Engine.GetGUIObjectByName("mbTitleBar").caption = data.title;

View file

@ -3,7 +3,7 @@
<objects> <objects>
<script directory="gui/common/"/> <script directory="gui/common/"/>
<script directory="gui/msgbox/"/> <script module="gui/msgbox/msgbox.js"/>
<!-- Fade out the background because it's non-interactable --> <!-- Fade out the background because it's non-interactable -->
<object sprite="ModernFade" type="image"/> <object sprite="ModernFade" type="image"/>

View file

@ -1,4 +1,4 @@
async function init() export async function init()
{ {
return { [Engine.openRequest]: { return { [Engine.openRequest]: {
"page": "page_modmod.xml", "page": "page_modmod.xml",

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<objects> <objects>
<script directory="gui/pregame/"/> <script module="gui/pregame/mainmenu.js"/>
</objects> </objects>

View file

@ -7,11 +7,11 @@
* The user should be able to save and print the text of the terms. * The user should be able to save and print the text of the terms.
*/ */
var g_TermsPage; let g_TermsPage;
var g_TermsFile; let g_TermsFile;
var g_TermsSprintf; let g_TermsSprintf;
async function init(data) export async function init(data)
{ {
g_TermsPage = data.page; g_TermsPage = data.page;
g_TermsFile = data.file; g_TermsFile = data.file;

View file

@ -2,7 +2,7 @@
<objects> <objects>
<script directory="gui/common/"/> <script directory="gui/common/"/>
<script directory="gui/termsdialog/"/> <script module="gui/termsdialog/termsdialog.js"/>
<object type="image" sprite="ModernFade"/> <object type="image" sprite="ModernFade"/>

View file

@ -69,7 +69,7 @@ class TimedConfirmation
} }
} }
function init(data) export function init(data)
{ {
return new TimedConfirmation().setup(data); return new TimedConfirmation().setup(data);
} }

View file

@ -3,7 +3,7 @@
<objects> <objects>
<script directory="gui/common/"/> <script directory="gui/common/"/>
<script directory="gui/timedconfirmation/"/> <script module="gui/timedconfirmation/timedconfirmation.js"/>
<!-- Fade out the background because it's non-interactable --> <!-- Fade out the background because it's non-interactable -->
<object sprite="ModernFade" type="image"/> <object sprite="ModernFade" type="image"/>