Skip to content
Snippets Groups Projects
Commit 893fe709 authored by baletiballo's avatar baletiballo
Browse files

Parser for Objects from the backend

parent 06ccf058
No related branches found
No related tags found
No related merge requests found
"use strict";
// A hack to make a list of strings on type level.
// If you add another type to be parsable i.e. implement a parser for it, also add its name here
const parsable = ["string", "MathMLElement", "HTMLElement", "SVGElement"];
function is_primitive(a) {
return "parseAs" in a
&& parsable.includes(a.parseAs)
&& "content" in a
&& typeof a.content === "string";
}
function backendObject_fromJSON(json_object) {
const parser = new DOMParser;
// just a shorthand we will need several times
const parse = function (s) {
const element = parser.parseFromString(s, "text/xml").childNodes[0];
return element;
};
// the Backend_Object to be
const bo = {};
for (let i in json_object) {
const member = json_object[i];
if (is_primitive(member)) {
switch (member.parseAs) {
case "string":
bo[i] = member.content;
break;
case "MathMLElement":
bo[i] = parse(member.content);
break;
case "HTMLElement":
bo[i] = parse(member.content);
break;
case "SVGElement":
bo[i] = parse(member.content);
break;
}
}
else {
bo[i] = backendObject_fromJSON(member);
}
}
if (bo.label instanceof MathMLElement
&& typeof bo.uri === "string"
&& typeof bo.type === "string") {
return bo;
}
else {
console.error(`This is not a Backend_Object:`, json_object);
throw new TypeError(`This is not a Backend_Object: \n ${json_object}`);
}
}
"use strict"; "use strict";
/**
* A {@link Backend_Object} without any further properties known to us
*/
class Pure_Reference {
constructor(label, uri, type) {
this.label = label;
this.uri = uri;
this.type = type ? type : "none";
}
}
/** /**
* A fact without any value known to us * A fact without any value known to us
*/ */
...@@ -174,3 +184,61 @@ class Ray_Fact extends Line_Fact { ...@@ -174,3 +184,61 @@ class Ray_Fact extends Line_Fact {
this.type = "Ray_Fact"; this.type = "Ray_Fact";
} }
} }
//#endregion Facts
/**
* A Slot is an interface that can stand in for either
* - a {@link Fact}, or
* - the {@link Backend_Object} used to define the {@link Scroll} (in the backend)
*
* depending on what is needed.
*
* If all Slots of a {@link Scroll} are assigned, it can compute its {@link Scroll.acquiredFacts}.
*/
class Slot {
/**
* @param default_label The default label of the Slot. Fallback if no Fact is assigned.
* @param uri The uri of the Slot
* @param type The expected type of the assigned Fact
* @param assignedFact The Fact assigned to this Slot (may not exist yet)
*/
constructor(default_label, uri, type, assignedFact) {
this.default_label = default_label;
this.uri = uri;
this.type = type;
this.assignedFact = assignedFact;
}
/**
* The MathML element to display when this Slot is referenced.
*
* This is either the label of the {@link assignedFact}, or {@link default_label} if the former doesn't exist.
*/
get label() {
if (this.assignedFact) {
return this.assignedFact.label;
}
else {
return this.default_label;
}
}
}
/**
* A Scroll, as it is implemented in the backend.
*
* Can do fancy stuff elsewhere, here we only want display its {@link description} and (possibly) {@link depiction}.
* Both will reference the {@link slots}, and need dynamic adaption to the {@link Fact}s assigned to them.
* The {@link acquiredFacts} referenced do not change, but they are semantically important and deserve special treatment.
*/
class Scroll {
constructor(label, uri, slots, acquiredFacts, description, depiction) {
this.label = label;
this.uri = uri;
this.slots = slots;
this.acquiredFacts = acquiredFacts;
this.description = description;
this.depiction = depiction;
this.type = "Scroll";
}
}
function isScroll(s) {
return s.type === "Scroll";
}
"use strict"; "use strict";
/**
* A MMT..whatever. Somewhere between the first and second "meta-" MMT had to leave common nomenclature behind
* @typedef {{kind : string, uri: string}} MMTReference
*/
/**
* Facts, as they are send by MMT. Not *quite* the same format as Unity uses \*sigh\*, and everything has shortened names to avoid five additional letters \*double sigh\*
* @typedef {Object} MMTFact
* @property {MMTReference} ref the reference MMT uses to identify this fact
* @property {string} label the human readable lable to display this fact.
* @property {?any} df the definition of the Fact. May be null for {@link MMTScroll.requiredFacts}
* @property {?MMTReference} tp the MMT type of this fact
* @property {string} kind since a Fact is a MMTThingy, they also have a {@link MMTReference.kind}
*/
/**
* A Slot is an interface that can stand in for either
* - a {@link Fact}, or
* - the {@link Backend_Object} used to define the {@link Scroll} (in the backend)
*
* depending on what is needed.
*
* If all Slots of a {@link Scroll} are assigned, it can compute its {@link Scroll.acquiredFacts}.
*/
class Slot {
/**
* @param default_label The default label of the Slot. Fallback if no Fact is assigned.
* @param uri The uri of the Slot
* @param type The expected type of the assigned Fact
* @param assignedFact The Fact assigned to this Slot (may not exist yet)
*/
constructor(default_label, uri, type, assignedFact) {
this.default_label = default_label;
this.uri = uri;
this.type = type;
this.assignedFact = assignedFact;
this.assignedFact = assignedFact;
}
/**
* The MathML element to display when this Slot is referenced.
*
* This is either the label of the {@link assignedFact}, or {@link default_label} if the former doesn't exist.
*/
get label() {
if (this.assignedFact) {
return this.assignedFact.label;
}
else {
return this.default_label;
}
}
}
/**
* A Scroll, as it is implemented in the backend.
*
* Can do fancy stuff elsewhere, here we only want display its {@link description} and (possibly) {@link depiction}.
* Both will reference the {@link slots}, and need dynamic adaption to the {@link Fact}s assigned to them.
* The {@link acquiredFacts} referenced do not change, but they are semantically important and deserve special treatment.
*/
class Scroll {
constructor(label, uri, slots, acquiredFacts, description, depiction) {
this.label = label;
this.uri = uri;
this.slots = slots;
this.acquiredFacts = acquiredFacts;
this.description = description;
this.depiction = depiction;
this.type = "Scroll";
}
/** TODO */
static fromString(scrollString) {
throw new Error("Not implemented.");
}
}
let currentScrollRef = ""; // ref of the scroll currently displayed let currentScrollRef = ""; // ref of the scroll currently displayed
function RenderScroll() { function RenderScroll() {
const dataSource = document.querySelector("#Unity-Data-Interface"); const dataSource = document.querySelector("#Unity-Data-Interface");
...@@ -80,7 +8,12 @@ function RenderScroll() { ...@@ -80,7 +8,12 @@ function RenderScroll() {
console.error("No Scroll found in the Unity-Data-Interface"); console.error("No Scroll found in the Unity-Data-Interface");
return; return;
} }
const scroll = Scroll.fromString(dataSource.dataset.scrollDynamic); const scroll_json = JSON.parse(dataSource.dataset.scrollDynamic);
const scroll = backendObject_fromJSON(scroll_json);
if (!isScroll(scroll)) {
console.error("The Scroll in the Unity-Data-Interface cannot be parsed");
return;
}
//console.log(scroll.requiredFacts); //console.log(scroll.requiredFacts);
const scrollContainer = document.querySelector("#scrollContainer"); const scrollContainer = document.querySelector("#scrollContainer");
// replace the description if the scroll changed, otherwise only its content needs update // replace the description if the scroll changed, otherwise only its content needs update
......
...@@ -161,18 +161,18 @@ ...@@ -161,18 +161,18 @@
} }
loadScript("./build/Drop_facts.js") loadScript("./build/Drop_facts.js")
loadScript("./build/API_Parsers.js")
loadScript("./build/SetScrollContent.js") loadScript("./build/SetScrollContent.js")
//loadScript("./scroll_interaction/webgl-demo.js") //loadScript("./scroll_interaction/webgl-demo.js")
</script> </script>
<script src="./build/Math_Mind.js" type="module"></script> <!-- <script src="./build/Math_Mind.js" type="module"></script> -->
<data id="Unity-Data-Interface" hidden <data id="Unity-Data-Interface" hidden
data-assignments='{&quot;http://mathhub.info/FrameIT/frameworld?TriangleProblem?A&quot;:{&quot;Item1&quot;:&quot;(C)&quot;,&quot;Item2&quot;:&quot;http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact310&quot;},&quot;http://mathhub.info/FrameIT/frameworld?TriangleProblem?B&quot;:{&quot;Item1&quot;:&quot;(B)&quot;,&quot;Item2&quot;:&quot;http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact309&quot;},&quot;http://mathhub.info/FrameIT/frameworld?TriangleProblem?C&quot;:{&quot;Item1&quot;:&quot;C&quot;,&quot;Item2&quot;:&quot;&quot;},&quot;http://mathhub.info/FrameIT/frameworld?TriangleProblem_RightAngleAtC?rightAngleC&quot;:{&quot;Item1&quot;:&quot;⊾C&quot;,&quot;Item2&quot;:&quot;&quot;},&quot;http://mathhub.info/FrameIT/frameworld?OppositeLen/Problem?distanceBC&quot;:{&quot;Item1&quot;:&quot;BC&quot;,&quot;Item2&quot;:&quot;&quot;},&quot;http://mathhub.info/FrameIT/frameworld?TriangleProblem_AngleAtB?angleB&quot;:{&quot;Item1&quot;:&quot;∠ABC&quot;,&quot;Item2&quot;:&quot;&quot;},&quot;http://mathhub.info/FrameIT/frameworld?OppositeLen/Solution?deducedLineCA&quot;:{&quot;Item1&quot;:&quot;CA&quot;,&quot;Item2&quot;:&quot;&quot;}}' data-assignments='{&quot;http://mathhub.info/FrameIT/frameworld?TriangleProblem?A&quot;:{&quot;Item1&quot;:&quot;(C)&quot;,&quot;Item2&quot;:&quot;http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact310&quot;},&quot;http://mathhub.info/FrameIT/frameworld?TriangleProblem?B&quot;:{&quot;Item1&quot;:&quot;(B)&quot;,&quot;Item2&quot;:&quot;http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact309&quot;},&quot;http://mathhub.info/FrameIT/frameworld?TriangleProblem?C&quot;:{&quot;Item1&quot;:&quot;C&quot;,&quot;Item2&quot;:&quot;&quot;},&quot;http://mathhub.info/FrameIT/frameworld?TriangleProblem_RightAngleAtC?rightAngleC&quot;:{&quot;Item1&quot;:&quot;⊾C&quot;,&quot;Item2&quot;:&quot;&quot;},&quot;http://mathhub.info/FrameIT/frameworld?OppositeLen/Problem?distanceBC&quot;:{&quot;Item1&quot;:&quot;BC&quot;,&quot;Item2&quot;:&quot;&quot;},&quot;http://mathhub.info/FrameIT/frameworld?TriangleProblem_AngleAtB?angleB&quot;:{&quot;Item1&quot;:&quot;∠ABC&quot;,&quot;Item2&quot;:&quot;&quot;},&quot;http://mathhub.info/FrameIT/frameworld?OppositeLen/Solution?deducedLineCA&quot;:{&quot;Item1&quot;:&quot;CA&quot;,&quot;Item2&quot;:&quot;&quot;}}'
data-scroll-dynamic='{ data-scroll-dynamic='{
"ref": "http://mathhub.info/FrameIT/frameworld?OppositeLen", "uri": "http://mathhub.info/FrameIT/frameworld?OppositeLen",
"label": "OppositeLen", "label": "<mtext>OppositeLen</mtext>",
"description": "<scroll-description title=&#x27;OppositeLenScroll&#x27; alt=&#x27;Given a triangle △ABC right-angled at ⊾C, the opposite side has length CA = tan(∠ABC) ⋅ BC.&#x27;> <span>Given a triangle</span> <math> <mi>&xutri;<!-- △ --></mi> <mi data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem?A&#x27;></mi> <mi data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem?B&#x27;></mi> <mi data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem?C&#x27;></mi> </math> <span>right-angled at</span> <math> <!--<mi>&angrtvbd;</mi>--><!-- ⦝ --> <mi data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem_RightAngleAtC?rightAngleC&#x27;></mi> </math>,<br /> <span>the opposite side has length</span> <math> <mi data-solution-id=&#x27;http://mathhub.info/FrameIT/frameworld?OppositeLen/Solution?deducedLineCA&#x27;></mi> <mo>&equals;</mo> <mrow> <mi>tan</mi> <!--<mo>&#8289;</mo>--> <mo>(</mo> <mi data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem_AngleAtB?angleB&#x27;></mi> <mo>)</mo> </mrow> <mo>&#8290;</mo> <mi data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?OppositeLen/Problem?distanceBC&#x27;></mi> </math> <span>.</span> <div> <svg width=&#x27;50mm&#x27; height=&#x27;45mm&#x27; viewBox=&#x27;35 0 90 70&#x27; version=&#x27;1.1&#x27; id=&#x27;triangle&#x27; xmlns=&#x27;http://www.w3.org/2000/svg&#x27; xmlns:svg=&#x27;http://www.w3.org/2000/svg&#x27;> <g id=&#x27;shape&#x27;> <path style=&#x27;fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1&#x27; d=&#x27;M 42.871972,64.67128 H 84.290656 V 7.6297578 Z&#x27; id=&#x27;triangle&#x27; /> <path id=&#x27;angleABC&#x27; style=&#x27;fill:none;stroke:#000000;stroke-width:0.265;stroke-dasharray:none;stroke-opacity:1&#x27; d=&#x27;m 46.024276,60.304806 a 5.3589964,5.3589964 0 0 1 2.252109,4.366474 h -5.358996 z&#x27; /> <g id=&#x27;angleBCA&#x27;> <path style=&#x27;fill:none;stroke:#000000;stroke-width:0.264999;stroke-dasharray:none;stroke-opacity:1&#x27; id=&#x27;rightAngle&#x27; d=&#x27;m 78.972396,64.665062 a 5.3308268,5.3308268 0 0 1 5.330827,-5.330827 v 5.330827 z&#x27; /> <circle style=&#x27;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-dasharray:none;stroke-opacity:1&#x27; id=&#x27;rightAngleDot&#x27; cx=&#x27;82.081886&#x27; cy=&#x27;62.813831&#x27; r=&#x27;0.32113415&#x27; /> </g> </g> <g id=&#x27;labels&#x27; style=&#x27;font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583&#x27; > <text xml:space=&#x27;preserve&#x27; x=&#x27;39.242592&#x27; y=&#x27;67.117035&#x27; id=&#x27;pointB&#x27; style=&#x27;fill:#0000ff&#x27; data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem?B&#x27;>B</text> <text xml:space=&#x27;preserve&#x27; x=&#x27;85.100548&#x27; y=&#x27;68.080437&#x27; id=&#x27;pointC&#x27; style=&#x27;fill:#0000ff&#x27; data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem?C&#x27;>C</text> <text xml:space=&#x27;preserve&#x27; x=&#x27;84.650963&#x27; y=&#x27;6.551136&#x27; id=&#x27;pointA&#x27; style=&#x27;fill:#0000ff&#x27; data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem?A&#x27;>A</text> <text xml:space=&#x27;preserve&#x27; x=&#x27;48.234348&#x27; y=&#x27;62.492699&#x27; id=&#x27;angleAtB&#x27; style=&#x27;fill:#ffcc00&#x27; data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem_AngleAtB?angleB&#x27;>∠ABC</text> <text xml:space=&#x27;preserve&#x27; x=&#x27;71.548683&#x27; y=&#x27;60.951256&#x27; id=&#x27;rightAngleAtC&#x27; style=&#x27;fill:#ffcc00&#x27; data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem_RightAngleAtC?rightAngleC&#x27;>⊾C</text> <text xml:space=&#x27;preserve&#x27; x=&#x27;59.409813&#x27; y=&#x27;68.273117&#x27; id=&#x27;distanceBC&#x27; style=&#x27;fill:#008000&#x27; data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?OppositeLen/Problem?distanceBC&#x27;>BC</text> <text xml:space=&#x27;preserve&#x27; x=&#x27;84.972092&#x27; y=&#x27;35.260529&#x27; id=&#x27;solutionCA&#x27; style=&#x27;fill:#008000&#x27; data-solution-id=&#x27;http://mathhub.info/FrameIT/frameworld?OppositeLen/Solution?deducedLineCA&#x27;>CA</text> </g> </svg> </div> </scroll-description>", "slots": [
"requiredFacts": [
{ {
"tp": { "tp": {
"kind": "OMS", "kind": "OMS",
...@@ -499,8 +499,8 @@ ...@@ -499,8 +499,8 @@
"label": "CA" "label": "CA"
} }
], ],
"name": "http://mathhub.info/FrameIT/frameworld?OppositeLen", "description": "<scroll-description title=&#x27;OppositeLenScroll&#x27; alt=&#x27;Given a triangle △ABC right-angled at ⊾C, the opposite side has length CA = tan(∠ABC) ⋅ BC.&#x27;> <span>Given a triangle</span> <math> <mi>&xutri;<!-- △ --></mi> <mi data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem?A&#x27;></mi> <mi data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem?B&#x27;></mi> <mi data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem?C&#x27;></mi> </math> <span>right-angled at</span> <math> <!--<mi>&angrtvbd;</mi>--><!-- ⦝ --> <mi data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem_RightAngleAtC?rightAngleC&#x27;></mi> </math>,<br /> <span>the opposite side has length</span> <math> <mi data-solution-id=&#x27;http://mathhub.info/FrameIT/frameworld?OppositeLen/Solution?deducedLineCA&#x27;></mi> <mo>&equals;</mo> <mrow> <mi>tan</mi> <!--<mo>&#8289;</mo>--> <mo>(</mo> <mi data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem_AngleAtB?angleB&#x27;></mi> <mo>)</mo> </mrow> <mo>&#8290;</mo> <mi data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?OppositeLen/Problem?distanceBC&#x27;></mi> </math> <span>.</span> </scroll-description>",
"path": null "depiction": "<div> <svg width=&#x27;50mm&#x27; height=&#x27;45mm&#x27; viewBox=&#x27;35 0 90 70&#x27; version=&#x27;1.1&#x27; id=&#x27;triangle&#x27; xmlns=&#x27;http://www.w3.org/2000/svg&#x27; xmlns:svg=&#x27;http://www.w3.org/2000/svg&#x27;> <g id=&#x27;shape&#x27;> <path style=&#x27;fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1&#x27; d=&#x27;M 42.871972,64.67128 H 84.290656 V 7.6297578 Z&#x27; id=&#x27;triangle&#x27; /> <path id=&#x27;angleABC&#x27; style=&#x27;fill:none;stroke:#000000;stroke-width:0.265;stroke-dasharray:none;stroke-opacity:1&#x27; d=&#x27;m 46.024276,60.304806 a 5.3589964,5.3589964 0 0 1 2.252109,4.366474 h -5.358996 z&#x27; /> <g id=&#x27;angleBCA&#x27;> <path style=&#x27;fill:none;stroke:#000000;stroke-width:0.264999;stroke-dasharray:none;stroke-opacity:1&#x27; id=&#x27;rightAngle&#x27; d=&#x27;m 78.972396,64.665062 a 5.3308268,5.3308268 0 0 1 5.330827,-5.330827 v 5.330827 z&#x27; /> <circle style=&#x27;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-dasharray:none;stroke-opacity:1&#x27; id=&#x27;rightAngleDot&#x27; cx=&#x27;82.081886&#x27; cy=&#x27;62.813831&#x27; r=&#x27;0.32113415&#x27; /> </g> </g> <g id=&#x27;labels&#x27; style=&#x27;font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583&#x27; > <text xml:space=&#x27;preserve&#x27; x=&#x27;39.242592&#x27; y=&#x27;67.117035&#x27; id=&#x27;pointB&#x27; style=&#x27;fill:#0000ff&#x27; data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem?B&#x27;>B</text> <text xml:space=&#x27;preserve&#x27; x=&#x27;85.100548&#x27; y=&#x27;68.080437&#x27; id=&#x27;pointC&#x27; style=&#x27;fill:#0000ff&#x27; data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem?C&#x27;>C</text> <text xml:space=&#x27;preserve&#x27; x=&#x27;84.650963&#x27; y=&#x27;6.551136&#x27; id=&#x27;pointA&#x27; style=&#x27;fill:#0000ff&#x27; data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem?A&#x27;>A</text> <text xml:space=&#x27;preserve&#x27; x=&#x27;48.234348&#x27; y=&#x27;62.492699&#x27; id=&#x27;angleAtB&#x27; style=&#x27;fill:#ffcc00&#x27; data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem_AngleAtB?angleB&#x27;>∠ABC</text> <text xml:space=&#x27;preserve&#x27; x=&#x27;71.548683&#x27; y=&#x27;60.951256&#x27; id=&#x27;rightAngleAtC&#x27; style=&#x27;fill:#ffcc00&#x27; data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?TriangleProblem_RightAngleAtC?rightAngleC&#x27;>⊾C</text> <text xml:space=&#x27;preserve&#x27; x=&#x27;59.409813&#x27; y=&#x27;68.273117&#x27; id=&#x27;distanceBC&#x27; style=&#x27;fill:#008000&#x27; data-slot-id=&#x27;http://mathhub.info/FrameIT/frameworld?OppositeLen/Problem?distanceBC&#x27;>BC</text> <text xml:space=&#x27;preserve&#x27; x=&#x27;84.972092&#x27; y=&#x27;35.260529&#x27; id=&#x27;solutionCA&#x27; style=&#x27;fill:#008000&#x27; data-solution-id=&#x27;http://mathhub.info/FrameIT/frameworld?OppositeLen/Solution?deducedLineCA&#x27;>CA</text> </g> </svg> </div>"
}'>hi</data> }'>hi</data>
<!--<script src="visualiseCursor.mjs" defer type="module"></script>--> <!--<script src="visualiseCursor.mjs" defer type="module"></script>-->
......
// A hack to make a list of strings on type level.
// If you add another type to be parsable i.e. implement a parser for it, also add its name here
const parsable = ["string", "MathMLElement", "HTMLElement", "SVGElement"] as const
type Primitive = string | MathMLElement | HTMLElement | SVGElement
type Parsable_Primitive = { parseAs: typeof parsable[number], content: string };
function is_primitive(a: any): a is Parsable_Primitive {
return "parseAs" in a
&& parsable.includes(a.parseAs)
&& "content" in a
&& typeof a.content === "string"
}
type Parsable_BO = {[key: string]: Parsable_Primitive | Parsable_BO};
function backendObject_fromJSON(json_object: Parsable_BO): Backend_Object {
const parser = new DOMParser;
// just a shorthand we will need several times
const parse = function <E extends Element>(s: string): E {
const element = parser.parseFromString(s, "text/xml").childNodes[0]
return element as E
}
// the Backend_Object to be
const bo: {
[key: keyof typeof json_object]: Primitive | Backend_Object
} = { }
for (let i in json_object) {
const member = json_object[i]
if (is_primitive(member)) {
switch (member.parseAs) {
case "string":
bo[i] = member.content
break;
case "MathMLElement":
bo[i] = parse<MathMLElement>(member.content)
break;
case "HTMLElement":
bo[i] = parse<HTMLElement>(member.content)
break;
case "SVGElement":
bo[i] = parse<SVGElement>(member.content)
break;
}
}
else {
bo[i] = backendObject_fromJSON(member)
}
}
if (bo.label instanceof MathMLElement
&& typeof bo.uri === "string"
&& typeof bo.type === "string") {
return bo as unknown as Backend_Object
}
else {
console.error(`This is not a Backend_Object:`, json_object)
throw new TypeError(`This is not a Backend_Object: \n ${json_object}`)
}
}
\ No newline at end of file
...@@ -12,6 +12,22 @@ interface Backend_Object{ ...@@ -12,6 +12,22 @@ interface Backend_Object{
readonly type: string readonly type: string
} }
/**
* A {@link Backend_Object} without any further properties known to us
*/
class Pure_Reference implements Backend_Object{
readonly type: string
constructor(
readonly label: MathMLElement,
readonly uri: string,
type?: string,
) {
this.type = type ? type : "none"
}
}
//#region Facts
/** /**
* A Fact is an instance (witness) of a `Backend_Object`, and as such it also has a value. * A Fact is an instance (witness) of a `Backend_Object`, and as such it also has a value.
* @see representations Internal storage of possible MathML elements to display to the user when the value is referenced. For access using {@link show_value} is preferable, as it can have a default value and alike. * @see representations Internal storage of possible MathML elements to display to the user when the value is referenced. For access using {@link show_value} is preferable, as it can have a default value and alike.
...@@ -241,3 +257,67 @@ class Ray_Fact extends Line_Fact { ...@@ -241,3 +257,67 @@ class Ray_Fact extends Line_Fact {
super(label,uri,p1,p2,_representations) super(label,uri,p1,p2,_representations)
} }
} }
//#endregion Facts
/**
* A Slot is an interface that can stand in for either
* - a {@link Fact}, or
* - the {@link Backend_Object} used to define the {@link Scroll} (in the backend)
*
* depending on what is needed.
*
* If all Slots of a {@link Scroll} are assigned, it can compute its {@link Scroll.acquiredFacts}.
*/
class Slot implements Backend_Object{
/**
* @param default_label The default label of the Slot. Fallback if no Fact is assigned.
* @param uri The uri of the Slot
* @param type The expected type of the assigned Fact
* @param assignedFact The Fact assigned to this Slot (may not exist yet)
*/
constructor(
readonly default_label: MathMLElement,
readonly uri: string,
readonly type: string,
public assignedFact?: Fact
) { }
/**
* The MathML element to display when this Slot is referenced.
*
* This is either the label of the {@link assignedFact}, or {@link default_label} if the former doesn't exist.
*/
get label(): MathMLElement{
if (this.assignedFact) {
return this.assignedFact.label
}
else {
return this.default_label
}
}
}
/**
* A Scroll, as it is implemented in the backend.
*
* Can do fancy stuff elsewhere, here we only want display its {@link description} and (possibly) {@link depiction}.
* Both will reference the {@link slots}, and need dynamic adaption to the {@link Fact}s assigned to them.
* The {@link acquiredFacts} referenced do not change, but they are semantically important and deserve special treatment.
*/
class Scroll implements Backend_Object{
readonly type: string = "Scroll"
constructor(
readonly label: MathMLElement,
readonly uri: string,
readonly slots: Slot[],
readonly acquiredFacts: Backend_Object[],
readonly description: HTMLElement,
readonly depiction?: HTMLElement,
) { }
}
function isScroll(s: any): s is Scroll{
return s.type === "Scroll"
}
\ No newline at end of file
/**
* A MMT..whatever. Somewhere between the first and second "meta-" MMT had to leave common nomenclature behind
* @typedef {{kind : string, uri: string}} MMTReference
*/
/**
* Facts, as they are send by MMT. Not *quite* the same format as Unity uses \*sigh\*, and everything has shortened names to avoid five additional letters \*double sigh\*
* @typedef {Object} MMTFact
* @property {MMTReference} ref the reference MMT uses to identify this fact
* @property {string} label the human readable lable to display this fact.
* @property {?any} df the definition of the Fact. May be null for {@link MMTScroll.requiredFacts}
* @property {?MMTReference} tp the MMT type of this fact
* @property {string} kind since a Fact is a MMTThingy, they also have a {@link MMTReference.kind}
*/
/**
* A Slot is an interface that can stand in for either
* - a {@link Fact}, or
* - the {@link Backend_Object} used to define the {@link Scroll} (in the backend)
*
* depending on what is needed.
*
* If all Slots of a {@link Scroll} are assigned, it can compute its {@link Scroll.acquiredFacts}.
*/
class Slot implements Backend_Object{
/**
* @param default_label The default label of the Slot. Fallback if no Fact is assigned.
* @param uri The uri of the Slot
* @param type The expected type of the assigned Fact
* @param assignedFact The Fact assigned to this Slot (may not exist yet)
*/
constructor(
readonly default_label: MathMLElement,
readonly uri: string,
readonly type: string,
public assignedFact?: Fact
) { this.assignedFact = assignedFact }
/**
* The MathML element to display when this Slot is referenced.
*
* This is either the label of the {@link assignedFact}, or {@link default_label} if the former doesn't exist.
*/
get label(): MathMLElement{
if (this.assignedFact) {
return this.assignedFact.label
}
else {
return this.default_label
}
}
}
/**
* A Scroll, as it is implemented in the backend.
*
* Can do fancy stuff elsewhere, here we only want display its {@link description} and (possibly) {@link depiction}.
* Both will reference the {@link slots}, and need dynamic adaption to the {@link Fact}s assigned to them.
* The {@link acquiredFacts} referenced do not change, but they are semantically important and deserve special treatment.
*/
class Scroll implements Backend_Object{
readonly type: string = "Scroll"
constructor(
readonly label: MathMLElement,
readonly uri: string,
readonly slots: Slot[],
readonly acquiredFacts: Backend_Object[],
readonly description: HTMLElement,
readonly depiction?: HTMLElement,
) { }
/** TODO */
static fromString(scrollString: string): Scroll {
throw new Error("Not implemented.");
}
}
let currentScrollRef = "" // ref of the scroll currently displayed let currentScrollRef = "" // ref of the scroll currently displayed
function RenderScroll() { function RenderScroll() {
...@@ -88,7 +9,12 @@ function RenderScroll() { ...@@ -88,7 +9,12 @@ function RenderScroll() {
console.error("No Scroll found in the Unity-Data-Interface") console.error("No Scroll found in the Unity-Data-Interface")
return return
} }
const scroll = Scroll.fromString(dataSource.dataset.scrollDynamic); const scroll_json = JSON.parse(dataSource.dataset.scrollDynamic);
const scroll = backendObject_fromJSON(scroll_json)
if (!isScroll(scroll)) {
console.error("The Scroll in the Unity-Data-Interface cannot be parsed")
return
}
//console.log(scroll.requiredFacts); //console.log(scroll.requiredFacts);
const scrollContainer = document.querySelector("#scrollContainer"); const scrollContainer = document.querySelector("#scrollContainer");
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment