diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py
index f89cb0f990..3d7b8a9f02 100644
--- a/common/lib/xmodule/xmodule/gst_module.py
+++ b/common/lib/xmodule/xmodule/gst_module.py
@@ -26,10 +26,10 @@ class GraphicalSliderToolModule(XModule):
js = {
'js': [
resource_string(__name__, 'js/src/graphical_slider_tool/gst_main.js'),
- resource_string(__name__, 'js/src/graphical_slider_tool/mod1.js'),
- resource_string(__name__, 'js/src/graphical_slider_tool/mod2.js'),
- resource_string(__name__, 'js/src/graphical_slider_tool/mod3.js'),
- resource_string(__name__, 'js/src/graphical_slider_tool/mod4.js'),
+ resource_string(__name__, 'js/src/graphical_slider_tool/state.js'),
+ resource_string(__name__, 'js/src/graphical_slider_tool/logme.js'),
+ resource_string(__name__, 'js/src/graphical_slider_tool/general_methods.js'),
+ resource_string(__name__, 'js/src/graphical_slider_tool/sliders.js'),
resource_string(__name__, 'js/src/graphical_slider_tool/mod5.js'),
resource_string(__name__, 'js/src/graphical_slider_tool/gst.js')
@@ -128,7 +128,7 @@ class GraphicalSliderToolModule(XModule):
Simple variant: slider and plot controls are not inside any tag.
"""
#substitute plot
- plot_div = '
\
This is plot
'
html_string = html_string.replace('$plot$', plot_div)
@@ -139,7 +139,7 @@ class GraphicalSliderToolModule(XModule):
sliders = [sliders]
vars = [x['@var'] for x in sliders]
- slider_div = 'This is input
'
for var in vars:
diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod3.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/general_methods.js
similarity index 65%
rename from common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod3.js
rename to common/lib/xmodule/xmodule/js/src/graphical_slider_tool/general_methods.js
index 21961f3611..9cdd4fff0f 100644
--- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod3.js
+++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/general_methods.js
@@ -2,12 +2,16 @@
// define() functions from Require JS available inside the anonymous function.
(function (requirejs, require, define) {
-define('mod3', ['mod5'], function (mod5) {
- console.log('we are in the mod3 callback');
-
- console.log('mod5 status: [' + mod5.module_status + '].');
+define('GeneralMethods', [], function () {
+ if (!String.prototype.trim) {
+ // http://blog.stevenlevithan.com/archives/faster-trim-javascript
+ String.prototype.trim = function trim(str) {
+ return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
+ };
+ }
return {
+ 'module_name': 'GeneralMethods',
'module_status': 'OK'
};
});
diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst_main.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst_main.js
index 66f98eddf7..9f2c4c356d 100644
--- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst_main.js
+++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst_main.js
@@ -2,11 +2,19 @@
// define() functions from Require JS available inside the anonymous function.
(function (requirejs, require, define) {
-define('GstMain', ['mod1', 'mod2', 'mod3', 'mod4'], function (mod1, mod2, mod3, mod4) {
+define('GstMain', ['State', 'logme', 'GeneralMethods', 'Sliders'], function (State, logme, GeneralMethods, Sliders) {
+ logme(GeneralMethods);
+
return GstMain;
function GstMain(gstId) {
- console.log('The DOM ID of the current GST element is ' + gstId);
+ var config, state;
+
+ config = JSON.parse($('#' + gstId + '_json').html()).root;
+
+ state = State(gstId, config);
+
+ Sliders(gstId, config, state);
}
});
diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/logme.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/logme.js
new file mode 100644
index 0000000000..c045757044
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/logme.js
@@ -0,0 +1,54 @@
+// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
+// define() functions from Require JS available inside the anonymous function.
+(function (requirejs, require, define) {
+
+define('logme', [], function () {
+ var debugMode;
+
+ // debugMode can be one of the following:
+ //
+ // true - All messages passed to logme will be written to the internal
+ // browser console.
+ // false - Suppress all output to the internal browser console.
+ //
+ // Obviously, if anywhere there is a direct console.log() call, we can't do
+ // anything about it. That's why use logme() - it will allow to turn off
+ // the output of debug information with a single change to a variable.
+ debugMode = true;
+
+ return logme;
+
+ /*
+ * function: logme
+ *
+ * A helper function that provides logging facilities. We don't want
+ * to call console.log() directly, because sometimes it is not supported
+ * by the browser. Also when everything is routed through this function.
+ * the logging output can be easily turned off.
+ *
+ * logme() supports multiple parameters. Each parameter will be passed to
+ * console.log() function separately.
+ *
+ */
+ function logme() {
+ var i;
+
+ if (
+ (typeof debugMode === 'undefined') ||
+ (debugMode !== true) ||
+ (typeof window.console === 'undefined')
+ ) {
+ return;
+ }
+
+ for (i = 0; i < arguments.length; i++) {
+ window.console.log(arguments[i]);
+ }
+ } // End-of: function logme
+});
+
+// End of wrapper for RequireJS. As you can see, we are passing
+// namespaced Require JS variables to an anonymous function. Within
+// it, you can use the standard requirejs(), require(), and define()
+// functions as if they were in the global namespace.
+}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod1.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod1.js
deleted file mode 100644
index 44674b96d3..0000000000
--- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod1.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
-// define() functions from Require JS available inside the anonymous function.
-(function (requirejs, require, define) {
-
-define('mod1', [], function () {
- console.log('we are in the mod1 callback');
- return {
- 'module_status': 'OK'
- };
-});
-
-// End of wrapper for RequireJS. As you can see, we are passing
-// namespaced Require JS variables to an anonymous function. Within
-// it, you can use the standard requirejs(), require(), and define()
-// functions as if they were in the global namespace.
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod2.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod2.js
deleted file mode 100644
index 9c26bb1dfe..0000000000
--- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod2.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
-// define() functions from Require JS available inside the anonymous function.
-(function (requirejs, require, define) {
-
-define('mod2', [], function () {
- console.log('we are in the mod2 callback');
- return {
- 'module_status': 'OK'
- };
-});
-
-// End of wrapper for RequireJS. As you can see, we are passing
-// namespaced Require JS variables to an anonymous function. Within
-// it, you can use the standard requirejs(), require(), and define()
-// functions as if they were in the global namespace.
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod4.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod4.js
deleted file mode 100644
index 0edf809155..0000000000
--- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod4.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
-// define() functions from Require JS available inside the anonymous function.
-(function (requirejs, require, define) {
-
-define('mod4', [], function () {
- console.log('we are in the mod4 callback');
- return {
- 'module_status': 'OK'
- };
-});
-
-// End of wrapper for RequireJS. As you can see, we are passing
-// namespaced Require JS variables to an anonymous function. Within
-// it, you can use the standard requirejs(), require(), and define()
-// functions as if they were in the global namespace.
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js
new file mode 100644
index 0000000000..6ef53bdbeb
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js
@@ -0,0 +1,142 @@
+// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
+// define() functions from Require JS available inside the anonymous function.
+(function (requirejs, require, define) {
+
+define('Sliders', ['logme'], function (logme) {
+ return Sliders;
+
+ function Sliders(gstId, config, state) {
+ logme('We are inside Sliders function.');
+
+ logme('gstId: ' + gstId);
+ logme(config);
+ logme(state);
+
+ // We will go through all of the sliders. For each one, we will make a
+ // jQuery UI slider for it, attach "on change" events, and set it's
+ // state - initial value, max, and min parameters.
+ if ((typeof config.sliders !== 'undefined') &&
+ (typeof config.sliders.slider !== 'undefined')) {
+ if ($.isArray(config.sliders.slider)) {
+ // config.sliders.slider is an array
+
+ for (c1 = 0; c1 < config.sliders.slider.length; c1++) {
+ createSlider(config.sliders.slider[c1]);
+ }
+ } else if ($.isPlainObject(config.sliders.slider)) {
+ // config.sliders.slider is an object
+ createSlider(config.sliders.slider);
+ }
+ }
+
+ function createSlider(obj) {
+ var constName, constValue, rangeBlobs, valueMin, valueMax,
+ sliderDiv, sliderWidth;
+
+ // The name of the constant is obj['@var']. Multiple sliders and/or
+ // inputs can represent the same constant - therefore we will get
+ // the most recent const value from the state object. The range is
+ // a string composed of 3 blobs, separated by commas. The first
+ // blob is the min value for the slider, the third blob is the max
+ // value for the slider.
+
+ if (typeof obj['@var'] === 'undefined') {
+ return;
+ }
+
+ constName = obj['@var'];
+
+ constValue = state.getConstValue(constName);
+ if (constValue === undefined) {
+ constValue = 0;
+ }
+
+ if (typeof obj['@range'] !== 'string') {
+ valueMin = constValue - 10;
+ valueMax = constValue + 10;
+ } else {
+ rangeBlobs = obj['@range'].split(',');
+
+ // We must have gotten exactly 3 blobs (pieces) from the split.
+ if (rangeBlobs.length !== 3) {
+ valueMin = constValue - 10;
+ valueMax = constValue + 10;
+ } else {
+ // Get the first blob from the split string.
+ valueMin = parseFloat(rangeBlobs[0]);
+
+ if (isNaN(valueMin) === true) {
+ valueMin = constValue - 10;
+ }
+
+ // Get the third blob from the split string.
+ valueMax = parseFloat(rangeBlobs[2]);
+
+ if (isNaN(valueMax) === true) {
+ valueMax = constValue + 10;
+ }
+
+ // Logically, the min, value, and max should make sense.
+ // I.e. we will make sure that:
+ //
+ // min <= value <= max
+ //
+ // If this is not the case, we will set some defaults.
+ if ((valueMin > valueMax) ||
+ (valueMin > constValue) ||
+ (valueMax < constValue)) {
+ valueMin = constValue - 10;
+ valueMax = constValue + 10;
+ }
+ }
+ }
+
+ sliderDiv = $('#' + gstId + '_slider_' + constName);
+
+ // If a corresponding slider DIV for this constant does not exist,
+ // do not do anything.
+ if (sliderDiv.length === 0) {
+ return;
+ }
+
+ // The default slider width.
+ sliderWidth = 400;
+
+ logme('width: 0');
+ logme(obj['@width']);
+ if (typeof obj['@width'] === 'string') {
+ logme('width: 1');
+ if (isNaN(parseInt(obj['@width'], 10)) === false) {
+ logme('width: 2');
+ sliderWidth = parseInt(obj['@width'], 10);
+ }
+ }
+
+ // Set the new width to the slider.
+ sliderDiv.width(sliderWidth);
+
+ // Create a jQuery UI slider from the current DIV. We will set
+ // starting parameters, and will also attach a handler to update
+ // the state on the change event.
+ sliderDiv.slider({
+ 'min': valueMin,
+ 'max': valueMax,
+ 'value': constValue,
+
+ 'change': sliderOnChange
+ });
+
+ return;
+
+ function sliderOnChange(event, ui) {
+ state.setConstValue(constName, ui.value);
+ }
+ }
+ }
+});
+
+// End of wrapper for RequireJS. As you can see, we are passing
+// namespaced Require JS variables to an anonymous function. Within
+// it, you can use the standard requirejs(), require(), and define()
+// functions as if they were in the global namespace.
+}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js
new file mode 100644
index 0000000000..17c8721a73
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js
@@ -0,0 +1,165 @@
+// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
+// define() functions from Require JS available inside the anonymous function.
+(function (requirejs, require, define) {
+
+define('State', ['logme'], function (logme) {
+ // Since there will be (can be) multiple GST on a page, and each will have
+ // a separate state, we will create a factory constructor function. The
+ // constructor will expect the ID of the DIV with the GST contents, and the
+ // configuration object (parsed from a JSON string). It will return and
+ // object containing methods to set and get the private state properties.
+
+ // This module defines and returns a factory constructor.
+ return State;
+
+ /*
+ * function: State
+ *
+ *
+ */
+ function State(gstId, config) {
+ var constants, c1;
+
+ constants = {};
+
+ // We must go through all of the input, and slider elements and
+ // retrieve all of the available constants. These will be added to an
+ // object as it's properties.
+ //
+ // First we will go through all of the inputs.
+ if ((typeof config.inputs !== 'undefined') &&
+ (typeof config.inputs.input !== 'undefined')) {
+ if ($.isArray(config.inputs.input)) {
+ // config.inputs.input is an array
+
+ for (c1 = 0; c1 < config.inputs.input.length; c1++) {
+ addConstFromInput(config.inputs.input[c1]);
+ }
+ } else if ($.isPlainObject(config.inputs.input)) {
+ // config.inputs.input is an object
+ addConstFromInput(config.inputs.input);
+ }
+ }
+
+ // Now we will go through all of the sliders.
+ if ((typeof config.sliders !== 'undefined') &&
+ (typeof config.sliders.slider !== 'undefined')) {
+ if ($.isArray(config.sliders.slider)) {
+ // config.sliders.slider is an array
+
+ for (c1 = 0; c1 < config.sliders.slider.length; c1++) {
+ addConstFromSlider(config.sliders.slider[c1]);
+ }
+ } else if ($.isPlainObject(config.sliders.slider)) {
+ // config.sliders.slider is an object
+ addConstFromSlider(config.sliders.slider);
+ }
+ }
+
+ logme(constants);
+
+ // The constructor will return an object with methods to operate on
+ // it's private properties.
+ return {
+ 'getConstValue': getConstValue,
+ 'setConstValue': setConstValue
+ };
+
+ function getConstValue(constName) {
+ if (constants.hasOwnProperty(constName) === false) {
+ // If the name of the constant is not tracked by state, return an
+ // 'undefined' value.
+ return;
+ }
+
+ return constants[constName];
+ }
+
+ function setConstValue(constName, constValue) {
+ if (constants.hasOwnProperty(constName) === false) {
+ // If the name of the constant is not tracked by state, return an
+ // 'undefined' value.
+ return;
+ }
+
+ if (isNaN(parseFloat(constValue)) === true) {
+ // We are interested only in valid float values.
+ return;
+ }
+
+ constants[constName] = parseFloat(constValue);
+
+ logme('From setConstValue: new value for "' + constName + '" is ' + constValue);
+ }
+
+ function addConstFromInput(obj) {
+ var constName, constValue;
+
+ // The name of the constant is obj['@var']. The value (initial) of
+ // the constant is obj['@initial']. I have taken the word 'initial'
+ // into brackets, because multiple inputs and/or sliders can
+ // represent the state of a single constant.
+
+ if (typeof obj['@var'] === 'undefined') {
+ return;
+ }
+
+ constName = obj['@var'];
+
+ if (typeof obj['@initial'] === 'undefined') {
+ constValue = 0;
+ } else {
+ constValue = parseFloat(obj['@initial']);
+
+ if (isNaN(constValue) === true) {
+ constValue = 0;
+ }
+ }
+
+ constants[constName] = constValue;
+ }
+
+ function addConstFromSlider(obj) {
+ var constName, constValue, rangeBlobs;
+
+ // The name of the constant is obj['@var']. The value (initial) of
+ // the constant is the second blob of the 'range' parameter of the
+ // slider which is obj['@range']. Multiple sliders and/or inputs
+ // can represent the same constant - therefore 'initial' is in
+ // brackets. The range is a string composed of 3 blobs, separated
+ // by commas.
+
+ if (typeof obj['@var'] === 'undefined') {
+ return;
+ }
+
+ constName = obj['@var'];
+
+ if (typeof obj['@range'] !== 'string') {
+ constValue = 0;
+ } else {
+ rangeBlobs = obj['@range'].split(',');
+
+ // We must have gotten exactly 3 blobs (pieces) from the split.
+ if (rangeBlobs.length !== 3) {
+ constValue = 0;
+ } else {
+ // Get the second blob from the split string.
+ constValue = parseFloat(rangeBlobs[1]);
+
+ if (isNaN(constValue) === true) {
+ constValue = 0;
+ }
+ }
+ }
+
+ constants[constName] = constValue;
+ }
+ } // End-of: function State
+});
+
+// End of wrapper for RequireJS. As you can see, we are passing
+// namespaced Require JS variables to an anonymous function. Within
+// it, you can use the standard requirejs(), require(), and define()
+// functions as if they were in the global namespace.
+}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
diff --git a/lms/templates/graphical_slider_tool.html b/lms/templates/graphical_slider_tool.html
index d6cffc67e2..17d2bae5e9 100644
--- a/lms/templates/graphical_slider_tool.html
+++ b/lms/templates/graphical_slider_tool.html
@@ -1,12 +1,14 @@
-
-
+
+
+ ${configuration_json}
+
-
-
+
+
+ ${plot_code}
+
-
+
${gst_html}