Commit 5f0d8f31 by Mark Hoeber

Merge pull request #3267 from edx/markhoeber/documentation/doc-255

JavaScript update in developer documentation
parents 1a086927 f6e11f14
...@@ -15,7 +15,7 @@ This section of the developers' documentation lists and explains the different w ...@@ -15,7 +15,7 @@ This section of the developers' documentation lists and explains the different w
:header-rows: 1 :header-rows: 1
* - * -
- :ref:`Custom JavaScript Display and Grading` - :ref:`Custom JavaScript Applications`
- LTI - LTI
- External Graders - External Graders
- XBlocks - XBlocks
...@@ -63,7 +63,7 @@ This section of the developers' documentation lists and explains the different w ...@@ -63,7 +63,7 @@ This section of the developers' documentation lists and explains the different w
- Yes - Yes
- Yes - Yes
* - Server Side Grading * - Server Side Grading
- No (See JavaScript) - Possibly (See JavaScript)
- Yes - Yes
- Yes - Yes
- Yes - Yes
......
...@@ -6,4 +6,5 @@ Extending the edX Platform ...@@ -6,4 +6,5 @@ Extending the edX Platform
:maxdepth: 2 :maxdepth: 2
extending.rst extending.rst
javascript javascript
\ No newline at end of file js_template_example
\ No newline at end of file
.. _Custom JavaScript Applications:
.. _Custom JavaScript Display and Grading:
########################################## ##########################################
Custom JavaScript Display and Grading Custom JavaScript Applications
########################################## ##########################################
Custom JavaScript display and grading problems (also called custom JavaScript
problems or JS Input problems) allow you to create a custom problem or tool that
uses JavaScript and then add the problem or tool directly into Studio. When you
create a JS Input problem, Studio embeds the problem in an inline frame (IFrame)
so that your students can interact with it in the LMS. You can grade your
students’ work using JavaScript and some basic Python, and the grading is
integrated into the edX grading system.
Course staff should see `documentation on using custom JavaScript <http://edx.re *******************************
adthedocs.org/projects/ca/en/latest/problems_tools/advanced_problems.html Overview
#custom-javascript-display-and-grading>`_ and `Establishing a Grading Policy <http: *******************************
//edx.readthedocs.org/projects/ca/en/latest/building_course/establish_grading_po
licy.html>`_ in *Building and Running an edX Course*.
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 Python, and with how problems are constructed in edX Studio. You can include custom JavaScript applications (also called custom JavaScript
problems or JS Input problems) in a course. You add the application directly
into edX Studio.
******************************* When you create a JavaScript application, Studio embeds the problem in an inline
The Template Example frame (HTML ``iframe`` tag) so that students can interact with it in the LMS.
*******************************
As referred to in `course staff documentation <http://edx.readthedocs.org/projec See the following sections for more information:
ts/ca/en/latest/problems_tools/advanced_problems.html#custom-javascript-display-
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
*******************************
To enable grading of students' interactions, your JavaScript application must contain three global methods: The rest of this section provides more information for developers who are
creating JavaScript applications for courses on the edX platform.
* ``getState`` .. note:: This section assumes proficiency with JavaScript and with how problems
* ``setState`` are constructed in edX Studio. If you intend to grade students' interactions
* ``getGrade`` with your JavaScript application, you must also be proficient with Python.
You reference these methods in the XML problem specification, as described below.
====================
getState() Function
====================
Your application must be able to return the state of objects on which grades will be based. *******************************************************
Grading Options for Custom JavaScript Applications
*******************************************************
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: When using a JavaScript application in your course content, you have three
options:
.. code-block:: javascript #. A JavaScript application that visually demonstrates a concept or process. The
application would not require student interaction, and students would not be
graded.
var state = { #. A JavaScript application that requires student interaction but does not grade
'selectedObjects': { performance. Referred to as a formative assessment, such an application
'cylinder': false, provides feedback to students based on their interactions.
'cube': false
}
}
User interactions toggle the ``state`` values of the cylinder and cube between ``true`` and ``false``. #. A JavaScript application that requires and grades student interaction.
Referred to as a summative assessment, such an application can be used to
evaluate student learning against a standard. To use the JavaScript
application as a summative assessment and have student performance integrated
into the edX grading system, you must also use basic Python code in the
component.
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. These options are explained through examples below.
The following is the ``getState()`` function in the sample application: *******************************************************
Use a JavaScript Application Without Grading
*******************************************************
.. code-block:: javascript The simplest option is to use JavaScript to show content to students, and
optionally to provide feedback as a formative assessment.
function getState() { #. In edX Studio, upload an HTML file that contains the JavaScript you want to
return JSON.stringify(state); 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:
.. code-block:: xml
==================== <customresponse>
setState() Function <jsinput
==================== width="width needed to display your application"
height="height needed to display your application"
html_file="Embed URL of the HTML file"
sop="false"/>
</customresponse>
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. For example:
.. code-block:: xml
<customresponse>
<jsinput
width="400"
height="400"
html_file="/static/electrol_demo.html"
sop="false"/>
</customresponse>
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: **************************************************************
Use a JavaScript Application for a Summative Assessment
**************************************************************
.. code-block:: javascript To use a JavaScript Application for a summative assessment and have student
results calculated by the edX grading system, you must:
function setState() { * Include required functions in the JavaScript application.
stateStr = arguments.length === 1 ? arguments[0] : arguments[1];
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: * `getState() Function`_
* `setState() Function`_
* `getGrade() Function`_
.. code-block:: javascript * Reference functions in the problem XML.
function updateMaterials() { * `Grade the Student Response with Python`_.
if (state.selectedObjects.cylinder) {
cylinder.material = selectedMaterial;
}
else {
cylinder.material = unselectedMaterial;
}
if (state.selectedObjects.cube) {
cube.material = selectedMaterial;
}
else {
cube.material = unselectedMaterial;
}
}
==================== ====================
getGrade() function getState() Function
==================== ====================
The student's interactions with your application, and the resulting application state, must be able to be graded. Your application must contain a ``getState()`` function that returns the state
of all objects as a JSON string.
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 ``getState()`` function retrieves the state of objects in the application,
so each student experiences that application in its initial or last saved state.
The following is the ``getGrade()`` function in the sample application: The name of the ``getState()`` function must be the value of the ``get_statefn``
attribute of the ``jsinput`` element for the problem.
.. code-block:: javascript For example:
function getGrade() { .. code-block:: xml
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. <customresponse cfn="vglcfn">
<jsinput get_statefn="JSObject.getState"
. . . .
*******************************
Grading the Student Response
*******************************
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.
The following is the Python function ``vglcfn`` in the sample application: ====================
setState() Function
====================
.. code-block:: python Your application must contain a ``setState()`` function.
<script type="loncapa/python"> The ``setState()`` function is executed when the student clicks **Check**.
import json
def vglcfn(e, ans):
'''
par is a dictionary containing two keys, "answer" and "state"
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>
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``. 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.
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. The name of the ``setState()`` function must be the value of the ``set_statefn``
attribute of the ``jsinput`` element for the problem.
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. For example:
.. code-block:: xml
******************************* <customresponse cfn="vglcfn">
XML Problem Structure <jsinput set_statefn="JSObject.setState"
******************************* . . . .
====================
getGrade() Function
====================
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. Your application must contain a ``getGrade()`` function.
The XML problem for the sample template is: 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.
.. code-block:: xml The JSON string returned by ``getGrade()`` is used by the Python code in the
problem to determine the student's results, as explained below.
The name of the ``getGrade()`` function must be the value of the ``gradefn``
attribute of the ``jsinput`` element for the problem.
For example:
.. code-block:: xml
<customresponse cfn="vglcfn"> <customresponse cfn="vglcfn">
<jsinput gradefn="WebGLDemo.getGrade" <jsinput gradefn="JSObject.getGrade"
get_statefn="WebGLDemo.getState" . . . .
set_statefn="WebGLDemo.setState"
width="400" ***************************************
height="400" Grade the Student Response with Python
html_file="/static/webGLDemo.html" ***************************************
sop="false"/>
</customresponse> 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.
.. note:: Grading for JavaScript applications supports determining if a student's submission is correct or not. You cannot give partial credit with JavaScript applications.
In the Python code, you must:
As in this example, the JS Input problem is defined in a ``<customresponse>`` element. * Enclose all code in a ``script`` element of type ``loncapa/python``.
The value of the ``cfn`` attribute is the name of the Python function in the problem that evaluates the submission's grade. * Import ``json``
The ``<customresponse>`` element contains a ``<jsinput>`` element, which defines how your JavaScript application is used in the course. * 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">
import json
def vglcfn(e, ans):
'''
Code that parses ans and returns True or False
'''
</script>
<customresponse cfn="vglcfn">
. . . .
</problem>
*******************************************************
XML for Custom JavaScript Applications
*******************************************************
The problem component XML that you define in Studio to provide students with a
JavaScript application has the following structure:
.. code-block::
<problem>
<!-- Optional script tag for summative assessments -->
<script type="loncapa/python">
import json
def vglcfn(e, ans):
'''
Code that parses ans and returns True or False
'''
</script>
<customresponse cfn="vglcfn">
<jsinput
gradefn="JSObject.getGrade"
get_statefn="JSObject.getState"
set_statefn="JSObject.setState"
width="100%"
height="360"
html_file="/static/file-name.html"
sop="false"/>
</customresponse>
</problem>
Following are details about the attributes of the ``<jsinput>`` element.
=================== ===================
jsinput attributes jsinput attributes
=================== ===================
The following table describes the attributes of the ``jsinput`` element.
.. list-table:: .. list-table::
:widths: 10 80 10 :widths: 10 50 10
:header-rows: 1 :header-rows: 1
* - Attribute * - Attribute
- Description - Description
- Example - Example
* - gradefn * - gradefn
- The function in your JavaScript application that returns the state of the objects to be evaluated as a JSON string. - The function in your JavaScript application that returns the state of the
- ``WebGLDemo.getGrade`` objects to be evaluated as a JSON string.
- ``JSObject.getGrade``
* - get_statefun * - get_statefun
- The function in your JavaScript application that returns the state of the objects. [NOT CLEAR TO ME WHY YOU NEED BOTH getGrade and setState] - The function in your JavaScript application that returns the state of the
- ``WebGLDemo.getState`` objects.
- ``JSObject.getState``
* - set_statefun * - set_statefun
- The function in your JavaScript application that saves the state of the objects. - The function in your JavaScript application that saves the state of the
- ``WebGLDemo.setState`` objects.
- ``JSObject.setState``
* - width * - width
- The width of the IFrame in which your JavaScript application will be displayed, in pixels. - The width of the IFrame in which your JavaScript application will be
displayed, in pixels.
- 400 - 400
* - height * - height
- The height of the IFrame in which your JavaScript application will be displayed, in pixels. - The height of the IFrame in which your JavaScript application will be
displayed, in pixels.
- 400 - 400
* - html_file * - html_file
- The name of the HTML file containing your JavaScript application that will be loaded in the IFrame. - The name of the HTML file containing your JavaScript application that
will be loaded in the IFrame.
- /static/webGLDemo.html - /static/webGLDemo.html
* - sop * - sop
- The same-origin policy (SOP), meaning that all elements have the same protocol, host, and port. To bypass the SOP, set to ``true``. - The same-origin policy (SOP), meaning that all elements have the same
- false protocol, host, and port. To bypass the SOP, set to ``true``.
- false
\ No newline at end of file
.. _The Custom JavaScript Display and Grading Example Template:
###########################################################
The Custom JavaScript Display and Grading Example Template
###########################################################
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
state:
.. code-block:: javascript
function setState() {
stateStr = arguments.length === 1 ? arguments[0] : arguments[1];
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:
.. code-block:: javascript
function updateMaterials() {
if (state.selectedObjects.cylinder) {
cylinder.material = selectedMaterial;
}
else {
cylinder.material = unselectedMaterial;
}
if (state.selectedObjects.cube) {
cube.material = selectedMaterial;
}
else {
cube.material = unselectedMaterial;
}
}
******************************
Example getGrade() function
******************************
In the example, when a student clicks **Check**, the ``getGrade()`` function in
returns the selected objects:
.. code-block:: javascript
function getGrade() {
return JSON.stringify(state['selectedObjects']);
}
The returned JSON string is then used by the Python code defined in the problem
to determine if correct objects were selected or not, and to return a result.
*******************************
Grade the Student Response
*******************************
The following is the Python function ``vglcfn`` in the sample application:
.. code-block:: python
<script type="loncapa/python">
import json
def vglcfn(e, ans):
'''
par is a dictionary containing two keys, "answer" and "state"
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>
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
*******************************
The XML problem for the sample template is:
.. code-block:: xml
<problem display_name="webGLDemo">
<script type="loncapa/python">
import json
def vglcfn(e, ans):
'''
par is a dictionary containing two keys, "answer" and "state"
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>
<p>
The shapes below can be selected (yellow) or unselected (cyan).
Clicking on them repeatedly will cycle through these two states.
</p>
<p>
If the cone is selected (and not the cube), a correct answer will be
generated after pressing "Check". Clicking on either "Check" or "Save"
will register the current state.
</p>
<customresponse cfn="vglcfn">
<jsinput gradefn="WebGLDemo.getGrade"
get_statefn="WebGLDemo.getState"
set_statefn="WebGLDemo.setState"
width="400"
height="400"
html_file="https://studio.edx.org/c4x/edX/DemoX/asset/webGLDemo.html"
sop="false"/>
</customresponse>
</problem>
\ No newline at end of file
...@@ -37,6 +37,7 @@ Internationalization ...@@ -37,6 +37,7 @@ Internationalization
i18n.rst i18n.rst
i18n_translators_guide.rst i18n_translators_guide.rst
pavelib.rst pavelib.rst
xblocks.rst
Indices and tables Indices and tables
================== ==================
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment