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,