Stub out reacting to a button click

This commit is contained in:
Tangent Wantwight 2023-11-20 21:13:56 -05:00
parent 48c07e792d
commit d5a7033adc
3 changed files with 77 additions and 29 deletions

View File

@ -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... <b>this</b> 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);

View File

@ -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<CardContext> = (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<CardContext> = (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 }
);
}

View File

@ -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<Context> = (
state: Vm<Context>,