From 4c80325db3eb2eacf1f259f1b42ba1bdcd2bd7ee Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Mon, 20 May 2013 08:11:54 -0400 Subject: [PATCH 01/20] Start working on COE editor, fix name checking in module_render --- .../xmodule/combined_open_ended_module.py | 6 + .../js/src/combinedopenended/edit.coffee | 299 ++++++++++++++++++ .../xmodule/xmodule/peer_grading_module.py | 3 + lms/djangoapps/courseware/module_render.py | 24 +- 4 files changed, 323 insertions(+), 9 deletions(-) create mode 100644 common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index f4074283fe..bffd4d4c78 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -221,3 +221,9 @@ class CombinedOpenEndedDescriptor(CombinedOpenEndedFields, RawDescriptor): has_score = True always_recalculate_grades = True template_dir_name = "combinedopenended" + + #Specify whether or not to pass in S3 interface + needs_s3_interface = True + + #Specify whether or not to pass in open ended interface + needs_open_ended_interface = True diff --git a/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee b/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee new file mode 100644 index 0000000000..b723f230e9 --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee @@ -0,0 +1,299 @@ +class @MarkdownEditingDescriptor extends XModule.Descriptor + # TODO really, these templates should come from or also feed the cheatsheet + @multipleChoiceTemplate : "( ) incorrect\n( ) incorrect\n(x) correct\n" + @checkboxChoiceTemplate: "[x] correct\n[ ] incorrect\n[x] correct\n" + @stringInputTemplate: "= answer\n" + @numberInputTemplate: "= answer +- x%\n" + @selectTemplate: "[[incorrect, (correct), incorrect]]\n" + @headerTemplate: "Header\n=====\n" + @explanationTemplate: "[explanation]\nShort explanation\n[explanation]\n" + + constructor: (element) -> + @element = element + + if $(".markdown-box", @element).length != 0 + @markdown_editor = CodeMirror.fromTextArea($(".markdown-box", element)[0], { + lineWrapping: true + mode: null + }) + @setCurrentEditor(@markdown_editor) + # Add listeners for toolbar buttons (only present for markdown editor) + @element.on('click', '.xml-tab', @onShowXMLButton) + @element.on('click', '.format-buttons a', @onToolbarButton) + @element.on('click', '.cheatsheet-toggle', @toggleCheatsheet) + # Hide the XML text area + $(@element.find('.xml-box')).hide() + else + @createXMLEditor() + + ### + Creates the XML Editor and sets it as the current editor. If text is passed in, + it will replace the text present in the HTML template. + + text: optional argument to override the text passed in via the HTML template + ### + createXMLEditor: (text) -> + @xml_editor = CodeMirror.fromTextArea($(".xml-box", @element)[0], { + mode: "xml" + lineNumbers: true + lineWrapping: true + }) + if text + @xml_editor.setValue(text) + @setCurrentEditor(@xml_editor) + + ### + User has clicked to show the XML editor. Before XML editor is swapped in, + the user will need to confirm the one-way conversion. + ### + onShowXMLButton: (e) => + e.preventDefault(); + if @confirmConversionToXml() + @createXMLEditor(MarkdownEditingDescriptor.markdownToXml(@markdown_editor.getValue())) + # Need to refresh to get line numbers to display properly (and put cursor position to 0) + @xml_editor.setCursor(0) + @xml_editor.refresh() + # Hide markdown-specific toolbar buttons + $(@element.find('.editor-bar')).hide() + + ### + Have the user confirm the one-way conversion to XML. + Returns true if the user clicked OK, else false. + ### + confirmConversionToXml: -> + # TODO: use something besides a JavaScript confirm dialog? + return confirm("If you use the Advanced Editor, this problem will be converted to XML and you will not be able to return to the Simple Editor Interface.\n\nProceed to the Advanced Editor and convert this problem to XML?") + + ### + Event listener for toolbar buttons (only possible when markdown editor is visible). + ### + onToolbarButton: (e) => + e.preventDefault(); + selection = @markdown_editor.getSelection() + revisedSelection = null + switch $(e.currentTarget).attr('class') + when "multiple-choice-button" then revisedSelection = MarkdownEditingDescriptor.insertMultipleChoice(selection) + when "string-button" then revisedSelection = MarkdownEditingDescriptor.insertStringInput(selection) + when "number-button" then revisedSelection = MarkdownEditingDescriptor.insertNumberInput(selection) + when "checks-button" then revisedSelection = MarkdownEditingDescriptor.insertCheckboxChoice(selection) + when "dropdown-button" then revisedSelection = MarkdownEditingDescriptor.insertSelect(selection) + when "header-button" then revisedSelection = MarkdownEditingDescriptor.insertHeader(selection) + when "explanation-button" then revisedSelection = MarkdownEditingDescriptor.insertExplanation(selection) + else # ignore click + + if revisedSelection != null + @markdown_editor.replaceSelection(revisedSelection) + @markdown_editor.focus() + + ### + Event listener for toggling cheatsheet (only possible when markdown editor is visible). + ### + toggleCheatsheet: (e) => + e.preventDefault(); + if !$(@markdown_editor.getWrapperElement()).find('.simple-editor-cheatsheet')[0] + @cheatsheet = $($('#simple-editor-cheatsheet').html()) + $(@markdown_editor.getWrapperElement()).append(@cheatsheet) + + setTimeout (=> @cheatsheet.toggleClass('shown')), 10 + + ### + Stores the current editor and hides the one that is not displayed. + ### + setCurrentEditor: (editor) -> + if @current_editor + $(@current_editor.getWrapperElement()).hide() + @current_editor = editor + $(@current_editor.getWrapperElement()).show() + $(@current_editor).focus(); + + ### + Called when save is called. Listeners are unregistered because editing the block again will + result in a new instance of the descriptor. Note that this is NOT the case for cancel-- + when cancel is called the instance of the descriptor is reused if edit is selected again. + ### + save: -> + @element.off('click', '.xml-tab', @changeEditor) + @element.off('click', '.format-buttons a', @onToolbarButton) + @element.off('click', '.cheatsheet-toggle', @toggleCheatsheet) + if @current_editor == @markdown_editor + { + data: MarkdownEditingDescriptor.markdownToXml(@markdown_editor.getValue()) + metadata: + markdown: @markdown_editor.getValue() + } + else + { + data: @xml_editor.getValue() + metadata: + markdown: null + } + + @insertMultipleChoice: (selectedText) -> + return MarkdownEditingDescriptor.insertGenericChoice(selectedText, '(', ')', MarkdownEditingDescriptor.multipleChoiceTemplate) + + @insertCheckboxChoice: (selectedText) -> + return MarkdownEditingDescriptor.insertGenericChoice(selectedText, '[', ']', MarkdownEditingDescriptor.checkboxChoiceTemplate) + + @insertGenericChoice: (selectedText, choiceStart, choiceEnd, template) -> + if selectedText.length > 0 + # Replace adjacent newlines with a single newline, strip any trailing newline + cleanSelectedText = selectedText.replace(/\n+/g, '\n').replace(/\n$/,'') + lines = cleanSelectedText.split('\n') + revisedLines = '' + for line in lines + revisedLines += choiceStart + # a stand alone x before other text implies that this option is "correct" + if /^\s*x\s+(\S)/i.test(line) + # Remove the x and any initial whitespace as long as there's more text on the line + line = line.replace(/^\s*x\s+(\S)/i, '$1') + revisedLines += 'x' + else + revisedLines += ' ' + revisedLines += choiceEnd + ' ' + line + '\n' + return revisedLines + else + return template + + @insertStringInput: (selectedText) -> + return MarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '', MarkdownEditingDescriptor.stringInputTemplate) + + @insertNumberInput: (selectedText) -> + return MarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '', MarkdownEditingDescriptor.numberInputTemplate) + + @insertSelect: (selectedText) -> + return MarkdownEditingDescriptor.insertGenericInput(selectedText, '[[', ']]', MarkdownEditingDescriptor.selectTemplate) + + @insertHeader: (selectedText) -> + return MarkdownEditingDescriptor.insertGenericInput(selectedText, '', '\n====\n', MarkdownEditingDescriptor.headerTemplate) + + @insertExplanation: (selectedText) -> + return MarkdownEditingDescriptor.insertGenericInput(selectedText, '[explanation]\n', '\n[explanation]', MarkdownEditingDescriptor.explanationTemplate) + + @insertGenericInput: (selectedText, lineStart, lineEnd, template) -> + if selectedText.length > 0 + # TODO: should this insert a newline afterwards? + return lineStart + selectedText + lineEnd + else + return template + +# We may wish to add insertHeader. Here is Tom's code. +# function makeHeader() { +# var selection = simpleEditor.getSelection(); +# var revisedSelection = selection + '\n'; +# for(var i = 0; i < selection.length; i++) { +#revisedSelection += '='; +# } +# simpleEditor.replaceSelection(revisedSelection); +#} +# + @markdownToXml: (markdown)-> + toXml = `function(markdown) { + var xml = markdown; + + // replace headers + xml = xml.replace(/(^.*?$)(?=\n\=\=+$)/gm, '

$1

'); + xml = xml.replace(/\n^\=\=+$/gm, ''); + + // group multiple choice answers + xml = xml.replace(/(^\s*\(.?\).*?$\n*)+/gm, function(match, p) { + var groupString = '\n'; + groupString += ' \n'; + var options = match.split('\n'); + for(var i = 0; i < options.length; i++) { + if(options[i].length > 0) { + var value = options[i].split(/^\s*\(.?\)\s*/)[1]; + var correct = /^\s*\(x\)/i.test(options[i]); + groupString += ' ' + value + '\n'; + } + } + groupString += ' \n'; + groupString += '\n\n'; + return groupString; + }); + + // group check answers + xml = xml.replace(/(^\s*\[.?\].*?$\n*)+/gm, function(match, p) { + var groupString = '\n'; + groupString += ' \n'; + var options = match.split('\n'); + for(var i = 0; i < options.length; i++) { + if(options[i].length > 0) { + var value = options[i].split(/^\s*\[.?\]\s*/)[1]; + var correct = /^\s*\[x\]/i.test(options[i]); + groupString += ' ' + value + '\n'; + } + } + groupString += ' \n'; + groupString += '\n\n'; + return groupString; + }); + + // replace string and numerical + xml = xml.replace(/^\=\s*(.*?$)/gm, function(match, p) { + var string; + var floatValue = parseFloat(p); + if(!isNaN(floatValue)) { + var params = /(.*?)\+\-\s*(.*?$)/.exec(p); + if(params) { + string = '\n'; + string += ' \n'; + } else { + string = '\n'; + } + string += ' \n'; + string += '\n\n'; + } else { + string = '\n \n\n\n'; + } + return string; + }); + + // replace selects + xml = xml.replace(/\[\[(.+?)\]\]/g, function(match, p) { + var selectString = '\n\n'; + selectString += ' \n'; + return selectString; + }); + + // split scripts and wrap paragraphs + var splits = xml.split(/(\<\/?script.*?\>)/g); + var scriptFlag = false; + for(var i = 0; i < splits.length; i++) { + if(/\ diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index bffd4d4c78..008cf5acb0 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -69,6 +69,7 @@ class CombinedOpenEndedFields(object): version = VersionInteger(help="Current version number", default=DEFAULT_VERSION, scope=Scope.settings) data = String(help="XML data for the problem", scope=Scope.content) weight = StringyFloat(help="How much to weight this problem by", scope=Scope.settings) + markdown = String(help="Markdown source of this module", scope=Scope.settings) class CombinedOpenEndedModule(CombinedOpenEndedFields, XModule): @@ -213,9 +214,8 @@ class CombinedOpenEndedDescriptor(CombinedOpenEndedFields, RawDescriptor): """ Module for adding combined open ended questions """ - mako_template = "widgets/raw-edit.html" + mako_template = "widgets/open-ended-edit.html" module_class = CombinedOpenEndedModule - filename_extension = "xml" stores_state = True has_score = True @@ -227,3 +227,23 @@ class CombinedOpenEndedDescriptor(CombinedOpenEndedFields, RawDescriptor): #Specify whether or not to pass in open ended interface needs_open_ended_interface = True + + metadata_attributes = RawDescriptor.metadata_attributes + + js = {'coffee': [resource_string(__name__, 'js/src/combinedopenended/edit.coffee')]} + js_module_name = "OpenEndedMarkdownEditingDescriptor" + css = {'scss': [resource_string(__name__, 'css/editor/edit.scss'), resource_string(__name__, 'css/combinedopenended/edit.scss')]} + + def get_context(self): + _context = RawDescriptor.get_context(self) + _context.update({'markdown': self.markdown, + 'enable_markdown': self.markdown is not None}) + return _context + + @property + def non_editable_metadata_fields(self): + non_editable_fields = super(CombinedOpenEndedDescriptor, self).non_editable_metadata_fields + non_editable_fields.extend([CombinedOpenEndedDescriptor.due, CombinedOpenEndedDescriptor.graceperiod, + CombinedOpenEndedDescriptor.markdown]) + return non_editable_fields + diff --git a/common/lib/xmodule/xmodule/css/combinedopenended/edit.scss b/common/lib/xmodule/xmodule/css/combinedopenended/edit.scss new file mode 100644 index 0000000000..1e4b300c28 --- /dev/null +++ b/common/lib/xmodule/xmodule/css/combinedopenended/edit.scss @@ -0,0 +1,122 @@ +.editor-bar { + + .editor-tabs { + + .advanced-toggle { + @include white-button; + height: auto; + margin-top: -1px; + padding: 3px 9px; + font-size: 12px; + + &.current { + border: 1px solid $lightGrey !important; + border-radius: 3px !important; + background: $lightGrey !important; + color: $darkGrey !important; + pointer-events: none; + cursor: none; + + &:hover { + box-shadow: 0 0 0 0 !important; + } + } + } + + .cheatsheet-toggle { + width: 21px; + height: 21px; + padding: 0; + margin: 0 5px 0 15px; + border-radius: 22px; + border: 1px solid #a5aaaf; + background: #e5ecf3; + font-size: 13px; + font-weight: 700; + color: #565d64; + text-align: center; + } + } +} + +.simple-editor-cheatsheet { + position: absolute; + top: 0; + left: 100%; + width: 0; + border-radius: 0 3px 3px 0; + @include linear-gradient(left, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0) 4px); + background-color: #fff; + overflow: hidden; + @include transition(width .3s); + + &.shown { + width: 300px; + height: 100%; + overflow-y: scroll; + } + + .cheatsheet-wrapper { + width: 240px; + padding: 20px 30px; + } + + h6 { + margin-bottom: 7px; + font-size: 15px; + font-weight: 700; + } + + .row { + @include clearfix; + padding-bottom: 5px !important; + margin-bottom: 10px !important; + border-bottom: 1px solid #ddd !important; + + &:last-child { + border-bottom: none !important; + margin-bottom: 0 !important; + } + } + + .col { + float: left; + + &.sample { + width: 60px; + margin-right: 30px; + } + } + + pre { + font-size: 12px; + line-height: 18px; + } + + code { + padding: 0; + background: none; + } +} + +.combinedopenended-editor-icon { + display: inline-block; + width: 26px; + height: 21px; + vertical-align: middle; + background: url(../img/problem-editor-icons.png) no-repeat; +} + +.combinedopenended-editor-icon.multiple-choice { + background-position: 0 0; +} + +.combinedopenended-editor-icon.explanation { + width: 28px; + background-position: -111px 0; +} + +.combinedopenended-editor-icon.dropdown { + width: 28px; + background-position: -111px 0; +} \ No newline at end of file diff --git a/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee b/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee index b723f230e9..58697aff07 100644 --- a/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee +++ b/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee @@ -1,4 +1,4 @@ -class @MarkdownEditingDescriptor extends XModule.Descriptor +class @OpenEndedMarkdownEditingDescriptor extends XModule.Descriptor # TODO really, these templates should come from or also feed the cheatsheet @multipleChoiceTemplate : "( ) incorrect\n( ) incorrect\n(x) correct\n" @checkboxChoiceTemplate: "[x] correct\n[ ] incorrect\n[x] correct\n" diff --git a/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml b/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml index a11367b46f..cfbb5b7334 100644 --- a/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml +++ b/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml @@ -7,6 +7,7 @@ metadata: skip_spelling_checks: False accept_file_upload: False weight: "" + markdown: "" data: | From 3a15f935646508eba952a306c8551ef0e589a8ce Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Mon, 20 May 2013 09:20:46 -0400 Subject: [PATCH 03/20] Render proper templates when user clicks on editor buttons --- .../js/src/combinedopenended/edit.coffee | 76 ++++--------------- .../templates/combinedopenended/default.yaml | 29 ------- 2 files changed, 13 insertions(+), 92 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee b/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee index 58697aff07..bccac80570 100644 --- a/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee +++ b/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee @@ -1,12 +1,8 @@ class @OpenEndedMarkdownEditingDescriptor extends XModule.Descriptor # TODO really, these templates should come from or also feed the cheatsheet - @multipleChoiceTemplate : "( ) incorrect\n( ) incorrect\n(x) correct\n" - @checkboxChoiceTemplate: "[x] correct\n[ ] incorrect\n[x] correct\n" - @stringInputTemplate: "= answer\n" - @numberInputTemplate: "= answer +- x%\n" - @selectTemplate: "[[incorrect, (correct), incorrect]]\n" - @headerTemplate: "Header\n=====\n" - @explanationTemplate: "[explanation]\nShort explanation\n[explanation]\n" + @rubricTemplate : "+ Color Identification\n- Incorrect\n- Correct\n + Grammar\n- Poor\n- Acceptable\n- Superb \n" + @tasksTemplate: "[[Self, {0,1}AI, {1,3}Peer]]\n" + @promptTemplate: "[prompt]\nWhy is the sky blue?\n[prompt]\n" constructor: (element) -> @element = element @@ -49,7 +45,7 @@ class @OpenEndedMarkdownEditingDescriptor extends XModule.Descriptor onShowXMLButton: (e) => e.preventDefault(); if @confirmConversionToXml() - @createXMLEditor(MarkdownEditingDescriptor.markdownToXml(@markdown_editor.getValue())) + @createXMLEditor(OpenEndedMarkdownEditingDescriptor.markdownToXml(@markdown_editor.getValue())) # Need to refresh to get line numbers to display properly (and put cursor position to 0) @xml_editor.setCursor(0) @xml_editor.refresh() @@ -72,13 +68,9 @@ class @OpenEndedMarkdownEditingDescriptor extends XModule.Descriptor selection = @markdown_editor.getSelection() revisedSelection = null switch $(e.currentTarget).attr('class') - when "multiple-choice-button" then revisedSelection = MarkdownEditingDescriptor.insertMultipleChoice(selection) - when "string-button" then revisedSelection = MarkdownEditingDescriptor.insertStringInput(selection) - when "number-button" then revisedSelection = MarkdownEditingDescriptor.insertNumberInput(selection) - when "checks-button" then revisedSelection = MarkdownEditingDescriptor.insertCheckboxChoice(selection) - when "dropdown-button" then revisedSelection = MarkdownEditingDescriptor.insertSelect(selection) - when "header-button" then revisedSelection = MarkdownEditingDescriptor.insertHeader(selection) - when "explanation-button" then revisedSelection = MarkdownEditingDescriptor.insertExplanation(selection) + when "rubric-button" then revisedSelection = OpenEndedMarkdownEditingDescriptor.insertRubric(selection) + when "prompt-button" then revisedSelection = OpenEndedMarkdownEditingDescriptor.insertPrompt(selection) + when "tasks-button" then revisedSelection = OpenEndedMarkdownEditingDescriptor.insertTasks(selection) else # ignore click if revisedSelection != null @@ -128,46 +120,14 @@ class @OpenEndedMarkdownEditingDescriptor extends XModule.Descriptor markdown: null } - @insertMultipleChoice: (selectedText) -> - return MarkdownEditingDescriptor.insertGenericChoice(selectedText, '(', ')', MarkdownEditingDescriptor.multipleChoiceTemplate) + @insertRubric: (selectedText) -> + return OpenEndedMarkdownEditingDescriptor.insertGenericInput(selectedText, '(', ')', OpenEndedMarkdownEditingDescriptor.rubricTemplate) - @insertCheckboxChoice: (selectedText) -> - return MarkdownEditingDescriptor.insertGenericChoice(selectedText, '[', ']', MarkdownEditingDescriptor.checkboxChoiceTemplate) + @insertPrompt: (selectedText) -> + return OpenEndedMarkdownEditingDescriptor.insertGenericInput(selectedText, '[', ']', OpenEndedMarkdownEditingDescriptor.promptTemplate) - @insertGenericChoice: (selectedText, choiceStart, choiceEnd, template) -> - if selectedText.length > 0 - # Replace adjacent newlines with a single newline, strip any trailing newline - cleanSelectedText = selectedText.replace(/\n+/g, '\n').replace(/\n$/,'') - lines = cleanSelectedText.split('\n') - revisedLines = '' - for line in lines - revisedLines += choiceStart - # a stand alone x before other text implies that this option is "correct" - if /^\s*x\s+(\S)/i.test(line) - # Remove the x and any initial whitespace as long as there's more text on the line - line = line.replace(/^\s*x\s+(\S)/i, '$1') - revisedLines += 'x' - else - revisedLines += ' ' - revisedLines += choiceEnd + ' ' + line + '\n' - return revisedLines - else - return template - - @insertStringInput: (selectedText) -> - return MarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '', MarkdownEditingDescriptor.stringInputTemplate) - - @insertNumberInput: (selectedText) -> - return MarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '', MarkdownEditingDescriptor.numberInputTemplate) - - @insertSelect: (selectedText) -> - return MarkdownEditingDescriptor.insertGenericInput(selectedText, '[[', ']]', MarkdownEditingDescriptor.selectTemplate) - - @insertHeader: (selectedText) -> - return MarkdownEditingDescriptor.insertGenericInput(selectedText, '', '\n====\n', MarkdownEditingDescriptor.headerTemplate) - - @insertExplanation: (selectedText) -> - return MarkdownEditingDescriptor.insertGenericInput(selectedText, '[explanation]\n', '\n[explanation]', MarkdownEditingDescriptor.explanationTemplate) + @insertTasks: (selectedText) -> + return OpenEndedMarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '', OpenEndedMarkdownEditingDescriptor.tasksTemplate) @insertGenericInput: (selectedText, lineStart, lineEnd, template) -> if selectedText.length > 0 @@ -176,16 +136,6 @@ class @OpenEndedMarkdownEditingDescriptor extends XModule.Descriptor else return template -# We may wish to add insertHeader. Here is Tom's code. -# function makeHeader() { -# var selection = simpleEditor.getSelection(); -# var revisedSelection = selection + '\n'; -# for(var i = 0; i < selection.length; i++) { -#revisedSelection += '='; -# } -# simpleEditor.replaceSelection(revisedSelection); -#} -# @markdownToXml: (markdown)-> toXml = `function(markdown) { var xml = markdown; diff --git a/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml b/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml index cfbb5b7334..5bf8552997 100644 --- a/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml +++ b/common/lib/xmodule/xmodule/templates/combinedopenended/default.yaml @@ -10,35 +10,6 @@ metadata: markdown: "" data: | - - - - Category 1 - - - - - - -

Why is the sky blue?

-
- - - - - - - Enter essay here. - This is the answer. - {"grader_settings" : "peer_grading.conf", "problem_id" : "700x/Demo"} - - -
- children: [] From 986999c62edecbe28e51a68dec3c59329e46d032 Mon Sep 17 00:00:00 2001 From: Vik Paruchuri Date: Mon, 20 May 2013 09:50:15 -0400 Subject: [PATCH 04/20] Fix cheatsheet, start working on xml replacement --- cms/templates/widgets/open-ended-edit.html | 18 +++-- .../js/src/combinedopenended/edit.coffee | 71 +++++++------------ 2 files changed, 38 insertions(+), 51 deletions(-) diff --git a/cms/templates/widgets/open-ended-edit.html b/cms/templates/widgets/open-ended-edit.html index b59e6f7068..f6aababa8c 100644 --- a/cms/templates/widgets/open-ended-edit.html +++ b/cms/templates/widgets/open-ended-edit.html @@ -41,7 +41,7 @@
-
[explanation] A short explanation of the answer. [explanation]
+
[prompt]Why is the sky blue?[prompt]
@@ -49,9 +49,17 @@
-
( ) red
-                    ( ) green
-                    (x) blue
+

+                    [rubric]
+                    + Color Identification
+                    - Incorrect
+                    - Correct
+                    + Grammar
+                    - Poor
+                    - Acceptable
+                    - Superb
+                    [rubric]
+                
@@ -59,7 +67,7 @@
-
[[wrong, (right)]]
+
[tasks](Self), ({0,1}AI), ({1,3}Peer)[tasks]
diff --git a/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee b/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee index bccac80570..31944a0217 100644 --- a/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee +++ b/common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee @@ -1,7 +1,7 @@ class @OpenEndedMarkdownEditingDescriptor extends XModule.Descriptor # TODO really, these templates should come from or also feed the cheatsheet - @rubricTemplate : "+ Color Identification\n- Incorrect\n- Correct\n + Grammar\n- Poor\n- Acceptable\n- Superb \n" - @tasksTemplate: "[[Self, {0,1}AI, {1,3}Peer]]\n" + @rubricTemplate : "[rubric]\n+ Color Identification\n- Incorrect\n- Correct\n + Grammar\n- Poor\n- Acceptable\n- Superb \n[rubric]\n" + @tasksTemplate: "[tasks]\n(Self), ({0,1}AI), ({1,3}Peer)\n[tasks]\n" @promptTemplate: "[prompt]\nWhy is the sky blue?\n[prompt]\n" constructor: (element) -> @@ -108,26 +108,26 @@ class @OpenEndedMarkdownEditingDescriptor extends XModule.Descriptor @element.off('click', '.format-buttons a', @onToolbarButton) @element.off('click', '.cheatsheet-toggle', @toggleCheatsheet) if @current_editor == @markdown_editor - { - data: MarkdownEditingDescriptor.markdownToXml(@markdown_editor.getValue()) - metadata: - markdown: @markdown_editor.getValue() - } + { + data: MarkdownEditingDescriptor.markdownToXml(@markdown_editor.getValue()) + metadata: + markdown: @markdown_editor.getValue() + } else - { - data: @xml_editor.getValue() - metadata: - markdown: null - } + { + data: @xml_editor.getValue() + metadata: + markdown: null + } @insertRubric: (selectedText) -> - return OpenEndedMarkdownEditingDescriptor.insertGenericInput(selectedText, '(', ')', OpenEndedMarkdownEditingDescriptor.rubricTemplate) + return OpenEndedMarkdownEditingDescriptor.insertGenericInput(selectedText, '[rubric]', '[rubric]', OpenEndedMarkdownEditingDescriptor.rubricTemplate) @insertPrompt: (selectedText) -> - return OpenEndedMarkdownEditingDescriptor.insertGenericInput(selectedText, '[', ']', OpenEndedMarkdownEditingDescriptor.promptTemplate) + return OpenEndedMarkdownEditingDescriptor.insertGenericInput(selectedText, '[prompt]', '[prompt]', OpenEndedMarkdownEditingDescriptor.promptTemplate) @insertTasks: (selectedText) -> - return OpenEndedMarkdownEditingDescriptor.insertGenericInput(selectedText, '= ', '', OpenEndedMarkdownEditingDescriptor.tasksTemplate) + return OpenEndedMarkdownEditingDescriptor.insertGenericInput(selectedText, '[tasks]', '[tasks]', OpenEndedMarkdownEditingDescriptor.tasksTemplate) @insertGenericInput: (selectedText, lineStart, lineEnd, template) -> if selectedText.length > 0 @@ -140,12 +140,8 @@ class @OpenEndedMarkdownEditingDescriptor extends XModule.Descriptor toXml = `function(markdown) { var xml = markdown; - // replace headers - xml = xml.replace(/(^.*?$)(?=\n\=\=+$)/gm, '

$1

'); - xml = xml.replace(/\n^\=\=+$/gm, ''); - - // group multiple choice answers - xml = xml.replace(/(^\s*\(.?\).*?$\n*)+/gm, function(match, p) { + // group rubrics + xml = xml.replace(/\[rubric\]\n?([^\]]*)\[\/?rubric\]/gmi, function(match, p) { var groupString = '\n'; groupString += ' \n'; var options = match.split('\n'); @@ -213,37 +209,20 @@ class @OpenEndedMarkdownEditingDescriptor extends XModule.Descriptor selectString += '
\n\n'; return selectString; }); - - // replace explanations - xml = xml.replace(/\[explanation\]\n?([^\]]*)\[\/?explanation\]/gmi, function(match, p1) { - var selectString = '\n
\nExplanation\n\n' + p1 + '\n
\n
'; + + // replace prompts + xml = xml.replace(/\[prompt\]\n?([^\]]*)\[\/?prompt\]/gmi, function(match, p1) { + var selectString = '\n' + p1 + '\n'; return selectString; }); - // split scripts and wrap paragraphs - var splits = xml.split(/(\<\/?script.*?\>)/g); - var scriptFlag = false; - for(var i = 0; i < splits.length; i++) { - if(/\ + -