diff --git a/src/3x5.ts b/src/3x5.ts
index 620aa63..7ec7790 100644
--- a/src/3x5.ts
+++ b/src/3x5.ts
@@ -1,4 +1,4 @@
-import { Button } from './lib/button';
+import { Button, RegisterButtonOnClick } from './lib/button';
import { Card, CardVm, GetField } from './lib/card';
import { Here, RegisterJumpHere } from './lib/debug';
import { Expr } from './lib/expr';
@@ -30,21 +30,6 @@ function parseFields(card: Card, fields: string) {
}
}
-/**
- * @param state VM state
- * @param code Script to run
- * @returns Markup to render / output
- */
-function renderCard(state: CardVm, code: string) {
- const script = parse(code);
- if (script[0]) {
- runNoctl(state, script[1], (word) => (state.output += AsHtml(word) + "\n"));
- } else {
- state.output = script[1];
- }
- return state.output;
-}
-
/**
* Global state: a single card
*/
@@ -69,6 +54,12 @@ const codeInput = document.createElement("textarea");
Object.assign(codeInput.style, TEXTAREA_STYLE, { height: "20em" });
codeInput.value = String.raw`
h1 [get title]
+
+button disabled
+button "Hello" -onClick {
+ alert Hiya
+}
+
para [2 + 2]
block {
This is a paragraph of text, with one [b bold] word. Yes, this means there has to be some magic in text processing... this won't work.
@@ -116,29 +107,65 @@ const state = document.createElement("pre");
const display = document.createElement("blockquote");
const debugDisplay = document.createElement("pre");
+const COMMANDS = {
+ ...HTML,
+ get: GetField,
+ expr: Expr,
+ here: Here,
+ button: Button,
+};
+
function render() {
parseFields(theCard, fieldInput.value);
theCard.code = codeInput.value;
const vm: CardVm = {
- mode: "render",
- commands: {
- ...HTML,
- get: GetField,
- expr: Expr,
- here: Here,
- button: Button,
- },
+ mode: ["render"],
+ commands: COMMANDS,
output: "",
card: theCard,
};
- const html = renderCard(vm, theCard.code);
+
+ const script = parse(theCard.code);
+
+ let html = "";
+ if (script[0]) {
+ runNoctl(vm, script[1], (word) => (vm.output += AsHtml(word) + "\n"));
+ } else {
+ vm.output = script[1];
+ }
+ html = vm.output;
state.textContent = JSON.stringify(theCard, null, 2);
display.innerHTML = html;
debugDisplay.textContent = html;
}
+function triggerEvent(handlerPos: number) {
+ parseFields(theCard, fieldInput.value);
+ theCard.code = codeInput.value;
+
+ const vm: CardVm = {
+ mode: ["findingAction", handlerPos],
+ commands: COMMANDS,
+ output: "",
+ card: theCard,
+ };
+
+ const script = parse(theCard.code);
+
+ let html = "";
+ if (script[0]) {
+ runNoctl(vm, script[1], (word) => {});
+ } else {
+ vm.output = script[1];
+ }
+ html = vm.output;
+ console.debug(html);
+
+ state.textContent = JSON.stringify(theCard, null, 2);
+}
+
render();
document.body.append(
fieldInput,
@@ -150,3 +177,4 @@ document.body.append(
);
RegisterJumpHere(codeInput);
+RegisterButtonOnClick(triggerEvent);
diff --git a/src/lib/button.ts b/src/lib/button.ts
index 780f7de..a76db46 100644
--- a/src/lib/button.ts
+++ b/src/lib/button.ts
@@ -1,5 +1,5 @@
import { Proc } from '../vm';
-import { AsHtml, ProcResult, TextPiece } from '../words';
+import { AsHtml, ProcResult, SourcePos, TextPiece } from '../words';
import { CardContext } from './card';
import { getOptRaw } from './options';
@@ -10,7 +10,7 @@ export const Button: Proc = (vm, argv: TextPiece[]): ProcResult =>
({ onClick: [onClick = null] }, [label]) => {
let buttonTrigger = "disabled";
if (onClick && "pos" in onClick && onClick.pos != undefined) {
- buttonTrigger = `data-notcl-onClick="${onClick.pos}"`;
+ buttonTrigger = `data-notcl-button="${onClick.pos}"`;
}
return {
@@ -18,3 +18,21 @@ export const Button: Proc = (vm, argv: TextPiece[]): ProcResult =>
};
}
);
+
+export function RegisterButtonOnClick(
+ triggerDispatch: (pos: SourcePos) => void
+) {
+ document.body.addEventListener(
+ "click",
+ (evt) => {
+ const dataNoctlButton = (evt.target as HTMLElement)?.getAttribute?.(
+ "data-notcl-button"
+ );
+ if (dataNoctlButton !== null) {
+ const handlerPos = Number(dataNoctlButton);
+ triggerDispatch(handlerPos);
+ }
+ },
+ { passive: true }
+ );
+}
diff --git a/src/vm.ts b/src/vm.ts
index 8b68325..5a463db 100644
--- a/src/vm.ts
+++ b/src/vm.ts
@@ -1,15 +1,17 @@
import {
- AsText, Concat, ErrorResult, InterpolatedPiece, ProcResult, Script, TextPiece, Word
+ AsText, Concat, ErrorResult, InterpolatedPiece, ProcResult, Script, SourcePos, TextPiece, Word
} from './words';
/**
* "Mode" of the environment a script runs in; determines access to mutability features and such.
*
+ * "findingAction": preparing a response to a UI action, which can involve recalculating variables, but has no side-effects itself.
+ *
* "action": response to a UI action; allowed to modify card fields and access time and random numbers.
*
* "render": deterministic generation of display markup from card and workspace state; can only modify temporary variables.
*/
-export type ScriptType = "action" | "render";
+export type ScriptType = ["findingAction", SourcePos] | ["action"] | ["render"];
export type Proc = (
state: Vm,