Easy JavaScript Simulation (EJSS) Browser Editor
current site: https://ejss-6l7k.onrender.com/
source code: https://github.com/fazli1702/ejss-browser-editor
The source code is referencing the original writer of the code with minor changes made.
original source code: https://github.com/rphly/ejss-browser-editor
Changes
Displaying Comments
We want to display the comment for the variable that has been written in EJSS so that users have a better idea of what the variable is. The following is the function that displays the comment for the variables. It can be found in src/components/Editor.js
findCommentInXML = (variable) => {
var parser = new DOMParser();
var xDoc = parser.parseFromString(
iconv.decode(Buffer.from(this.state.ejssFile.slice(3)), "utf16"),
"text/xml"
);
var x = xDoc.getElementsByTagName("Variable");
for (var i = 0; i < x.length; i++) {
let variableName = x[i].firstElementChild.childNodes[0].nodeValue;
if (variableName === variable) {
let nodeName = x[i].lastElementChild.nodeName;
if (nodeName == "Comment") {
let comment = x[i].lastElementChild.childNodes[0].nodeValue;
if (comment === "null") {
return "";
}
return comment;
}
}
}
};
Explanation
findCommentInXML = (variable)
This function helps to find the comment from the input parameter (variable), which is the name of the variable that we want the comment
From the findCommentInXML function, the following lines helps to read and decode the XML file that is produced from the .ejss file.
var parser = new DOMParser();
var xDoc = parser.parseFromString(
iconv.decode(Buffer.from(this.state.ejssFile.slice(3)), "utf16"),
"text/xml"
);
This is a snippet of what the XML file looks like.
<Variable>
<Name><![CDATA[Slidera]]></Name>
<Value><![CDATA[80]]></Value>
<Type><![CDATA[double]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[public]]></Domain>
<Comment><![CDATA[sliderA mass of person in kg]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[Sliderb]]></Name>
<Value><![CDATA[2]]></Value>
<Type><![CDATA[String]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[public]]></Domain>
<Comment><![CDATA[sliderB time after drinking]]></Comment>
</Variable>
The variable x is then assigned with all the information that is contained within a Variable tag. Since there are multiple Variable tags, x will be an array where each element represents the information available within each Variable tag.
var x = xDoc.getElementsByTagName("Variable");
Extracting the comment
for (var i = 0; i < x.length; i++) {
let variableName = x[i].firstElementChild.childNodes[0].nodeValue;
if (variableName === variable) {
let nodeName = x[i].lastElementChild.nodeName;
if (nodeName == "Comment") {
let comment = x[i].lastElementChild.childNodes[0].nodeValue;
if (comment === "null") {
return "";
}
return comment;
}
}
}
Variable Name
Iterating through each variable, we first find the name of the variable and check if it is the same as the variable that we inputted so that we can ensure the correct comment is displayed for the correct variable.
Since we know that the name of the variable is within the <Name> tag, which is also the first tag within the <Variable> tag, we can just extract it using the firstElementChild function, giving us
<Name><![CDATA[Slidera]]></Name>
We then use the function childNodes[0] to get <![CDATA[Slidera]]>
and nodeValue to get Slidera
Shown below is the code for extracting and checking the variable name.
let variableName = x[i].firstElementChild.childNodes[0].nodeValue;
if (variableName === variable) {
...
Comment
Now, we want to extract the comment. The <Comment> tag is the last tag within the <Variable> tag which enables us to use the lastElementChild function. The nodeName function enables us to get the name of the tag, which is Comment (<Comment> --> "Comment").
We first ensure that the last tag is "Comment" so that there would not be any error or incorrect information displayed.
if (variableName === variable) {
let nodeName = x[i].lastElementChild.nodeName;
if (nodeName == "Comment") {
...
Then, we extract the comment itself similar to how we extract the variable name above.
let comment = x[i].lastElementChild.childNodes[0].nodeValue;
We then check if the comment is null and if so, we will not display anything else we will display the comment itself.
if (comment === "null") {
return "";
}
return comment;
Show below is the code for what that has just been explained.
if (variableName === variable) {
let nodeName = x[i].lastElementChild.nodeName;
if (nodeName == "Comment") {
let comment = x[i].lastElementChild.childNodes[0].nodeValue;
if (comment === "null") {
return "";
}
return comment;
}
}
Displaying the comment
<TabPane tab="Variables" key="1">
{variables && Object.keys(variables).length > 0 ? (
Object.keys(variables).map((name, i) => {
let value = variables[name];
let comment = this.findCommentInXML(name);
return (
<div
style={{
marginBottom: 20,
}}
key={i}
>
<b>
<code>{name}</code>
</b>
<br />
<i>{comment}</i>
<Input
name={`variables_${name}`}
placeholder={value}
value={value}
onChange={this.onChange}
/>
</div>
);
})
) : (
<div>No editable variables found. email weelookang@gmail.com ...</div>
)}
Now, we need to display the comment on the site itself.
First, we call the findCommentInXML function with the input of the variable name which we one to get the comment from.
let comment = this.findCommentInXML(name);
We then display it in italics, <i>{comment}</i>
Increasing Width of Edit Model Box
One of the minor changes we made was increasing the size of the "Edit Model" box. This is so that the information can be displayed nicely without being too clustered.
Before
After
The following is the code where we edit the width of the box, under style variable. You can edit the value from 50vw to any value of your liking. The code can be found in src/components/Editor.js
<Modal
title="Edit Model"
visible={showEditor}
okButtonProps={{ disabled: disabledDownload }}
onOk={this.onOkEditor}
onCancel={toggleEditor}
okText="Download model"
style={{
minWidth:`50vw`, // width for entire edit model box
}}
>
Increasing Height of input for editing function
Other than variables, the site also allows users to edit the function so that it fits their own simulation. We realise that the space given for the function to be written has a very limited view, so we decide to increase it.
Before
After
The following is the code where we edit the height of the input, under style variable. You can edit the value from 50vh to any other value of your liking. The code can be found in line 261, under src/components/Editor.js
<Input.TextArea
name={`functions_${name}`}
placeholder={value}
value={value}
onChange={this.onChange}
style={{
minHeight:`50vh`,
}}
/>
Displaying "Open" Link on Hover
This feature will display the text "open" when the user hover their mouse over the card. The text "open"
is a link to the EJSS simulation and the user will be able to experience and play around with the
"simulation" before using the browser editor to edit the simulation for their own use. The code can
be found in src/containers/Home.js
Explanation
First, we need to create two variables, isHovering and isHoveringName.
isHovering is a boolean which represents whether the user mouse is hovering over a card or not.
isHoveringName represents the folder name which the file is hovering over so that we know exactly
which card the user is hovering over.
These variables are added to the class component state so that it can be easily referred within the class.
this.state = {
...
isHovering: false,
isHoveringName: "",
};
Now, we use the built-in function onMouseOver and onMouseOut in the card tag. This function can
detect when a user mouse is hovering over the card or is hovering elsewhere.
When onMouseOver is true, it means that the mouse is hovering over the card. We then want to update
the value of isHovering to true and isHoveringName to the folder name, which can be represented by
item.folderName. This is so that we know which card it is hovering over.
When onMouseOut is true, the user mouse is not hovering over any card. Thus, we will update the value
of isHovering to false.
<Card
...
onMouseOver={() => {
this.setState({
isHovering: true,
isHoveringName: item.folderName,
})
}}
onMouseOut={() => {
this.setState({isHovering: false})
}}
>
We created a function, getHoveringLink which will help to generate the link for each specific card.
The link follows a standard template but ends with the folder name (i.e ....../fileName/). We can get
fileName from isHoveringName but since the link does not require the .zip extension on fileName,
we remove it. We add the fileName to the end of the link and return the entire link.
getHoveringLink() {
let fileName = this.state.isHoveringName;
let link = "https://iwant2study.org/lookangejss/EditableSimulations/";
fileName = fileName.substring(0, fileName.length - 4);
link += fileName + '/'
return link
}
For displaying the link, when isHovering is false, we want it to be hidden and when isHovering is true,
we want the link to be visible. We also check if isHoveringName==item.folderName so that the "open"
link is displayed on the correct card.
<a
href={this.getHoveringLink()}
target="_blank" // open link on new tab
style={{
visibility:
(this.state.isHovering&&this.state.isHoveringName==item.folderName)?`visible`:`hidden`,
}}
>
Open
</a>
Displaying Red Border
The EJSS Browser Editor allows user to edit simulation by two different ways, using the templates
provided or by using their own files. In order to differentiate the different functions, we added a red
border around it. This can be done by adding the border css within the div that wraps around the
container. The code can be found in src/containers/Home.js
<div
style={{
...
border: `3px solid red`,
}}
>
.png)




.png)
No comments:
Post a Comment