ICT:Documentation:JavaScript in Asset v2
Explanation of JavaScript Usage in Asset v2
This page documents the role, purpose, and strict limitations of the JavaScript used in Asset v2.
It is intended as long-term reference documentation and is written to remain understandable years after the implementation.
Purpose of This Document
JavaScript in MediaWiki systems often becomes problematic because:
- it runs in the browser, not on the server
- it can be bypassed
- it depends on UI behavior
- it is easy to give it too much authority
This document explains exactly what JavaScript is allowed to do in Asset v2, and just as importantly, what it must NEVER do.
Big Picture
In Asset v2, JavaScript is used only as a form assistant.
JavaScript:
- helps the user
- reacts to user input
- fills form fields automatically
- improves usability
JavaScript does NOT:
- define identity
- create or rename pages
- rename files
- write to Cargo
- enforce immutability
- guarantee correctness
JavaScript is never authoritative.
Where the JavaScript Lives
The JavaScript code is stored in:
MediaWiki:Asset.js
It is loaded explicitly by the Asset form using:
mw.loader.load(
mw.util.getUrl(
'MediaWiki:Asset.js',
{ action: 'raw', ctype: 'text/javascript' }
)
);
This means:
- The script runs only on pages that include it
- It is not globally injected into the wiki
When the Script Runs
The script starts with:
$(document).ready(function () {
...
});
This means:
- The script runs after the form HTML is fully loaded
- All form fields already exist in the DOM
This avoids race conditions.
Helper Function for Form Fields
function f(name) {
return $("[name='Asset[" + name + "]']");
}
What this does:
- Provides a short way to access form fields
- Maps template parameter names to HTML input elements
Example:
f("Chapter")returns the Chapter field input
This is purely a convenience function.
Detecting Create Mode
function isCreateMode() {
return $("input[name='pfFormPageName']").val() === "Asset:DRAFT";
}
What this does:
- Detects whether the user is creating a new Asset
- Prevents logic from running on existing Assets
Why this is critical:
- Existing Assets must never be renumbered
- Editing an Asset must never regenerate identifiers
This guard is essential for immutability.
The generate() Function
The core logic lives in:
function generate() {
if (!isCreateMode()) return;
...
}
What this means:
- All generation logic is disabled unless we are creating a new Asset
- JavaScript cannot affect existing Assets
Reading User Input
const ch = f("Chapter").val();
const pl = f("Place").val();
const org = f("Organisation").val();
What this does:
- Reads current user selections
- Does not modify them
- Does not validate beyond basic presence checks
Basic Input Validation
if (!ch || (pl && org) || (!pl && !org)) return;
What this does:
- Ensures Chapter is selected
- Ensures exactly one context is selected
- Silently stops if conditions are not met
Important: This is only a UI convenience check. The authoritative validation happens in Lua.
Calling the Lua Module
new mw.Api().get({
action: "scribunto-console",
title: "Module:AssetID",
question:
"return require('Module:AssetID').generate{" +
"Chapter='" + ch + "'," +
"Place='" + pl + "'," +
"Organisation='" + org + "'}"
});
What this does:
- Calls the Lua module on the server
- Passes current form values
- Receives computed data
Why Lua is called from JS:
- JavaScript cannot query Cargo safely
- Lua runs server-side
- Lua is deterministic
Handling the Lua Response
const r = JSON.parse(data.return);
What this does:
- Parses the JSON returned by Lua
- Allows structured access to values
If an error exists:
if (r.error) {
alert(r.error);
return;
}
This displays a message to the user but does not force behavior.
Writing Values Back to the Form
f("Label").val(r.identifier);
f("Sequence").val(r.sequence);
$("input[name='pfFormPageName']").val(r.identifier);
What this does:
- Displays the generated identifier
- Displays the sequence number
- Sets the final page name
Important: This does NOT create the page. The page is only created when Save is clicked.
Capturing the Original Filename
$("input[type='file']").on("change", function () {
if (this.files[0]) {
f("OriginalFilename").val(this.files[0].name);
}
});
What this does:
- Listens for file selection
- Reads the local filename
- Stores it in a readonly field
Why this is done in JavaScript:
- Only the browser knows the local filename
- The server never sees it otherwise
This value is informational only.
What JavaScript Must NEVER Do
In Asset v2, JavaScript must never:
- rename files
- move pages
- reserve identifiers
- enforce immutability
- decide final truth
- write directly to Cargo
Any logic placed in JavaScript must be safe to bypass.
Failure Tolerance
If JavaScript fails completely:
- The form still works
- The user can still save
- Asset v1-style behavior is possible
- No data corruption occurs
This is intentional.
Mental Model to Keep
You can safely remember:
- JavaScript = assistant
- Lua = calculator
- Cargo = storage
- PHP extension = enforcement
- Browser logic is never trusted
Status
This document is stable reference documentation.
It exists to support long-term understanding and memory retention.