/// RHAI HOMEPAGE: https://schungx.github.io/rhai/
///
/// HTML in RHAI uses the JSON data model (VIA serde in Rust).
/// For example, the following HTML snippet:
/// ```html
///
/// y = x^2
///
/// ```
/// Becomes this in RHAI:
/// ```json
/// [{
/// "tag": "desmos",
/// "styling": {},
/// "attrs": {},
/// "children": [{
/// "tag": "expr",
/// "styling": {},
/// "attrs": {},
/// "children": ["y = x^2"]
/// }]
/// }]
/// ```
/// Note that the `styling` field will probbaly change and is currently unimplemented.
///
/// API EXAMPLE:
/// ```
///
/// y = x^2
///
/// ```
///
///////////////////////////////////////////////////////////////////////////////
// HTML UTILS
///////////////////////////////////////////////////////////////////////////////
fn is_element(html) {
type_of(html) == "map" && html.has("tag")
}
fn is_text(html) {
type_of(html) == "string"
}
fn is_tag(html, tag) {
is_element(html) && html.tag == tag
}
fn new_element_node(tag, attrs, children) {
#{
tag: tag,
attrs: attrs,
children: children
}
}
fn new_text_node(txt) {txt}
fn get_children(html) {
if is_element(html) && html.has("children") {
return html.children
} else {
return []
}
}
fn get_attr(html, attr) {
if is_element(html) && html.attrs.has(attr) {
return html.attrs.get(attr)
} else {
return ()
}
}
fn get_attr_or(html, attr, def) {
if is_element(html) && html.attrs.has(attr) {
return html.attrs.get(attr)
} else {
return def
}
}
fn get_text_contents(html) {
let contents = "";
for child in get_children(html) {
if type_of(child) == "string" {
contents += child;
}
}
return contents
}
///////////////////////////////////////////////////////////////////////////////
// DESMOS UTILS
///////////////////////////////////////////////////////////////////////////////
fn init_container(uid, width, height) {
let style = "width:"+width+";height:"+height+";";
new_element_node(
"div",
#{
id: uid,
style: style,
},
[]
)
}
fn init_script(
uid,
math_bounds,
show_expressions,
lockViewport,
xAxisNumbers,
yAxisNumbers,
showGrid,
commands,
) {
let lines = [
"window.addEventListener('load', function on_load() {",
" var elt = document.getElementById('"+uid+"');",
" var options = {",
" expressionsCollapsed: true,",
" expressions: "+show_expressions+",",
" lockViewport: "+lockViewport+",",
" settingsMenu: false,",
" border: false,",
" // xAxisNumbers: "+xAxisNumbers+",",
" // yAxisNumbers: "+yAxisNumbers+",",
" showGrid: "+showGrid+",",
" };",
" var calculator = Desmos.GraphingCalculator(elt, options);",
" if (",
" "+math_bounds+" &&",
" "+math_bounds+" !== null &&",
" "+math_bounds+" !== undefined",
" ) {",
" calculator.setMathBounds("+math_bounds+");",
" }",
" for (cmd of "+commands+") {",
" calculator.setExpression(cmd);",
" }",
"});",
];
let code = "";
for line in lines {
code += line + "\n";
}
new_element_node(
"script",
#{},
[code]
)
}
///////////////////////////////////////////////////////////////////////////////
// MACRO
///////////////////////////////////////////////////////////////////////////////
fn apply(html) {
let uid = new_rand_id();
///////////////////////////////////////////////////////////////////////////
// DIV CONTAINER
///////////////////////////////////////////////////////////////////////////
let width = get_attr_or(html, "width", "300px");
let height = get_attr_or(html, "height", "300px");
let container = init_container(uid, width, height);
///////////////////////////////////////////////////////////////////////////
// JS SETUP
///////////////////////////////////////////////////////////////////////////
let math_bounds = "null";
let show_expressions = "false";
let lockViewport = "true";
let xAxisNumbers = "false";
let yAxisNumbers = "false";
let showGrid = "false";
///////////////////////////////////////////////////////////////////////////
// COMMANDS
///////////////////////////////////////////////////////////////////////////
let commands = "[";
for child in get_children(html) {
if is_tag(child, "expr") {
let latex = get_text_contents(child);
if latex.len() > 0 {
let id = new_rand_id();
commands += "{\"latex\":\""+latex+"\", \"id\":\""+id+"\"},";
}
}
}
commands += "]";
///////////////////////////////////////////////////////////////////////////
// JS SCRIPT
///////////////////////////////////////////////////////////////////////////
let script = init_script(
uid,
math_bounds,
show_expressions,
lockViewport,
xAxisNumbers,
yAxisNumbers,
showGrid,
commands,
);
///////////////////////////////////////////////////////////////////////////
// DONE
///////////////////////////////////////////////////////////////////////////
new_element_node(
"div",
#{macro: "desmos1"},
[
container,
script,
]
)
}
export let plugins = [
#{
type: "tag-macro",
tag: "desmos1",
trans: "apply",
}
];