and-grading>`_, there is a built-in template in Studio that uses a sample
JavaScript application.
This sample application has students select two different shapes, a cone
* `Grading Options for Custom JavaScript Applications`_
and a cube. The correct state is when the cone is selected and the cube is not selected:
* `Use a JavaScript Application Without Grading`_
* `Use a JavaScript Application for a Summative Assessment`_
* `Grade the Student Response with Python`_
* `XML for Custom JavaScript Applications`_
.. image:: ../images/JavaScriptInputExample.png
See :ref:`The Custom JavaScript Display and Grading Example Template` for
:alt: Image of the sample JavaScript application, with the cone selected
information about the template application built in to edX Studio.
You can `download files for that application <http://files.edx.org/JSInput.zip>`_. You must upload these files in edX Studio to use them in a problem.
Course staff should see the following sections of the document `Building and Running an edX Course <http://edx.readthedocs.org/projects/ca/en/latest/>`_:
The following information uses this example to explain what developers need to know to embed their JavaScript applications in an edX course.
* `Custom JavaScript Display and Grading <http://edx.readthedocs.org/projects/ca/en/latest/problems_tools/advanced_problems.html#custom-javascript-display-and-grading>`_
*******************************
* `Establishing a Grading Policy <http://edx.readthedocs.org/projects/ca/en/latest/building_course/establish_grading_policy.html>`_
Required JavaScript Functions
*******************************
The rest of this section provides more information for developers who are
creating JavaScript applications for courses on the edX platform.
.. note:: This section assumes proficiency with JavaScript and with how problems
are constructed in edX Studio. If you intend to grade students' interactions
with your JavaScript application, you must also be proficient with Python.
The simplest option is to use JavaScript to show content to students, and
optionally to provide feedback as a formative assessment.
#. In edX Studio, upload an HTML file that contains the JavaScript you want to
show students.
#. Copy the **Embed URL** of the file.
#. `Create a Custom JavaScript Display and Grading Problem <http://edx.readthedocs.org/projects/ca/en/latest/problems_tools/advanced_problems.html#custom-javascript-display-and-grading>`_. The template
for the problem contains the definition for a sample JavaScript application
that requires and grades student interaction.
#. Edit the XML of the component to remove grading information and refer to the
HTML file you uploaded:
To enable grading of students' interactions, your JavaScript application must contain three global methods:
.. code-block:: xml
<customresponse>
<jsinput
width="width needed to display your application"
height="height needed to display your application"
To use a JavaScript Application for a summative assessment and have student
results calculated by the edX grading system, you must:
* ``getState``
* Include required functions in the JavaScript application.
* ``setState``
* ``getGrade``
* `getState() Function`_
* `setState() Function`_
* `getGrade() Function`_
* Reference functions in the problem XML.
* `Grade the Student Response with Python`_.
You reference these methods in the XML problem specification, as described below.
====================
====================
getState() Function
getState() Function
====================
====================
Your application must be able to return the state of objects on which grades will be based.
Your application must contain a ``getState()`` function that returns the state
of all objects as a JSON string.
In the template example, grading is based on the the state of the cylinder and cone objects. The state is initialized for the cylinder and cube in the ``WebGLDemo.js`` file:
.. code-block:: javascript
var state = {
The ``getState()`` function retrieves the state of objects in the application,
'selectedObjects': {
so each student experiences that application in its initial or last saved state.
'cylinder': false,
'cube': false
}
}
User interactions toggle the ``state`` values of the cylinder and cube between ``true`` and ``false``.
The name of the ``getState()`` function must be the value of the ``get_statefn``
attribute of the ``jsinput`` element for the problem.
Your application must contain a ``getState()`` function that is referenced in the XML problem specification and that returns the current state as a JSON string.
For example:
The following is the ``getState()`` function in the sample application:
.. code-block:: xml
.. code-block:: javascript
<customresponse cfn="vglcfn">
<jsinput get_statefn="JSObject.getState"
. . . .
function getState() {
return JSON.stringify(state);
}
====================
====================
setState() Function
setState() Function
====================
====================
When a student clicks **Check** for the JavaScript problem, the application's state must be saved so that the student can later return to the application and find it in the same state.
Your application must contain a ``setState()`` function.
Your application must contain a ``setState()`` function that is referenced in the XML problem specification and that saves the current state.
The following is the ``setState()`` function in the sample application:
The ``setState()`` function is executed when the student clicks **Check**.
.. code-block:: javascript
The function saves application's state so that the student can later return to
the application and find it as he or she left it.
function setState() {
The name of the ``setState()`` function must be the value of the ``set_statefn``
attribute of the ``jsinput`` element for the problem.
state = JSON.parse(stateStr);
updateMaterials();
}
The ``updateMaterials()`` function called by ``setState()`` updates the state of the cylinder and cone with the user's current selections:
For example:
.. code-block:: javascript
.. code-block:: xml
function updateMaterials() {
<customresponse cfn="vglcfn">
if (state.selectedObjects.cylinder) {
<jsinput set_statefn="JSObject.setState"
cylinder.material = selectedMaterial;
. . . .
}
else {
cylinder.material = unselectedMaterial;
}
if (state.selectedObjects.cube) {
cube.material = selectedMaterial;
}
else {
cube.material = unselectedMaterial;
}
}
====================
====================
getGrade() function
getGrade() Function
====================
====================
The student's interactions with your application, and the resulting application state, must be able to be graded.
Your application must contain a ``getGrade()`` function.
Your application must contain a ``getGrade()`` function that is referenced in the XML problem specification and that returns the current state as a JSON string.
The ``getGrade()`` function is executed when the student clicks **Check**. The
``getState()`` function must return the state of objects on which grading is
based as a JSON string.
The following is the ``getGrade()`` function in the sample application:
The JSON string returned by ``getGrade()`` is used by the Python code in the
problem to determine the student's results, as explained below.
.. code-block:: javascript
The name of the ``getGrade()`` function must be the value of the ``gradefn``
attribute of the ``jsinput`` element for the problem.
function getGrade() {
For example:
return JSON.stringify(state['selectedObjects']);
}
The returned JSON string is then used by the Python code defined in the problem to determine if the student's submission is correct or not, as described in the next section.
.. code-block:: xml
*******************************
<customresponse cfn="vglcfn">
Grading the Student Response
<jsinput gradefn="JSObject.getGrade"
*******************************
. . . .
***************************************
Grade the Student Response with Python
***************************************
The problem definition contains Python code that, when the student clicks **Check**, parses the JSON string returned by your application's ``getGrade()`` function and determines if the student's submission is correct or not.
To grade a student's interaction with your JavaScript application, you must
write Python code in the problem. When a student clicks **Check**, the Python
code parses the JSON string returned by the application's ``getGrade()``
function and determines if the student's submission is correct or not.
The following is the Python function ``vglcfn`` in the sample application:
.. note:: Grading for JavaScript applications supports determining if a student's submission is correct or not. You cannot give partial credit with JavaScript applications.
.. code-block:: python
In the Python code, you must:
* Enclose all code in a ``script`` element of type ``loncapa/python``.
* Import ``json``
* Define a function that is executed when the student clicks Check. This
function:
* Is placed before the ``customresponse`` element that defines the problem.
* By default is named ``vglcfn``
* Has two parameters: ``e`` for the submission event, and ``ans``, which is
the JSON string returned by the JavaScript function ``getGrade()``.
* Must return ``True`` if the student's submission is correct, or ``False`` if
it is incorrect.
The structure of the Python code in the problem is:
.. code-block:: xml
<problem>
<script type="loncapa/python">
<script type="loncapa/python">
import json
import json
def vglcfn(e, ans):
def vglcfn(e, ans):
'''
'''
par is a dictionary containing two keys, "answer" and "state"
Code that parses ans and returns True or False
The value of answer is the JSON string returned by getGrade
The value of state is the JSON string returned by getState
'''
par = json.loads(ans)
# We can use either the value of the answer key to grade
answer = json.loads(par["answer"])
return answer["cylinder"] and not answer["cube"]
'''
# Or we could use the value of the state key
state = json.loads(par["state"])
selectedObjects = state["selectedObjects"]
return selectedObjects["cylinder"] and not selectedObjects["cube"]
'''
'''
</script>
</script>
<customresponse cfn="vglcfn">
. . . .
</problem>
In this example, the ``ans`` parameter contains the JSON string returned by ``getGrade()``. The value is converted to a Python Unicode (?) structure in the variable ``par``.
In the function's first option, object(s) the student selected are stored in the ``answer`` variable. If the student selected the cylinder and not the cube, the ``answer`` variable contains only ``cylinder``, and the function returns ``True``, which signifies a correct answer. Otherwise, it returns ``False`` and the answer is incorrect.
In the function's second option, the objects' states are retrieved. If the cylinder is selected and not the cube, the function returns ``True``, which signifies a correct answer. Otherwise, it returns ``False`` and the answer is incorrect.
*******************************
XML Problem Structure
*******************************
Following the Python code and any HTML content you want to precede the IFrame containing your JavaScript application, you define the XML for the problem.
As referred to in `course staff documentation <http://edx.readthedocs.org/projects/ca/en/latest/problems_tools/advanced_problems.html#custom-javascript-display-and-grading>`_, there is a built-in template in edX Studio that uses a sample JavaScript application.
This sample application has students select two different shapes, a cone and a
cube. The correct state is when the cone is selected and the cube is not
selected:
.. image:: ../images/JavaScriptInputExample.png
:alt: Image of the sample JavaScript application, with the cone selected
You can `download files for that application <http://files.edx.org/JSInput.zip>`_.
You must upload these files in Studio to use them in a problem.
The following information steps through this example to demonstrate how to apply
the guidelines in `Custom JavaScript Display and Grading`.
****************************
Example getState() Function
****************************
In the example, the ``state`` variable is initialized for the cylinder and cube
in the ``WebGLDemo.js`` file:
.. code-block:: javascript
var state = {
'selectedObjects': {
'cylinder': false,
'cube': false
}
}
User interactions toggle the ``state`` values of the cylinder and cube between
``true`` and ``false``.
The ``getState()`` function in the sample application returns the state as a
JSON string:
.. code-block:: javascript
function getState() {
return JSON.stringify(state);
}
******************************
Example setState() Function
******************************
In the example, when a student clicks **Check**, the ``state`` variable is saved
so that the student can later return to the application and find it in the same