feat(editor): F4.6d the web browser and web server on a computer's desktop

The oracle BrowserWindowRun uses Java's browser and web server windows as a
person does; the room keeps a browser window per computer and sends a
program window's view, the start names the person's language. The editor
shows the page in a sandboxed frame, links and forms go to the room, the web
server has its button, virtual hosts and lines. Better than Java: relative
images and links count from the page's folder, a mark stays in the page, the
error page from Java's template, the virtual hosts' file with complete rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 16:09:05 +00:00
co-authored by Claude Opus 5.5
parent f0e7c73ec7
commit aa54e5400e
31 changed files with 2773 additions and 55 deletions
+45
View File
@@ -122,6 +122,20 @@ const FROM_JAVA: Readonly<Record<string, string>> = {
'network.dnsServer': 'network_msg2',
'network.gateway': 'network_msg3',
'network.macAddress': 'network_msg9',
'browser.go': 'webbrowser_msg2',
'server.start': 'webserver_msg1',
'server.stop': 'webserver_msg2',
'webServer.virtualHosts': 'webserver_msg3',
'webServer.hostName': 'webserver_msg4',
'webServer.folder': 'webserver_msg5',
'webServer.useVirtualHosts': 'webserver_msg6',
'server.acceptingStopped': 'sw_serveranwendung_msg1',
'server.acceptingStarted': 'sw_serveranwendung_msg2',
'server.serverSocketClosed': 'sw_serveranwendung_msg3',
'server.serverSocketFailed': 'sw_serveranwendung_msg6',
'server.sendFailed.notConnected': 'sw_tcpsocket_msg6',
'server.sendFailed.connectionLost': 'sw_tcpsocket_msg7',
'server.sendFailed.timedOut': 'sw_tcpsocket_msg8',
};
/** Java's words, mended: the prompt says "Vermittlungsrechnerns" (guicontainer_msg1). */
@@ -156,6 +170,20 @@ const FROM_JAVA_MENDED: Readonly<Record<string, readonly [string, (java: string)
],
};
/** Java's words around a value, as its programs join them („Verbindung zu“ + address + „hergestellt“). */
const FROM_JAVA_JOINED: Readonly<Record<string, readonly [string, string, string]>> = {
'server.connectionAccepted': ['sw_serveranwendung_msg4', '{address}', 'sw_serveranwendung_msg5'],
'server.connectionClosed': ['sw_servermitarbeiter_msg1', '{address}', 'sw_servermitarbeiter_msg2'],
};
/** Java's page for a server it cannot reach (sw_webbrowser_msg1): its title and its heading. */
const FROM_JAVA_PAGE: Readonly<Record<string, readonly [string, RegExp]>> = {
'browser.unreachableTitle': ['sw_webbrowser_msg1', /<title>(.*)<\/title>/],
'browser.unreachable': ['sw_webbrowser_msg1', /<h1>(.*)<\/h1>/],
};
const templates = join(dirname(fileURLToPath(import.meta.url)), '../../../tools/java-oracle/.upstream/src/main/resources/tmpl');
describe('the catalogs', () => {
it('have the same keys in German and English, each with a text', () => {
expect(Object.keys(CATALOGS.en).sort()).toEqual(Object.keys(CATALOGS.de).sort());
@@ -184,5 +212,22 @@ describe('the catalogs', () => {
expect(CATALOGS.de[key], key).toBe(mend(de.get(javaKey)!));
expect(CATALOGS.en[key], key).toBe(mend(en.get(javaKey)!));
}
for (const [key, [before, value, after]] of Object.entries(FROM_JAVA_JOINED)) {
expect(CATALOGS.de[key], key).toBe(`${de.get(before)} ${value} ${de.get(after)}`);
expect(CATALOGS.en[key], key).toBe(`${en.get(before)} ${value} ${en.get(after)}`);
}
for (const [key, [javaKey, part]] of Object.entries(FROM_JAVA_PAGE)) {
expect(CATALOGS.de[key], key).toBe(part.exec(de.get(javaKey)!)![1]);
expect(CATALOGS.en[key], key).toBe(part.exec(en.get(javaKey)!)![1]);
}
});
it.skipIf(!existsSync(templates))("write the browser's error page as Java's template does (tmpl/http_fehler)", () => {
for (const [language, file] of [['de', 'http_fehler_de_DE.txt'], ['en', 'http_fehler_en_GB.txt']] as const) {
const template = readFileSync(join(templates, file), 'utf8').replaceAll(':meldung:', '{message}').replaceAll(':code:', '{code}');
expect(CATALOGS[language]['browser.errorTitle']).toBe(/<title>(.*)<\/title>/.exec(template)![1]);
expect(CATALOGS[language]['browser.errorText']).toBe(/<p>(.*)<\/p>/.exec(template)![1]!.trim());
expect(/<h1>(.*)<\/h1>/.exec(template)![1]).toBe('{message}');
}
});
});