Applied copyright headers

This commit is contained in:
2023-05-13 00:42:57 +02:00
parent 23cd7bca8d
commit 1e21a8e226
22 changed files with 1540 additions and 37 deletions

View File

@@ -1,3 +1,21 @@
/*************************************************************************
* D3270 - Detachable 3270 interface *
* Copyright (C) 2023 Daniel Hirsch *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
*************************************************************************/
import './style.css'
import {Action, Color, Cursor, IndErase, Indication, IndScreen, InitializeIndication, Operation} from "./suite3270.ts";
@@ -31,22 +49,76 @@ class CharCell {
}
}
type OiaRowStruct = {
undera: HTMLSpanElement,
conn: HTMLSpanElement,
status: HTMLSpanElement,
compose: HTMLSpanElement,
ta: HTMLSpanElement,
rm: HTMLSpanElement,
im: HTMLSpanElement,
pr: HTMLSpanElement,
st: HTMLSpanElement,
sc: HTMLSpanElement,
lu: HTMLSpanElement,
time: HTMLSpanElement,
posn: HTMLSpanElement,
}
class Js3270 {
private character_tbl: HTMLTableElement;
private cgrid: CharCell[][];
private oia_row: HTMLDivElement;
private ws: WebSocket;
private character_tbl!: HTMLTableElement;
private cgrid!: CharCell[][];
private oia_row!: HTMLDivElement;
private oia!: OiaRowStruct;
private ws!: WebSocket;
private def_fg: Color;
private def_bg: Color;
private cursor: Cursor;
private cursor_cell: CharCell|null;
private cursor!: Cursor;
private cursor_cell!: CharCell|null;
private app_container: HTMLDivElement;
private ui_buffer: DocumentFragment;
private backoff: number;
private key_event_listener: OmitThisParameter<(evt: KeyboardEvent) => void>;
constructor(root: HTMLDivElement) {
this.app_container = root;
// set up default properties
this.def_fg = "neutralWhite";
this.def_bg = "neutralBlack";
this.backoff = 1; // sec to wait between connection attempts. Clamped to 1 in reconnect
this.ui_buffer = document.createDocumentFragment();
this.buildUi();
this.reconnect_ws()
this.key_event_listener = this.on_keydown.bind(this);
window.addEventListener("keydown", this.key_event_listener)
}
private reconnect_ws() {
this.backoff = Math.max(1, Math.min(this.backoff * 1.5, 30));
let ws = this.ws = new WebSocket(`ws://${document.location.host}:${document.location.port}/api/ws`);
this.ws.addEventListener("message", this.on_message.bind(this))
this.ws.addEventListener("open", () => {
this.backoff = 1;
this.attach_ui()
})
this.ws.addEventListener("close", (evt) => {
this.detach_ui();
setTimeout(this.reconnect_ws.bind(this), Math.min(this.backoff, 1) * 1000);
console.log(evt);
})
}
private buildUi() {
this.ui_buffer = document.createDocumentFragment();
this.character_tbl = document.createElement("table");
this.character_tbl.className = "cgrid";
this.cursor = {enabled: true, row: 1, column: 1};
@@ -55,13 +127,37 @@ class Js3270 {
this.oia_row = document.createElement("div");
// TODO: make this lookup the address based on where it's loaded from
this.ws = new WebSocket("ws://127.0.0.1:13270/api/ws");
this.ws.addEventListener("message", this.on_message.bind(this))
this.oia_row.className = "oia";
root.replaceChildren(this.character_tbl, this.oia_row);
// create OIA fields
window.addEventListener("keydown", this.on_keydown.bind(this))
let oia: OiaRowStruct = <OiaRowStruct>{}
// If you modify this, make sure you modify OiaRowStruct as well
for (let name of ["undera", "conn", "status", "compose", "ta", "rm", "im", "pr", "st", "sc", "lu", "time", "posn"] as (keyof OiaRowStruct)[]) {
let sp = document.createElement("span");
sp.className = name;
oia[name] = sp;
this.oia_row.append(sp);
}
// set default values for the things that should always be set.
oia.rm.replaceChildren(">");
this.oia = oia;
this.ui_buffer.replaceChildren(this.character_tbl, this.oia_row)
}
private attach_ui() {
if (this.ui_buffer.children.length > 0) {
this.app_container.replaceChildren(this.ui_buffer);
window.addEventListener("keydown", this.key_event_listener)
}
}
private detach_ui() {
if (this.ui_buffer.children.length == 0) {
while (this.app_container.children.length > 0)
this.ui_buffer.append(this.app_container.children[0]);
}
window.removeEventListener("keydown", this.key_event_listener);
}
private send(actions: Action[]) {
@@ -82,6 +178,8 @@ class Js3270 {
"ArrowLeft": ["Left", []],
"M+r": ["Reset", []],
"M+a": ["Attn", []],
"M+c": ["Reconnect", []],
"Insert": ["Toggle", ["insertMode"]],
}
private on_keydown(evt: KeyboardEvent) {
let key_str = [
@@ -91,7 +189,7 @@ class Js3270 {
evt.key
].join("");
if (evt.key.length == 1 && !evt.altKey) {
if (evt.key.length == 1 && !evt.altKey && !evt.ctrlKey) {
this.send([{action: "Key", args: [evt.key]}]);
evt.stopPropagation();
return;
@@ -126,6 +224,68 @@ class Js3270 {
this.handle_ind_screen(ind.screen)
} else if ("erase" in ind) {
this.handle_ind_erase(ind.erase);
} else if ("connection" in ind) {
let cchar: string = {
"not-connected": " ",
"reconnecting": "~",
"resolving": "?",
"tcp-pending": "-",
"tls-pending": "=",
"telnet-pending": "t",
"connected-nvt": "n",
"connected-nvt-charmode": "C",
"connected-3270": "3",
"connected-unbound": "!",
"connected-e-nvt": "N",
"connected-sscp": "S",
"connected-tn3270e": "E"
}[ind.connection.state];
this.oia.conn.replaceChildren(cchar)
} else if ("oia" in ind) {
let oia = ind.oia;
console.log(oia);
switch (oia.field) {
case "compose":
if (oia.value) {
this.oia.compose.replaceChildren(`${oia.type[0] == 'G' ? 'G' : ' '}${oia.char}`)
} else {
this.oia.compose.replaceChildren(" ");
}
break;
case "insert":
this.oia.im.replaceChildren(oia.value ? '^' : ' ');
break;
case "lock":
this.oia.status.replaceChildren(oia.value || "READY")
console.log(this.oia);
break;
case "lu":
this.oia.lu.replaceChildren(oia.value);
this.oia.pr.replaceChildren(oia.lu ? "P" : " ");
break;
case "not-undera":
this.oia.undera.replaceChildren(oia.value ? ' ':'B');
break;
case "reverse-input":
this.oia.rm.replaceChildren(oia.value ? "<":">");
break;
case "screen-trace":
this.oia.st.replaceChildren((oia.value || 0) > 0 ? 't' : ' ');
break;
case "script":
this.oia.sc.replaceChildren(oia.value ? 's' : ' ');
break;
case "timing":
this.oia.time.replaceChildren(oia.value || " ")
break;
case "typeahead":
this.oia.ta.replaceChildren(oia.value ? 'T' : ' ')
break;
}
} else {
console.log(ind);
}
}
@@ -183,6 +343,7 @@ class Js3270 {
if (this.cursor.enabled) {
this.cursor_cell = this.cgrid[this.cursor.row-1][this.cursor.column-1];
this.cursor_cell.td.dataset.cursor = "";
this.oia.posn.replaceChildren((this.cursor.column + "").padStart(3, "0") + "/" + (this.cursor.row + "").padStart(3, "0"));
}
}

View File

@@ -1,8 +1,41 @@
/*************************************************************************
* D3270 - Detachable 3270 interface *
* Copyright (C) 2023 Daniel Hirsch *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
*************************************************************************/
$chroma: 100%;
$lightnessMain: 75%;
$lightnessIntense: 85%;
$lightnessDark: 60%;
@font-face {
font-family: 'HackWoff';
src: url('../fonts/hack-regular-subset.woff2') format('woff2'), url('../fonts/hack-regular-subset.woff') format('woff');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'HackWoff';
src: url('../fonts/hack-bold-subset.woff2') format('woff2'), url('../fonts/hack-bold-subset.woff') format('woff');
font-weight: 700;
font-style: normal;
}
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
/*line-height: 1.25;*/
@@ -107,17 +140,33 @@ button:focus-visible {
border-spacing: 0;
}
table.cgrid td {
#app {
white-space: pre;
font-family: "IBM P", "Operator Mono", monospace;
font-family: "HackWoff", monospace;
font-weight: 300;
padding: 0;
}
.cgrid [data-bg="neutralBlack"] {
background: oklch(0 0 0);
table.cgrid td {
padding: 0;
}
.cgrid [data-bg="neutralBlack"] { background: oklch(0.2 0 0); }
.cgrid [data-bg="blue"] { background: oklch($lightnessMain $chroma 240deg); }
.cgrid [data-bg="red"] { background: oklch($lightnessMain $chroma 20deg); }
.cgrid [data-bg="pink"] { background: oklch($lightnessMain $chroma 340deg); }
.cgrid [data-bg="green"] { background: oklch($lightnessMain $chroma 150deg); }
.cgrid [data-bg="turquoise"] { background: oklch($lightnessMain $chroma 190deg); }
.cgrid [data-bg="yellow"] { background: oklch($lightnessMain $chroma 110deg); }
.cgrid [data-bg="neutralWhite"] { background: oklch($lightnessMain 0 0); }
.cgrid [data-bg="black"] {background: #000; }
.cgrid [data-bg="deepBlue"] {background: oklch($lightnessDark $chroma 240deg); }
.cgrid [data-bg="orange"] {background: oklch($lightnessDark $chroma 70deg); }
.cgrid [data-bg="purple"] { background: oklch($lightnessDark $chroma 320deg);}
.cgrid [data-bg="paleGreen"] { background: oklch(92% $chroma 150deg); }
.cgrid [data-bg="paleTurquoise"] { background: oklch(95% $chroma 190deg); }
.cgrid [data-bg="gray"] { background: oklch(55% 0 0); }
.cgrid [data-bg="white"] { background: oklch($lightnessIntense 0 0); }
.cgrid [data-fg="neutralBlack"] { color: oklch(0.2 0 0); }
.cgrid [data-fg="blue"] { color: oklch($lightnessMain $chroma 240deg); }
.cgrid [data-fg="red"] { color: oklch($lightnessMain $chroma 20deg); }
@@ -139,3 +188,55 @@ table.cgrid td {
.cgrid [data-gr~="underline"] { text-decoration: underline; }
.cgrid [data-gr~="highlight"] { font-synthesis: weight; font-weight: 400; }
/******************************************************************************
* OIA line
******************************************************************************/
#app .oia {
background: oklch(0.2 0 0);
border-top: 1px solid oklch($lightnessMain $chroma 240deg);
color: oklch($lightnessMain $chroma 240deg);
width: 100%;
height: 1lh;
white-space: pre;
display: flex;
}
#app .oia span {
/*box-shadow: inset 0px 0px 0 1px darkgreen;*/
min-width: 1ex;
text-align: left;
}
#app .oia .undera {
margin-left: 1ex;
}
#app .oia .time {
margin-left: 1ex;
text-align: right;
width: 7ex;
}
#app .oia .lu {
width: 10ex;
margin-left: 1ex;
}
#app .oia .compose {
width: 10ex;
margin-left: 1ex;
margin-right: 1ex;
}
#app .oia .posn {
width: 7ex;
margin-right: 1ex;
margin-left: 1ex;
}
#app .oia .status {
margin-left: 1ex;
flex-grow: 1;
}
#app .oia .undera {
}

View File

@@ -1,3 +1,21 @@
/*************************************************************************
* D3270 - Detachable 3270 interface *
* Copyright (C) 2023 Daniel Hirsch *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
*************************************************************************/
export type CodePage = {
name: string,
aliases?: string[],