From 6bcec494e28f16c3625e4da1b8ce05a989f7fac0 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Tue, 5 Sep 2023 23:20:17 -0700 Subject: [PATCH] chore: Check types. Enabling type checking involves a full rearrangement of the build process, as well as supplying types for some of the packages. The X_ITE types are still a work in progress, but they are enough for this initial state of the project to compile and run. Resolves #14. --- .gitignore | 2 + etc/depPreamble.text | 5 + etc/deps/geogebra/api.ts | 382 ++++++++++++++++++++++++++++++++++ etc/deps/geogebra/entry.ts | 76 +++++++ etc/deps/geogebra/params.ts | 160 ++++++++++++++ etc/deps/geogebraAmbient.d.ts | 7 + etc/deps/x_ite.d.ts | 16 ++ package.json5 | 15 +- pnpm-lock.yaml | 16 ++ public/hartPoly.html | 2 +- src/adapptlet.civet | 59 ++++-- src/giveAwrl.civet | 4 +- tools/copyDeps.bash | 3 + tools/fetchDeps.bash | 10 + tsconfig.json | 11 +- 15 files changed, 736 insertions(+), 32 deletions(-) create mode 100644 etc/depPreamble.text create mode 100644 etc/deps/geogebra/api.ts create mode 100644 etc/deps/geogebra/entry.ts create mode 100644 etc/deps/geogebra/params.ts create mode 100644 etc/deps/geogebraAmbient.d.ts create mode 100644 etc/deps/x_ite.d.ts create mode 100644 tools/copyDeps.bash create mode 100644 tools/fetchDeps.bash diff --git a/.gitignore b/.gitignore index a7f1abe..bd3dc16 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ # Object files +tsbuild +jsbuild public/js # Editor backups diff --git a/etc/depPreamble.text b/etc/depPreamble.text new file mode 100644 index 0000000..4358d5f --- /dev/null +++ b/etc/depPreamble.text @@ -0,0 +1,5 @@ +// This source file was replicated from the netless GitHub repository +// https://github.com/netless-io/netless-app +// compliant with the MIT License, under which it was released. +// The authors of archematics wish to express their thanks to the +// netless team for creating and releasing this code. diff --git a/etc/deps/geogebra/api.ts b/etc/deps/geogebra/api.ts new file mode 100644 index 0000000..8f623f6 --- /dev/null +++ b/etc/deps/geogebra/api.ts @@ -0,0 +1,382 @@ +// This source file was replicated from the netless GitHub repository +// https://github.com/netless-io/netless-app +// compliant with the MIT License, under which it was released. +// The authors of archematics wish to express their thanks to the +// netless team for creating and releasing this code. +/** + * @link https://wiki.geogebra.org/en/Reference:GeoGebra_Apps_API + */ +export interface AppletObject { + remove(): void; + getXML(objName?: string): string; + getAlgorithmXML(objName: string): string; + getPerspectiveXML(): string; + getBase64: { + (callback?: (base64string: string) => void): string; + (includeThumbnail?: boolean, callback?: (base64string: string) => void): string; + }; + setBase64(base64string: string, callback: () => void): void; + openFile(filename: string, callback: () => void): void; + login(token: string, ui: boolean): void; + logout(): void; + setXML(xml: string): void; + evalXML(xmlString: string): void; + setDisplayStyle(objName: string, style: string): void; + evalCommand(cmdString: string): boolean; + evalCommandGetLabels(cmdString: string): string; + asyncEvalCommand(cmdString: string): Promise; + asyncEvalCommandGetLabels(cmdString: string): Promise; + evalCommandCAS(cmdString: string): string; + evalGeoGebraCAS(cmdString: string): string; + setFixed(objName: string, flag: boolean, selection?: boolean): void; + isFixed(objName: string): boolean; + isSelectionAllowed(objName: string): boolean; + setOnTheFlyPointCreationActive(flag: boolean): void; + setUndoPoint(): void; + setSaved(): void; + isSaved(): boolean; + startSaveCallback(title: string, visibility: string, callbackAction: string): void; + initCAS(): void; + setErrorDialogsActive(flag: boolean): void; + setCoordSystem(xmin: number, xmax: number, ymin: number, ymax: number, zmin?: number, zmax?: number, yVertical?: boolean): void; + reset(): void; + refreshViews(): void; + setVisible(objName: string, visible: boolean): void; + getVisible(objName: string, view?: number): boolean; + setLayer(objName: string, layer: number): void; + getLayer(objName: string): number; + setLayerVisible(layer: number, visible: boolean): void; + setTrace(objName: string, flag: boolean): void; + isTracing(objName: string): boolean; + setLabelVisible(objName: string, visible: boolean): void; + setLabelStyle(objName: string, style: number): void; + getLabelStyle(objName: string): number; + getLabelVisible(objName: string): boolean; + setColor(objName: string, red: number, green: number, blue: number): void; + setCorner(objName: string, x: number, y: number, index?: number): void; + setLineStyle(objName: string, style: number): void; + setLineThickness(objName: string, thickness: number): void; + setPointStyle(objName: string, style: number): void; + setPointSize(objName: string, style: number): void; + setFilling(objName: string, filling: number): void; + getColor(objName: string): string; + getPenColor(): string; + getPenSize(): number; + setPenSize(size: number): void; + setPenColor(red: number, green: number, blue: number): void; + getFilling(objName: string): number; + getImageFileName(objName: string): string; + getLineStyle(objName: string): number; + getLineThickness(objName: string): number; + getPointStyle(objName: string): number; + getPointSize(objName: string): number; + deleteObject(objName: string): void; + setAnimating(objName: string, animate: boolean): void; + setAnimationSpeed(objName: string, speed: number): void; + startAnimation(): void; + stopAnimation(): void; + setAuxiliary(objName: string, auxiliary: boolean): void; + hideCursorWhenDragging(hideCursorWhenDragging: boolean): void; + isAnimationRunning(): boolean; + getFrameRate(): number; + renameObject(oldName: string, newName: string, force?: boolean): boolean; + exists(objName: string): boolean; + isDefined(objName: string): boolean; + getValueString(objName: string, localized?: boolean): string; + getListValue(objName: string, index: number): number; + getDefinitionString(objName: string, localized?: boolean): string; + getLaTeXString(objName: string): string; + getLaTeXBase64(objName: string, value: boolean): string; + getCommandString(objName: string, localized?: boolean): string; + getCaption(objName: string, subst?: boolean): string; + setCaption(objName: string, caption: string): void; + getXcoord(objName: string): number; + getYcoord(objName: string): number; + getZcoord(objName: string): number; + setCoords(objName: string, x: number, y: number, z: number): void; + getValue(objName: string): number; + getVersion(): string; + getScreenshotBase64(callback: (data: string) => void, scale?: number): void; + getThumbnailBase64(): string; + setValue(objName: string, x: number): void; + setTextValue(objName: string, x: string): void; + setListValue(objName: string, x: number | boolean, y: number | boolean): void; + setRepaintingActive(flag: boolean): void; + setAxesVisible: { + (x: boolean, y: boolean): void; + (view: number, x: boolean, y: boolean, z: boolean): void; + }; + setAxisUnits(view: number, x: string, y: string, z: string): void; + setAxisLabels(view: number, x: string, y: string, z: string): void; + setAxisSteps(view: number, x: string, y: string, z: string): void; + getAxisUnits(view: number): string[]; + getAxisLabels(view: number): string[]; + setPointCapture(view: number, capture?: number): void; + getGridVisible(view?: number): boolean; + setGridVisible: { + (visible: boolean): void; + (view: number, visible?: boolean): void; + }; + getAllObjectNames(objectType?: string): string[]; + getObjectNumber(): number; + getObjectName(i: number): string; + getObjectType(objName: string): string; + setMode(mode: number): void; + getMode(): number; + getToolName(i: number): string; + openMaterial(material: string): void; + undo(): void; + redo(): void; + newConstruction(): void; + resetAfterSaveLoginCallbacks(): void; + debug(str: string): void; + setWidth(width: number): void; + setHeight(height: number): void; + setSize(width: number, height: number): void; + enableRightClick(enable: boolean): void; + enableLabelDrags(enable: boolean): void; + enableShiftDragZoom(enable: boolean): void; + showToolBar(show: boolean): void; + setCustomToolBar(toolbarDef: string): void; + showMenuBar(show: boolean): void; + showAlgebraInput(show: boolean): void; + showResetIcon(show: boolean): void; + getViewProperties(view: number): string; + setFont(label: string, size: number, bold: boolean, italic: boolean, serif: boolean): void; + insertImage(url: string, corner1: string, corner2: string, corner4: string): string; + addImage(fileName: string, urlOrSvgContent: string): void; + recalculateEnvironments(): void; + isIndependent(label: string): boolean; + isMoveable(label: string): boolean; + setPerspective(code: string): void; + enableCAS(enable: boolean): void; + enable3D(enable: boolean): void; + getFileJSON(thumbnail?: boolean): { archive: { fileName: string; fileContent: string }[] }; + setFileJSON(zip: { archive: { fileName: string; fileContent: string }[] }): void; + setLanguage(lang: string): void; + showTooltip(tooltip: boolean): void; + addMultiuserSelection( + clientId: string, + name: string, + color: string, + label: string, + newGeo: boolean + ): void; + removeMultiuserSelections(clientId: string): void; + getExerciseFraction(): number; + isExercise(): boolean; + setExternalPath(path: string): void; + checkSaved(path: () => void): void; + getCASObjectNumber(): number; + exportPGF(callback: (data: string) => void): void; + exportSVG: { + (filename: string): void; + (callback: (svg: string) => void): void; + }; + exportPDF: { + (scale: number, filename: string, sliderLabel: string): void; + (scale: number, callback: (pdf: string) => void, sliderLabel: string): void; + }; + exportPSTricks(callback: (data: string) => void): void; + exportAsymptote(callback: (data: string) => void): void; + setRounding(digits: string): void; + getRounding(): string; + copyTextToClipboard(text: string): void; + evalLaTeX(text: string, mode: number): void; + evalMathML(text: string): boolean; + getScreenReaderOutput(text: string): string; + getEditorState(): string; + setEditorState(state: string, label: string): void; + getGraphicsOptions(viewId: number): GraphicsOptions; + setGraphicsOptions(viewId: number, options: string | RecursivePartial): void; + translate(arg1: string, callback: (data: string) => void): string; + exportConstruction(flags: string[]): string; + updateConstruction(): void; + getConstructionSteps(breakpoints?: boolean): number; + setConstructionStep(n: number, breakpoints?: boolean): void; + previousConstructionStep(): void; + nextConstructionStep(): void; + getEmbeddedCalculators(includeGraspableMath?: boolean): Record; + getFrame(): HTMLElement; + enableFpsMeasurement(): void; + disableFpsMeasurement(): void; + testDraw(): void; + startDrawRecording(): void; + endDrawRecordingAndLogResults(): void; + registerAddListener(JSFunctionName: string | ((objName: string) => void)): void; + unregisterAddListener(JSFunctionName: string | ((objName: string) => void)): void; + registerStoreUndoListener(JSFunctionName: string | (() => void)): void; + unregisterStoreUndoListener(JSFunctionName: string | (() => void)): void; + registerRemoveListener(JSFunctionName: string | ((objName: string) => void)): void; + unregisterRemoveListener(JSFunctionName: string | ((objName: string) => void)): void; + registerClearListener(JSFunctionName: string | (() => void)): void; + unregisterClearListener(JSFunctionName: string | (() => void)): void; + registerRenameListener( + JSFunctionName: string | ((oldName: string, newName: string) => void) + ): void; + unregisterRenameListener( + JSFunctionName: string | ((oldName: string, newName: string) => void) + ): void; + registerUpdateListener(JSFunctionName: string | ((objName: string) => void)): void; + unregisterUpdateListener(JSFunctionName: string | ((objName: string) => void)): void; + registerClientListener(JSFunctionName: string | ((event: ClientEvent) => void)): void; + unregisterClientListener(JSFunctionName: string | ((event: ClientEvent) => void)): void; + registerObjectUpdateListener( + objName: string, + JSFunctionName: string | ((objName: string) => void) + ): void; + unregisterObjectUpdateListener(objName: string): void; + registerObjectClickListener(objName: string, JSFunctionName: string | (() => void)): void; + unregisterObjectClickListener(objName: string): void; + registerClickListener(JSFunctionName: string | ((objName: string) => void)): void; + unregisterClickListener(JSFunctionName: string | ((objName: string) => void)): void; + handleSlideAction(eventType: string, pageIdx: string, appState?: string): void; + selectSlide(pageIdx: string): void; + updateOrdering(labels: string): void; + previewRefresh(): void; + groupObjects(objects: string[]): void; + ungroupObjects(objects: string[]): void; + getObjectsOfItsGroup(object: string): string[]; + addToGroup(item: string, objectsInGroup: string[]): void; + setEmbedContent(label: string, base64: string): void; + addGeoToTV(label: string): void; + removeGeoFromTV(label: string): void; + setValuesOfTV(values: string): void; + showPointsTV(column: string, show: string): void; + hasUnlabeledPredecessors(label: string): boolean; + lockTextElement(label: string): void; + unlockTextElement(label: string): void; +} + +export type AxisConfiguration = { + label: string | null, + unitLabel: string | null, + positiveAxis: boolean, + showNumbers: boolean, + tickStyle: number, + visible: boolean +} + +export type AxesConfiguration = { + x: AxisConfiguration, + y: AxisConfiguration, + z: AxisConfiguration +} + +export type GraphicsOptions = { + axesColor: string, + bgColor: string, + gridColor: string, + axes: AxesConfiguration, + grid: boolean, + gridDistance: {x: number | null, y: number | null}, + gridType: number, + pointCapturing: number, + rightAngleStyle: number, + rulerType: number +} + +type RecursivePartial = { + [P in keyof T]?: RecursivePartial; +}; + +/** + * @link https://wiki.geogebra.org/en/Reference:GeoGebra_Apps_API#Client_Events + */ +export type ClientEvent = + // when new macro is added, `argument`: macro name + | { type: "addMacro"; argument: string } + // polygon construction started + | { type: "addPolygon" } + // polygon construction finished, `target`: polygon label + | { type: "addPolygonComplete"; target: string } + // Graphing / Geometry apps: algebra tab selected in sidebar + | { type: "algebraPanelSelected" } + // multiple objects deleted + | { type: "deleteGeos" } + // one or all objects removed from selection, `target`: object name (for single object) or null (deselect all) + | { type: "deselect"; target: string | null } + // mouse drag ended + | { type: "dragEnd" } + // dropdown list closed, `target`: dropdown list name, `index` index of selected item (0 based) */ + | { type: "dropdownClosed"; target: string; index: number } + // dropdown list item focused using mouse or keyboard, `target`: dropdown list name, `index` index of focused item (0 based) */ + | { type: "dropdownItemFocused"; target: string; index: number } + // dropdown list opened, `target`: dropdown list name + | { type: "dropdownOpened"; target: string } + // key typed in editor (Algebra view of any app or standalone Evaluator app), + | { type: "editorKeyTyped" } + // user moves focus to the editor (Algebra view of any app or standalone Evaluator app), `target:` object label if editing existing object + | { type: "editorStart"; target?: string } + // user (Algebra view of any app or standalone Evaluator app), `target`: object label if editing existing object + | { type: "editorStop"; target?: string } + // export started, `argument`: JSON encoded array including export format + | { type: "export"; argument: string } + // user pressed the mouse button, `x`: mouse x-coordinate, `y`: mouse y-coordinate + | { type: "mouseDown"; x: number; y: number } + // multiple objects move ended, `argument`: object labels + | { type: "movedGeos"; argument: string[] } + // multiple objects are being moved, `argument`: object labels + | { type: "movingGeos"; argument: string[] } + // dialog is opened (currently just for export dialog), `argument`: dialog ID + | { type: "openDialog"; argument: string } + // main menu or one of its submenus were open, `argument`: submenu ID + | { type: "openMenu"; argument: string } + // pasting multiple objects started, `argument`: pasted objects as XML + | { type: "pasteElms"; argument: string } + // pasting multiple objects ended, + | { type: "pasteElmsComplete" } + // perspective changed (e.g. a view was opened or closed), + | { type: "perspectiveChange" } + // redo button pressed, + | { type: "redo" } + // relation tool used, `argument`: HTML description of the object relation + | { type: "relationTool"; argument: string } + // custom tool removed, `argument`: custom tool name + | { type: "removeMacro"; argument: string } + // object renaming complete (in case of chain renames), + | { type: "renameComplete" } + // custom tool was renamed, `argument`: array [old name, new name] + | { type: "renameMacro"; argument: [oldName: string, newName: string] } + // object added to selection, `target`: object label + | { type: "select"; target: string } + // app mode changed (e.g. a tool was selected), `argument`: mode number (see toolbar reference for details) + | { type: "setMode"; argument: string } + // navigation bar visibility changed, `argument`: "true" or "false" + | { type: "showNavigationBar"; argument: string } + // style bar visibility changed, `argument`: "true" or "false" + | { type: "showStyleBar"; argument: string } + // side panel (where algebra view is in Graphing Calculator) closed, + | { type: "sidePanelClosed" } + // side panel (where algebra view is in Graphing Calculator) opened, + | { type: "sidePanelOpened" } + // table of values panel selected, + | { type: "tablePanelSelected" } + // tools panel selected, + | { type: "toolsPanelSelected" } + // undo pressed, + | { type: "undo" } + // object style changed, `target`: object label + | { type: "updateStyle"; target: string } + // graphics view dimensions changed by zooming or panning, `xZero`: horizontal pixel position of point (0,0), `yZero`: vertical pixel position of point (0,0), `xscale`: ratio pixels / horizontal units, `yscale`: ratio pixels / vertical units, `viewNo`: graphics view number (1 or 2) + | { + type: "viewChanged2D"; + xZero: number; + yZero: number; + scale: number; + yscale: number; + viewNo: 1 | 2; + } + // 3D view dimensions changed by zooming or panning, similar to 2D, e.g. `xZero: 0,yZero: 0,scale: 50,yscale: 50,viewNo: 512,zZero: -1.5,zscale: 50,xAngle: -40,zAngle: 24` + | { + type: "viewChanged3D"; + xZero: number; + yZero: number; + zZero: number; + scale: number; + yscale: number; + zscale: number; + xAngle: number; + zAngle: number; + viewNo: 1 | 2; + }; diff --git a/etc/deps/geogebra/entry.ts b/etc/deps/geogebra/entry.ts new file mode 100644 index 0000000..00a91c5 --- /dev/null +++ b/etc/deps/geogebra/entry.ts @@ -0,0 +1,76 @@ +// This source file was replicated from the netless GitHub repository +// https://github.com/netless-io/netless-app +// compliant with the MIT License, under which it was released. +// The authors of archematics wish to express their thanks to the +// netless team for creating and releasing this code. +import type { AppletObject } from "./api"; +import type { AppletParameters } from "./params"; + +export type AppletType = "preferJava" | "preferHTML5" | "java" | "html5" | "auto" | "screenshot"; + +export type Views = Record< + "is3D" | "AV" | "SV" | "CV" | "EV2" | "CP" | "PC" | "DA" | "FI" | "PV" | "macro", + boolean +>; + +export type GGBAppletParameters = AppletParameters & { + material_id?: string; + appletOnLoad?: (api: AppletObject) => void; +}; + +export declare class GGBApplet { + constructor( + version?: number | string, + parameters?: GGBAppletParameters, + html5NoWebSimple?: boolean + ); + constructor(parameters?: GGBAppletParameters, html5NoWebSimple?: boolean); + + /** + * Overrides the codebase for HTML5. + * @param codebase Can be an URL or a local file path. + * @param offline Set to true, if the codebase is a local URL and no web URL + */ + setHTML5Codebase(codebase: string, offline?: boolean): void; + + /** @deprecated not supported */ + setJavaCodebase(): void; + /** @deprecated not supported */ + setJavaCodebaseVersion(): void; + /** @deprecated not supported */ + isCompiledInstalled(): void; + /** @deprecated not supported */ + setPreCompiledScriptPath(): void; + /** @deprecated not supported */ + setPreCompiledResourcePath(): void; + + /** + * Overrides the codebase version for HTML5. + * If another codebase than the default codebase should be used, this method has to be called before setHTML5Codebase. + * @param version The version of the codebase that should be used for HTML5 applets. + */ + setHTML5CodebaseVersion(version: number | string, offline?: boolean): void; + + getHTML5CodebaseVersion(): string; + getParameters(): GGBAppletParameters | undefined; + setFontsCSSURL(url: string): void; + + inject(containerID: string | HTMLElement, type?: AppletType, noPreview?: boolean): void; + inject(containerID: string | HTMLElement, noPreview?: boolean): void; + + getViews(): Views | null; + + isJavaInstalled(): false; + isHTML5Installed(): true; + + getLoadedAppletType(): AppletType | null; + setPreviewImage(previewFilePath: string, loadingFilePath: string, playFilePath: string): void; + removeExistingApplet(appletParent: string, showScreenshot?: boolean): void; + + refreshHitPoints(): boolean; + startAnimation(): boolean; + stopAnimation(): boolean; + + getAppletObject(): AppletObject | undefined; + resize(): void; +} diff --git a/etc/deps/geogebra/params.ts b/etc/deps/geogebra/params.ts new file mode 100644 index 0000000..b631798 --- /dev/null +++ b/etc/deps/geogebra/params.ts @@ -0,0 +1,160 @@ +// This source file was replicated from the netless GitHub repository +// https://github.com/netless-io/netless-app +// compliant with the MIT License, under which it was released. +// The authors of archematics wish to express their thanks to the +// netless team for creating and releasing this code. +/** + * @link https://wiki.geogebra.org/en/Reference:GeoGebra_App_Parameters + */ +export interface AppletParameters { + /** @default "ggbApplet" */ + id?: string; + /** @default "" */ + filename?: string; + /** @default "" */ + json?: string; + /** @default true */ + enableLabelDrags?: boolean; + /** @default true */ + enableUndoRedo?: boolean; + /** @default true */ + enableRightClick?: boolean; + /** @default false */ + enableCAS?: boolean; + /** @default false */ + enable3D?: boolean; + /** @default false */ + lockExam?: boolean; + /** @default "" */ + rounding?: `${number}${"" | "s" | "r"}`; + /** @default "" */ + ggbBase64?: string; + /** @default false */ + showMenuBar?: boolean; + /** @default false */ + showToolBar?: boolean; + /** @default true */ + showToolBarHelp?: boolean; + /** @link https://wiki.geogebra.org/en/Reference:Toolbar @default "" */ + customToolBar?: string; + /** @default false */ + showAlgebraInput?: boolean; + /** @default "algebra" */ + algebraInputPosition?: "algebra" | "top" | "bottom"; + /** @default false */ + showResetIcon?: boolean; + /** @default true */ + showAnimationButton?: boolean; + /** @default 3 */ + capturingThreshold?: number; + /** @link https://www.wikiwand.com/en/List_of_ISO_639-1_codes @default "" */ + language?: string; + /** @default "" */ + country?: string; + /** @default false */ + useBrowserForJS?: boolean; + /** @default true */ + enableShiftDragZoom?: boolean; + /** @default 0 */ + width?: number; + /** @default 0 */ + height?: number; + /** @default false */ + fittoscreen?: boolean; + /** @default "" */ + borderColor?: string; + /** @default false */ + showLogging?: boolean; + /** @default true */ + allowSymbolTable?: boolean; + /** @default false */ + allowStyleBar?: boolean; + /** @default false */ + app?: boolean; + /** @default false */ + screenshotGenerator?: boolean; + /** @default "" */ + laf?: string; + /** @default false */ + preventFocus?: boolean; + /** @link https://wiki.geogebra.org/en/SetPerspective_Command @default "" */ + perspective?: string; + /** @default "classic" */ + appName?: "graphing" | "geometry" | "3d" | "classic" | "suite" | "evaluator" | "scientific"; + /** @default 1.0 */ + scale?: number; + /** @default false */ + buttonShadows?: boolean; + /** @default 0.2 */ + buttonRounding?: number; + /** @default "#000000" */ + buttonBorderColor?: string; + /** @default false */ + prerelease?: boolean; + /** @default "" */ + tubeid?: string; + /** @default false */ + showTutorialLink?: boolean; + /** @default true */ + enableFileFeatures?: boolean; + /** @default true */ + errorDialogsActive?: boolean; + /** @default false */ + showAppsPicker?: boolean; + /** @default false */ + showZoomButtons?: boolean; + /** @default false */ + showFullscreenButton?: boolean; + /** @default false */ + showSuggestionButtons?: boolean; + /** @default false */ + showStartTooltip?: boolean; + /** @default 0 */ + marginTop?: number; + /** @default -1 */ + randomSeed?: number; + /** @default "" */ + fontscssurl?: string; + /** @default "" */ + scaleContainerClass?: string; + /** @default false */ + allowUpscale?: boolean; + /** @default false */ + playButton?: boolean; + /** @default false */ + autoHeight?: boolean; + /** @default false */ + disableAutoScale?: boolean; + /** @default true */ + randomize?: boolean; + /** @default "" */ + loginURL?: string; + /** @default "" */ + logoutURL?: string; + /** @default "" */ + backendURL?: string; + /** @default "" */ + fullscreenContainer?: string; + /** @default "" */ + shareLinkPrefix?: string; + /** @default "" */ + vendor?: string; + /** @default 0 */ + fontSize?: number; + /** @default undefined */ + keyboardType?: "scientific" | "normal" | "notes"; + /** @default false */ + textMode?: boolean; + /** @default "white" */ + editorBackgroundColor?: string; + /** @default "black" */ + editorForegroundColor?: string; + /** @default false */ + showSlides?: boolean; + /** @default false */ + useLocalizedDigits?: boolean; + /** @default true */ + useLocalizedPointNames?: boolean; + /** @default "undef" */ + detachKeyboard?: string; +} diff --git a/etc/deps/geogebraAmbient.d.ts b/etc/deps/geogebraAmbient.d.ts new file mode 100644 index 0000000..3b3c893 --- /dev/null +++ b/etc/deps/geogebraAmbient.d.ts @@ -0,0 +1,7 @@ +// Hack to move GGBApplet into the global namespace +// (since we are getting it from a script) +import {GGBApplet as moduleGGBApplet} from './geogebra/entry.ts' +declare global { + class GGBApplet extends moduleGGBApplet { + } +} diff --git a/etc/deps/x_ite.d.ts b/etc/deps/x_ite.d.ts new file mode 100644 index 0000000..dc84434 --- /dev/null +++ b/etc/deps/x_ite.d.ts @@ -0,0 +1,16 @@ +declare module 'https://create3000.github.io/code/x_ite/latest/x_ite.mjs' { + const x3d: X3D; + export default x3d; + export interface X3D { + createBrowser(): HTMLElement; + getBrowser(canvas: HTMLElement): X3DBrowser; + } + export interface X3DBrowser { + createX3DFromString(x3dSyntax: string): Promise; + replaceWorld(scene: X3DScene): Promise; + } + export interface X3DScene { + removeExportedNode(exportedName: string): void; + } +} + diff --git a/package.json5 b/package.json5 index a9c2175..630af6b 100644 --- a/package.json5 +++ b/package.json5 @@ -4,12 +4,21 @@ description: 'Uncovering lost digital mathematical treasures', scripts: { test: 'echo "Error: no test specified" && exit 1', - build_js: 'civet --js -c src/*.civet -o public/js/.js', - build_deps: 'cp -rLT node_modules/vrml1to97 public/js/deps', + // Obtain additional source code needed: + prebuild: 'bash tools/fetchDeps.bash', + // Use civet to create .ts files from the source... + build_ts1: 'mkdir -p tsbuild && civet -c -o tsbuild/.ts src/*.civet', + // ... but also grab other existing files: + build_ts2: 'cp -r etc/deps tsbuild', + build_ts3: 'bash tools/copyDeps.bash tsbuild/deps', + // Use the Typescript compiler to create the final .js files: + build_js: 'tsc && mkdir -p public/js && cp -r jsbuild/* public/js', + build_deps: 'bash tools/copyDeps.bash public/js/deps', build: 'pnpm --sequential /build_/', start: 'node public/js', go: 'pnpm --sequential "/build|start/"', serve: 'pnpm build && http-server', + clean: 'rm -rf tsbuild jsbuild public/js', }, packageManager: 'pnpm', keywords: [ @@ -25,7 +34,9 @@ }, devDependencies: { '@danielx/civet': '^0.6.31', + '@types/jquery': '^3.5.18', 'http-server': '^14.1.1', + typescript: '^5.2.2', }, dependencies: { vrml1to97: '^0.1.3', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4bed961..b5e9b8a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,9 +13,15 @@ devDependencies: '@danielx/civet': specifier: ^0.6.31 version: 0.6.31(typescript@5.2.2) + '@types/jquery': + specifier: ^3.5.18 + version: 3.5.18 http-server: specifier: ^14.1.1 version: 14.1.1 + typescript: + specifier: ^5.2.2 + version: 5.2.2 packages: @@ -57,6 +63,16 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true + /@types/jquery@3.5.18: + resolution: {integrity: sha512-sNm7O6LECFhHmF+3KYo6QIl2fIbjlPYa0PDgDQwfOaEJzwpK20Eub9Ke7VKkGsSJ2K0HUR50S266qYzRX4GlSw==} + dependencies: + '@types/sizzle': 2.3.3 + dev: true + + /@types/sizzle@2.3.3: + resolution: {integrity: sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==} + dev: true + /@typescript/vfs@1.5.0: resolution: {integrity: sha512-AJS307bPgbsZZ9ggCT3wwpg3VbTKMFNHfaY/uF0ahSkYYrPF2dSSKDNIDIQAHm9qJqbLvCsSJH7yN4Vs/CsMMg==} dependencies: diff --git a/public/hartPoly.html b/public/hartPoly.html index bfea16a..509ea58 100644 --- a/public/hartPoly.html +++ b/public/hartPoly.html @@ -7,7 +7,7 @@

Here is a - Hart polyhedron + Hart polyhedron .

diff --git a/src/adapptlet.civet b/src/adapptlet.civet index 354f06a..2bc1f99 100644 --- a/src/adapptlet.civet +++ b/src/adapptlet.civet @@ -1,11 +1,19 @@ import https://code.jquery.com/jquery-3.7.1.js +import type {AppletObject} from ./deps/geogebra/api.ts -joyceApplets := [] +type AppletDescription + html: string + children: HTMLCollection + id: string + width: number + height: number + +joyceApplets: AppletDescription[] := [] $('applet[code="Geometry"]').before (i, html) -> id := `joyceApplet${i}` joyceApplets.push { html, this.children, id, - width: parseInt(this.getAttribute 'width'), - height: parseInt(this.getAttribute 'height') } + width: parseInt(this.getAttribute('width') ?? '200'), + height: parseInt(this.getAttribute('height') ?? '200') } `
` jQuery.getScript 'https://www.geogebra.org/apps/deployggb.js', => @@ -14,20 +22,25 @@ jQuery.getScript 'https://www.geogebra.org/apps/deployggb.js', => appName: 'classic', jApp.width, jApp.height, - appletOnLoad: (api) => + appletOnLoad: (api: AppletObject) => for child of jApp.children dispatchJcommand api, child api.setCoordSystem(-10, 10 + jApp.width, -10, 10 + jApp.height) - } + } as const geoApp := new GGBApplet params geoApp.inject jApp.id -type Cmdr - command: string - callbacks: ((api) => boolean)[] +type GeogebraCallback = (api: AppletObject) => void +type Commander + command: string + callbacks: GeogebraCallback[] -function dispatchJcommand(api, param) +type ClassHandler = ( + name: string, m: string, data: string, colors: string[]) => Commander + +function dispatchJcommand(api: AppletObject, param: Element): void val := param.getAttribute 'value' + unless val return switch param.getAttribute 'name' 'background' api.setGraphicsOptions 1, bgColor: `#${val}` @@ -48,39 +61,39 @@ function dispatchJcommand(api, param) else console.log `Unkown param ${param}` -function jToG(jCom: string): Cmdr +function jToG(jCom: string): Commander [name, klass, method, data, ...colors] := jCom.split(';') if klass in classHandler return classHandler[klass] name, method, data, colors console.log `Unknown entity class ${klass}` - return '' + command: '', callbacks: [] -classHandler := - point: (name: string, m: string, data: string, colors: string[]): Cmdr => +classHandler: Record := + point: (name, method, data, colors) => command .= '' - callbacks .= [] - switch m + callbacks: GeogebraCallback[] .= [] + switch method /free|fixed/ command += `${name} = (${data})` - if m is 'fixed' - callbacks.push (api) => api.setFixed(name, true) + if method is 'fixed' + callbacks.push (api: AppletObject) => api.setFixed(name, true) 'perpendicular' [center, direction] := data.split(',') command += `${name} = Rotate(${direction}, 3*pi/2, ${center})` return {command, callbacks} - line: (name: string, m: string, data: string, colors: string[]): Cmdr => + line: (name, method, data, colors) => command .= '' - callbacks .= [] - switch m + callbacks: GeogebraCallback[] .= [] + switch method 'connect' command += `${name} = Segment(${data})` return {command, callbacks} - circle: (name: string, m: string, data: string, colors: string[]): Cmdr => + circle: (name, method, data, colors) => command .= '' - callbacks .= [] - switch m + callbacks: GeogebraCallback[] .= [] + switch method 'radius' [center, point] := data.split(',') command += `${name} = Circle(${center}, ${point})` diff --git a/src/giveAwrl.civet b/src/giveAwrl.civet index 3345bf0..f9c890d 100644 --- a/src/giveAwrl.civet +++ b/src/giveAwrl.civet @@ -5,9 +5,9 @@ X3D from https://create3000.github.io/code/x_ite/latest/x_ite.mjs certainlyHandled := '.x3d .gltf .glb .obj .stl .ply'.split ' ' canvas := X3D.createBrowser() site := $('a[href^="http"]') -url := site.attr 'href' +url := site.attr('href') ?? '' if certainlyHandled.some((ext) => url.includes ext) - canvas.setAttribute 'src', site.attr 'href' + canvas.setAttribute 'src', url else if url.includes '.wrl' // Need to obtain the text and check what level it is response := await fetch url diff --git a/tools/copyDeps.bash b/tools/copyDeps.bash new file mode 100644 index 0000000..66c2e44 --- /dev/null +++ b/tools/copyDeps.bash @@ -0,0 +1,3 @@ +# Takes one parameter, the destination directory +mkdir -p $1 +cp -rL node_modules/vrml1to97/{deps,vrml1to97,streamToString.js} $1 diff --git a/tools/fetchDeps.bash b/tools/fetchDeps.bash new file mode 100644 index 0000000..8f60c46 --- /dev/null +++ b/tools/fetchDeps.bash @@ -0,0 +1,10 @@ +mkdir -p etc/deps/geogebra + +cp etc/depPreamble.text etc/deps/geogebra/api.ts +curl 'https://raw.githubusercontent.com/netless-io/netless-app/master/packages/app-geogebra/src/types/api.ts' >> etc/deps/geogebra/api.ts + +cp etc/depPreamble.text etc/deps/geogebra/entry.ts +curl 'https://raw.githubusercontent.com/netless-io/netless-app/master/packages/app-geogebra/src/types/entry.ts' >> etc/deps/geogebra/entry.ts + +cp etc/depPreamble.text etc/deps/geogebra/params.ts +curl 'https://raw.githubusercontent.com/netless-io/netless-app/master/packages/app-geogebra/src/types/params.ts' >> etc/deps/geogebra/params.ts diff --git a/tsconfig.json b/tsconfig.json index f5e6879..a227703 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,14 @@ { "compilerOptions": { "strict": true, - "lib": ["esnext"], + "target": "esnext", "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "esModuleInterop": true + "module": "esnext", + "esModuleInterop": true, + "rootDir": "tsbuild", + "outDir": "jsbuild", }, + "include": [ "tsbuild/**/*" ], "ts-node": { "transpileOnly": true, "compilerOptions": { @@ -13,4 +16,4 @@ } } } -} +