From c5107d42de7d3cafef4c7f0fec8f7785aa7f50fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Mon, 26 Nov 2012 17:38:59 +0200 Subject: [PATCH 001/107] bug --- common/lib/xmodule/setup.py | 1 + common/lib/xmodule/xmodule/gst_module.py | 141 +++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 common/lib/xmodule/xmodule/gst_module.py diff --git a/common/lib/xmodule/setup.py b/common/lib/xmodule/setup.py index c867fca228..8deb2a7ce5 100644 --- a/common/lib/xmodule/setup.py +++ b/common/lib/xmodule/setup.py @@ -36,6 +36,7 @@ setup( "videodev = xmodule.backcompat_module:TranslateCustomTagDescriptor", "videosequence = xmodule.seq_module:SequenceDescriptor", "discussion = xmodule.discussion_module:DiscussionDescriptor", + "gst = xmodule.gst_module:GSTDescriptor", ] } ) diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py new file mode 100644 index 0000000000..8847a5224c --- /dev/null +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -0,0 +1,141 @@ +""" +GST (Graphical-Slider-Tool) module is ungraded xmodule used by students to +understand functional dependencies +""" + +# import json +import logging + +from lxml import etree + +from xmodule.mako_module import MakoModuleDescriptor +from xmodule.xml_module import XmlDescriptor +from xmodule.x_module import XModule +from xmodule.progress import Progress +from xmodule.exceptions import NotFoundError +from pkg_resources import resource_string +from xmodule.raw_module import RawDescriptor + +# log = logging.getLogger("mitx.common.lib.seq_module") + + +class GSTModule(XModule): + ''' Graphical-Slider-Tool Module + ''' + # js = {'js': [resource_string(__name__, 'js/src/gst/gst.js')]} + # #css = {'scss': [resource_string(__name__, 'css/capa/display.scss')]} + # js_module_name = "GST" + + def __init__(self, system, location, definition, descriptor, instance_state=None, + shared_state=None, **kwargs): + """ + pass + # Definition should have.... + # sliders, text, module + + # Sample file: + + # + #

Plot...

+ # + # + # + # + # + # + # + # + #
+ # """ + # XModule.__init__(self, system, location, definition, descriptor, + # instance_state, shared_state, **kwargs) + # import ipdb; ipdb.set_trace() + # self.rendered = False + + # def get_html(self): + # self.render() + # return self.content + + # def render(self): + # import ipdb; ipdb.set_trace() + # if self.rendered: + # return + # ## Returns a set of all types of all sub-children + # contents = [] + # # import ipdb; ipdb.set_trace() + # for child in self.get_display_items(): + # progress = child.get_progress() + # childinfo = { + # 'gst': child.get_html(), + # 'plot': "\n".join( + # grand_child.display_name.strip() + # for grand_child in child.get_children() + # if 'display_name' in grand_child.metadata + # ), + # # 'progress_status': Progress.to_js_status_str(progress), + # 'progress_detail': Progress.to_js_detail_str(progress), + # 'type': child.get_icon_class(), + # } + # # if childinfo['title']=='': + # # childinfo['title'] = child.metadata.get('display_name','') + # contents.append(childinfo) + + # params = {'items': contents, + # 'element_id': self.location.html_id(), + # 'item_id': self.id, + # 'position': self.position, + # 'tag': self.location.category + # } + + # self.content = self.system.render_template('seq_module.html', params) + # self.rendered = True + + +class GSTDescriptor(RawDescriptor): + mako_template = "widgets/html-edit.html" + module_class = GSTModule + template_dir_name = 'gst' + + # @classmethod + # def definition_from_xml(cls, xml_object, system): + # """ + # Pull out the data into dictionary. + + # Returns: + # { + # 'def1': 'def1-some-html', + # 'def2': 'def2-some-html' + # } + # """ + # import ipdb; ipdb.set_trace() + # children = [] + # for child in xml_object: + # try: + # children.append(system.process_xml(etree.tostring(child)).location.url()) + # except: + # log.exception("Unable to load child when parsing GST. Continuing...") + # continue + # return {'children': children} + + # def definition_to_xml(self, resource_fs): + # '''Return an xml element representing this definition.''' + # import ipdb; ipdb.set_trace() + # xml_object = etree.Element('gst') + + # def add_child(k): + # # child_str = '<{tag}>{body}'.format(tag=k, body=self.definition[k]) + # child_str = child.export_to_xml(resource_fs) + # child_node = etree.fromstring(child_str) + # xml_object.append(child_node) + + # for child in self.get_children(): + # add_child(child) + + # return xml_object + + + # def __init__(self, system, definition, **kwargs): + # '''Render and save the template for this descriptor instance''' + # super(CustomTagDescriptor, self).__init__(system, definition, **kwargs) + # self.rendered_html = self.render_template(system, definition['data']) \ No newline at end of file From d0fcaf0ac4f2de72ce696e125905184eab934ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Mon, 26 Nov 2012 18:11:01 +0200 Subject: [PATCH 002/107] next step --- common/lib/xmodule/xmodule/gst_module.py | 71 ++++++++++++------------ 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py index 8847a5224c..285eeb8fce 100644 --- a/common/lib/xmodule/xmodule/gst_module.py +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -97,45 +97,46 @@ class GSTDescriptor(RawDescriptor): module_class = GSTModule template_dir_name = 'gst' - # @classmethod - # def definition_from_xml(cls, xml_object, system): - # """ - # Pull out the data into dictionary. + @classmethod + def definition_from_xml(cls, xml_object, system): + """ + Pull out the data into dictionary. - # Returns: - # { - # 'def1': 'def1-some-html', - # 'def2': 'def2-some-html' - # } - # """ - # import ipdb; ipdb.set_trace() - # children = [] - # for child in xml_object: - # try: - # children.append(system.process_xml(etree.tostring(child)).location.url()) - # except: - # log.exception("Unable to load child when parsing GST. Continuing...") - # continue - # return {'children': children} + Returns: + { + 'def1': 'def1-some-html', + 'def2': 'def2-some-html' + } + """ + import ipdb; ipdb.set_trace() + children = [] + for child in xml_object: + try: + children.append(system.process_xml(etree.tostring(child)).location.url()) + except: + log.exception("Unable to load child when parsing GST. Continuing...") + continue + return {'children': children} - # def definition_to_xml(self, resource_fs): - # '''Return an xml element representing this definition.''' - # import ipdb; ipdb.set_trace() - # xml_object = etree.Element('gst') + def definition_to_xml(self, resource_fs): + '''Return an xml element representing this definition.''' + import ipdb; ipdb.set_trace() + xml_object = etree.Element('gst') - # def add_child(k): - # # child_str = '<{tag}>{body}'.format(tag=k, body=self.definition[k]) - # child_str = child.export_to_xml(resource_fs) - # child_node = etree.fromstring(child_str) - # xml_object.append(child_node) + def add_child(k): + # child_str = '<{tag}>{body}'.format(tag=k, body=self.definition[k]) + child_str = child.export_to_xml(resource_fs) + child_node = etree.fromstring(child_str) + xml_object.append(child_node) - # for child in self.get_children(): - # add_child(child) + for child in self.get_children(): + add_child(child) - # return xml_object + return xml_object - # def __init__(self, system, definition, **kwargs): - # '''Render and save the template for this descriptor instance''' - # super(CustomTagDescriptor, self).__init__(system, definition, **kwargs) - # self.rendered_html = self.render_template(system, definition['data']) \ No newline at end of file + def __init__(self, system, definition, **kwargs): + '''Render and save the template for this descriptor instance''' + import ipdb; ipdb.set_trace() + super(CustomTagDescriptor, self).__init__(system, definition, **kwargs) + self.rendered_html = self.render_template(system, definition['data']) \ No newline at end of file From 884db888f953d651d18a1f4cf5445da436451bdd Mon Sep 17 00:00:00 2001 From: Alexander Kryklia Date: Wed, 28 Nov 2012 16:48:07 +0200 Subject: [PATCH 003/107] teting gst --- common/lib/xmodule/xmodule/gst_module.py | 128 +++++++++++------------ 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py index 285eeb8fce..f5b2095d95 100644 --- a/common/lib/xmodule/xmodule/gst_module.py +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -29,70 +29,70 @@ class GSTModule(XModule): def __init__(self, system, location, definition, descriptor, instance_state=None, shared_state=None, **kwargs): """ - pass - # Definition should have.... - # sliders, text, module + Definition should have.... + sliders, text, module - # Sample file: + Sample file: - # - #

Plot...

- # - # - # - # - # - # - # - # - #
- # """ - # XModule.__init__(self, system, location, definition, descriptor, - # instance_state, shared_state, **kwargs) - # import ipdb; ipdb.set_trace() - # self.rendered = False + +

Plot...

+ + + + + + + + +
+ """ + XModule.__init__(self, system, location, definition, descriptor, + instance_state, shared_state, **kwargs) + # import ipdb; ipdb.set_trace() + # self.rendered = False - # def get_html(self): - # self.render() - # return self.content + def get_html(self): + self.render() + return self.content - # def render(self): - # import ipdb; ipdb.set_trace() - # if self.rendered: - # return - # ## Returns a set of all types of all sub-children - # contents = [] - # # import ipdb; ipdb.set_trace() - # for child in self.get_display_items(): - # progress = child.get_progress() - # childinfo = { - # 'gst': child.get_html(), - # 'plot': "\n".join( - # grand_child.display_name.strip() - # for grand_child in child.get_children() - # if 'display_name' in grand_child.metadata - # ), - # # 'progress_status': Progress.to_js_status_str(progress), - # 'progress_detail': Progress.to_js_detail_str(progress), - # 'type': child.get_icon_class(), - # } - # # if childinfo['title']=='': - # # childinfo['title'] = child.metadata.get('display_name','') - # contents.append(childinfo) + def render(self): + # import ipdb; ipdb.set_trace() + # if self.rendered: + return + ## Returns a set of all types of all sub-children + # contents = [] + # # import ipdb; ipdb.set_trace() + # for child in self.get_display_items(): + # progress = child.get_progress() + # childinfo = { + # 'gst': child.get_html(), + # 'plot': "\n".join( + # grand_child.display_name.strip() + # for grand_child in child.get_children() + # if 'display_name' in grand_child.metadata + # ), + # # 'progress_status': Progress.to_js_status_str(progress), + # 'progress_detail': Progress.to_js_detail_str(progress), + # 'type': child.get_icon_class(), + # } + # # if childinfo['title']=='': + # # childinfo['title'] = child.metadata.get('display_name','') + # contents.append(childinfo) - # params = {'items': contents, - # 'element_id': self.location.html_id(), - # 'item_id': self.id, - # 'position': self.position, - # 'tag': self.location.category - # } - - # self.content = self.system.render_template('seq_module.html', params) - # self.rendered = True + # params = {'items': contents, + # 'element_id': self.location.html_id(), + # 'item_id': self.id, + # 'position': self.position, + # 'tag': self.location.category + # } + params= {} + self.content = self.system.render_template('gst_module.html', params) + # self.rendered = True -class GSTDescriptor(RawDescriptor): +# class GSTDescriptor(RawDescriptor): +class GSTDescriptor(MakoModuleDescriptor, XmlDescriptor): mako_template = "widgets/html-edit.html" module_class = GSTModule template_dir_name = 'gst' @@ -108,7 +108,7 @@ class GSTDescriptor(RawDescriptor): 'def2': 'def2-some-html' } """ - import ipdb; ipdb.set_trace() + # import ipdb; ipdb.set_trace() children = [] for child in xml_object: try: @@ -120,7 +120,7 @@ class GSTDescriptor(RawDescriptor): def definition_to_xml(self, resource_fs): '''Return an xml element representing this definition.''' - import ipdb; ipdb.set_trace() + # import ipdb; ipdb.set_trace() xml_object = etree.Element('gst') def add_child(k): @@ -135,8 +135,8 @@ class GSTDescriptor(RawDescriptor): return xml_object - def __init__(self, system, definition, **kwargs): - '''Render and save the template for this descriptor instance''' - import ipdb; ipdb.set_trace() - super(CustomTagDescriptor, self).__init__(system, definition, **kwargs) - self.rendered_html = self.render_template(system, definition['data']) \ No newline at end of file + # def __init__(self, system, definition, **kwargs): + # '''Render and save the template for this descriptor instance''' + # # import ipdb; ipdb.set_trace() + # super(GSTDescriptor, self).__init__(system, definition, **kwargs) + # self.rendered_html = self.render_template(system, definition['data']) \ No newline at end of file From 07cb76a7d99e822b4dbc9c140c6ad929c2bbbbc9 Mon Sep 17 00:00:00 2001 From: Alexander Kryklia Date: Thu, 29 Nov 2012 16:43:33 +0200 Subject: [PATCH 004/107] first working version of gst module --- common/lib/xmodule/setup.py | 2 +- common/lib/xmodule/xmodule/gst_module.py | 150 +++++++++++------------ 2 files changed, 73 insertions(+), 79 deletions(-) diff --git a/common/lib/xmodule/setup.py b/common/lib/xmodule/setup.py index 8deb2a7ce5..86636ef05a 100644 --- a/common/lib/xmodule/setup.py +++ b/common/lib/xmodule/setup.py @@ -36,7 +36,7 @@ setup( "videodev = xmodule.backcompat_module:TranslateCustomTagDescriptor", "videosequence = xmodule.seq_module:SequenceDescriptor", "discussion = xmodule.discussion_module:DiscussionDescriptor", - "gst = xmodule.gst_module:GSTDescriptor", + "graphical_slider_tool = xmodule.gst_module:GraphicalSliderToolDescriptor", ] } ) diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py index f5b2095d95..d90bc46e6e 100644 --- a/common/lib/xmodule/xmodule/gst_module.py +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -1,6 +1,6 @@ """ -GST (Graphical-Slider-Tool) module is ungraded xmodule used by students to -understand functional dependencies +Graphical slider tool module is ungraded xmodule used by students to +understand functional dependencies. """ # import json @@ -15,11 +15,12 @@ from xmodule.progress import Progress from xmodule.exceptions import NotFoundError from pkg_resources import resource_string from xmodule.raw_module import RawDescriptor +from xmodule.stringify import stringify_children # log = logging.getLogger("mitx.common.lib.seq_module") -class GSTModule(XModule): +class GraphicalSliderToolModule(XModule): ''' Graphical-Slider-Tool Module ''' # js = {'js': [resource_string(__name__, 'js/src/gst/gst.js')]} @@ -34,92 +35,92 @@ class GSTModule(XModule): Sample file: - -

Plot...

- - - - - - - - -
+ + + + + Graphic slider tool html. Can include + 'number', 'slider' and plot tags. They will be replaced + by proper number, slider and plot widgets. + + + + + + + + + + + + + -10, 1, 10 + + 1 + 1 + + + + + + """ XModule.__init__(self, system, location, definition, descriptor, instance_state, shared_state, **kwargs) - # import ipdb; ipdb.set_trace() - # self.rendered = False def get_html(self): - self.render() + params = { + 'main_html': self.definition['render'].strip(), + 'element_id': self.location.html_id(), + 'element_class': self.location.category + } + self.content = (self.system.render_template( + 'graphical_slider_tool.html', params)) return self.content - def render(self): - # import ipdb; ipdb.set_trace() - # if self.rendered: - return - ## Returns a set of all types of all sub-children - # contents = [] - # # import ipdb; ipdb.set_trace() - # for child in self.get_display_items(): - # progress = child.get_progress() - # childinfo = { - # 'gst': child.get_html(), - # 'plot': "\n".join( - # grand_child.display_name.strip() - # for grand_child in child.get_children() - # if 'display_name' in grand_child.metadata - # ), - # # 'progress_status': Progress.to_js_status_str(progress), - # 'progress_detail': Progress.to_js_detail_str(progress), - # 'type': child.get_icon_class(), - # } - # # if childinfo['title']=='': - # # childinfo['title'] = child.metadata.get('display_name','') - # contents.append(childinfo) - # params = {'items': contents, - # 'element_id': self.location.html_id(), - # 'item_id': self.id, - # 'position': self.position, - # 'tag': self.location.category - # } - params= {} - self.content = self.system.render_template('gst_module.html', params) - # self.rendered = True - - -# class GSTDescriptor(RawDescriptor): -class GSTDescriptor(MakoModuleDescriptor, XmlDescriptor): - mako_template = "widgets/html-edit.html" - module_class = GSTModule - template_dir_name = 'gst' +class GraphicalSliderToolDescriptor(MakoModuleDescriptor, XmlDescriptor): + module_class = GraphicalSliderToolModule + template_dir_name = 'graphical_slider_tool' @classmethod def definition_from_xml(cls, xml_object, system): """ Pull out the data into dictionary. + Args: + xml_object: xml from file. + Returns: - { - 'def1': 'def1-some-html', - 'def2': 'def2-some-html' - } + dict """ - # import ipdb; ipdb.set_trace() - children = [] - for child in xml_object: - try: - children.append(system.process_xml(etree.tostring(child)).location.url()) - except: - log.exception("Unable to load child when parsing GST. Continuing...") - continue - return {'children': children} + # check for presense of required tags in xml + expected_children_level_0 = ['render', 'configuration'] + for child in expected_children_level_0: + if len(xml_object.xpath(child)) != 1: + raise ValueError("Self a\ssessment definition must include \ + exactly one '{0}' tag".format(child)) + expected_children_level_1 = ['plot'] + for child in expected_children_level_1: + if len(xml_object.xpath('configuration')[0].xpath(child)) != 1: + raise ValueError("Self a\ssessment definition must include \ + exactly one '{0}' tag".format(child)) + # finished + + def parse(k): + """Assumes that xml_object has child k""" + return stringify_children(xml_object.xpath(k)[0]) + + return { + 'render': parse('render'), + 'configuration': xml_object.xpath('configuration')[0], + } def definition_to_xml(self, resource_fs): - '''Return an xml element representing this definition.''' + '''Return an xml element representing this definition. + Not implemented''' # import ipdb; ipdb.set_trace() xml_object = etree.Element('gst') @@ -133,10 +134,3 @@ class GSTDescriptor(MakoModuleDescriptor, XmlDescriptor): add_child(child) return xml_object - - - # def __init__(self, system, definition, **kwargs): - # '''Render and save the template for this descriptor instance''' - # # import ipdb; ipdb.set_trace() - # super(GSTDescriptor, self).__init__(system, definition, **kwargs) - # self.rendered_html = self.render_template(system, definition['data']) \ No newline at end of file From 54c222a0153073126a74cec3acb050a3e578e24e Mon Sep 17 00:00:00 2001 From: Alexander Kryklia Date: Thu, 29 Nov 2012 16:44:10 +0200 Subject: [PATCH 005/107] template for gst --- lms/templates/graphical_slider_tool.html | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 lms/templates/graphical_slider_tool.html diff --git a/lms/templates/graphical_slider_tool.html b/lms/templates/graphical_slider_tool.html new file mode 100644 index 0000000000..cb484d9e6c --- /dev/null +++ b/lms/templates/graphical_slider_tool.html @@ -0,0 +1,3 @@ +
+${main_html} +
From 169d4b123ca9f803ab7b5381a4c4450ece1719a8 Mon Sep 17 00:00:00 2001 From: Alexander Kryklia Date: Fri, 30 Nov 2012 14:55:00 +0200 Subject: [PATCH 006/107] updates --- common/lib/xmodule/xmodule/gst_module.py | 50 +++++++++++++++++++----- lms/templates/graphical_slider_tool.html | 14 ++++++- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py index d90bc46e6e..e98b7b6c90 100644 --- a/common/lib/xmodule/xmodule/gst_module.py +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -3,21 +3,19 @@ Graphical slider tool module is ungraded xmodule used by students to understand functional dependencies. """ -# import json +import json import logging - from lxml import etree +import xmltodict +import re from xmodule.mako_module import MakoModuleDescriptor from xmodule.xml_module import XmlDescriptor from xmodule.x_module import XModule -from xmodule.progress import Progress -from xmodule.exceptions import NotFoundError -from pkg_resources import resource_string -from xmodule.raw_module import RawDescriptor from xmodule.stringify import stringify_children -# log = logging.getLogger("mitx.common.lib.seq_module") + +log = logging.getLogger("mitx.common.lib.gst_module") class GraphicalSliderToolModule(XModule): @@ -71,15 +69,49 @@ class GraphicalSliderToolModule(XModule): instance_state, shared_state, **kwargs) def get_html(self): + self.get_configuration() + gst_html = self.substitute_controls(self.definition['render'].strip()) + params = { - 'main_html': self.definition['render'].strip(), + 'gst_html': gst_html, 'element_id': self.location.html_id(), - 'element_class': self.location.category + 'element_class': self.location.category, + 'configuration_json': self.configuration_json } self.content = (self.system.render_template( 'graphical_slider_tool.html', params)) + # import ipdb; ipdb.set_trace() return self.content + def substitute_controls(self, html_string): + """ Substitue control element via their divs. + Simple variant: slider and plot controls are not inside any tag. + """ + plot_div = '
\ + This is plot
' + html_string.replace('$plot$', plot_div) + vars = [x['@var'] for x in json.loads(self.configuration_json)['root']['sliders']['slider']] + for var in vars: + m = re.match('$slider\[([0-9]+),([0-9]+)]', self.value.strip().replace(' ', '')) + if m: + # Note: we subtract 15 to compensate for the size of the dot on the screen. + # (is a 30x30 image--lms/static/green-pointer.png). + (self.gx, self.gy) = [int(x) - 15 for x in m.groups()] + html.replace('$slider' + ' ' + x['@var']) + return html_string + + def get_configuration(self): + """Parse self.definition['configuration'] and transfer it to javascript + via json. + """ + # root added for interface compatibility with xmltodict.parse + self.configuration_json = json.dumps( + xmltodict.parse('' + + stringify_children(self.definition['configuration']) + + '')) + return self.configuration_json + class GraphicalSliderToolDescriptor(MakoModuleDescriptor, XmlDescriptor): module_class = GraphicalSliderToolModule diff --git a/lms/templates/graphical_slider_tool.html b/lms/templates/graphical_slider_tool.html index cb484d9e6c..7d6cc292c5 100644 --- a/lms/templates/graphical_slider_tool.html +++ b/lms/templates/graphical_slider_tool.html @@ -1,3 +1,13 @@ -
-${main_html} +
+ +
+ + +${gst_html} + + +{# widgests
#} + +
From 69d0156c36c9316b365aa6128d09c737f3b78177 Mon Sep 17 00:00:00 2001 From: Alexander Kryklia Date: Fri, 30 Nov 2012 17:17:32 +0200 Subject: [PATCH 007/107] slider, plot and input contrlos are transferred from xml to html substituted to proper div elements --- common/lib/xmodule/xmodule/gst_module.py | 50 ++++++++++++++++++------ lms/templates/graphical_slider_tool.html | 7 +--- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py index e98b7b6c90..2d65b768ec 100644 --- a/common/lib/xmodule/xmodule/gst_module.py +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -70,12 +70,14 @@ class GraphicalSliderToolModule(XModule): def get_html(self): self.get_configuration() + self.html_id = self.location.html_id() + self.html_class = self.location.category gst_html = self.substitute_controls(self.definition['render'].strip()) - + params = { 'gst_html': gst_html, - 'element_id': self.location.html_id(), - 'element_class': self.location.category, + 'element_id': self.html_id, + 'element_class': self.html_class, 'configuration_json': self.configuration_json } self.content = (self.system.render_template( @@ -87,18 +89,44 @@ class GraphicalSliderToolModule(XModule): """ Substitue control element via their divs. Simple variant: slider and plot controls are not inside any tag. """ + #substitute plot plot_div = '
\ This is plot
' - html_string.replace('$plot$', plot_div) - vars = [x['@var'] for x in json.loads(self.configuration_json)['root']['sliders']['slider']] + html_string = html_string.replace('$plot$', plot_div) + + # substitute sliders + sliders = json.loads(self.configuration_json)['root']['sliders']['slider'] + if type(sliders) == dict: + sliders = [sliders] + vars = [x['@var'] for x in sliders] + + slider_div = '
This is slider
' + for var in vars: - m = re.match('$slider\[([0-9]+),([0-9]+)]', self.value.strip().replace(' ', '')) - if m: - # Note: we subtract 15 to compensate for the size of the dot on the screen. - # (is a 30x30 image--lms/static/green-pointer.png). - (self.gx, self.gy) = [int(x) - 15 for x in m.groups()] - html.replace('$slider' + ' ' + x['@var']) + html_string = re.sub(r'\$slider\s+' + var + r'\$', + slider_div.format(element_class=self.html_class, + element_id=self.html_id, + var=var), + html_string, flags=re.IGNORECASE | re.UNICODE) + + # substitute numbers + inputs = json.loads(self.configuration_json)['root']['inputs']['input'] + if type(inputs) == dict: + inputs = [inputs] + vars = [x['@var'] for x in inputs] + + input_div = '
This is input
' + + for var in vars: + html_string = re.sub(r'\$input\s+' + var + r'\$', + input_div.format(element_class=self.html_class, + element_id=self.html_id, + var=var), + html_string, flags=re.IGNORECASE | re.UNICODE) + # import ipdb; ipdb.set_trace() return html_string def get_configuration(self): diff --git a/lms/templates/graphical_slider_tool.html b/lms/templates/graphical_slider_tool.html index 7d6cc292c5..920e53cab3 100644 --- a/lms/templates/graphical_slider_tool.html +++ b/lms/templates/graphical_slider_tool.html @@ -1,13 +1,10 @@
+
+data-json="${configuration_json}">
${gst_html} - -{# widgests
#} - -
From 30df77b9b24131c9e5960a81838379844c11727e Mon Sep 17 00:00:00 2001 From: Alexander Kryklia Date: Fri, 30 Nov 2012 17:21:30 +0200 Subject: [PATCH 008/107] added xmltodict to dependencies --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index a3e1e3e6e5..08cfe57e2e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -56,3 +56,4 @@ dogstatsd-python==0.2.1 sphinx==1.1.3 Shapely==1.2.16 ipython==0.13.1 +xmltodict==0.4.1 From da4a676513e201290ce02bdd36b90725163068f6 Mon Sep 17 00:00:00 2001 From: Alexander Kryklia Date: Mon, 3 Dec 2012 15:08:37 +0200 Subject: [PATCH 009/107] working xmodule - GsT --- common/lib/xmodule/xmodule/gst_module.py | 68 +++++++++++++------ .../js/src/graphical_slider_tool/gst.js | 17 +++++ lms/templates/graphical_slider_tool.html | 12 ++++ 3 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst.js diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py index 2d65b768ec..60c03dec10 100644 --- a/common/lib/xmodule/xmodule/gst_module.py +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -13,6 +13,7 @@ from xmodule.mako_module import MakoModuleDescriptor from xmodule.xml_module import XmlDescriptor from xmodule.x_module import XModule from xmodule.stringify import stringify_children +from pkg_resources import resource_string log = logging.getLogger("mitx.common.lib.gst_module") @@ -21,9 +22,8 @@ log = logging.getLogger("mitx.common.lib.gst_module") class GraphicalSliderToolModule(XModule): ''' Graphical-Slider-Tool Module ''' - # js = {'js': [resource_string(__name__, 'js/src/gst/gst.js')]} - # #css = {'scss': [resource_string(__name__, 'css/capa/display.scss')]} - # js_module_name = "GST" + js = {'js': [resource_string(__name__, 'js/src/graphical_slider_tool/gst.js')]} + js_module_name = "GraphicalSliderTool" def __init__(self, system, location, definition, descriptor, instance_state=None, shared_state=None, **kwargs): @@ -37,30 +37,55 @@ class GraphicalSliderToolModule(XModule): - Graphic slider tool html. Can include - 'number', 'slider' and plot tags. They will be replaced - by proper number, slider and plot widgets. +

Graphic slider tool html.

+

Can include 'input', 'slider' and 'plot' tags. + They will be replaced by proper number, slider and plot + widgets.

+ For example: $slider a$, second $slider b$, + number $input a$, and, plot: + $plot$ + +
- + + + - - - + + + + - - - - -10, 1, 10 - - 1 - 1 + + + + + + + + -10, 10 + + 60 + + -9, 1, 9 + -9, 1, 9 + + + + +
@@ -73,12 +98,13 @@ class GraphicalSliderToolModule(XModule): self.html_id = self.location.html_id() self.html_class = self.location.category gst_html = self.substitute_controls(self.definition['render'].strip()) - + # import ipdb; ipdb.set_trace() params = { 'gst_html': gst_html, 'element_id': self.html_id, 'element_class': self.html_class, - 'configuration_json': self.configuration_json + 'configuration_json': self.configuration_json, + 'plot_code': self.definition['plot_code'] } self.content = (self.system.render_template( 'graphical_slider_tool.html', params)) @@ -157,11 +183,12 @@ class GraphicalSliderToolDescriptor(MakoModuleDescriptor, XmlDescriptor): dict """ # check for presense of required tags in xml - expected_children_level_0 = ['render', 'configuration'] + expected_children_level_0 = ['render', 'configuration', 'plot_code'] for child in expected_children_level_0: if len(xml_object.xpath(child)) != 1: raise ValueError("Self a\ssessment definition must include \ exactly one '{0}' tag".format(child)) + expected_children_level_1 = ['plot'] for child in expected_children_level_1: if len(xml_object.xpath('configuration')[0].xpath(child)) != 1: @@ -176,6 +203,7 @@ class GraphicalSliderToolDescriptor(MakoModuleDescriptor, XmlDescriptor): return { 'render': parse('render'), 'configuration': xml_object.xpath('configuration')[0], + 'plot_code': parse('plot_code'), } def definition_to_xml(self, resource_fs): diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst.js new file mode 100644 index 0000000000..03778ea437 --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst.js @@ -0,0 +1,17 @@ +// Graphical Slider Tool module + +(function() { + this.GraphicalSliderTool = (function() { + function GST(el) { + console.log(el); + // element is : + //
+ } + // console.log('in GST'); + return GST; + + })(); +}).call(this); +// this=window, after call +// window['Graphical_Slider_Tool'] is available. \ No newline at end of file diff --git a/lms/templates/graphical_slider_tool.html b/lms/templates/graphical_slider_tool.html index 920e53cab3..fc5052893a 100644 --- a/lms/templates/graphical_slider_tool.html +++ b/lms/templates/graphical_slider_tool.html @@ -4,7 +4,19 @@
+ +
+ ${gst_html}
+ + + From 643ac69a57af84733318fd06675a3f1126661ff2 Mon Sep 17 00:00:00 2001 From: valera-rozuvan Date: Wed, 5 Dec 2012 16:56:31 +0200 Subject: [PATCH 010/107] Separating JS from the html for GST. --- common/static/js/graphical_slider_tool/main.js | 1 + lms/templates/graphical_slider_tool.html | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 common/static/js/graphical_slider_tool/main.js diff --git a/common/static/js/graphical_slider_tool/main.js b/common/static/js/graphical_slider_tool/main.js new file mode 100644 index 0000000000..bb624d5888 --- /dev/null +++ b/common/static/js/graphical_slider_tool/main.js @@ -0,0 +1 @@ +alert('Hello, world!'); diff --git a/lms/templates/graphical_slider_tool.html b/lms/templates/graphical_slider_tool.html index fc5052893a..97fca83ff4 100644 --- a/lms/templates/graphical_slider_tool.html +++ b/lms/templates/graphical_slider_tool.html @@ -14,9 +14,9 @@ ${gst_html}
- From 0913e9ef69c6f12f5d87195c54d683de040bc82c Mon Sep 17 00:00:00 2001 From: valera-rozuvan Date: Wed, 5 Dec 2012 17:16:57 +0200 Subject: [PATCH 011/107] Work on GST. --- .../js/src/graphical_slider_tool/module.js | 15 ++++ .../js/graphical_slider_tool/gst_module.js | 15 ++++ .../static/js/graphical_slider_tool/main.js | 76 ++++++++++++++++++- lms/envs/common.py | 1 + lms/templates/graphical_slider_tool.html | 26 ++----- 5 files changed, 114 insertions(+), 19 deletions(-) create mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/module.js create mode 100644 common/static/js/graphical_slider_tool/gst_module.js diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/module.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/module.js new file mode 100644 index 0000000000..c4661b5e44 --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/module.js @@ -0,0 +1,15 @@ +// 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([], function () { + 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/static/js/graphical_slider_tool/gst_module.js b/common/static/js/graphical_slider_tool/gst_module.js new file mode 100644 index 0000000000..c4661b5e44 --- /dev/null +++ b/common/static/js/graphical_slider_tool/gst_module.js @@ -0,0 +1,15 @@ +// 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([], function () { + 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/static/js/graphical_slider_tool/main.js b/common/static/js/graphical_slider_tool/main.js index bb624d5888..da36d9c9d6 100644 --- a/common/static/js/graphical_slider_tool/main.js +++ b/common/static/js/graphical_slider_tool/main.js @@ -1 +1,75 @@ -alert('Hello, world!'); +// 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) { + +// For documentation please check: +// http://requirejs.org/docs/api.html +requirejs.config({ + // Because require.js is included as a simple From 5990fa2ef5e382465f2d042efbe5a44eba5a4762 Mon Sep 17 00:00:00 2001 From: Valera Rozuvan Date: Fri, 7 Dec 2012 17:25:24 +0200 Subject: [PATCH 012/107] Integrated RequireJS with xmodule for GST. --- common/lib/xmodule/xmodule/gst_module.py | 14 ++++++- .../js/src/graphical_slider_tool/gst.js | 37 ++++++++++--------- .../js/src/graphical_slider_tool/gst_main.js | 17 +++++++++ .../{module.js => mod1.js} | 3 +- .../js/src/graphical_slider_tool/mod2.js | 16 ++++++++ .../js/src/graphical_slider_tool/mod3.js | 19 ++++++++++ .../js/src/graphical_slider_tool/mod4.js | 16 ++++++++ .../js/src/graphical_slider_tool/mod5.js | 16 ++++++++ 8 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst_main.js rename common/lib/xmodule/xmodule/js/src/graphical_slider_tool/{module.js => mod1.js} (88%) create mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod2.js create mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod3.js create mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod4.js create mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod5.js diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py index 60c03dec10..f89cb0f990 100644 --- a/common/lib/xmodule/xmodule/gst_module.py +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -22,7 +22,19 @@ log = logging.getLogger("mitx.common.lib.gst_module") class GraphicalSliderToolModule(XModule): ''' Graphical-Slider-Tool Module ''' - js = {'js': [resource_string(__name__, 'js/src/graphical_slider_tool/gst.js')]} + + 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/mod5.js'), + + resource_string(__name__, 'js/src/graphical_slider_tool/gst.js') + ] + } js_module_name = "GraphicalSliderTool" def __init__(self, system, location, definition, descriptor, instance_state=None, diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst.js index 03778ea437..1434d05f70 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst.js @@ -1,17 +1,20 @@ -// Graphical Slider Tool module - -(function() { - this.GraphicalSliderTool = (function() { - function GST(el) { - console.log(el); - // element is : - //
- } - // console.log('in GST'); - return GST; - - })(); -}).call(this); -// this=window, after call -// window['Graphical_Slider_Tool'] is available. \ No newline at end of file +/* + * We will add a function that will be called for all GraphicalSliderTool + * xmodule module instances. It must be available globally by design of + * xmodule. + */ +window.GraphicalSliderTool = function (el) { + // All the work will be performed by the GstMain module. We will get access + // to it, and all it's dependencies, via Require JS. Currently Require JS + // is namespaced and is available via a global object RequireJS. + RequireJS.require(['GstMain'], function (GstMain) { + // The GstMain module expects the DOM ID of a Graphical Slider Tool + // element. Since we are given a
element which might in + // theory contain multiple graphical_slider_tool
elements (each + // with a unique DOM ID), we will iterate over all children, and for + // each match, we will call GstMain module. + $(el).children('.graphical_slider_tool').each(function (index, value) { + GstMain($(value).attr('id')); + }); + }); +}; 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 new file mode 100644 index 0000000000..66f98eddf7 --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst_main.js @@ -0,0 +1,17 @@ +// 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('GstMain', ['mod1', 'mod2', 'mod3', 'mod4'], function (mod1, mod2, mod3, mod4) { + return GstMain; + + function GstMain(gstId) { + console.log('The DOM ID of the current GST element is ' + gstId); + } +}); + +// 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/module.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod1.js similarity index 88% rename from common/lib/xmodule/xmodule/js/src/graphical_slider_tool/module.js rename to common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod1.js index c4661b5e44..44674b96d3 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/module.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod1.js @@ -2,7 +2,8 @@ // define() functions from Require JS available inside the anonymous function. (function (requirejs, require, define) { -define([], function () { +define('mod1', [], function () { + console.log('we are in the mod1 callback'); return { 'module_status': 'OK' }; 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 new file mode 100644 index 0000000000..9c26bb1dfe --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod2.js @@ -0,0 +1,16 @@ +// 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/mod3.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod3.js new file mode 100644 index 0000000000..21961f3611 --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod3.js @@ -0,0 +1,19 @@ +// 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('mod3', ['mod5'], function (mod5) { + console.log('we are in the mod3 callback'); + + console.log('mod5 status: [' + mod5.module_status + '].'); + + 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 new file mode 100644 index 0000000000..0edf809155 --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod4.js @@ -0,0 +1,16 @@ +// 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/mod5.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod5.js new file mode 100644 index 0000000000..5e843ac468 --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod5.js @@ -0,0 +1,16 @@ +// 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('mod5', [], function () { + console.log('we are in the mod5 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) From 080e96fdc481b95f9a50348c368872baacc17a12 Mon Sep 17 00:00:00 2001 From: Valera Rozuvan Date: Mon, 10 Dec 2012 08:28:34 +0200 Subject: [PATCH 013/107] Work in progress on GST. --- common/lib/xmodule/xmodule/gst_module.py | 14 +- .../{mod3.js => general_methods.js} | 12 +- .../js/src/graphical_slider_tool/gst_main.js | 12 +- .../js/src/graphical_slider_tool/logme.js | 54 ++++++ .../js/src/graphical_slider_tool/mod1.js | 16 -- .../js/src/graphical_slider_tool/mod2.js | 16 -- .../js/src/graphical_slider_tool/mod4.js | 16 -- .../js/src/graphical_slider_tool/sliders.js | 142 +++++++++++++++ .../js/src/graphical_slider_tool/state.js | 165 ++++++++++++++++++ lms/templates/graphical_slider_tool.html | 16 +- 10 files changed, 395 insertions(+), 68 deletions(-) rename common/lib/xmodule/xmodule/js/src/graphical_slider_tool/{mod3.js => general_methods.js} (65%) create mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/logme.js delete mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod1.js delete mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod2.js delete mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod4.js create mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js create mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js 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 @@
- -
+ + - -
+ + - + ${gst_html}
From ce7a01dd26b0f407487b4c78a27bad559b9699ae Mon Sep 17 00:00:00 2001 From: Valera Rozuvan Date: Mon, 10 Dec 2012 09:08:36 +0200 Subject: [PATCH 014/107] GST work in progress. --- common/lib/xmodule/xmodule/gst_module.py | 2 +- .../js/src/graphical_slider_tool/graph.js | 62 +++++++++++++++++++ .../js/src/graphical_slider_tool/gst_main.js | 7 ++- .../js/src/graphical_slider_tool/mod5.js | 16 ----- .../js/src/graphical_slider_tool/state.js | 8 +++ 5 files changed, 77 insertions(+), 18 deletions(-) create mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js delete mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod5.js diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py index 3d7b8a9f02..633f5e9406 100644 --- a/common/lib/xmodule/xmodule/gst_module.py +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -30,7 +30,7 @@ class GraphicalSliderToolModule(XModule): 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/graph.js'), resource_string(__name__, 'js/src/graphical_slider_tool/gst.js') ] diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js new file mode 100644 index 0000000000..2aa19cfc02 --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js @@ -0,0 +1,62 @@ +// 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('Graph', ['logme'], function (logme) { + + return Graph; + + function Graph(gstId, state) { + var plotDiv, data; + logme('We are inside Graph module.', gstId, state); + + plotDiv = $('#' + gstId + '_plot'); + + if (plotDiv.length === 0) { + return; + } + + plotDiv.width(300); + plotDiv.height(300); + + plotDiv.bind('update_plot', function (event, forGstId) { + if (forGstId !== gstId) { + logme('update_plot event not for current ID'); + } + + logme('redrawing plot'); + + generateData(); + updatePlot(); + }); + + generateData(); + updatePlot(); + + return; + + function generateData() { + var a, b, c1; + + a = state.getConstValue('a'); + b = state.getConstValue('b'); + + data = []; + data.push([]); + + for (c1 = 0; c1 < 30; c1++) { + data[0].push([c1, a * c1 * (c1 + a)* (c1 - b) + b * c1 * (c1 + b * a)]); + } + } + + function updatePlot() { + $.plot(plotDiv, data, {xaxis: {min: 0, max: 30}}); + } + } +}); + +// 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/gst_main.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst_main.js index 9f2c4c356d..68ef73e441 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,7 +2,10 @@ // define() functions from Require JS available inside the anonymous function. (function (requirejs, require, define) { -define('GstMain', ['State', 'logme', 'GeneralMethods', 'Sliders'], function (State, logme, GeneralMethods, Sliders) { +define( + 'GstMain', + ['State', 'logme', 'GeneralMethods', 'Sliders', 'Graph'], + function (State, logme, GeneralMethods, Sliders, Graph) { logme(GeneralMethods); return GstMain; @@ -15,6 +18,8 @@ define('GstMain', ['State', 'logme', 'GeneralMethods', 'Sliders'], function (Sta state = State(gstId, config); Sliders(gstId, config, state); + + Graph(gstId, state); } }); diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod5.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod5.js deleted file mode 100644 index 5e843ac468..0000000000 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/mod5.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('mod5', [], function () { - console.log('we are in the mod5 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/state.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js index 17c8721a73..ffd618c51b 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js @@ -76,6 +76,8 @@ define('State', ['logme'], function (logme) { } function setConstValue(constName, constValue) { + var plotDiv; + if (constants.hasOwnProperty(constName) === false) { // If the name of the constant is not tracked by state, return an // 'undefined' value. @@ -90,6 +92,12 @@ define('State', ['logme'], function (logme) { constants[constName] = parseFloat(constValue); logme('From setConstValue: new value for "' + constName + '" is ' + constValue); + + plotDiv = $('#' + gstId + '_plot'); + + if (plotDiv.length === 1) { + plotDiv.trigger('update_plot', [gstId]); + } } function addConstFromInput(obj) { From 7de575a84bf5f1915b5a58c0e0646e8c7f6e99e7 Mon Sep 17 00:00:00 2001 From: Valera Rozuvan Date: Mon, 10 Dec 2012 09:26:29 +0200 Subject: [PATCH 015/107] GST work in progress. --- .../js/src/graphical_slider_tool/graph.js | 18 ++++++++---------- .../js/src/graphical_slider_tool/state.js | 19 +++++++++++-------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js index 2aa19cfc02..fbd1f96da1 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js @@ -19,22 +19,20 @@ define('Graph', ['logme'], function (logme) { plotDiv.width(300); plotDiv.height(300); - plotDiv.bind('update_plot', function (event, forGstId) { - if (forGstId !== gstId) { - logme('update_plot event not for current ID'); - } - - logme('redrawing plot'); - - generateData(); - updatePlot(); - }); + state.bindUpdatePlotEvent(plotDiv, onUpdatePlot); generateData(); updatePlot(); return; + function onUpdatePlot(event) { + logme('redrawing plot'); + + generateData(); + updatePlot(); + } + function generateData() { var a, b, c1; 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 index ffd618c51b..735c100344 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js @@ -18,7 +18,7 @@ define('State', ['logme'], function (logme) { * */ function State(gstId, config) { - var constants, c1; + var constants, c1, plotDiv; constants = {}; @@ -62,9 +62,16 @@ define('State', ['logme'], function (logme) { // it's private properties. return { 'getConstValue': getConstValue, - 'setConstValue': setConstValue + 'setConstValue': setConstValue, + 'bindUpdatePlotEvent': bindUpdatePlotEvent }; + function bindUpdatePlotEvent(newPlotDiv, callback) { + plotDiv = newPlotDiv; + + plotDiv.bind('update_plot', callback); + } + function getConstValue(constName) { if (constants.hasOwnProperty(constName) === false) { // If the name of the constant is not tracked by state, return an @@ -76,8 +83,6 @@ define('State', ['logme'], function (logme) { } function setConstValue(constName, constValue) { - var plotDiv; - if (constants.hasOwnProperty(constName) === false) { // If the name of the constant is not tracked by state, return an // 'undefined' value. @@ -93,10 +98,8 @@ define('State', ['logme'], function (logme) { logme('From setConstValue: new value for "' + constName + '" is ' + constValue); - plotDiv = $('#' + gstId + '_plot'); - - if (plotDiv.length === 1) { - plotDiv.trigger('update_plot', [gstId]); + if (plotDiv !== undefined) { + plotDiv.trigger('update_plot'); } } From 32c70a524c3a3dca1cb1939b6417f9677ee8809b Mon Sep 17 00:00:00 2001 From: Valera Rozuvan Date: Mon, 10 Dec 2012 11:37:55 +0200 Subject: [PATCH 016/107] GST work in progress. --- .../js/src/graphical_slider_tool/graph.js | 95 ++++++++++++++++--- .../js/src/graphical_slider_tool/gst_main.js | 7 +- .../js/src/graphical_slider_tool/sliders.js | 12 +-- .../js/src/graphical_slider_tool/state.js | 34 +++++-- 4 files changed, 113 insertions(+), 35 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js index fbd1f96da1..762789cbf5 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js @@ -2,13 +2,12 @@ // define() functions from Require JS available inside the anonymous function. (function (requirejs, require, define) { -define('Graph', ['logme'], function (logme) { +define('Graph', [], function () { return Graph; - function Graph(gstId, state) { - var plotDiv, data; - logme('We are inside Graph module.', gstId, state); + function Graph(gstId, config, state) { + var plotDiv, dataSets, functions; plotDiv = $('#' + gstId + '_plot'); @@ -21,34 +20,102 @@ define('Graph', ['logme'], function (logme) { state.bindUpdatePlotEvent(plotDiv, onUpdatePlot); + createFunctions(); + generateData(); updatePlot(); return; - function onUpdatePlot(event) { - logme('redrawing plot'); + function createFunctions() { + functions = []; + if (typeof config.plot['function'] === 'undefined') { + return; + } + + if (typeof config.plot['function'] === 'string') { + addFunction(config.plot['function']); + } else if ($.isPlainObject(config.plot['function']) === true) { + + } else if ($.isArray(config.plot['function'])) { + + } + + return; + + function addFunction(funcString, color, line, dot, label, style, point_size) { + var newFunctionObject, func, constNames; + + if (typeof funcString !== 'string') { + return; + } + + newFunctionObject = {}; + + constNames = state.getAllConstantNames(); + + // The 'x' is always one of the function parameters. + constNames.push('x'); + + // Must make sure that the function body also gets passed to + // the Function cosntructor. + constNames.push(funcString); + + func = Function.apply(null, constNames); + newFunctionObject['func'] = func; + + if (typeof color === 'string') { + newFunctionObject['color'] = color; + } + + if (typeof line === 'boolean') { + newFunctionObject['line'] = line; + } + + if (typeof dot === 'boolean') { + newFunctionObject['dot'] = dot; + } + + if (typeof label === 'string') { + newFunctionObject['label'] = label; + } + + functions.push(newFunctionObject); + } + } + + function onUpdatePlot(event) { generateData(); updatePlot(); } function generateData() { - var a, b, c1; + var c0, c1, datapoints, constValues, x, y; - a = state.getConstValue('a'); - b = state.getConstValue('b'); + constValues = state.getAllConstantValues(); - data = []; - data.push([]); + dataSets = []; - for (c1 = 0; c1 < 30; c1++) { - data[0].push([c1, a * c1 * (c1 + a)* (c1 - b) + b * c1 * (c1 + b * a)]); + for (c0 = 0; c0 < functions.length; c0 += 1) { + datapoints = []; + + for (c1 = 0; c1 < 30; c1 += 0.1) { + x = c1; + // Push the 'x' variable to the end of the parameter array. + constValues.push(x); + y = functions[c0].func.apply(window, constValues); + constValues.pop(); + + datapoints.push([x, y]); + } + + dataSets.push(datapoints); } } function updatePlot() { - $.plot(plotDiv, data, {xaxis: {min: 0, max: 30}}); + $.plot(plotDiv, dataSets); } } }); 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 68ef73e441..71de12b423 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 @@ -4,9 +4,8 @@ define( 'GstMain', - ['State', 'logme', 'GeneralMethods', 'Sliders', 'Graph'], - function (State, logme, GeneralMethods, Sliders, Graph) { - logme(GeneralMethods); + ['State', 'GeneralMethods', 'Sliders', 'Graph'], + function (State, GeneralMethods, Sliders, Graph) { return GstMain; @@ -19,7 +18,7 @@ define( Sliders(gstId, config, state); - Graph(gstId, state); + Graph(gstId, config, state); } }); 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 index 6ef53bdbeb..e871e9f035 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js @@ -2,16 +2,10 @@ // define() functions from Require JS available inside the anonymous function. (function (requirejs, require, define) { -define('Sliders', ['logme'], function (logme) { +define('Sliders', [], function () { 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. @@ -102,12 +96,8 @@ define('Sliders', ['logme'], function (logme) { // 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); } } 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 index 735c100344..d632429c9b 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js @@ -2,7 +2,7 @@ // define() functions from Require JS available inside the anonymous function. (function (requirejs, require, define) { -define('State', ['logme'], function (logme) { +define('State', [], function () { // 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 @@ -56,16 +56,40 @@ define('State', ['logme'], function (logme) { } } - logme(constants); - // The constructor will return an object with methods to operate on // it's private properties. return { 'getConstValue': getConstValue, 'setConstValue': setConstValue, - 'bindUpdatePlotEvent': bindUpdatePlotEvent + 'bindUpdatePlotEvent': bindUpdatePlotEvent, + 'getAllConstantNames': getAllConstantNames, + 'getAllConstantValues': getAllConstantValues }; + function getAllConstantNames() { + var constName, allConstNames; + + allConstNames = []; + + for (constName in constants) { + allConstNames.push(constName); + } + + return allConstNames; + } + + function getAllConstantValues() { + var constName, allConstValues; + + allConstValues = []; + + for (constName in constants) { + allConstValues.push(constants[constName]); + } + + return allConstValues; + } + function bindUpdatePlotEvent(newPlotDiv, callback) { plotDiv = newPlotDiv; @@ -96,8 +120,6 @@ define('State', ['logme'], function (logme) { constants[constName] = parseFloat(constValue); - logme('From setConstValue: new value for "' + constName + '" is ' + constValue); - if (plotDiv !== undefined) { plotDiv.trigger('update_plot'); } From ae03090f3c980ce5b7c7ee5862f31acc86b08773 Mon Sep 17 00:00:00 2001 From: Valera Rozuvan Date: Mon, 10 Dec 2012 12:43:01 +0200 Subject: [PATCH 017/107] GST work in progress. --- common/lib/xmodule/xmodule/gst_module.py | 5 ++--- .../xmodule/xmodule/js/src/graphical_slider_tool/graph.js | 8 +++++++- .../xmodule/js/src/graphical_slider_tool/sliders.js | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py index 633f5e9406..c07c0670d7 100644 --- a/common/lib/xmodule/xmodule/gst_module.py +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -129,8 +129,7 @@ class GraphicalSliderToolModule(XModule): """ #substitute plot plot_div = '
\ - This is plot
' + style="width: 600px; height: 600px; padding: 0px; position: relative;">This is plot
' html_string = html_string.replace('$plot$', plot_div) # substitute sliders @@ -140,7 +139,7 @@ class GraphicalSliderToolModule(XModule): vars = [x['@var'] for x in sliders] slider_div = '
This is slider
' + data-var="{var}">' for var in vars: html_string = re.sub(r'\$slider\s+' + var + r'\$', diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js index 762789cbf5..991cb0a26e 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js @@ -28,6 +28,8 @@ define('Graph', [], function () { return; function createFunctions() { + var c1; + functions = []; if (typeof config.plot['function'] === 'undefined') { @@ -39,7 +41,11 @@ define('Graph', [], function () { } else if ($.isPlainObject(config.plot['function']) === true) { } else if ($.isArray(config.plot['function'])) { - + for (c1 = 0; c1 < config.plot['function'].length; c1++) { + if (typeof config.plot['function'][c1] === 'string') { + addFunction(config.plot['function'][c1]); + } + } } return; 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 index e871e9f035..226f53d696 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js @@ -112,6 +112,7 @@ define('Sliders', [], function () { 'min': valueMin, 'max': valueMax, 'value': constValue, + 'step': 0.01, 'change': sliderOnChange }); From 3e9d325a9f166901a2e24bc2dfe3942173f892c8 Mon Sep 17 00:00:00 2001 From: Valera Rozuvan Date: Mon, 10 Dec 2012 14:07:06 +0200 Subject: [PATCH 018/107] GST work in progress. --- common/lib/xmodule/xmodule/gst_module.py | 5 +- .../js/src/graphical_slider_tool/gst_main.js | 5 +- .../js/src/graphical_slider_tool/inputs.js | 70 +++++++++++++++++++ .../js/src/graphical_slider_tool/sliders.js | 1 + .../js/src/graphical_slider_tool/state.js | 7 ++ 5 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 common/lib/xmodule/xmodule/js/src/graphical_slider_tool/inputs.js diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py index c07c0670d7..9e9273bc25 100644 --- a/common/lib/xmodule/xmodule/gst_module.py +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -30,6 +30,7 @@ class GraphicalSliderToolModule(XModule): 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/inputs.js'), resource_string(__name__, 'js/src/graphical_slider_tool/graph.js'), resource_string(__name__, 'js/src/graphical_slider_tool/gst.js') @@ -154,8 +155,8 @@ class GraphicalSliderToolModule(XModule): inputs = [inputs] vars = [x['@var'] for x in inputs] - input_div = '
This is input
' + input_div = '' for var in vars: html_string = re.sub(r'\$input\s+' + var + r'\$', 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 71de12b423..47881b66c6 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 @@ -4,8 +4,8 @@ define( 'GstMain', - ['State', 'GeneralMethods', 'Sliders', 'Graph'], - function (State, GeneralMethods, Sliders, Graph) { + ['State', 'GeneralMethods', 'Sliders', 'Inputs', 'Graph'], + function (State, GeneralMethods, Sliders, Inputs, Graph) { return GstMain; @@ -17,6 +17,7 @@ define( state = State(gstId, config); Sliders(gstId, config, state); + Inputs(gstId, config, state); Graph(gstId, config, state); } diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/inputs.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/inputs.js new file mode 100644 index 0000000000..5b9f1f87c2 --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/inputs.js @@ -0,0 +1,70 @@ +// 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('Inputs', ['logme'], function (logme) { + return Inputs; + + function Inputs(gstId, config, state) { + logme('Inside "Inputs" module.'); + logme(gstId, config, state); + + // We will go thorugh all of the inputs, and those that have a valid + // '@var' property will be added to the page as a HTML text input + // element. + 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++) { + createInput(config.inputs.input[c1]); + } + } else if ($.isPlainObject(config.inputs.input)) { + // config.inputs.input is an object + createInput(config.inputs.input); + } + } + + function createInput(obj) { + var constName, constValue, inputDiv, textInputDiv; + + if (typeof obj['@var'] === 'undefined') { + return; + } + + constName = obj['@var']; + + constValue = state.getConstValue(constName); + if (constValue === undefined) { + constValue = 0; + } + + inputDiv = $('#' + gstId + '_input_' + constName); + + if (inputDiv.length === 0) { + return; + } + + textInputDiv = $(''); + textInputDiv.width(50); + + textInputDiv.appendTo(inputDiv); + textInputDiv.val(constValue); + + textInputDiv.bind('change', inputOnChange); + + return; + + function inputOnChange(event) { + state.setConstValue(constName, $(this).val()); + } + } + } +}); + +// 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 index 226f53d696..51bd2c8b12 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js @@ -104,6 +104,7 @@ define('Sliders', [], function () { // Set the new width to the slider. sliderDiv.width(sliderWidth); + sliderDiv.css('display', 'inline-block'); // Create a jQuery UI slider from the current DIV. We will set // starting parameters, and will also attach a handler to update 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 index d632429c9b..88951f0e9d 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js @@ -107,6 +107,8 @@ define('State', [], function () { } function setConstValue(constName, constValue) { + var inputDiv; + if (constants.hasOwnProperty(constName) === false) { // If the name of the constant is not tracked by state, return an // 'undefined' value. @@ -123,6 +125,11 @@ define('State', [], function () { if (plotDiv !== undefined) { plotDiv.trigger('update_plot'); } + + inputDiv = $('#' + gstId + '_input_' + constName).children('input'); + if (inputDiv.length !== 0) { + inputDiv.val(constValue); + } } function addConstFromInput(obj) { From b08b25b98388e4f42f501c930f8d7a4490fca960 Mon Sep 17 00:00:00 2001 From: Valera Rozuvan Date: Mon, 10 Dec 2012 16:11:29 +0200 Subject: [PATCH 019/107] GST work in progress. --- common/lib/xmodule/xmodule/gst_module.py | 4 +-- .../js/src/graphical_slider_tool/inputs.js | 27 ++++++++++++------- .../js/src/graphical_slider_tool/sliders.js | 20 ++++++++------ 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py index 9e9273bc25..61a883fbf8 100644 --- a/common/lib/xmodule/xmodule/gst_module.py +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -139,8 +139,8 @@ class GraphicalSliderToolModule(XModule): sliders = [sliders] vars = [x['@var'] for x in sliders] - slider_div = '
' + slider_div = '' for var in vars: html_string = re.sub(r'\$slider\s+' + var + r'\$', diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/inputs.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/inputs.js index 5b9f1f87c2..d7f64328e0 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/inputs.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/inputs.js @@ -27,9 +27,9 @@ define('Inputs', ['logme'], function (logme) { } function createInput(obj) { - var constName, constValue, inputDiv, textInputDiv; + var constName, constValue, spanEl, inputEl; - if (typeof obj['@var'] === 'undefined') { + if (typeof obj['@var'] !== 'string') { return; } @@ -40,19 +40,28 @@ define('Inputs', ['logme'], function (logme) { constValue = 0; } - inputDiv = $('#' + gstId + '_input_' + constName); + spanEl = $('#' + gstId + '_input_' + constName); - if (inputDiv.length === 0) { + if (spanEl.length === 0) { return; } - textInputDiv = $(''); - textInputDiv.width(50); + inputEl = $(''); - textInputDiv.appendTo(inputDiv); - textInputDiv.val(constValue); + // inputEl.width(50); + inputEl.val(constValue); + inputEl.bind('change', inputOnChange); + inputEl.button().css({ + 'font': 'inherit', + 'color': 'inherit', + 'text-align': 'left', + 'outline': 'none', + 'cursor': 'text', + 'height': '15px', + 'width': '50px' + }); - textInputDiv.bind('change', inputOnChange); + inputEl.appendTo(spanEl); return; 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 index 51bd2c8b12..3db0c3e67c 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js @@ -25,7 +25,7 @@ define('Sliders', [], function () { function createSlider(obj) { var constName, constValue, rangeBlobs, valueMin, valueMax, - sliderDiv, sliderWidth; + spanEl, sliderEl, sliderWidth; // The name of the constant is obj['@var']. Multiple sliders and/or // inputs can represent the same constant - therefore we will get @@ -34,7 +34,7 @@ define('Sliders', [], function () { // blob is the min value for the slider, the third blob is the max // value for the slider. - if (typeof obj['@var'] === 'undefined') { + if (typeof obj['@var'] !== 'string') { return; } @@ -85,14 +85,16 @@ define('Sliders', [], function () { } } - sliderDiv = $('#' + gstId + '_slider_' + constName); + spanEl = $('#' + gstId + '_slider_' + constName); // If a corresponding slider DIV for this constant does not exist, // do not do anything. - if (sliderDiv.length === 0) { + if (spanEl.length === 0) { return; } + sliderEl = $('
'); + // The default slider width. sliderWidth = 400; @@ -103,21 +105,23 @@ define('Sliders', [], function () { } // Set the new width to the slider. - sliderDiv.width(sliderWidth); - sliderDiv.css('display', 'inline-block'); + sliderEl.width(sliderWidth); + sliderEl.css('display', 'inline-block'); // 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({ + sliderEl.slider({ 'min': valueMin, 'max': valueMax, 'value': constValue, - 'step': 0.01, + 'step': (valueMax - valueMin) / 50.0, 'change': sliderOnChange }); + sliderEl.appendTo(spanEl); + return; function sliderOnChange(event, ui) { From 3682cb46c4522bee93c6acafa7e38c02cc052403 Mon Sep 17 00:00:00 2001 From: Valera Rozuvan Date: Mon, 10 Dec 2012 18:37:20 +0200 Subject: [PATCH 020/107] GST work in progress. --- .../js/src/graphical_slider_tool/graph.js | 15 +- .../js/src/graphical_slider_tool/inputs.js | 72 +++++++-- .../js/src/graphical_slider_tool/sliders.js | 137 ++++++++++++++---- 3 files changed, 186 insertions(+), 38 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js index 991cb0a26e..61228413f5 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js @@ -121,7 +121,20 @@ define('Graph', [], function () { } function updatePlot() { - $.plot(plotDiv, dataSets); + $.plot( + plotDiv, + dataSets, + { + 'xaxis': { + 'min': 0, + 'max': 30 + }, + 'yaxis': { + 'min': -5, + 'max': 5 + } + } + ); } } }); diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/inputs.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/inputs.js index d7f64328e0..3e7e55f02c 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/inputs.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/inputs.js @@ -2,12 +2,24 @@ // define() functions from Require JS available inside the anonymous function. (function (requirejs, require, define) { -define('Inputs', ['logme'], function (logme) { +define('Inputs', [], function () { return Inputs; function Inputs(gstId, config, state) { - logme('Inside "Inputs" module.'); - logme(gstId, config, state); + var constNamesUsed; + + // There should not be more than one text input per a constant. This + // just does not make sense. However, nothing really prevents the user + // from specifying more than one text input for the same constant name. + // That's why we have to track which constant names already have + // text inputs for them, and prevent adding further text inputs to + // these constants. + // + // constNamesUsed is an object to which we will add properties having + // the name of the constant to which we are adding a text input to. + // When creating a new text input, we must consult with this object, to + // see if the constant name is not defined as it's property. + constNamesUsed = {}; // We will go thorugh all of the inputs, and those that have a valid // '@var' property will be added to the page as a HTML text input @@ -15,42 +27,75 @@ define('Inputs', ['logme'], function (logme) { if ((typeof config.inputs !== 'undefined') && (typeof config.inputs.input !== 'undefined')) { if ($.isArray(config.inputs.input)) { - // config.inputs.input is an array + // config.inputs.input is an array. For each element, we will + // add a text input. for (c1 = 0; c1 < config.inputs.input.length; c1++) { createInput(config.inputs.input[c1]); } } else if ($.isPlainObject(config.inputs.input)) { - // config.inputs.input is an object + + // config.inputs.input is an object. Add a text input for it. createInput(config.inputs.input); + } } function createInput(obj) { var constName, constValue, spanEl, inputEl; + // The name of the constant is obj['@var']. If it is not specified, + // we will skip creating a text input for this constant. if (typeof obj['@var'] !== 'string') { return; } - constName = obj['@var']; - constValue = state.getConstValue(constName); - if (constValue === undefined) { - constValue = 0; + // We will not add a text input for a constant which already has a + // text input defined for it. + // + // We will add the constant name to the 'constNamesUsed' object in + // the end, when everything went successfully. + if (constNamesUsed.hasOwnProperty(constName)) { + return; } + // Multiple sliders and/or inputs can represent the same constant. + // Therefore we will get the most recent const value from the state + // object. If it is undefined, we will skip creating a text input + // for this constant. + constValue = state.getConstValue(constName); + if (constValue === undefined) { + return; + } + + // With the constant name, and the constant value being defined, + // lets get the element on the page into which the text input will + // be inserted. spanEl = $('#' + gstId + '_input_' + constName); + // If a corresponding element for this constant does not exist on + // the page, we will not be making a text input. if (spanEl.length === 0) { return; } + // Create the text input element. inputEl = $(''); - // inputEl.width(50); + // Set the current constant to the text input. It will be visible + // to the user. inputEl.val(constValue); + + // Bind a function to the 'change' event. Whenever the user changes + // the value of this text input, and presses 'enter' (or clicks + // somewhere else on the page), this event will be triggered, and + // our callback will be called. inputEl.bind('change', inputOnChange); + + // Lets style the input element nicely. We will use the button() + // widget for this since there is no native widget for the text + // input. inputEl.button().css({ 'font': 'inherit', 'color': 'inherit', @@ -61,10 +106,17 @@ define('Inputs', ['logme'], function (logme) { 'width': '50px' }); + // And finally, publish the text input element to the page. inputEl.appendTo(spanEl); + // Don't forget to add the constant to the list of used constants. + // Next time a slider for this constant will not be created. + constNamesUsed[constName] = true; + return; + // When the user changes the value of this text input, the 'state' + // will be updated, forcing the plot to be redrawn. function inputOnChange(event) { state.setConstValue(constName, $(this).val()); } 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 index 3db0c3e67c..33bdd89dd1 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/sliders.js @@ -6,68 +6,117 @@ define('Sliders', [], function () { return Sliders; function Sliders(gstId, config, state) { + var constNamesUsed; + + // There should not be more than one slider per a constant. This just + // does not make sense. However, nothing really prevents the user from + // specifying more than one slider for the same constant name. That's + // why we have to track which constant names already have sliders for + // them, and prevent adding further sliders to these constants. + // + // constNamesUsed is an object to which we will add properties having + // the name of the constant to which we are adding a slider to. When + // creating a new slider, we must consult with this object, to see if + // the constant name is not defined as it's property. + constNamesUsed = {}; + // 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 + // config.sliders.slider is an array. For each object in the + // array, create a slider. 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 + + // config.sliders.slider is an object. Create a slider for it. createSlider(config.sliders.slider); + } } function createSlider(obj) { - var constName, constValue, rangeBlobs, valueMin, valueMax, - spanEl, sliderEl, 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. + var constName, constValue, rangeBlobs, valueMin, valueMax, spanEl, + sliderEl, sliderWidth; + // The name of the constant is obj['@var']. If it is not specified, + // we will skip creating a slider for this constant. if (typeof obj['@var'] !== 'string') { return; } - constName = obj['@var']; - constValue = state.getConstValue(constName); - if (constValue === undefined) { - constValue = 0; + // We will not add a slider for a constant which already has a + // slider defined for it. + // + // We will add the constant name to the 'constNamesUsed' object in + // the end, when everything went successfully. + if (constNamesUsed.hasOwnProperty(constName)) { + return; } + // Multiple sliders and/or inputs can represent the same constant. + // Therefore we will get the most recent const value from the state + // object. If it is undefined, then something terrible has + // happened! We will skip creating a slider for this constant. + constValue = state.getConstValue(constName); + if (constValue === undefined) { + return; + } + + // 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['@range'] !== 'string') { + + // If the range is not a string, we will set a default range. + // No promise as to the quality of the data points that this + // range will produce. valueMin = constValue - 10; valueMax = constValue + 10; + } else { + + // Separate the range string by commas, and store each blob as + // an element in an array. 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; + + // Set some sensible defaults, if the range string was + // split into more or less than 3 pieces. + setDefaultMinMax(); + } else { - // Get the first blob from the split string. + + // Get the first blob from the split string. It is the min + // value. valueMin = parseFloat(rangeBlobs[0]); + // Is it a well-formed float number? if (isNaN(valueMin) === true) { + + // No? Then set a sensible default value. valueMin = constValue - 10; + } - // Get the third blob from the split string. + // Get the third blob from the split string. It is the max. valueMax = parseFloat(rangeBlobs[2]); + // Is it a well-formed float number? if (isNaN(valueMax) === true) { + + // No? Then set a sensible default value. valueMax = constValue + 10; + } // Logically, the min, value, and max should make sense. @@ -79,38 +128,53 @@ define('Sliders', [], function () { if ((valueMin > valueMax) || (valueMin > constValue) || (valueMax < constValue)) { - valueMin = constValue - 10; - valueMax = constValue + 10; + + // Set some sensible defaults, if min/value/max logic + // is broken. + setDefaultMinMax(); + } } } + // At this point we have the constant name, the constant value, and + // the min and max values for this slider. Lets get the element on + // the page into which the slider will be inserted. spanEl = $('#' + gstId + '_slider_' + constName); - // If a corresponding slider DIV for this constant does not exist, - // do not do anything. + // If a corresponding element for this constant does not exist on + // the page, we will not be making a slider. if (spanEl.length === 0) { return; } + // Create the slider DIV. sliderEl = $('
'); - // The default slider width. + // We will define the width of the slider to a sensible default. sliderWidth = 400; + // Then we will see if one is provided in the config for this + // slider. If we find it, and it is a well-formed integer, we will + // use it, instead of the default width. if (typeof obj['@width'] === 'string') { if (isNaN(parseInt(obj['@width'], 10)) === false) { sliderWidth = parseInt(obj['@width'], 10); } } - // Set the new width to the slider. + // Set the defined width to the slider. sliderEl.width(sliderWidth); + + // And make sure that it gets added to the page as an + // 'inline-block' element. This will allow for the insertion of the + // slider into a paragraph, without the browser forcing it out of + // the paragraph onto a new line, separate line. sliderEl.css('display', 'inline-block'); - // Create a jQuery UI slider from the current DIV. We will set + // Create a jQuery UI slider from the slider DIV. We will set // starting parameters, and will also attach a handler to update - // the state on the change event. + // the 'state' on the 'change' event. sliderEl.slider({ 'min': valueMin, 'max': valueMax, @@ -120,13 +184,32 @@ define('Sliders', [], function () { 'change': sliderOnChange }); + // Append the slider DIV to the element on the page where the user + // wants to see it. sliderEl.appendTo(spanEl); + // OK! So we made it this far... + // + // Adding the constant to the list of used constants. Next time a + // slider for this constant will not be created. + constNamesUsed[constName] = true; + return; + // Update the 'state' - i.e. set the value of the constant this + // slider is attached to to a new value. + // + // This will cause the plot to be redrawn each time after the user + // drags the slider handle and releases it. function sliderOnChange(event, ui) { state.setConstValue(constName, ui.value); } + + // The sensible defaults for the slider's range. + function setDefaultMinMax() { + valueMin = constValue - 10; + valueMax = constValue + 10; + } } } }); From 28f4921924c1e47c7a68a754292a63dcdea6c35e Mon Sep 17 00:00:00 2001 From: Valera Rozuvan Date: Tue, 11 Dec 2012 06:56:43 +0200 Subject: [PATCH 021/107] GST work in progress. --- .../js/src/graphical_slider_tool/graph.js | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js index 61228413f5..dba0483674 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js @@ -2,13 +2,15 @@ // define() functions from Require JS available inside the anonymous function. (function (requirejs, require, define) { -define('Graph', [], function () { +define('Graph', ['logme'], function (logme) { return Graph; function Graph(gstId, config, state) { var plotDiv, dataSets, functions; + logme(config); + plotDiv = $('#' + gstId + '_plot'); if (plotDiv.length === 0) { @@ -39,11 +41,29 @@ define('Graph', [], function () { if (typeof config.plot['function'] === 'string') { addFunction(config.plot['function']); } else if ($.isPlainObject(config.plot['function']) === true) { - + addFunction( + config.plot['function']['#text'], + config.plot['function']['@color'], + config.plot['function']['@dot'], + config.plot['function']['@label'], + config.plot['function']['@line'], + config.plot['function']['@point_size'], + config.plot['function']['@style'] + ); } else if ($.isArray(config.plot['function'])) { for (c1 = 0; c1 < config.plot['function'].length; c1++) { if (typeof config.plot['function'][c1] === 'string') { addFunction(config.plot['function'][c1]); + } else if ($.isPlainObject(config.plot['function'][c1])) { + addFunction( + config.plot['function'][c1]['#text'], + config.plot['function'][c1]['@color'], + config.plot['function'][c1]['@dot'], + config.plot['function'][c1]['@label'], + config.plot['function'][c1]['@line'], + config.plot['function'][c1]['@point_size'], + config.plot['function'][c1]['@style'] + ); } } } @@ -76,17 +96,31 @@ define('Graph', [], function () { } if (typeof line === 'boolean') { - newFunctionObject['line'] = line; + if ((line === 'true') || (line === true)) { + newFunctionObject['line'] = true; + } else { + newFunctionObject['line'] = false; + } } - if (typeof dot === 'boolean') { - newFunctionObject['dot'] = dot; + if ((typeof dot === 'boolean') || (typeof dot === 'string')) { + if ((dot === 'true') || (dot === true)) { + newFunctionObject['dot'] = true; + } else { + newFunctionObject['dot'] = false; + } + } + + if ((newFunctionObject['dot'] === false) && (newFunctionObject['line'] === false)) { + newFunctionObject['line'] = true; } if (typeof label === 'string') { newFunctionObject['label'] = label; } + logme(newFunctionObject); + functions.push(newFunctionObject); } } From 3e46ecef646f194798dff81dc4f4176a9e69a27f Mon Sep 17 00:00:00 2001 From: Valera Rozuvan Date: Tue, 11 Dec 2012 10:47:46 +0200 Subject: [PATCH 022/107] GST work in progress. --- .../js/src/graphical_slider_tool/graph.js | 132 ++++++++++++++---- .../js/src/graphical_slider_tool/gst_main.js | 4 + .../js/graphical_slider_tool/gst_module.js | 15 -- .../static/js/graphical_slider_tool/main.js | 75 ---------- 4 files changed, 108 insertions(+), 118 deletions(-) delete mode 100644 common/static/js/graphical_slider_tool/gst_module.js delete mode 100644 common/static/js/graphical_slider_tool/main.js diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js index dba0483674..c0c8addf80 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js @@ -7,7 +7,7 @@ define('Graph', ['logme'], function (logme) { return Graph; function Graph(gstId, config, state) { - var plotDiv, dataSets, functions; + var plotDiv, dataSeries, functions; logme(config); @@ -39,37 +39,55 @@ define('Graph', ['logme'], function (logme) { } if (typeof config.plot['function'] === 'string') { + + // If just one function string is present. addFunction(config.plot['function']); + } else if ($.isPlainObject(config.plot['function']) === true) { - addFunction( - config.plot['function']['#text'], - config.plot['function']['@color'], - config.plot['function']['@dot'], - config.plot['function']['@label'], - config.plot['function']['@line'], - config.plot['function']['@point_size'], - config.plot['function']['@style'] - ); + + // If a function is present, but it also has properties + // defined. + callAddFunction(config.plot['function']); + } else if ($.isArray(config.plot['function'])) { + + // If more than one function is defined. for (c1 = 0; c1 < config.plot['function'].length; c1++) { + + // For each definition, we must check if it is a simple + // string definition, or a complex one with properties. if (typeof config.plot['function'][c1] === 'string') { + + // Simple string. addFunction(config.plot['function'][c1]); + } else if ($.isPlainObject(config.plot['function'][c1])) { - addFunction( - config.plot['function'][c1]['#text'], - config.plot['function'][c1]['@color'], - config.plot['function'][c1]['@dot'], - config.plot['function'][c1]['@label'], - config.plot['function'][c1]['@line'], - config.plot['function'][c1]['@point_size'], - config.plot['function'][c1]['@style'] - ); + + // Properties are present. + callAddFunction(config.plot['function'][c1]); + } } } return; + // This function will reduce code duplications. We have to call + // the function addFunction() several times passing object + // properties. A parameters. Rather than writing them out every + // time, we will have a single point of + function callAddFunction(obj) { + addFunction( + obj['#text'], + obj['@color'], + obj['@line'], + obj['@dot'], + obj['@label'], + obj['@style'], + obj['@point_size'] + ); + } + function addFunction(funcString, color, line, dot, label, style, point_size) { var newFunctionObject, func, constNames; @@ -95,7 +113,7 @@ define('Graph', ['logme'], function (logme) { newFunctionObject['color'] = color; } - if (typeof line === 'boolean') { + if ((typeof line === 'boolean') || (typeof line === 'string')) { if ((line === 'true') || (line === true)) { newFunctionObject['line'] = true; } else { @@ -111,6 +129,9 @@ define('Graph', ['logme'], function (logme) { } } + // By default, if no preference was set, or if the preference + // is conflicting (we must have either line or dot, none is + // not an option), we will show line. if ((newFunctionObject['dot'] === false) && (newFunctionObject['line'] === false)) { newFunctionObject['line'] = true; } @@ -131,33 +152,68 @@ define('Graph', ['logme'], function (logme) { } function generateData() { - var c0, c1, datapoints, constValues, x, y; + var c0, c1, functionObj, seriesObj, dataPoints, constValues, x, y; constValues = state.getAllConstantValues(); - dataSets = []; + dataSeries = []; for (c0 = 0; c0 < functions.length; c0 += 1) { - datapoints = []; + functionObj = functions[c0]; + logme('Functions obj:', functionObj); - for (c1 = 0; c1 < 30; c1 += 0.1) { + seriesObj = {}; + dataPoints = []; + + for (c1 = 0; c1 < 30; c1 += 1) { x = c1; + // Push the 'x' variable to the end of the parameter array. constValues.push(x); - y = functions[c0].func.apply(window, constValues); + + // We call the user defined function, passing all of the + // available constant values. inside this function they + // will be accessible by their names. + y = functionObj.func.apply(window, constValues); + + // Return the constValues array to how it was before we + // added 'x' variable to the end of it. constValues.pop(); - datapoints.push([x, y]); + // Add the generated point to the data points set. + dataPoints.push([x, y]); + } - dataSets.push(datapoints); + // Put the entire data points set into the series object. + seriesObj.data = dataPoints; + + // See if user defined a specific color for this function. + if (functionObj.hasOwnProperty('color') === true) { + seriesObj.color = functionObj.color; + } + + // See if a user defined a label for this function. + if (functionObj.hasOwnProperty('label') === true) { + seriesObj.label = functionObj.label; + } + + seriesObj.lines = { + 'show': functionObj.line + }; + + seriesObj.points = { + 'show': functionObj.dot + }; + + dataSeries.push(seriesObj); } } function updatePlot() { $.plot( plotDiv, - dataSets, + dataSeries, { 'xaxis': { 'min': 0, @@ -166,9 +222,29 @@ define('Graph', ['logme'], function (logme) { 'yaxis': { 'min': -5, 'max': 5 + }, + 'legend': { + + // To show the legend or not. Note, even if 'show' is + // 'true', the legend will only show if labels are + // provided for at least one of the series that are + // going to be plotted. + 'show': true, + + // A floating point number in the range [0, 1]. The + // smaller the number, the more transparent will the + // legend background become. + 'backgroundOpacity': 0 + } } ); + + MathJax.Hub.Queue([ + 'Typeset', + MathJax.Hub, + plotDiv.attr('id') + ]); } } }); 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 47881b66c6..8611fed1f2 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 @@ -4,6 +4,10 @@ define( 'GstMain', + + // Even though it is not explicitly in this module, we have to specify + // 'GeneralMethods' as a dependency. It expands some of the core JS objects + // with additional useful methods that are used in other modules. ['State', 'GeneralMethods', 'Sliders', 'Inputs', 'Graph'], function (State, GeneralMethods, Sliders, Inputs, Graph) { diff --git a/common/static/js/graphical_slider_tool/gst_module.js b/common/static/js/graphical_slider_tool/gst_module.js deleted file mode 100644 index c4661b5e44..0000000000 --- a/common/static/js/graphical_slider_tool/gst_module.js +++ /dev/null @@ -1,15 +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([], function () { - 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/static/js/graphical_slider_tool/main.js b/common/static/js/graphical_slider_tool/main.js deleted file mode 100644 index da36d9c9d6..0000000000 --- a/common/static/js/graphical_slider_tool/main.js +++ /dev/null @@ -1,75 +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) { - -// For documentation please check: -// http://requirejs.org/docs/api.html -requirejs.config({ - // Because require.js is included as a simple