chore: Check types and add draft full typing for x_ite. (#18)

Enabling type checking involves a full rearrangement of the
  build process, as well as supplying types for some of the
  dependencies.

  Now that (hopefully) all of the methods are typed, can call
  (for example) browser.setBrowserOption to manage the
  viewer navigation.

  Resolves #14.
  Resolves #17.

Reviewed-on: #18
Co-authored-by: Glen Whitney <glen@studioinfinity.org>
Co-committed-by: Glen Whitney <glen@studioinfinity.org>
This commit is contained in:
Glen Whitney 2023-09-11 01:52:39 +00:00 committed by Glen Whitney
parent a8707386aa
commit b5478254af
15 changed files with 2767 additions and 33 deletions

2
.gitignore vendored
View File

@ -1,4 +1,6 @@
# Object files # Object files
tsbuild
jsbuild
public/js public/js
# Editor backups # Editor backups

5
etc/depPreamble.text Normal file
View File

@ -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.

390
etc/deps/geogebra/api.ts Normal file
View File

@ -0,0 +1,390 @@
// 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<string>;
asyncEvalCommandGetLabels(cmdString: string): Promise<string>;
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<GraphicsOptions>): 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<string, AppletObject>;
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<T> = {
[P in keyof T]?: RecursivePartial<T[P]>;
};
/**
* @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;
};

View File

@ -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;
}

160
etc/deps/geogebra/params.ts Normal file
View File

@ -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;
}

7
etc/deps/geogebraAmbient.d.ts vendored Normal file
View File

@ -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 {
}
}

2035
etc/deps/x_ite.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,12 +4,21 @@
description: 'Uncovering lost digital mathematical treasures', description: 'Uncovering lost digital mathematical treasures',
scripts: { scripts: {
test: 'echo "Error: no test specified" && exit 1', test: 'echo "Error: no test specified" && exit 1',
build_js: 'civet --js -c src/*.civet -o public/js/.js', // Obtain additional source code needed:
build_deps: 'cp -rLT node_modules/vrml1to97 public/js/deps', 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_/', build: 'pnpm --sequential /build_/',
start: 'node public/js', start: 'node public/js',
go: 'pnpm --sequential "/build|start/"', go: 'pnpm --sequential "/build|start/"',
serve: 'pnpm build && http-server', serve: 'pnpm build && http-server',
clean: 'rm -rf tsbuild jsbuild public/js',
}, },
packageManager: 'pnpm', packageManager: 'pnpm',
keywords: [ keywords: [
@ -25,7 +34,9 @@
}, },
devDependencies: { devDependencies: {
'@danielx/civet': '^0.6.31', '@danielx/civet': '^0.6.31',
'@types/jquery': '^3.5.18',
'http-server': '^14.1.1', 'http-server': '^14.1.1',
typescript: '^5.2.2',
}, },
dependencies: { dependencies: {
vrml1to97: '^0.1.3', vrml1to97: '^0.1.3',

View File

@ -13,9 +13,15 @@ devDependencies:
'@danielx/civet': '@danielx/civet':
specifier: ^0.6.31 specifier: ^0.6.31
version: 0.6.31(typescript@5.2.2) version: 0.6.31(typescript@5.2.2)
'@types/jquery':
specifier: ^3.5.18
version: 3.5.18
http-server: http-server:
specifier: ^14.1.1 specifier: ^14.1.1
version: 14.1.1 version: 14.1.1
typescript:
specifier: ^5.2.2
version: 5.2.2
packages: packages:
@ -57,6 +63,16 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/sourcemap-codec': 1.4.15
dev: true 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: /@typescript/vfs@1.5.0:
resolution: {integrity: sha512-AJS307bPgbsZZ9ggCT3wwpg3VbTKMFNHfaY/uF0ahSkYYrPF2dSSKDNIDIQAHm9qJqbLvCsSJH7yN4Vs/CsMMg==} resolution: {integrity: sha512-AJS307bPgbsZZ9ggCT3wwpg3VbTKMFNHfaY/uF0ahSkYYrPF2dSSKDNIDIQAHm9qJqbLvCsSJH7yN4Vs/CsMMg==}
dependencies: dependencies:

View File

@ -7,7 +7,7 @@
</head> </head>
<body> <body>
<p>Here is a <p>Here is a
<a href="http://127.0.0.1:8080/assets/hartWings.wrl">Hart polyhedron <a href="http://127.0.0.1:8080/assets/hartPoly.wrl">Hart polyhedron
</a>. </a>.
</p> </p>
</body> </body>

View File

@ -1,11 +1,19 @@
import https://code.jquery.com/jquery-3.7.1.js 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) -> $('applet[code="Geometry"]').before (i, html) ->
id := `joyceApplet${i}` id := `joyceApplet${i}`
joyceApplets.push { html, this.children, id, joyceApplets.push { html, this.children, id,
width: parseInt(this.getAttribute 'width'), width: parseInt(this.getAttribute('width') ?? '200'),
height: parseInt(this.getAttribute 'height') } height: parseInt(this.getAttribute('height') ?? '200') }
`<div id="${id}"></div>` `<div id="${id}"></div>`
jQuery.getScript 'https://www.geogebra.org/apps/deployggb.js', => jQuery.getScript 'https://www.geogebra.org/apps/deployggb.js', =>
@ -14,20 +22,25 @@ jQuery.getScript 'https://www.geogebra.org/apps/deployggb.js', =>
appName: 'classic', appName: 'classic',
jApp.width, jApp.width,
jApp.height, jApp.height,
appletOnLoad: (api) => appletOnLoad: (api: AppletObject) =>
for child of jApp.children for child of jApp.children
dispatchJcommand api, child dispatchJcommand api, child
api.setCoordSystem(-10, 10 + jApp.width, -10, 10 + jApp.height) api.setCoordSystem(-10, 10 + jApp.width, -10, 10 + jApp.height)
} } as const
geoApp := new GGBApplet params geoApp := new GGBApplet params
geoApp.inject jApp.id geoApp.inject jApp.id
type Cmdr type GeogebraCallback = (api: AppletObject) => void
type Commander
command: string command: string
callbacks: ((api) => boolean)[] 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' val := param.getAttribute 'value'
unless val return
switch param.getAttribute 'name' switch param.getAttribute 'name'
'background' 'background'
api.setGraphicsOptions 1, bgColor: `#${val}` api.setGraphicsOptions 1, bgColor: `#${val}`
@ -48,39 +61,39 @@ function dispatchJcommand(api, param)
else else
console.log `Unkown param ${param}` console.log `Unkown param ${param}`
function jToG(jCom: string): Cmdr function jToG(jCom: string): Commander
[name, klass, method, data, ...colors] := jCom.split(';') [name, klass, method, data, ...colors] := jCom.split(';')
if klass in classHandler if klass in classHandler
return classHandler[klass] name, method, data, colors return classHandler[klass] name, method, data, colors
console.log `Unknown entity class ${klass}` console.log `Unknown entity class ${klass}`
return '' command: '', callbacks: []
classHandler := classHandler: Record<string, ClassHandler> :=
point: (name: string, m: string, data: string, colors: string[]): Cmdr => point: (name, method, data, colors) =>
command .= '' command .= ''
callbacks .= [] callbacks: GeogebraCallback[] .= []
switch m switch method
/free|fixed/ /free|fixed/
command += `${name} = (${data})` command += `${name} = (${data})`
if m is 'fixed' if method is 'fixed'
callbacks.push (api) => api.setFixed(name, true) callbacks.push (api: AppletObject) => api.setFixed(name, true)
'perpendicular' 'perpendicular'
[center, direction] := data.split(',') [center, direction] := data.split(',')
command += `${name} = Rotate(${direction}, 3*pi/2, ${center})` command += `${name} = Rotate(${direction}, 3*pi/2, ${center})`
return {command, callbacks} return {command, callbacks}
line: (name: string, m: string, data: string, colors: string[]): Cmdr => line: (name, method, data, colors) =>
command .= '' command .= ''
callbacks .= [] callbacks: GeogebraCallback[] .= []
switch m switch method
'connect' 'connect'
command += `${name} = Segment(${data})` command += `${name} = Segment(${data})`
return {command, callbacks} return {command, callbacks}
circle: (name: string, m: string, data: string, colors: string[]): Cmdr => circle: (name, method, data, colors) =>
command .= '' command .= ''
callbacks .= [] callbacks: GeogebraCallback[] .= []
switch m switch method
'radius' 'radius'
[center, point] := data.split(',') [center, point] := data.split(',')
command += `${name} = Circle(${center}, ${point})` command += `${name} = Circle(${center}, ${point})`

View File

@ -4,17 +4,20 @@ X3D from https://create3000.github.io/code/x_ite/latest/x_ite.mjs
certainlyHandled := '.x3d .gltf .glb .obj .stl .ply'.split ' ' certainlyHandled := '.x3d .gltf .glb .obj .stl .ply'.split ' '
canvas := X3D.createBrowser() canvas := X3D.createBrowser()
browser := X3D.getBrowser canvas
browser.setBrowserOption 'StraightenHorizon', false
site := $('a[href^="http"]') site := $('a[href^="http"]')
url := site.attr 'href' url := site.attr('href') ?? ''
if certainlyHandled.some((ext) => url.includes ext) if certainlyHandled.some((ext) => url.includes ext)
canvas.setAttribute 'src', site.attr 'href' canvas.setAttribute 'src', url
else if url.includes '.wrl' else if url.includes '.wrl'
// Need to obtain the text and check what level it is // Need to obtain the text and check what level it is
response := await fetch url response := await fetch url
text .= await response.text() text .= await response.text()
if /#\s*VRML\s*V?1./i.test(text) if /#\s*VRML\s*V?1./i.test(text)
text = convert(text) text = convert(text)
browser := X3D.getBrowser canvas
scene := await browser.createX3DFromString text scene := await browser.createX3DFromString text
browser.replaceWorld(scene) browser.replaceWorld(scene)
site.after(canvas) site.after(canvas)

3
tools/copyDeps.bash Normal file
View File

@ -0,0 +1,3 @@
# Takes one parameter, the destination directory
mkdir -p $1
cp -rL node_modules/vrml1to97/{deps,vrml1to97,streamToString.js} $1

10
tools/fetchDeps.bash Normal file
View File

@ -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

View File

@ -1,11 +1,14 @@
{ {
"compilerOptions": { "compilerOptions": {
"strict": true, "strict": true,
"lib": ["esnext"], "target": "esnext",
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"resolveJsonModule": true, "module": "esnext",
"esModuleInterop": true "esModuleInterop": true,
"rootDir": "tsbuild",
"outDir": "jsbuild",
}, },
"include": [ "tsbuild/**/*" ],
"ts-node": { "ts-node": {
"transpileOnly": true, "transpileOnly": true,
"compilerOptions": { "compilerOptions": {
@ -13,4 +16,4 @@
} }
} }
} }
}