Repository navigation
"Graphical Slider Tool" integration into studio #497
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| // In the LMS sliders use built-in styles from jquery-ui-1.8.22.custom.css. | ||
| // CMS uses its own sliders styles. | ||
| // These styles we use only to sure, that slider in GST module | ||
| // will be render correctly (just like a duplication some from jquery-ui-1.8.22.custom.css). | ||
| // Cause, for example, CMS overwrites many jquery-ui-1.8.22.custom.css styles, | ||
| // and we must overwrite them again. | ||
|
|
||
| .ui-widget-content { | ||
| border: 1px solid #dddddd; | ||
| color: #333333; | ||
| } | ||
|
|
||
| .ui-widget { | ||
| font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; | ||
| font-size: 1.1em; | ||
| } | ||
|
|
||
| .ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { | ||
| -moz-border-radius-topleft: 4px; | ||
| -webkit-border-top-left-radius: 4px; | ||
| -khtml-border-top-left-radius: 4px; | ||
| border-top-left-radius: 4px; | ||
| } | ||
|
|
||
| .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { | ||
| -moz-border-radius-topright: 4px; | ||
| -webkit-border-top-right-radius: 4px; | ||
| -khtml-border-top-right-radius: 4px; | ||
| border-top-right-radius: 4px; | ||
| } | ||
|
|
||
| .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { | ||
| -moz-border-radius-bottomleft: 4px; | ||
| -webkit-border-bottom-left-radius: 4px; | ||
| -khtml-border-bottom-left-radius: 4px; | ||
| border-bottom-left-radius: 4px; | ||
| } | ||
|
|
||
| .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { | ||
| -moz-border-radius-bottomright: 4px; | ||
| -webkit-border-bottom-right-radius: 4px; | ||
| -khtml-border-bottom-right-radius: 4px; | ||
| border-bottom-right-radius: 4px; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,17 +9,16 @@ | |
| from lxml import html | ||
| import xmltodict | ||
|
|
||
| from xmodule.mako_module import MakoModuleDescriptor | ||
| from xmodule.editing_module import XMLEditingDescriptor | ||
| from xmodule.xml_module import XmlDescriptor | ||
| from xmodule.x_module import XModule | ||
| from xmodule.stringify import stringify_children | ||
| from pkg_resources import resource_string | ||
| from xblock.core import String, Scope | ||
|
|
||
|
|
||
| log = logging.getLogger(__name__) | ||
|
|
||
| DEFAULT_RENDER=""" | ||
| DEFAULT_RENDER = """ | ||
| <h2>Graphic slider tool: Dynamic range and implicit functions.</h2> | ||
|
|
||
| <p>You can make the range of the x axis (but not ticks of x axis) of | ||
|
|
@@ -33,13 +32,19 @@ | |
| </div> | ||
| <plot style="margin-top:15px;margin-bottom:15px;"/> | ||
| """ | ||
| DEFAULT_CONFIGURATION=""" | ||
|
|
||
| DEFAULT_CONFIGURATION = """ | ||
| <parameters> | ||
| <param var="r" min="5" max="25" step="0.5" initial="12.5" /> | ||
| </parameters> | ||
| <functions> | ||
| <function color="red">Math.sqrt(r * r - x * x)</function> | ||
| <function color="red">-Math.sqrt(r * r - x * x)</function> | ||
| <function color="red">Math.sqrt(r * r / 20 - Math.pow(x-r/2.5, 2)) + r/8</function> | ||
| <function color="red">-Math.sqrt(r * r / 20 - Math.pow(x-r/2.5, 2)) + r/5.5</function> | ||
| <function color="red">Math.sqrt(r * r / 20 - Math.pow(x+r/2.5, 2)) + r/8</function> | ||
| <function color="red">-Math.sqrt(r * r / 20 - Math.pow(x+r/2.5, 2)) + r/5.5</function> | ||
| <function color="red">-Math.sqrt(r * r / 5 - x * x) - r/5.5</function> | ||
| </functions> | ||
| <plot> | ||
| <xrange> | ||
|
|
@@ -54,51 +59,66 @@ | |
| """ | ||
|
|
||
|
|
||
|
|
||
| class GraphicalSliderToolFields(object): | ||
| render = String(scope=Scope.content, default=DEFAULT_RENDER) | ||
| configuration = String(scope=Scope.content, default=DEFAULT_CONFIGURATION) | ||
| data = String( | ||
| help="Html contents to display for this module", | ||
| default='<render>{}</render><configuration>{}</configuration>'.format( | ||
| DEFAULT_RENDER, DEFAULT_CONFIGURATION), | ||
| scope=Scope.content | ||
| ) | ||
|
|
||
|
|
||
| class GraphicalSliderToolModule(GraphicalSliderToolFields, XModule): | ||
| ''' Graphical-Slider-Tool Module | ||
| ''' | ||
|
|
||
| js = { | ||
| 'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee')], | ||
| 'js': [ | ||
| # 3rd party libraries used by graphic slider tool. | ||
| # TODO - where to store them - outside xmodule? | ||
| resource_string(__name__, 'js/src/graphical_slider_tool/gst_main.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/inputs.js'), | ||
| resource_string(__name__, 'js/src/graphical_slider_tool/graph.js'), | ||
| resource_string(__name__, 'js/src/graphical_slider_tool/el_output.js'), | ||
| resource_string(__name__, 'js/src/graphical_slider_tool/g_label_el_output.js'), | ||
| resource_string(__name__, 'js/src/graphical_slider_tool/gst.js') | ||
|
|
||
| ] | ||
| 'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee')], | ||
| 'js': [ | ||
| # 3rd party libraries used by graphic slider tool. | ||
| # TODO - where to store them - outside xmodule? | ||
| resource_string(__name__, 'js/src/graphical_slider_tool/gst_main.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/inputs.js'), | ||
| resource_string(__name__, 'js/src/graphical_slider_tool/graph.js'), | ||
| resource_string(__name__, 'js/src/graphical_slider_tool/el_output.js'), | ||
| resource_string(__name__, 'js/src/graphical_slider_tool/g_label_el_output.js'), | ||
| resource_string(__name__, 'js/src/graphical_slider_tool/gst.js') | ||
| ] | ||
| } | ||
| css = {'scss': [resource_string(__name__, 'css/gst/display.scss')]} | ||
| js_module_name = "GraphicalSliderTool" | ||
|
|
||
| @property | ||
| def configuration(self): | ||
| return stringify_children( | ||
| html.fromstring(self.data).xpath('configuration')[0]) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: per https://edx-wiki.atlassian.net/wiki/display/ENG/Python+Guidelines?src=search, the final |
||
|
|
||
| @property | ||
| def render(self): | ||
| return stringify_children( | ||
| html.fromstring(self.data).xpath('render')[0]) | ||
|
|
||
| def get_html(self): | ||
| """ Renders parameters to template. """ | ||
|
|
||
| # these 3 will be used in class methods | ||
| self.html_id = self.location.html_id() | ||
| self.html_class = self.location.category | ||
|
|
||
| self.configuration_json = self.build_configuration_json() | ||
| params = { | ||
| 'gst_html': self.substitute_controls(self.render), | ||
| 'element_id': self.html_id, | ||
| 'element_class': self.html_class, | ||
| 'configuration_json': self.configuration_json | ||
| } | ||
| 'gst_html': self.substitute_controls(self.render), | ||
| 'element_id': self.html_id, | ||
| 'element_class': self.html_class, | ||
| 'configuration_json': self.configuration_json | ||
| } | ||
| content = self.system.render_template( | ||
| 'graphical_slider_tool.html', params) | ||
| 'graphical_slider_tool.html', params | ||
| ) | ||
| return content | ||
|
|
||
| def substitute_controls(self, html_string): | ||
|
|
@@ -126,9 +146,10 @@ def substitute_controls(self, html_string): | |
| if plot_el: | ||
| plot_el = plot_el[0] | ||
| plot_el.getparent().replace(plot_el, html.fromstring( | ||
| plot_div.format(element_class=self.html_class, | ||
| element_id=self.html_id, | ||
| style=plot_el.get('style', "")))) | ||
| plot_div.format( | ||
| element_class=self.html_class, | ||
| element_id=self.html_id, | ||
| style=plot_el.get('style', "")))) | ||
|
|
||
| # substitute sliders | ||
| slider_div = '<div class="{element_class}_slider" \ | ||
|
|
@@ -139,10 +160,11 @@ def substitute_controls(self, html_string): | |
| slider_els = xml.xpath('//slider') | ||
| for slider_el in slider_els: | ||
| slider_el.getparent().replace(slider_el, html.fromstring( | ||
| slider_div.format(element_class=self.html_class, | ||
| element_id=self.html_id, | ||
| var=slider_el.get('var', ""), | ||
| style=slider_el.get('style', "")))) | ||
| slider_div.format( | ||
| element_class=self.html_class, | ||
| element_id=self.html_id, | ||
| var=slider_el.get('var', ""), | ||
| style=slider_el.get('style', "")))) | ||
|
|
||
| # substitute inputs aka textboxes | ||
| input_div = '<input class="{element_class}_input" \ | ||
|
|
@@ -151,11 +173,12 @@ def substitute_controls(self, html_string): | |
| input_els = xml.xpath('//textbox') | ||
| for input_index, input_el in enumerate(input_els): | ||
| input_el.getparent().replace(input_el, html.fromstring( | ||
| input_div.format(element_class=self.html_class, | ||
| element_id=self.html_id, | ||
| var=input_el.get('var', ""), | ||
| style=input_el.get('style', ""), | ||
| input_index=input_index))) | ||
| input_div.format( | ||
| element_class=self.html_class, | ||
| element_id=self.html_id, | ||
| var=input_el.get('var', ""), | ||
| style=input_el.get('style', ""), | ||
| input_index=input_index))) | ||
|
|
||
| return html.tostring(xml) | ||
|
|
||
|
|
@@ -170,11 +193,13 @@ def build_configuration_json(self): | |
| """ | ||
| # <root> added for interface compatibility with xmltodict.parse | ||
| # class added for javascript's part purposes | ||
| return json.dumps(xmltodict.parse('<root class="' + self.html_class + | ||
| '">' + self.configuration + '</root>')) | ||
| root = '<root class="{}">{}</root>'.format( | ||
| self.html_class, | ||
| self.configuration) | ||
| return json.dumps(xmltodict.parse(root)) | ||
|
|
||
|
|
||
| class GraphicalSliderToolDescriptor(GraphicalSliderToolFields, MakoModuleDescriptor, XmlDescriptor): | ||
| class GraphicalSliderToolDescriptor(GraphicalSliderToolFields, XMLEditingDescriptor, XmlDescriptor): | ||
| module_class = GraphicalSliderToolModule | ||
|
|
||
| @classmethod | ||
|
|
@@ -202,24 +227,14 @@ def definition_from_xml(cls, xml_object, system): | |
| 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': parse('configuration') | ||
| }, [] | ||
| 'data': stringify_children(xml_object) | ||
| }, [] | ||
|
|
||
| def definition_to_xml(self, resource_fs): | ||
| '''Return an xml element representing this definition.''' | ||
| xml_object = etree.Element('graphical_slider_tool') | ||
|
|
||
| def add_child(k): | ||
| child_str = '<{tag}>{body}</{tag}>'.format(tag=k, body=getattr(self, k)) | ||
| child_node = etree.fromstring(child_str) | ||
| xml_object.append(child_node) | ||
|
|
||
| for child in ['render', 'configuration']: | ||
| add_child(child) | ||
|
|
||
| data = '<{tag}>{body}</{tag}>'.format( | ||
| tag='graphical_slider_tool', | ||
| body=self.data) | ||
| xml_object = etree.fromstring(data) | ||
| return xml_object | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than setting these here, I think it would be better to have something like:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cpennington, thanks for your suggestions. Done.