From d14928cc613bae723c10c63fe8d8c2a708f1d3df Mon Sep 17 00:00:00 2001 From: muhammad-ammar Date: Wed, 8 Jun 2016 14:18:10 +0500 Subject: [PATCH 1/8] separation based on responsetypes poc FEDX-176 --- .../contentstore/tests/test_crud.py | 2 +- common/lib/capa/capa/capa_problem.py | 2 +- .../lib/xmodule/xmodule/css/capa/display.scss | 7 + .../xmodule/js/spec/problem/edit_spec.coffee | 530 +++++++++++------- .../js/spec/problem/edit_spec_hint.coffee | 279 ++++----- .../xmodule/js/src/problem/edit.coffee | 77 ++- .../problem/checkboxes_response.yaml | 49 +- .../problem/checkboxes_response_hint.yaml | 75 ++- .../templates/problem/circuitschematic.yaml | 90 +-- .../templates/problem/customgrader.yaml | 110 ++-- .../templates/problem/drag_and_drop.yaml | 33 +- .../templates/problem/formularesponse.yaml | 92 ++- .../templates/problem/imageresponse.yaml | 57 +- .../templates/problem/jsinput_response.yaml | 75 +-- .../templates/problem/latex_problem.yaml | 214 +++---- .../templates/problem/multiplechoice.yaml | 56 +- .../problem/multiplechoice_hint.yaml | 50 +- .../templates/problem/numericalresponse.yaml | 68 +-- .../problem/numericalresponse_hint.yaml | 51 +- .../templates/problem/optionresponse.yaml | 45 +- .../problem/optionresponse_hint.yaml | 52 +- .../templates/problem/problem_with_hint.yaml | 26 +- .../problem/problem_with_hint_in_latex.yaml | 24 +- .../templates/problem/string_response.yaml | 43 +- .../problem/string_response_hint.yaml | 48 +- .../js/spec_helpers/jasmine-extensions.js | 9 + lms/templates/problem.html | 4 +- 27 files changed, 1193 insertions(+), 975 deletions(-) diff --git a/cms/djangoapps/contentstore/tests/test_crud.py b/cms/djangoapps/contentstore/tests/test_crud.py index f7f73c9a26..9dc3ce26ba 100644 --- a/cms/djangoapps/contentstore/tests/test_crud.py +++ b/cms/djangoapps/contentstore/tests/test_crud.py @@ -36,7 +36,7 @@ class TemplateTests(ModuleStoreTestCase): self.assertIn('markdown', dropdown['metadata']) self.assertIn('data', dropdown) self.assertRegexpMatches(dropdown['metadata']['markdown'], r'^Dropdown.*') - self.assertRegexpMatches(dropdown['data'], r'\s*

Dropdown.*') + self.assertRegexpMatches(dropdown['data'], r'\s*\s*

Dropdown.*') def test_get_some_templates(self): self.assertEqual(len(SequenceDescriptor.templates()), 0) diff --git a/common/lib/capa/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py index b8af102243..4a719a5711 100644 --- a/common/lib/capa/capa/capa_problem.py +++ b/common/lib/capa/capa/capa_problem.py @@ -846,7 +846,7 @@ class LoncapaProblem(object): answer_id = 1 input_tags = inputtypes.registry.registered_tags() inputfields = tree.xpath( - "|".join(['//' + response.tag + '[@id=$id]//' + x for x in input_tags + solution_tags]), + "|".join(['//' + response.tag + '[@id=$id]//' + x for x in input_tags]), id=response_id_str ) diff --git a/common/lib/xmodule/xmodule/css/capa/display.scss b/common/lib/xmodule/xmodule/css/capa/display.scss index aecb4ab022..4f087eca05 100644 --- a/common/lib/xmodule/xmodule/css/capa/display.scss +++ b/common/lib/xmodule/xmodule/css/capa/display.scss @@ -152,6 +152,13 @@ div.problem { margin-top: $baseline; } } + + span > label { + display: block; + margin-bottom: $baseline; + font: inherit; + color: inherit; + } } // Choice Group - silent class diff --git a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee index b3f7171a4f..6f008fc49d 100644 --- a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee @@ -189,11 +189,11 @@ describe 'MarkdownEditingDescriptor', -> Enter 0 with a tolerance: = 0 +- .02 """) - expect(data).toEqual(""" -

Enter 0 with a tolerance:

+ expect(data).toXMLEqual(""" - - +

Enter 0 with a tolerance:

+ +
@@ -204,11 +204,11 @@ describe 'MarkdownEditingDescriptor', -> = 1 +- .02 or= 2 +- 5% """) - expect(data).toEqual(""" -

Enter 1 with a tolerance:

+ expect(data).toXMLEqual(""" - - +

Enter 1 with a tolerance:

+ +
@@ -218,7 +218,7 @@ describe 'MarkdownEditingDescriptor', -> One of the main elements that goes into a good multiple choice question is the existence of good distractors. That is, each of the alternate responses presented to the student should be the result of a plausible mistake that a student might make. - What Apple device competed with the portable CD player? + >>What Apple device competed with the portable CD player?<< ( ) The iPad ( ) Napster (x) The iPod @@ -230,31 +230,26 @@ describe 'MarkdownEditingDescriptor', -> The release of the iPod allowed consumers to carry their entire music library with them in a format that did not rely on fragile and energy-intensive spinning disks. [Explanation] """) - expect(data).toEqual(""" -

A multiple choice problem presents radio buttons for student input. Students can only select a single option presented. Multiple Choice questions have been the subject of many areas of research due to the early invention and adoption of bubble sheets.

- -

One of the main elements that goes into a good multiple choice question is the existence of good distractors. That is, each of the alternate responses presented to the student should be the result of a plausible mistake that a student might make.

- -

What Apple device competed with the portable CD player?

- - - The iPad - Napster - The iPod - The vegetable peeler - Android - The Beatles - - - - -
-

Explanation

- -

The release of the iPod allowed consumers to carry their entire music library with them in a format that did not rely on fragile and energy-intensive spinning disks.

- -
-
+ expect(data).toXMLEqual(""" + +

A multiple choice problem presents radio buttons for student input. Students can only select a single option presented. Multiple Choice questions have been the subject of many areas of research due to the early invention and adoption of bubble sheets.

+

One of the main elements that goes into a good multiple choice question is the existence of good distractors. That is, each of the alternate responses presented to the student should be the result of a plausible mistake that a student might make.

+ + + The iPad + Napster + The iPod + The vegetable peeler + Android + The Beatles + + +
+

Explanation

+

The release of the iPod allowed consumers to carry their entire music library with them in a format that did not rely on fragile and energy-intensive spinning disks.

+
+
+
""") it 'converts multiple choice shuffle to xml', -> data = MarkdownEditingDescriptor.markdownToXml("""A multiple choice problem presents radio buttons for student input. Students can only select a single option presented. Multiple Choice questions have been the subject of many areas of research due to the early invention and adoption of bubble sheets. @@ -273,31 +268,27 @@ describe 'MarkdownEditingDescriptor', -> The release of the iPod allowed consumers to carry their entire music library with them in a format that did not rely on fragile and energy-intensive spinning disks. [Explanation] """) - expect(data).toEqual(""" -

A multiple choice problem presents radio buttons for student input. Students can only select a single option presented. Multiple Choice questions have been the subject of many areas of research due to the early invention and adoption of bubble sheets.

- -

One of the main elements that goes into a good multiple choice question is the existence of good distractors. That is, each of the alternate responses presented to the student should be the result of a plausible mistake that a student might make.

- -

What Apple device competed with the portable CD player?

- - - The iPad - Napster - The iPod - The vegetable peeler - Android - The Beatles - - - - -
-

Explanation

- -

The release of the iPod allowed consumers to carry their entire music library with them in a format that did not rely on fragile and energy-intensive spinning disks.

- -
-
+ expect(data).toXMLEqual(""" + + +

A multiple choice problem presents radio buttons for student input. Students can only select a single option presented. Multiple Choice questions have been the subject of many areas of research due to the early invention and adoption of bubble sheets.

+

One of the main elements that goes into a good multiple choice question is the existence of good distractors. That is, each of the alternate responses presented to the student should be the result of a plausible mistake that a student might make.

+

What Apple device competed with the portable CD player?

+ + The iPad + Napster + The iPod + The vegetable peeler + Android + The Beatles + + +
+

Explanation

+

The release of the iPod allowed consumers to carry their entire music library with them in a format that did not rely on fragile and energy-intensive spinning disks.

+
+
+
""") it 'converts a series of multiplechoice to xml', -> @@ -367,25 +358,20 @@ describe 'MarkdownEditingDescriptor', -> Multiple Choice also allows students to select from a variety of pre-written responses, although the format makes it easier for students to read very long response options. Optionresponse also differs slightly because students are more likely to think of an answer and then search for it rather than relying purely on recognition to answer the question. [Explanation] """) - expect(data).toEqual(""" -

OptionResponse gives a limited set of options for students to respond with, and presents those options in a format that encourages them to search for a specific answer rather than being immediately presented with options from which to recognize the correct answer.

- -

The answer options and the identification of the correct answer is defined in the optioninput tag.

- -

Translation between Option Response and __________ is extremely straightforward:

- - - - - - -
-

Explanation

- -

Multiple Choice also allows students to select from a variety of pre-written responses, although the format makes it easier for students to read very long response options. Optionresponse also differs slightly because students are more likely to think of an answer and then search for it rather than relying purely on recognition to answer the question.

- -
-
+ expect(data).toXMLEqual(""" + + +

OptionResponse gives a limited set of options for students to respond with, and presents those options in a format that encourages them to search for a specific answer rather than being immediately presented with options from which to recognize the correct answer.

+

The answer options and the identification of the correct answer is defined in the optioninput tag.

+

Translation between Option Response and __________ is extremely straightforward:

+ + +
+

Explanation

+

Multiple Choice also allows students to select from a variety of pre-written responses, although the format makes it easier for students to read very long response options. Optionresponse also differs slightly because students are more likely to think of an answer and then search for it rather than relying purely on recognition to answer the question.

+
+
+
""") it 'converts StringResponse to xml', -> data = MarkdownEditingDescriptor.markdownToXml("""A string response problem accepts a line of text input from the student, and evaluates the input for correctness based on an expected answer within each input box. @@ -399,24 +385,20 @@ describe 'MarkdownEditingDescriptor', -> Lansing is the capital of Michigan, although it is not Michgan's largest city, or even the seat of the county in which it resides. [Explanation] """) - expect(data).toEqual(""" -

A string response problem accepts a line of text input from the student, and evaluates the input for correctness based on an expected answer within each input box.

- -

The answer is correct if it matches every character of the expected answer. This can be a problem with international spelling, dates, or anything where the format of the answer is not clear.

- -

Which US state has Lansing as its capital?

- - - - - -
-

Explanation

- -

Lansing is the capital of Michigan, although it is not Michgan's largest city, or even the seat of the county in which it resides.

- -
-
+ expect(data).toXMLEqual(""" + + +

A string response problem accepts a line of text input from the student, and evaluates the input for correctness based on an expected answer within each input box.

+

The answer is correct if it matches every character of the expected answer. This can be a problem with international spelling, dates, or anything where the format of the answer is not clear.

+

Which US state has Lansing as its capital?

+ + +
+

Explanation

+

Lansing is the capital of Michigan, although it is not Michgan's largest city, or even the seat of the county in which it resides.

+
+
+
""") it 'converts StringResponse with regular expression to xml', -> data = MarkdownEditingDescriptor.markdownToXml("""Who lead the civil right movement in the United States of America? @@ -426,20 +408,18 @@ describe 'MarkdownEditingDescriptor', -> Test Explanation. [Explanation] """) - expect(data).toEqual(""" -

Who lead the civil right movement in the United States of America?

- - - - - -
-

Explanation

- -

Test Explanation.

- -
-
+ expect(data).toXMLEqual(""" + + +

Who lead the civil right movement in the United States of America?

+ + +
+

Explanation

+

Test Explanation.

+
+
+
""") it 'converts StringResponse with multiple answers to xml', -> data = MarkdownEditingDescriptor.markdownToXml("""Who lead the civil right movement in the United States of America? @@ -452,23 +432,21 @@ describe 'MarkdownEditingDescriptor', -> Test Explanation. [Explanation] """) - expect(data).toEqual(""" -

Who lead the civil right movement in the United States of America?

- - - - - - - - -
-

Explanation

- -

Test Explanation.

- -
-
+ expect(data).toXMLEqual(""" + + +

Who lead the civil right movement in the United States of America?

+ + + + + +
+

Explanation

+

Test Explanation.

+
+
+
""") it 'converts StringResponse with multiple answers and regular expressions to xml', -> data = MarkdownEditingDescriptor.markdownToXml("""Write a number from 1 to 4. @@ -481,23 +459,21 @@ describe 'MarkdownEditingDescriptor', -> Test Explanation. [Explanation] """) - expect(data).toEqual(""" -

Write a number from 1 to 4.

- - - - - - - - -
-

Explanation

- -

Test Explanation.

- -
-
+ expect(data).toXMLEqual(""" + + +

Write a number from 1 to 4.

+ + + + + +
+

Explanation

+

Test Explanation.

+
+
+
""") # test labels it 'converts markdown labels to label attributes', -> @@ -508,21 +484,19 @@ describe 'MarkdownEditingDescriptor', -> Test Explanation. [Explanation] """) - expect(data).toEqual(""" -

Who lead the civil right movement in the United States of America?

- - - - - -
-

Explanation

- -

Test Explanation.

- -
-
-
""") + expect(data).toXMLEqual(""" + + + + + +
+

Explanation

+

Test Explanation.

+
+
+
+
""") it 'handles multiple questions with labels', -> data = MarkdownEditingDescriptor.markdownToXml(""" France is a country in Europe. @@ -538,7 +512,7 @@ describe 'MarkdownEditingDescriptor', -> (x) Berlin ( ) Donut """) - expect(data).toEqual(""" + expect(data).toXMLEqual("""

France is a country in Europe.

What is the capital of France?

@@ -575,7 +549,7 @@ describe 'MarkdownEditingDescriptor', -> (x) Berlin ( ) Donut """) - expect(data).toEqual(""" + expect(data).toXMLEqual("""

France is a country in Europe.

What is the capital of France?

@@ -597,66 +571,22 @@ describe 'MarkdownEditingDescriptor', ->
""") - it 'tests malformed labels', -> - data = MarkdownEditingDescriptor.markdownToXml(""" - France is a country in Europe. - >>What is the capital of France?< - = Paris - - blah>>What is the capital of < -

France is a country in Europe.

- -

>>What is the capital of France?<

- - - - -

blahWhat is the capital of Germany?

- - - Bonn - Hamburg - Berlin - Donut - - - - -
""") it 'adds labels to formulae', -> data = MarkdownEditingDescriptor.markdownToXml(""" >>Enter the numerical value of Pi:<< = 3.14159 +- .02 """) - expect(data).toEqual(""" -

Enter the numerical value of Pi:

- - - - + expect(data).toXMLEqual(""" + + + + + - """) - it 'escapes entities in labels', -> - data = MarkdownEditingDescriptor.markdownToXml(""" - >>What is the "capital" of France & the 'best' > place < to live"?<< - = Paris - """) - expect(data).toEqual(""" -

What is the "capital" of France & the 'best' > place < to live"?

- - - +
""") - -
""") # test oddities it 'converts headers and oddities to xml', -> data = MarkdownEditingDescriptor.markdownToXml("""Not a header @@ -780,4 +710,178 @@ describe 'MarkdownEditingDescriptor', -> Code should be nicely monospaced.
""") - # failure tests + + it 'can separate responsetypes based on ---', -> + data = MarkdownEditingDescriptor.markdownToXml(""" + Multiple choice problems allow learners to select only one option. Learners can see all the options along with the problem text. + + >>Which of the following countries has the largest population?<< + ( ) Brazil {{ timely feedback -- explain why an almost correct answer is wrong }} + ( ) Germany + (x) Indonesia + ( ) Russia + + [explanation] + According to September 2014 estimates: + The population of Indonesia is approximately 250 million. + The population of Brazil is approximately 200 million. + The population of Russia is approximately 146 million. + The population of Germany is approximately 81 million. + [explanation] + + --- + + Checkbox problems allow learners to select multiple options. Learners can see all the options along with the problem text. + + >>The following languages are in the Indo-European family:<< + [x] Urdu + [ ] Finnish + [x] Marathi + [x] French + [ ] Hungarian + + Note: Make sure you select all of the correct options—there may be more than one! + + [explanation] + Urdu, Marathi, and French are all Indo-European languages, while Finnish and Hungarian are in the Uralic family. + [explanation] + + """) + expect(data).toXMLEqual(""" + + +

Multiple choice problems allow learners to select only one option. Learners can see all the options along with the problem text.

+ + + Brazil timely feedback -- explain why an almost correct answer is wrong + + Germany + Indonesia + Russia + + +
+

Explanation

+

According to September 2014 estimates:

+

The population of Indonesia is approximately 250 million.

+

The population of Brazil is approximately 200 million.

+

The population of Russia is approximately 146 million.

+

The population of Germany is approximately 81 million.

+
+
+
+ + +

Checkbox problems allow learners to select multiple options. Learners can see all the options along with the problem text.

+ + + Urdu + Finnish + Marathi + French + Hungarian + +

Note: Make sure you select all of the correct options—there may be more than one!

+ +
+

Explanation

+

Urdu, Marathi, and French are all Indo-European languages, while Finnish and Hungarian are in the Uralic family.

+
+
+
+
+ """) + + it 'can separate other things based on ---', -> + data = MarkdownEditingDescriptor.markdownToXml(""" + Multiple choice problems allow learners to select only one option. Learners can see all the options along with the problem text. + + --- + + >>Which of the following countries has the largest population?<< + ( ) Brazil {{ timely feedback -- explain why an almost correct answer is wrong }} + ( ) Germany + (x) Indonesia + ( ) Russia + + [explanation] + According to September 2014 estimates: + The population of Indonesia is approximately 250 million. + The population of Brazil is approximately 200 million. + The population of Russia is approximately 146 million. + The population of Germany is approximately 81 million. + [explanation] + """) + expect(data).toXMLEqual(""" + +

Multiple choice problems allow learners to select only one option. Learners can see all the options along with the problem text.

+ + + + + Brazil timely feedback -- explain why an almost correct answer is wrong + + Germany + Indonesia + Russia + + +
+

Explanation

+

According to September 2014 estimates:

+

The population of Indonesia is approximately 250 million.

+

The population of Brazil is approximately 200 million.

+

The population of Russia is approximately 146 million.

+

The population of Germany is approximately 81 million.

+
+
+
+
+ """) + + it 'can do separation if spaces are prsent around ---', -> + data = MarkdownEditingDescriptor.markdownToXml(""" + >>The following languages are in the Indo-European family:<< + [x] Urdu + [ ] Finnish + [x] Marathi + [x] French + [ ] Hungarian + + --- + + >>Which of the following countries has the largest population?<< + ( ) Brazil {{ timely feedback -- explain why an almost correct answer is wrong }} + ( ) Germany + (x) Indonesia + ( ) Russia + """) + expect(data).toXMLEqual(""" + + + + + Urdu + Finnish + Marathi + French + Hungarian + + + + + + + + + Brazil timely feedback -- explain why an almost correct answer is wrong + + Germany + Indonesia + Russia + + + + + + """) diff --git a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.coffee b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.coffee index 94e5fb671c..296591e445 100644 --- a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.coffee +++ b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.coffee @@ -14,11 +14,11 @@ describe 'Markdown to xml extended hint dropdown', -> Clowns have funny _________ to make people laugh. - + [[ dogs {{ NOPE::Not dogs, not cats, not toads }} (FACES) {{ With lots of makeup, doncha know?}} - + money {{ Clowns don't have any money, of course }} donkeys {{don't be an ass.}} -no hint- @@ -46,7 +46,7 @@ describe 'Markdown to xml extended hint dropdown', -> - +
""") @@ -64,14 +64,17 @@ describe 'Markdown to xml extended hint dropdown', -> || 1) one || || 2) two || """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

Translation between Dropdown and ________ is straightforward.

- - - - +

Translation between Dropdown and ________ is straightforward.

+ + + +
@@ -91,11 +94,11 @@ describe 'Markdown to xml extended hint dropdown', -> || 0) zero || || 1) one || """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

A Question ________ is answered.

- +

A Question ________ is answered.

+
@@ -112,19 +115,20 @@ describe 'Markdown to xml extended hint dropdown', -> bb cc {{ hint2 }} ]] """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

q1

- - - + + + - + - - + +
""") @@ -132,28 +136,29 @@ describe 'Markdown to xml extended hint dropdown', -> data = MarkdownEditingDescriptor.markdownToXml(""" >>q1<< [[ - - + + aa {{ hint1 }} - + bb {{ hint2 }} (cc) - + ]] """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

q1

- - - - + + + + - - + +
""") @@ -161,20 +166,20 @@ describe 'Markdown to xml extended hint checkbox', -> it 'produces xml', -> data = MarkdownEditingDescriptor.markdownToXml(""" >>Select all the fruits from the list<< - + [x] Apple {{ selected: You're right that apple is a fruit. }, {unselected: Remember that apple is also a fruit.}} [ ] Mushroom {{U: You're right that mushrooms aren't fruit}, { selected: Mushroom is a fungus, not a fruit.}} [x] Grape {{ selected: You're right that grape is a fruit }, {unselected: Remember that grape is also a fruit.}} [ ] Mustang [ ] Camero {{S:I don't know what a Camero is but it isn't a fruit.},{U:What is a camero anyway?}} - + {{ ((A*B)) You're right that apple is a fruit, but there's one you're missing. Also, mushroom is not a fruit.}} {{ ((B*C)) You're right that grape is a fruit, but there's one you're missing. Also, mushroom is not a fruit. }} >>Select all the vegetables from the list<< - + [ ] Banana {{ selected: No, sorry, a banana is a fruit. }, {unselected: poor banana.}} [ ] Ice Cream [ ] Mushroom {{U: You're right that mushrooms aren't vegetables.}, { selected: Mushroom is a fungus, not a vegetable.}} @@ -184,7 +189,7 @@ describe 'Markdown to xml extended hint checkbox', -> {{ ((A*B)) Making a banana split? }} {{ ((B*D)) That will make a horrible dessert: a brussel sprout split? }} """) - expect(data).toEqual(""" + expect(data).toXMLEqual("""

Select all the fruits from the list

@@ -262,7 +267,7 @@ describe 'Markdown to xml extended hint checkbox', -> || Hint two. || || Hint three. || """) - expect(data).toEqual(""" + expect(data).toXMLEqual("""

Select all the fruits from the list

@@ -317,7 +322,7 @@ describe 'Markdown to xml extended hint multiple choice', -> it 'produces xml', -> data = MarkdownEditingDescriptor.markdownToXml(""" >>Select the fruit from the list<< - + () Mushroom {{ Mushroom is a fungus, not a fruit.}} () Potato (x) Apple {{ OUTSTANDING::Apple is indeed a fruit.}} @@ -328,7 +333,7 @@ describe 'Markdown to xml extended hint multiple choice', -> (x) Potato {{ Potato is a root vegetable. }} () Apple {{ OOPS::Apple is a fruit.}} """) - expect(data).toEqual(""" + expect(data).toXMLEqual("""

Select the fruit from the list

@@ -338,7 +343,7 @@ describe 'Markdown to xml extended hint multiple choice', -> Apple Apple is indeed a fruit. - +

Select the vegetables from the list

@@ -347,8 +352,8 @@ describe 'Markdown to xml extended hint multiple choice', -> Apple Apple is a fruit. - - + +
""") @@ -359,24 +364,24 @@ describe 'Markdown to xml extended hint multiple choice', -> () Mushroom {{ Mushroom is a fungus, not a fruit.}} () Potato (x) Apple {{ OUTSTANDING::Apple is indeed a fruit.}} - - + + || 0) spaces on previous line. || || 1) roses are red. || >>Select the vegetables from the list<< () Mushroom {{ Mushroom is a fungus, not a vegetable.}} - + (x) Potato {{ Potato is a root vegetable. }} () Apple {{ OOPS::Apple is a fruit.}} - - + + || 2) where are the lions? || """) - expect(data).toEqual(""" + expect(data).toXMLEqual("""

Select the fruit from the list

@@ -412,14 +417,15 @@ describe 'Markdown to xml extended hint text input', -> = France {{ BRAVO::Viva la France! }} """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

In which country would you find the city of Paris?

- - Viva la France! + + + Viva la France! +
""") @@ -429,15 +435,17 @@ describe 'Markdown to xml extended hint text input', -> or= USA {{ meh::hint2 }} """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

Where Paris?

- - hint1 - hint2 + + + hint1 + hint2 + - + +
""") @@ -447,15 +455,16 @@ describe 'Markdown to xml extended hint text input', -> not= warm {{feedback2}} """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

Revenge is a dish best served

- - khaaaaaan! + + + khaaaaaan! feedback2 +
""") @@ -464,14 +473,15 @@ describe 'Markdown to xml extended hint text input', -> s= 2 {{feedback1}} """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

q

- - feedback1 + + + feedback1 - + +
""") @@ -483,16 +493,18 @@ describe 'Markdown to xml extended hint text input', -> or= ccc """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

q

- - feedback1 + + + feedback1 + feedback2 - + +
""") @@ -503,16 +515,18 @@ describe 'Markdown to xml extended hint text input', -> or= ccc """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

q

- - feedback1 - feedback2 - + + + feedback1 + feedback2 + + +
""") @@ -523,7 +537,7 @@ describe 'Markdown to xml extended hint text input', -> s= ccc """) - expect(data).toEqual(""" + expect(data).toXMLEqual("""

q

@@ -549,7 +563,7 @@ describe 'Markdown to xml extended hint text input', -> paragraph 2 """) - expect(data).toEqual(""" + expect(data).toXMLEqual("""

paragraph

q

@@ -574,7 +588,7 @@ describe 'Markdown to xml extended hint text input', -> paragraph 2 """) - expect(data).toEqual(""" + expect(data).toXMLEqual("""

paragraph

q

@@ -591,7 +605,7 @@ describe 'Markdown to xml extended hint text input', -> = ccc {{feedback2}} """) - expect(data).toEqual(""" + expect(data).toXMLEqual("""

q

@@ -614,11 +628,11 @@ describe 'Markdown to xml extended hint text input', -> || Paris is the capital of one of those countries. || """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

Where Paris?

- - hint1 + + + hint1 @@ -640,10 +654,10 @@ describe 'Markdown to xml extended hint numeric input', -> >>Enter the number of fingers on a human hand<< = 5 - + """) - expect(data).toEqual(""" + expect(data).toXMLEqual("""

Enter the numerical value of Pi:

@@ -681,7 +695,7 @@ describe 'Markdown to xml extended hint numeric input', -> || hintB || """) - expect(data).toEqual(""" + expect(data).toXMLEqual("""

text1

@@ -707,10 +721,10 @@ describe 'Markdown to xml extended hint with multiline hints', -> data = MarkdownEditingDescriptor.markdownToXml(""" >>Checkboxes<< - [x] A {{ + [x] A {{ selected: aaa }, {unselected:bbb}} - [ ] B {{U: c}, { + [ ] B {{U: c}, { selected: d.}} {{ ((A*B)) A*B hint}} @@ -725,7 +739,7 @@ describe 'Markdown to xml extended hint with multiline hints', -> hello hint }} - + >>multiple choice<< (x) AA{{hint1}} () BB {{ @@ -733,11 +747,11 @@ describe 'Markdown to xml extended hint with multiline hints', -> }} ( ) CC {{ hint3 }} - + >>dropdown<< [[ - W1 {{ - no }} + W1 {{ + no }} W2 {{ nope}} (C1) {{ yes @@ -749,7 +763,7 @@ describe 'Markdown to xml extended hint with multiline hints', -> || ccc || """) - expect(data).toEqual(""" + expect(data).toXMLEqual("""

Checkboxes

@@ -816,23 +830,23 @@ describe 'Markdown to xml extended hint with tricky syntax cases', -> || Ø || """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

á and Ø

- - Ø Ø + + + Ø Ø + BB - - + Ø
""") - + it 'produces xml with quote-type characters', -> data = MarkdownEditingDescriptor.markdownToXml(""" >>"quotes" aren't `fun`<< @@ -840,13 +854,15 @@ describe 'Markdown to xml extended hint with tricky syntax cases', -> (x) "isn't" {{ "hello" }} """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

"quotes" aren't `fun`

- - "hello" isn't - "isn't" "hello" + + + "hello" isn't + + "isn't" "hello" + @@ -862,18 +878,20 @@ describe 'Markdown to xml extended hint with tricky syntax cases', -> (x) b that (y) """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

q1

-

this (x)

- - a (hint) + +

this (x)

+ + a (hint) + b +

that (y)

-

that (y)

+
""") @@ -886,18 +904,19 @@ describe 'Markdown to xml extended hint with tricky syntax cases', -> [x] b {{ this hint passes through }} that [] """) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

q1

-

this [x]

- + +

this [x]

+ a [square] b {{ this hint passes through }} +

that []

-

that []

+
""") @@ -907,7 +926,7 @@ describe 'Markdown to xml extended hint with tricky syntax cases', -> markdown = """ >>q22<< - [[ + [[ (x) {{ hintx these span @@ -919,18 +938,20 @@ describe 'Markdown to xml extended hint with tricky syntax cases', -> """ markdown = markdown.replace(/\n/g, '\r\n') # make DOS line endings data = MarkdownEditingDescriptor.markdownToXml(markdown) - expect(data).toEqual(""" + expect(data).toXMLEqual(""" -

q22

- - - - + + + + + - - + +
""") - diff --git a/common/lib/xmodule/xmodule/js/src/problem/edit.coffee b/common/lib/xmodule/xmodule/js/src/problem/edit.coffee index deec7d7282..a7aeeb1706 100644 --- a/common/lib/xmodule/xmodule/js/src/problem/edit.coffee +++ b/common/lib/xmodule/xmodule/js/src/problem/edit.coffee @@ -192,11 +192,15 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor else return template - @markdownToXml: (markdown)-> + # it will contain ... tags + demandHintTags = []; toXml = `function (markdown) { var xml = markdown, i, splits, scriptFlag; + var responseTypes = [ + 'optionresponse', 'multiplechoiceresponse', 'stringresponse', 'numericalresponse', 'choiceresponse' + ]; // fix DOS \r\n line endings to look like \n xml = xml.replace(/\r\n/g, '\n'); @@ -212,6 +216,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor for (i = 0; i < options.length; i += 1) { var inner = /\s*\|\|(.*?)\|\|/.exec(options[i]); if (inner) { + //safe-lint: disable=javascript-concat-html demandhints += ' ' + inner[1].trim() + '\n'; } } @@ -524,7 +529,8 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); - line = line.replace(/>>|< tag + line = line.replace(/>>(.*?)<$1

"); } else if (line.match(/<\w+response/) && didinput && curlabel == prevlabel) { // reset label to prevent gobbling up previous one (if multiple questions) curlabel = ''; @@ -570,12 +576,71 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor // if we've come across demand hints, wrap in at the end if (demandhints) { - demandhints = '\n\n' + demandhints + ''; + demandHintTags.push(demandhints); } - // make all elements descendants of a single problem element - xml = '\n' + xml + demandhints + '\n'; + // make selector to search responsetypes in xml + var responseTypesSelector = responseTypes.join(', '); + // make temporary xml + // safe-lint: disable=javascript-concat-html + var $xml = $($.parseXML('' + xml + '')); + responseType = $xml.find(responseTypesSelector); + + // convert if there is only one responsetype + if (responseType.length === 1) { + var inputtype = responseType[0].firstElementChild + // used to decide whether an element should be placed before or after an inputtype + var beforeInputtype = true; + + _.each($xml.find('prob').children(), function(child, index){ + // we don't want to add the responsetype again into new xml + if (responseType[0].nodeName === child.nodeName) { + beforeInputtype = false; + return; + } + + // replace

tag for question title with

tag for question title + xml = xml.replace(/\sclass=\'qtitle\'/gi, ''); return xml; }` - return toXml markdown + + responseTypesXML = [] + responseTypesMarkdown = markdown.split(/\n\s*---\s*\n/g) + _.each responseTypesMarkdown, (responseTypeMarkdown, index) -> + if responseTypeMarkdown.trim().length > 0 + responseTypesXML.push toXml(responseTypeMarkdown) + + # combine demandhints + demandHints = '' + if demandHintTags.length + ## safe-lint: disable=javascript-concat-html + demandHints = '\n\n' + demandHintTags.join('') + '' + + # make all responsetypes descendants of a single problem element + ## safe-lint: disable=javascript-concat-html + return '\n' + responseTypesXML.join('\n\n') + demandHints + '\n' diff --git a/common/lib/xmodule/xmodule/templates/problem/checkboxes_response.yaml b/common/lib/xmodule/xmodule/templates/problem/checkboxes_response.yaml index eab9aa3bb9..a576f882e5 100644 --- a/common/lib/xmodule/xmodule/templates/problem/checkboxes_response.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/checkboxes_response.yaml @@ -3,7 +3,7 @@ metadata: display_name: Checkboxes markdown: | Checkbox problems allow learners to select multiple options. Learners can see all the options along with the problem text. - + When you add the problem, be sure to select Settings to specify a Display Name and other values that apply. You can use the following example problem as a model. @@ -21,27 +21,26 @@ metadata: Urdu, Marathi, and French are all Indo-European languages, while Finnish and Hungarian are in the Uralic family. [explanation] -data: | - -

Checkbox problems allow learners to select multiple options. Learners can see all the options along with the problem text.

-

When you add the component, be sure to select Settings - to specify a Display Name and other values that apply.

-

You can use the following example problem as a model.

-

The following languages are in the Indo-European family:

- - - Urdu - Finnish - Marathi - French - Hungarian - - -

Note: Make sure you select all of the correct options—there may be more than one!

- -
-

Explanation

-

Urdu, Marathi, and French are all Indo-European languages, while Finnish and Hungarian are in the Uralic family.

-
-
-
\ No newline at end of file +data: | + + +

Checkbox problems allow learners to select multiple options. Learners can see all the options along with the problem text.

+

When you add the problem, be sure to select Settings to specify a Display Name and other values that apply.

+

You can use the following example problem as a model.

+ + + Urdu + Finnish + Marathi + French + Hungarian + +

Note: Make sure you select all of the correct options—there may be more than one!

+ +
+

Explanation

+

Urdu, Marathi, and French are all Indo-European languages, while Finnish and Hungarian are in the Uralic family.

+
+
+
+
diff --git a/common/lib/xmodule/xmodule/templates/problem/checkboxes_response_hint.yaml b/common/lib/xmodule/xmodule/templates/problem/checkboxes_response_hint.yaml index fc1f296c2e..9037a630a3 100644 --- a/common/lib/xmodule/xmodule/templates/problem/checkboxes_response_hint.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/checkboxes_response_hint.yaml @@ -2,7 +2,7 @@ metadata: display_name: Checkboxes with Hints and Feedback markdown: | - + You can provide feedback for each option in a checkbox problem, with distinct feedback depending on whether or not the learner selects that option. You can also provide compound feedback for a specific combination of answers. For example, if you have three possible answers in the problem, you can configure specific feedback for when a learner selects each combination of possible answers. @@ -28,42 +28,39 @@ metadata: ||A fruit contains seeds of the plant.|| hinted: true -data: | - - -

You can provide feedback for each option in a checkbox problem, with distinct feedback depending on whether or not the learner selects that option.

+data: | + + +

You can provide feedback for each option in a checkbox problem, with distinct feedback depending on whether or not the learner selects that option.

+

You can also provide compound feedback for a specific combination of answers. For example, if you have three possible answers in the problem, you can configure specific feedback for when a learner selects each combination of possible answers.

+

You can also add hints for learners.

+

Be sure to select Settings to specify a Display Name and other values that apply.

+

Use the following example problem as a model.

+ + + apple + You are correct that an apple is a fruit because it is the fertilized ovary that comes from an apple tree and contains seeds. + Remember that an apple is also a fruit. + + pumpkin + You are correct that a pumpkin is a fruit because it is the fertilized ovary of a squash plant and contains seeds. + Remember that a pumpkin is also a fruit. + + potato + A potato is a vegetable, not a fruit, because it does not come from a flower and does not contain seeds. + You are correct that a potato is a vegetable because it is an edible part of a plant in tuber form. + + tomato + You are correct that a tomato is a fruit because it is the fertilized ovary of a tomato plant and contains seeds. + Many people mistakenly think a tomato is a vegetable. However, because a tomato is the fertilized ovary of a tomato plant and contains seeds, it is a fruit. + + An apple, pumpkin, and tomato are all fruits as they all are fertilized ovaries of a plant and contain seeds. + You are correct that an apple, pumpkin, and tomato are all fruits as they all are fertilized ovaries of a plant and contain seeds. However, a potato is not a fruit as it is an edible part of a plant in tuber form and is a vegetable. + +
-

You can also provide compound feedback for a specific combination of answers. For example, if you have three possible answers in the problem, you can configure specific feedback for when a learner selects each combination of possible answers.

- -

You can also add hints for learners.

- -

Use the following example problem as a model.

- -

Which of the following is a fruit? Check all that apply.

- - - apple - You are correct that an apple is a fruit because it is the fertilized ovary that comes from an apple tree and contains seeds. - Remember that an apple is also a fruit. - - pumpkin - You are correct that a pumpkin is a fruit because it is the fertilized ovary of a squash plant and contains seeds. - Remember that a pumpkin is also a fruit. - - potato - A potato is a vegetable, not a fruit, because it does not come from a flower and does not contain seeds. - You are correct that a potato is a vegetable because it is an edible part of a plant in tuber form. - - tomato - You are correct that a tomato is a fruit because it is the fertilized ovary of a tomato plant and contains seeds. - Many people mistakenly think a tomato is a vegetable. However, because a tomato is the fertilized ovary of a tomato plant and contains seeds, it a fruit. - - An apple, pumpkin, and tomato are all fruits as they all are fertilized ovaries of a plant and contain seeds. - You are correct that an apple, pumpkin, and tomato are all fruits as they all are fertilized ovaries of a plant and contain seeds. However, a potato is not a fruit as it is an edible part of a plant in tuber form and is classified as a vegetable. - - - - A fruit is the fertilized ovary from a flower. - A fruit contains seeds of the plant. - -
+ + A fruit is the fertilized ovary from a flower. + A fruit contains seeds of the plant. + +
diff --git a/common/lib/xmodule/xmodule/templates/problem/circuitschematic.yaml b/common/lib/xmodule/xmodule/templates/problem/circuitschematic.yaml index 7f6c4e7e2e..bc44b78e0e 100644 --- a/common/lib/xmodule/xmodule/templates/problem/circuitschematic.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/circuitschematic.yaml @@ -5,27 +5,28 @@ metadata: data: |

- Circuit schematic problems allow students to create virtual circuits by - arranging elements such as voltage sources, capacitors, resistors, and - MOSFETs on an interactive grid. The system evaluates a DC, AC, or - transient analysis of the circuit. + Circuit schematic problems allow students to create virtual circuits by + arranging elements such as voltage sources, capacitors, resistors, and + MOSFETs on an interactive grid. The system evaluates a DC, AC, or + transient analysis of the circuit.

- For more information, see - - Circuit Schematic Builder Problem in Building and Running an edX Course. + For more information, see + + Circuit Schematic Builder Problem in Building and Running an edX Course.

- When you add the problem, be sure to select Settings - to specify a Display Name and other values that apply. + When you add the problem, be sure to select Settings + to specify a Display Name and other values that apply.

You can use the following example problems as models.

-

Make a voltage divider that splits the provided voltage evenly.

+ -
- -
+ +
+ +
dc_value = "dc analysis not found" for response in submission[0]: @@ -38,14 +39,26 @@ data: | else: correct = ['incorrect'] -
-

Make a high-pass filter.

- -
- -
+ +
+

Explanation

+

+ You can form a voltage divider that evenly divides the input + voltage with two identically valued resistors, with the sampled + voltage taken in between the two. +

+

+
+
+
+ + + +
+ +
ac_values = None for response in submission[0]: @@ -60,24 +73,17 @@ data: | else: correct = ['incorrect'] -
- - -
-

Explanation

-

- You can form a voltage divider that evenly divides the input - voltage with two identically valued resistors, with the sampled - voltage taken in between the two. -

-

-

- You can form a simple high-pass filter without any further - constraints by simply putting a resistor in series with a - capacitor. The actual values of the components do not really - matter in this problem. -

-

-
-
+ +
+

Explanation

+

+ You can form a simple high-pass filter without any further + constraints by simply putting a resistor in series with a + capacitor. The actual values of the components do not really + matter in this problem. +

+

+
+
+
diff --git a/common/lib/xmodule/xmodule/templates/problem/customgrader.yaml b/common/lib/xmodule/xmodule/templates/problem/customgrader.yaml index 0a5dc35c83..33d9993bc9 100644 --- a/common/lib/xmodule/xmodule/templates/problem/customgrader.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/customgrader.yaml @@ -4,33 +4,54 @@ metadata: markdown: !!null data: | -

- In custom Python-evaluated input (also called "write-your-own-grader" - problems), the grader uses a Python script that you create and embed in - the problem to evaluate a learner's response or provide hints. These - problems can be any type. Numerical input and text input problems are - the most common write-your-own-grader problems. -

-

- You can use script tag format or answer tag format to create these problems. -

-

- You can create custom Python-evaluated input problems that provide - partial credit or that randomize variables in the Python code. You can - also add images to the solution by using an HTML "img" tag. Note that - the "img" tag must be between the "div" tags that are inside the - "solution" tags, and that learners do not see these images until they - click the "Show Answer" button. -

-

For more information, see - Write-Your-Own-Grader Problem in Building and Running an edX Course. -

-

When you add the problem, be sure to select Settings - to specify a Display Name and other values that apply.

-

You can use the following example problem as a model.

-
+

+ In custom Python-evaluated input (also called "write-your-own-grader" + problems), the grader uses a Python script that you create and embed in + the problem to evaluate a learner's response or provide hints. These + problems can be any type. Numerical input and text input problems are + the most common write-your-own-grader problems. +

+

+ You can use script tag format or answer tag format to create these problems. +

+

+ You can create custom Python-evaluated input problems that provide + partial credit or that randomize variables in the Python code. You can + also add images to the solution by using an HTML "img" tag. Note that + the "img" tag must be between the "div" tags that are inside the + "solution" tags, and that learners do not see these images until they + click the "Show Answer" button. +

+

+ For more information, see + Write-Your-Own-Grader Problem in Building and Running an edX Course. +

+

+ When you add the problem, be sure to select Settings + to specify a Display Name and other values that apply. +

+

You can use the following example problem as a model.

+
+ + + +
+ + +
+

Explanation

+

Any set of integers on the line \(y = 10 - x\) satisfy these constraints.

+
+
+
+ + -

Enter two integers that sum to 10.

- -
- + +
+ + +
+

Explanation

+

Any set of integers on the line \(y = 20 - x\) satisfy these constraints.

+

To add an image to the solution, use an HTML "img" tag. Make sure to include alt text.

+ Description of image, with a primary goal of explaining its
+                    relevance to the problem or concept being illustrated for someone
+                    who is unable to see the image. +
+
-

Enter two integers that sum to 20.

- -
- -
- -
-

Explanation

-

Any set of integers on the line \(y = 10 - x\) and \(y = 20 - x\) satisfy these constraints.

-

To add an image to the solution, use an HTML "img" tag. Make sure to include alt text.

- Description of image, with a primary goal of explaining its
-          relevance to the problem or concept being illustrated for someone
-          who is unable to see the image. -
-
diff --git a/common/lib/xmodule/xmodule/templates/problem/drag_and_drop.yaml b/common/lib/xmodule/xmodule/templates/problem/drag_and_drop.yaml index 71343b77b0..21bcd1b928 100644 --- a/common/lib/xmodule/xmodule/templates/problem/drag_and_drop.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/drag_and_drop.yaml @@ -5,21 +5,22 @@ metadata: showanswer: never data: | +

In drag and drop problems, students respond to a question by dragging text or objects to a specific location on an image.

- In drag and drop problems, students respond to a question by dragging text or objects to a specific location on an image. + For more information, see + + Drag and Drop Problem (Deprecated) in Building and Running an edX Course.

- For more information, see - - Drag and Drop Problem (Deprecated) in Building and Running an edX Course.

-

When you add the problem, be sure to select Settings - to specify a Display Name and other values that apply.

+ When you add the problem, be sure to select Settings + to specify a Display Name and other values that apply. +

You can use the following example problems as models.

-
- -

Simple Drag and Drop

-

Drag each word in the scrollbar to the bucket that matches the number of letters in the word.

- +
+ +

Simple Drag and Drop

+

Drag each word in the scrollbar to the bucket that matches the number of letters in the word.

+ @@ -31,7 +32,7 @@ data: | - +
correct_answer = { '1': [[70, 150], 121], @@ -50,14 +51,14 @@ data: | else: correct = ['incorrect'] -
+ + -

Drag and Drop with Outline

-

Label the hydrogen atoms connected with the left carbon atom.

+

Drag and Drop with Outline

+

Label the hydrogen atoms connected with the left carbon atom.

- diff --git a/common/lib/xmodule/xmodule/templates/problem/formularesponse.yaml b/common/lib/xmodule/xmodule/templates/problem/formularesponse.yaml index b3a4b4a5b2..c98f4bd938 100644 --- a/common/lib/xmodule/xmodule/templates/problem/formularesponse.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/formularesponse.yaml @@ -3,54 +3,52 @@ metadata: display_name: Math Expression Input markdown: !!null data: | - -

- In math expression input problems, learners enter text that represents a - mathematical expression into a field, and text is converted to a symbolic - expression that appears below that field. You can refer learners to - - Entering Mathematical and Scientific Expressions in the EdX Learner's - Guide for information about how to enter text into the field. -

-

- Math expression problems can include unknown variables and relatively - complicated symbolic expressions. The grader uses a numerical sampling to - determine whether the student’s response matches your math expression, to a - specified numerical tolerance. You must specify the allowed variables in the - expression as well as the range of values for each variable. -

-

- To create these problems, you use MathJax to change your plain text into - "beautiful math." For more information about how to use MathJax in Studio, - see - A Brief Introduction to MathJax in Studio in Building and Running an edx - Course. -

-

When you add the problem, be sure to select Settings - to specify a Display Name and other values that apply.

-

You can use the following example problems as models.

+ +

+ In math expression input problems, learners enter text that represents a + mathematical expression into a field, and text is converted to a symbolic + expression that appears below that field. You can refer learners to + + Entering Mathematical and Scientific Expressions in the EdX Learner's + Guide for information about how to enter text into the field. +

+

+ Math expression problems can include unknown variables and relatively + complicated symbolic expressions. The grader uses a numerical sampling to + determine whether the student’s response matches your math expression, to a + specified numerical tolerance. You must specify the allowed variables in the + expression as well as the range of values for each variable. +

+

+ To create these problems, you use MathJax to change your plain text into + "beautiful math." For more information about how to use MathJax in Studio, + see + A Brief Introduction to MathJax in Studio in Building and Running an edx + Course. +

+

+ When you add the problem, be sure to select Settings + to specify a Display Name and other values that apply. +

+

You can use the following example problems as models.

-

Write an expression for the product of \( R_1\), \( R_2\), and - the inverse of \( R_3\) .

- - - - + + + + + - + -

Let \( x\) be a variable, and let \( n\) be an arbitrary constant. - What is the derivative of \( x^n\)?

+ - - - - - - - -
+ + + + + +
diff --git a/common/lib/xmodule/xmodule/templates/problem/imageresponse.yaml b/common/lib/xmodule/xmodule/templates/problem/imageresponse.yaml index 80a1782819..c73b8ebea4 100644 --- a/common/lib/xmodule/xmodule/templates/problem/imageresponse.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/imageresponse.yaml @@ -2,34 +2,29 @@ metadata: display_name: Image Mapped Input markdown: !!null -data: | - -

- In an image mapped input problem, also known as a "pointing on a picture" - problem, students click inside a defined region in an image. You define this - region by including coordinates in the body of the problem. You can define - one rectangular region, multiple rectangular regions, or one non-rectangular - region. For more information, see - Image Mapped Input - Problem in Building and Running an edx Course. -

-

When you add the problem, be sure to select Settings - to specify a Display Name and other values that apply.

-

You can use the following example problem as a model.

- -

What country is home to the Great Pyramid of Giza as well as the cities - of Cairo and Memphis? Click the country on the map below.

- - - - -
-

Explanation

-

Egypt is home to not only the Pyramids, Cairo, and Memphis, but also - the Sphinx and the ancient Royal Library of Alexandria.

-
-
-
- +data: | + +

+ In an image mapped input problem, also known as a "pointing on a picture" problem, students click inside a defined region in an image. You define this region by including coordinates in the body of the problem. You can define one rectangular region, + multiple rectangular regions, or one non-rectangular region. For more information, see + Image Mapped Input Problem + in + Building and Running an edx Course. +

+

When you add the problem, be sure to select + Settings + to specify a + Display Name + and other values that apply.

+

You can use the following example problem as a model.

+ + + + +
+

Explanation

+

Egypt is home to not only the Pyramids, Cairo, and Memphis, but also the Sphinx and the ancient Royal Library of Alexandria.

+
+
+
+
diff --git a/common/lib/xmodule/xmodule/templates/problem/jsinput_response.yaml b/common/lib/xmodule/xmodule/templates/problem/jsinput_response.yaml index f4bdeb9ce2..48642ec7e4 100644 --- a/common/lib/xmodule/xmodule/templates/problem/jsinput_response.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/jsinput_response.yaml @@ -5,31 +5,36 @@ metadata: showanswer: never data: | -

- In these problems (also called custom JavaScript problems or JS Input - problems), you add a problem or tool that uses JavaScript in Studio. - Studio embeds the problem in an IFrame so that your students can - interact with it in the LMS. You can grade your students' work using - JavaScript and some basic Python, and the grading is integrated into the - edX grading system. -

-

- The JS Input problem that you create must use HTML, JavaScript, and - cascading style sheets (CSS). You can use any application creation tool, - such as the Google Web Toolkit (GWT), to create your JS Input problem. -

-

- For more information, see - - Custom JavaScript Problem in Building and Running an edX Course. -

-

JavaScript developers can also see - - Custom JavaScript Applications in the EdX Developer's Guide.

-

When you add the problem, be sure to select Settings - to specify a Display Name and other values that apply.

-

You can use the following example problem as a model.

+

+ In these problems (also called custom JavaScript problems or JS Input + problems), you add a problem or tool that uses JavaScript in Studio. + Studio embeds the problem in an IFrame so that your students can + interact with it in the LMS. You can grade your students' work using + JavaScript and some basic Python, and the grading is integrated into the + edX grading system. +

+

+ The JS Input problem that you create must use HTML, JavaScript, and + cascading style sheets (CSS). You can use any application creation tool, + such as the Google Web Toolkit (GWT), to create your JS Input problem. +

+

+ For more information, see + + Custom JavaScript Problem in Building and Running an edX Course. +

+

+ JavaScript developers can also see + + Custom JavaScript Applications in the EdX Developer's Guide. +

+

+ When you add the problem, be sure to select Settings + to specify a Display Name and other values that apply. +

+

You can use the following example problem as a model.

+ -

In the following image, click the objects until the cone is yellow - and the cube is blue.

- - - + + +
diff --git a/common/lib/xmodule/xmodule/templates/problem/latex_problem.yaml b/common/lib/xmodule/xmodule/templates/problem/latex_problem.yaml index 443468c6d4..04ca968cca 100644 --- a/common/lib/xmodule/xmodule/templates/problem/latex_problem.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/latex_problem.yaml @@ -88,37 +88,41 @@ metadata: data: | - -

If you have a problem that is already written in LaTeX, you can use this problem type to - easily convert your code into XML. After you paste your code into the LaTeX editor, - you only need to make a few minor adjustments.

-

For more information, see - - Problem Written in LaTeX in Building and Running an edX Course.

+ +

+ If you have a problem that is already written in LaTeX, you can use this problem type to + easily convert your code into XML. After you paste your code into the LaTeX editor, + you only need to make a few minor adjustments. +

+

+ For more information, see + + Problem Written in LaTeX in Building and Running an edX Course. +

You can use the following example problems as models.

-

Example Option Problem

-

Which of the following countries celebrates its independence on August 15?

-
- - - +

Example Option Problem

+
+ + +

Explanation

India became an independent nation on August 15, 1947.

-
-

Example Multiple Choice Problem

-

Which of the following countries has the largest population?

- - - Brazil - Germany - Indonesia - Russia - - +
+
+ +

Example Multiple Choice Problem

+ + + + Brazil + Germany + Indonesia + Russia +

Explanation

@@ -129,38 +133,61 @@ data: |

The population of Germany is approximately 81 million.

-
-

Example Math Expression Problem

-

What is Einstein's equation for the energy equivalent of a mass [mathjaxinline]m[/mathjaxinline]?

- - - -
-

Example Numerical Problem

-

Estimate the energy savings (in J/y) if all the people ([mathjaxinline]3\times 10^8[/mathjaxinline]) in the U. S. switched from U. S. code to low-flow shower heads.

-

Energy saved =

- - - - -

 EJ/year

-
-
-

Example Fill-in-the-Blank Problem

-

What was the first post-secondary school in China to allow both male and female students?

- - National Central University - Nanjing University - - +
+
+ +

Example Math Expression Problem

+ + + + +
+ +

Example Numerical Problem

+ + +

Energy saved =

+ + + +

 EJ/year

+
+
+ +

Example Fill-in-the-Blank Problem

+ + + National Central University + Nanjing University +

Explanation

Nanjing Higher Normal Institute first admitted female students in 1920.

-
-

Example Custom Python-Evaluated Input Problem

+
+
+ +

Example Custom Python-Evaluated Input Problem

+ + + + +
+ + +
+

Explanation

+

Any set of integers on the line \(y = 10 - x\) satisfy these constraints.

+
+
+
+ + -

Enter two integers that sum to 10.

- -
- -
-

Enter two integers that sum to 20.

- -
- -
- -
-

Explanation

-

Any set of integers on the line \(y = 10 - x\) and \(y = 20 - x\) satisfy these constraints.

-

To add an image to the solution, use an HTML "img" tag. Make sure to include alt text.

- Description of image -
-
+ +
+ + +
+

Explanation

+

Any set of integers on the line \(y = 20 - x\) satisfy these constraints.

+

To add an image to the solution, use an HTML "img" tag. Make sure to include alt text.

+ Description of image +
+
+

+

Example Image Mapped Input Problem

-

What country is home to the Great Pyramid of Giza as well as the cities - of Cairo and Memphis? Click the country on the map below.

- - - + + +

Explanation

@@ -207,22 +227,24 @@ data: | the Sphinx and the ancient Royal Library of Alexandria.

-
-

Example Hidden Explanation

-

You can provide additional information that only appears at certain times by including a "showhide" flag.

-

- - - - - - - - - - -

+
+
+ +

Example Hidden Explanation

+

You can provide additional information that only appears at certain times by including a "showhide" flag.

+

+ + + + + + + + + + +

diff --git a/common/lib/xmodule/xmodule/templates/problem/multiplechoice.yaml b/common/lib/xmodule/xmodule/templates/problem/multiplechoice.yaml index bc9aa26e35..8b3cf4269d 100644 --- a/common/lib/xmodule/xmodule/templates/problem/multiplechoice.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/multiplechoice.yaml @@ -22,32 +22,30 @@ metadata: The population of Germany is approximately 81 million. [explanation] -data: | - -

Multiple choice problems allow learners to select only one option. - Learners can see all the options along with the problem text.

-

When you add the problem, be sure to select Settings - to specify a Display Name and other values that apply.

-

You can use the following example problem as a model.

-

Which of the following countries has the largest population?

- - - Brazil - timely feedback -- explain why an almost correct answer is wrong - - Germany - Indonesia - Russia - - - -
-

Explanation

-

According to September 2014 estimates:

-

The population of Indonesia is approximately 250 million.

-

The population of Brazil is approximately 200 million.

-

The population of Russia is approximately 146 million.

-

The population of Germany is approximately 81 million.

-
-
-
\ No newline at end of file +data: | + + +

Multiple choice problems allow learners to select only one option. Learners can see all the options along with the problem text.

+

When you add the problem, be sure to select Settings to specify a Display Name and other values that apply.

+

You can use the following example problem as a model.

+ + + Brazil + timely feedback -- explain why an almost correct answer is wrong + + Germany + Indonesia + Russia + + +
+

Explanation

+

According to September 2014 estimates:

+

The population of Indonesia is approximately 250 million.

+

The population of Brazil is approximately 200 million.

+

The population of Russia is approximately 146 million.

+

The population of Germany is approximately 81 million.

+
+
+
+
diff --git a/common/lib/xmodule/xmodule/templates/problem/multiplechoice_hint.yaml b/common/lib/xmodule/xmodule/templates/problem/multiplechoice_hint.yaml index 32c0fbb1c7..a05c0552d2 100644 --- a/common/lib/xmodule/xmodule/templates/problem/multiplechoice_hint.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/multiplechoice_hint.yaml @@ -21,26 +21,32 @@ metadata: ||A fruit contains seeds of the plant.|| hinted: true -data: | - - -

You can provide feedback for each option in a multiple choice problem.

+data: | + + +

You can provide feedback for each option in a multiple choice problem.

+

You can also add hints for learners.

+

Be sure to select Settings to specify a Display Name and other values that apply.

+

Use the following example problem as a model.

+ + + apple + An apple is the fertilized ovary that comes from an apple tree and contains seeds, meaning it is a fruit. + + pumpkin + A pumpkin is the fertilized ovary of a squash plant and contains seeds, meaning it is a fruit. + + potato + A potato is an edible part of a plant in tuber form and is a vegetable. + + tomato + Many people mistakenly think a tomato is a vegetable. However, because a tomato is the fertilized ovary of a tomato plant and contains seeds, it is a fruit. + + +
-

You can also add hints for learners.

- -

Use the following example problem as a model.

- -

Which of the following is a vegetable?

- - - apple An apple is the fertilized ovary that comes from an apple tree and contains seeds, meaning it is a fruit. - pumpkin A pumpkin is the fertilized ovary of a squash plant and contains seeds, meaning it is a fruit. - potato A potato is an edible part of a plant in tuber form and is a vegetable. - tomato Many people mistakenly think a tomato is a vegetable. However, because a tomato is the fertilized ovary of a tomato plant and contains seeds, it is a fruit. - - - - A fruit is the fertilized ovary from a flower. - A fruit contains seeds of the plant. - -
+ + A fruit is the fertilized ovary from a flower. + A fruit contains seeds of the plant. + +
diff --git a/common/lib/xmodule/xmodule/templates/problem/numericalresponse.yaml b/common/lib/xmodule/xmodule/templates/problem/numericalresponse.yaml index 324de1fe2e..72bd66e7e2 100644 --- a/common/lib/xmodule/xmodule/templates/problem/numericalresponse.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/numericalresponse.yaml @@ -15,44 +15,46 @@ metadata: = 9.3*10^7 or= 9.296*10^7 + [explanation] + The sun is 93,000,000, or 9.3*10^7, miles away from Earth. + [explanation] + + --- + >>The square of what number is -100?<< = 10*i [explanation] - The sun is 93,000,000, or 9.3*10^7, miles away from Earth. -100 is the square of 10 times the imaginary number, i. [explanation] -data: | - +data: | + + +

In a numerical input problem, learners enter numbers or a specific and relatively simple mathematical expression. Learners enter the response in plain text, and the system then converts the text to a symbolic expression that learners can see below the response field.

+

The system can handle several types of characters, including basic operators, fractions, exponents, and common constants such as i. You can refer learners to + Entering Mathematical and Scientific Expressionsin the EdX Learner's Guide + for information about how to enter text into the field.

+

When you add the problem, be sure to select Settings to specify a Display Name and other values that apply.

+

You can use the following example problems as models.

+ + + +
+

Explanation

+

The sun is 93,000,000, or 9.3*10^7, miles away from Earth.

+
+
+
-

In a numerical input problem, learners enter numbers or a specific and - relatively simple mathematical expression. Learners enter the response in - plain text, and the system then converts the text to a symbolic expression - that learners can see below the response field.

- -

The system can handle several types of characters, including basic - operators, fractions, exponents, and common constants such as i. You can - refer learners to - Entering Mathematical and Scientific Expressions in the EdX Learner's Guide for information about how to enter text into the field.

-

When you add the problem, be sure to select Settings - to specify a Display Name and other values that apply.

- -

You can use the following example problems as models.

-

How many miles away from Earth is the sun? Use scientific notation to answer.

- - - - -

The square of what number is -100?

- - - - -
-

Explanation

-

The sun is 93,000,000, or 9.3*10^7, miles away from Earth.

-

-100 is the square of 10 times the imaginary number, i.

-
-
-
+ + + + +
+

Explanation

+

-100 is the square of 10 times the imaginary number, i.

+
+
+
+
diff --git a/common/lib/xmodule/xmodule/templates/problem/numericalresponse_hint.yaml b/common/lib/xmodule/xmodule/templates/problem/numericalresponse_hint.yaml index b87732922c..fff5cd281f 100644 --- a/common/lib/xmodule/xmodule/templates/problem/numericalresponse_hint.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/numericalresponse_hint.yaml @@ -2,7 +2,7 @@ metadata: display_name: Numerical Input with Hints and Feedback markdown: | - + You can provide feedback for correct answers in numerical input problems. You cannot provide feedback for incorrect answers. Use feedback for the correct answer to reinforce the process for arriving at the numerical value. @@ -25,30 +25,27 @@ metadata: [explanation] hinted: true -data: | - - -

You can provide feedback for correct answers in numerical input problems. You cannot provide feedback for incorrect answers.

+data: | + + +

You can provide feedback for correct answers in numerical input problems. You cannot provide feedback for incorrect answers.

+

Use feedback for the correct answer to reinforce the process for arriving at the numerical value.

+

You can also add hints for learners.

+

Be sure to select Settings to specify a Display Name and other values that apply.

+

Use the following example problem as a model.

+ + + The mean for this set of numbers is 20 / 5, which equals 4. + +
+

Explanation

+

The mean is calculated by summing the set of numbers and dividing by n. In this case: (1 + 5 + 6 + 3 + 5) / 5 = 20 / 5 = 4.

+
+
+
-

Use feedback for the correct answer to reinforce the process for arriving at the numerical value.

- -

Use the following example problem as a model.

- -

What is the arithmetic mean for the following set of numbers? (1, 5, 6, 3, 5)

- - - The mean for this set of numbers is 20 / 5, which equals 4. - - - -
-

Explanation

-

The mean is calculated by summing the set of numbers and dividing by n. In this case: (1 + 5 + 6 + 3 + 5) / 5 = 20 / 5 = 4.

-
-
- - - The mean is calculated by summing the set of numbers and dividing by n. - n is the count of items in the set. - -
\ No newline at end of file + + The mean is calculated by summing the set of numbers and dividing by n. + n is the count of items in the set. + +
diff --git a/common/lib/xmodule/xmodule/templates/problem/optionresponse.yaml b/common/lib/xmodule/xmodule/templates/problem/optionresponse.yaml index 50ec67b528..60d40cd132 100644 --- a/common/lib/xmodule/xmodule/templates/problem/optionresponse.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/optionresponse.yaml @@ -8,29 +8,26 @@ metadata: You can use the following example problem as a model. - >>Which of the following countries celebrates its independence on August 15?<< + >>Which of the following countries celebrates its independence on August 15?<< - [[(India), Spain, China, Bermuda]] - - [explanation] - India became an independent nation on August 15, 1947. - [explanation] -data: | - -

Dropdown problems allow learners to select only one option from a list of options.

-

When you add the problem, be sure to select Settings - to specify a Display Name and other values that apply.

-

You can use the following example problem as a model.

-

Which of the following countries celebrates its independence on August 15?

-
- - - - -
-

Explanation

-

India became an independent nation on August 15, 1947.

-
-
-
+ [[(India), Spain, China, Bermuda]] + [explanation] + India became an independent nation on August 15, 1947. + [explanation] +data: | + + +

Dropdown problems allow learners to select only one option from a list of options.

+

When you add the problem, be sure to select Settings to specify a Display Name and other values that apply.

+

You can use the following example problem as a model.

+ + + +
+

Explanation

+

India became an independent nation on August 15, 1947.

+
+
+
+
diff --git a/common/lib/xmodule/xmodule/templates/problem/optionresponse_hint.yaml b/common/lib/xmodule/xmodule/templates/problem/optionresponse_hint.yaml index 139745f69f..80169409d8 100644 --- a/common/lib/xmodule/xmodule/templates/problem/optionresponse_hint.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/optionresponse_hint.yaml @@ -24,28 +24,32 @@ metadata: ||A fruit contains seeds of the plant.|| hinted: true -data: | - +data: | + + +

You can provide feedback for each available option in a dropdown problem.

+

You can also add hints for learners.

+

Be sure to select Settings to specify a Display Name and other values that apply.

+

Use the following example problem as a model.

+ + + + + + + +
-

You can provide feedback for each available option in a dropdown problem.

- -

You can also add hints for learners.

- -

Use the following example problem as a model.

- -

A/an ________ is a vegetable.

-
- - - - - - - - - - - A fruit is the fertilized ovary from a flower. - A fruit contains seeds of the plant. - -
+ + A fruit is the fertilized ovary from a flower. + A fruit contains seeds of the plant. + +
diff --git a/common/lib/xmodule/xmodule/templates/problem/problem_with_hint.yaml b/common/lib/xmodule/xmodule/templates/problem/problem_with_hint.yaml index e8981840b9..1f04d45f73 100644 --- a/common/lib/xmodule/xmodule/templates/problem/problem_with_hint.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/problem_with_hint.yaml @@ -4,13 +4,12 @@ metadata: markdown: !!null data: | - -

-

Problem With Adaptive Hint

-

-

- This problem demonstrates a question with hints, based on using the hintfn method.

- - -
+ + + +
+
diff --git a/common/lib/xmodule/xmodule/templates/problem/problem_with_hint_in_latex.yaml b/common/lib/xmodule/xmodule/templates/problem/problem_with_hint_in_latex.yaml index b4f5bda678..0c3efad132 100644 --- a/common/lib/xmodule/xmodule/templates/problem/problem_with_hint_in_latex.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/problem_with_hint_in_latex.yaml @@ -49,12 +49,11 @@ metadata: markdown: !!null data: | - -

-

Problem With Adaptive Hint

-

-

- This problem demonstrates a question with hints, based on using the hintfn method.

+ +

Problem With Adaptive Hint

+

This problem demonstrates a question with hints, based on using the hintfn method.

+ + - -
+ + + + +
diff --git a/common/lib/xmodule/xmodule/templates/problem/string_response.yaml b/common/lib/xmodule/xmodule/templates/problem/string_response.yaml index 223cf22d5b..0c7667a405 100644 --- a/common/lib/xmodule/xmodule/templates/problem/string_response.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/string_response.yaml @@ -3,7 +3,7 @@ metadata: display_name: Text Input markdown: | In text input problems, also known as "fill-in-the-blank" problems, learners enter text into a response field. The text can include letters and characters such as punctuation marks. The text that the learner enters must match your specified answer text exactly. You can specify more than one correct answer. Learners must enter a response that matches one of the correct answers exactly. - + When you add the problem, be sure to select Settings to specify a Display Name and other values that apply. You can use the following example problem as a model. @@ -18,26 +18,21 @@ metadata: Nanjing Higher Normal Institute first admitted female students in 1920. [explanation] -data: | - -

In text input problems, also known as "fill-in-the-blank" problems, - learners enter text into a response field. The text that the learner enters - must match your specified answer text exactly. You can specify more than - one correct answer. Learners must enter a response that matches one of the - correct answers exactly.

-

When you add the problem, be sure to select Settings - to specify a Display Name and other values that apply.

-

You can use the following example problem as a model.

-

What was the first post-secondary school in China to allow both male and female students?

- - National Central University - Nanjing University - - - -
-

Explanation

-

Nanjing Higher Normal Institute first admitted female students in 1920.

-
-
-
+data: | + + +

In text input problems, also known as "fill-in-the-blank" problems, learners enter text into a response field. The text that the learner enters must match your specified answer text exactly. You can specify more than one correct answer. Learners must enter a response that matches one of the correct answers exactly.

+

When you add the problem, be sure to select Settings to specify a Display Name and other values that apply.

+

You can use the following example problem as a model.

+ + National Central University + Nanjing University + + +
+

Explanation

+

Nanjing Higher Normal Institute first admitted female students in 1920.

+
+
+
+
diff --git a/common/lib/xmodule/xmodule/templates/problem/string_response_hint.yaml b/common/lib/xmodule/xmodule/templates/problem/string_response_hint.yaml index bbc6d5006f..415458ffc2 100644 --- a/common/lib/xmodule/xmodule/templates/problem/string_response_hint.yaml +++ b/common/lib/xmodule/xmodule/templates/problem/string_response_hint.yaml @@ -1,7 +1,7 @@ --- metadata: display_name: Text Input with Hints and Feedback - markdown: | + markdown: | You can provide feedback for the correct answer in text input problems, as well as for specific incorrect answers. @@ -24,31 +24,21 @@ metadata: ||Consider all 50 states, not just the continental United States.|| hinted: true -data: | - - -

You can provide feedback for the correct answer in text input problems, as well as for specific incorrect answers.

- -

Use feedback on expected incorrect answers to address common misconceptions and to provide guidance on how to arrive at the correct answer.

- -

Use the following example problem as a model.

- -

Which U.S. state has the largest land area?

- - - - Alaska is 576,400 square miles, more than double the land area of the second largest state, Texas. - - While many people think Texas is the largest state, it is actually the second largest, with 261,797 square miles. - - California is the third largest state, with 155,959 square miles. - - - - - - Consider the square miles, not population. - Consider all 50 states, not just the continental United States. - - -
+data: | + + +

You can provide feedback for the correct answer in text input problems, as well as for specific incorrect answers.

+

Use feedback on expected incorrect answers to address common misconceptions and to provide guidance on how to arrive at the correct answer.

+

Be sure to select Settings to specify a Display Name and other values that apply.

+

Use the following example problem as a model.

+ + Alaska is 576,400 square miles, more than double the land area of the second largest state, Texas. + While many people think Texas is the largest state, it is actually the second largest, with 261,797 square miles. + California is the third largest state, with 155,959 square miles. + +
+ + Consider the square miles, not population. + Consider all 50 states, not just the continental United States. + +
diff --git a/common/static/common/js/spec_helpers/jasmine-extensions.js b/common/static/common/js/spec_helpers/jasmine-extensions.js index 5d5a8407ce..3afc2ed7d5 100644 --- a/common/static/common/js/spec_helpers/jasmine-extensions.js +++ b/common/static/common/js/spec_helpers/jasmine-extensions.js @@ -86,6 +86,15 @@ }; } }; + }, + toXMLEqual: function() { + return { + compare: function(actual, expected) { + return { + pass: actual.replace(/\s+/g, '') === expected.replace(/\s+/g, '') + }; + } + }; } }); }); diff --git a/lms/templates/problem.html b/lms/templates/problem.html index 55e1e77c78..1b912ad821 100644 --- a/lms/templates/problem.html +++ b/lms/templates/problem.html @@ -12,9 +12,7 @@ from openedx.core.djangolib.markup import HTML
-
- ${ HTML(problem['html']) } -
+ ${ HTML(problem['html']) }
% if demand_hint_possible: From 3556f2a3ea9cdec97ffed966c77b1cb9b9808c0d Mon Sep 17 00:00:00 2001 From: Ehtesham Date: Tue, 21 Jun 2016 16:26:00 +0500 Subject: [PATCH 2/8] make CAPA problems (MultipleChoice and Checkboxes) accessible --- common/lib/capa/capa/capa_problem.py | 19 +++- common/lib/capa/capa/inputtypes.py | 5 +- common/lib/capa/capa/responsetypes.py | 14 ++- .../lib/capa/capa/templates/choicegroup.html | 87 +++++++++++-------- .../lib/capa/capa/tests/test_html_render.py | 32 ++++++- .../capa/capa/tests/test_input_templates.py | 25 +++--- .../xmodule/js/src/capa/display.coffee | 9 +- common/test/acceptance/pages/lms/problem.py | 22 +++++ .../tests/lms/test_certificate_web_view.py | 6 +- .../acceptance/tests/lms/test_lms_problems.py | 2 +- .../tests/lms/test_problem_types.py | 70 +++++++-------- 11 files changed, 183 insertions(+), 108 deletions(-) diff --git a/common/lib/capa/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py index 4a719a5711..15dd3f538a 100644 --- a/common/lib/capa/capa/capa_problem.py +++ b/common/lib/capa/capa/capa_problem.py @@ -176,7 +176,7 @@ class LoncapaProblem(object): # transformations. This also creates the dict (self.responders) of Response # instances for each question in the problem. The dict has keys = xml subtree of # Response, values = Response instance - self._preprocess_problem(self.tree) + self.problem_data = self._preprocess_problem(self.tree) if not self.student_answers: # True when student_answers is an empty dict self.set_initial_display() @@ -752,7 +752,10 @@ class LoncapaProblem(object): if problemtree.tag in inputtypes.registry.registered_tags(): # If this is an inputtype subtree, let it render itself. - status = "unsubmitted" + response_id = self.problem_id + '_' + problemtree.get('response_id') + response_data = self.problem_data[response_id] + + status = 'unsubmitted' msg = '' hint = '' hintmode = None @@ -766,7 +769,7 @@ class LoncapaProblem(object): hintmode = self.correct_map.get_hintmode(pid) answervariable = self.correct_map.get_property(pid, 'answervariable') - value = "" + value = '' if self.student_answers and problemid in self.student_answers: value = self.student_answers[problemid] @@ -780,6 +783,7 @@ class LoncapaProblem(object): 'id': input_id, 'input_state': self.input_state[input_id], 'answervariable': answervariable, + 'response_data': response_data, 'feedback': { 'message': msg, 'hint': hint, @@ -836,6 +840,7 @@ class LoncapaProblem(object): Obtain all responder answers and save as self.responder_answers dict (key = response) """ response_id = 1 + problem_data = {} self.responders = {} for response in tree.xpath('//' + "|//".join(responsetypes.registry.registered_tags())): response_id_str = self.problem_id + "_" + str(response_id) @@ -857,6 +862,12 @@ class LoncapaProblem(object): entry.attrib['id'] = "%s_%i_%i" % (self.problem_id, response_id, answer_id) answer_id = answer_id + 1 + # Find the label and save it for html transformation step + responsetype_label = response.find('label') + problem_data[self.problem_id + '_' + str(response_id)] = { + 'label': responsetype_label.text if responsetype_label is not None else '' + } + # instantiate capa Response responsetype_cls = responsetypes.registry.get_class_for_tag(response.tag) responder = responsetype_cls(response, inputfields, self.context, self.capa_system, self.capa_module) @@ -881,3 +892,5 @@ class LoncapaProblem(object): for solution in tree.findall('.//solution'): solution.attrib['id'] = "%s_solution_%i" % (self.problem_id, solution_id) solution_id += 1 + + return problem_data diff --git a/common/lib/capa/capa/inputtypes.py b/common/lib/capa/capa/inputtypes.py index f5d079ac64..53ff76c4d5 100644 --- a/common/lib/capa/capa/inputtypes.py +++ b/common/lib/capa/capa/inputtypes.py @@ -224,7 +224,8 @@ class InputTypeBase(object): self.hint = feedback.get('hint', '') self.hintmode = feedback.get('hintmode', None) self.input_state = state.get('input_state', {}) - self.answervariable = state.get("answervariable", None) + self.answervariable = state.get('answervariable', None) + self.response_data = state.get('response_data', None) # put hint above msg if it should be displayed if self.hintmode == 'always': @@ -316,8 +317,10 @@ class InputTypeBase(object): 'value': self.value, 'status': Status(self.status, self.capa_system.i18n.ugettext), 'msg': self.msg, + 'response_data': self.response_data, 'STATIC_URL': self.capa_system.STATIC_URL, } + context.update( (a, v) for (a, v) in self.loaded_attributes.iteritems() if a in self.to_render ) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 921148b1f7..15112853cb 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -250,8 +250,18 @@ class LoncapaResponse(object): - renderer : procedure which produces HTML given an ElementTree - response_msg: a message displayed at the end of the Response """ - # render ourself as a + our content - tree = etree.Element('span') + _ = self.capa_system.i18n.ugettext + + # get responsetype index to make responsetype label + response_index = self.xml.attrib['id'].split('_')[-1] + # Translators: index here could be 1,2,3 and so on + response_label = _(u'Question {index}').format(index=response_index) + + # wrap the content inside a section + tree = etree.Element('section') + tree.set('class', 'wrapper-problem-response') + tree.set('tabindex', '-1') + tree.set('aria-label', response_label) # problem author can make this span display:inline if self.xml.get('inline', ''): diff --git a/common/lib/capa/capa/templates/choicegroup.html b/common/lib/capa/capa/templates/choicegroup.html index 55314db731..f3ce336b54 100644 --- a/common/lib/capa/capa/templates/choicegroup.html +++ b/common/lib/capa/capa/templates/choicegroup.html @@ -1,43 +1,56 @@ +<% + def is_radio_input(choice_id): + return input_type == 'radio' and ((isinstance(value, basestring) and (choice_id == value)) or ( + not isinstance(value, basestring) and choice_id in value + )) +%>
-
- % for choice_id, choice_description in choices: -
@@ -45,9 +58,9 @@ % if input_type == 'checkbox' or not value: - %for choice_id, choice_description in choices: + %for choice_id, choice_label in choices: % if choice_id in value: - ${choice_description}, + ${choice_label}, %endif %endfor - diff --git a/common/lib/capa/capa/tests/test_html_render.py b/common/lib/capa/capa/tests/test_html_render.py index a83cd55cdb..d87343ba8a 100644 --- a/common/lib/capa/capa/tests/test_html_render.py +++ b/common/lib/capa/capa/tests/test_html_render.py @@ -155,11 +155,12 @@ class CapaHtmlRenderTest(unittest.TestCase): question_element = rendered_html.find("p") self.assertEqual(question_element.text, "Test question") - # Expect that the response has been turned into a - response_element = rendered_html.find("span") - self.assertEqual(response_element.tag, "span") + # Expect that the response has been turned into a
with correct attributes + response_element = rendered_html.find("section") + self.assertEqual(response_element.tag, "section") + self.assertEqual(response_element.attrib["aria-label"], "Question 1") - # Expect that the response + # Expect that the response
# that contains a
for the textline textline_element = response_element.find("div") self.assertEqual(textline_element.text, 'Input Template Render') @@ -201,6 +202,29 @@ class CapaHtmlRenderTest(unittest.TestCase): expected_calls ) + def test_correct_aria_label(self): + xml = """ + + + + over-suspicious + funny + + + + + Urdu + Finnish + + + + """ + problem = new_loncapa_problem(xml) + rendered_html = etree.XML(problem.get_html()) + sections = rendered_html.findall('section') + self.assertEqual(sections[0].attrib['aria-label'], 'Question 1') + self.assertEqual(sections[1].attrib['aria-label'], 'Question 2') + def test_render_response_with_overall_msg(self): # CustomResponse script that sets an overall_message script = textwrap.dedent(""" diff --git a/common/lib/capa/capa/tests/test_input_templates.py b/common/lib/capa/capa/tests/test_input_templates.py index c20dc28d9c..66296d6251 100644 --- a/common/lib/capa/capa/tests/test_input_templates.py +++ b/common/lib/capa/capa/tests/test_input_templates.py @@ -122,13 +122,16 @@ class ChoiceGroupTemplateTest(TemplateTestCase): def setUp(self): choices = [('1', 'choice 1'), ('2', 'choice 2'), ('3', 'choice 3')] - self.context = {'id': '1', - 'choices': choices, - 'status': Status('correct'), - 'label': 'test', - 'input_type': 'checkbox', - 'name_array_suffix': '1', - 'value': '3'} + self.context = { + 'id': '1', + 'choices': choices, + 'status': Status('correct'), + 'label': 'test', + 'input_type': 'checkbox', + 'name_array_suffix': '1', + 'value': '3', + 'response_data': {'label': 'test'} + } super(ChoiceGroupTemplateTest, self).setUp() def test_problem_marked_correct(self): @@ -229,7 +232,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase): for test_conditions in conditions: self.context.update(test_conditions) xml = self.render_to_xml(self.context) - xpath = "//label[@class='choicegroup_correct']" + xpath = "//label[contains(@class, 'choicegroup_correct')]" self.assert_has_xpath(xml, xpath, self.context) # Should NOT mark the whole problem @@ -250,7 +253,7 @@ class ChoiceGroupTemplateTest(TemplateTestCase): for test_conditions in conditions: self.context.update(test_conditions) xml = self.render_to_xml(self.context) - xpath = "//label[@class='choicegroup_incorrect']" + xpath = "//label[contains(@class, 'choicegroup_incorrect')]" self.assert_has_xpath(xml, xpath, self.context) # Should NOT mark the whole problem @@ -340,8 +343,8 @@ class ChoiceGroupTemplateTest(TemplateTestCase): def test_label(self): xml = self.render_to_xml(self.context) - xpath = "//fieldset[@aria-label='%s']" % self.context['label'] - self.assert_has_xpath(xml, xpath, self.context) + xpath = "//legend" + self.assert_has_text(xml, xpath, self.context['label']) class TextlineTemplateTest(TemplateTestCase): diff --git a/common/lib/xmodule/xmodule/js/src/capa/display.coffee b/common/lib/xmodule/xmodule/js/src/capa/display.coffee index 8c37b7cc7d..f88c9e6def 100644 --- a/common/lib/xmodule/xmodule/js/src/capa/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/capa/display.coffee @@ -66,7 +66,7 @@ class @Problem detail = @el.data('progress_detail') status = @el.data('progress_status') - # Render 'x/y point(s)' if student has attempted question + # Render 'x/y point(s)' if student has attempted question if status != 'none' and detail? and (jQuery.type(detail) == "string") and detail.indexOf('/') > 0 a = detail.split('/') earned = parseFloat(a[0]) @@ -628,10 +628,10 @@ class @Problem choicegroup: (element, display, answers) => element = $(element) - input_id = element.attr('id').replace(/inputtype_/,'') + input_id = element.attr('id').replace(/inputtype_/, '') answer = answers[input_id] for choice in answer - element.find("label[for='input_#{input_id}_#{choice}']").addClass 'choicegroup_correct' + element.find("#input_#{input_id}_#{choice}").parent("label").addClass 'choicegroup_correct' javascriptinput: (element, display, answers) => answer_id = $(element).attr('id').split("_")[1...].join("_") @@ -641,7 +641,7 @@ class @Problem choicetextgroup: (element, display, answers) => element = $(element) - input_id = element.attr('id').replace(/inputtype_/,'') + input_id = element.attr('id').replace(/inputtype_/, '') answer = answers[input_id] for choice in answer element.find("section#forinput#{choice}").addClass 'choicetextgroup_show_correct' @@ -821,4 +821,3 @@ class @Problem ] hint_container.attr('hint_index', response.hint_index) @$('.hint-button').focus() # a11y focus on click, like the Check button - diff --git a/common/test/acceptance/pages/lms/problem.py b/common/test/acceptance/pages/lms/problem.py index 0429637dc5..3af153fa4b 100644 --- a/common/test/acceptance/pages/lms/problem.py +++ b/common/test/acceptance/pages/lms/problem.py @@ -129,6 +129,11 @@ class ProblemPage(PageObject): self.q(css='div.problem button.reset').click() self.wait_for_ajax() + def click_show_hide_button(self): + """ Click the Show/Hide button. """ + self.q(css='div.problem div.action .show').click() + self.wait_for_ajax() + def wait_for_status_icon(self): """ wait for status icon @@ -199,3 +204,20 @@ class ProblemPage(PageObject): """ self.wait_for_element_visibility('body > .tooltip', 'A tooltip is visible.') return self.q(css='body > .tooltip').text[0] + + def is_solution_tag_present(self): + """ + Check if solution/explanation is shown. + """ + solution_selector = '.solution-span div.detailed-solution' + return self.q(css=solution_selector).is_present() + + def is_correct_choice_highlighted(self, correct_choices): + """ + Check if correct answer/choice highlighted for choice group. + """ + xpath = '//fieldset/div[contains(@class, "field")][{0}]/label[contains(@class, "choicegroup_correct")]' + for choice in correct_choices: + if not self.q(xpath=xpath.format(choice)).is_present(): + return False + return True diff --git a/common/test/acceptance/tests/lms/test_certificate_web_view.py b/common/test/acceptance/tests/lms/test_certificate_web_view.py index 1b928dd47e..7ea52cf30e 100644 --- a/common/test/acceptance/tests/lms/test_certificate_web_view.py +++ b/common/test/acceptance/tests/lms/test_certificate_web_view.py @@ -218,11 +218,11 @@ class CertificateProgressPageTest(UniqueCourseTest): self.course_nav.q(css='select option[value="{}"]'.format('blue')).first.click() # Select correct radio button for the answer - self.course_nav.q(css='fieldset label:nth-child(3) input').nth(0).click() + self.course_nav.q(css='fieldset div.field:nth-child(4) input').nth(0).click() # Select correct radio buttons for the answer - self.course_nav.q(css='fieldset label:nth-child(1) input').nth(1).click() - self.course_nav.q(css='fieldset label:nth-child(3) input').nth(1).click() + self.course_nav.q(css='fieldset div.field:nth-child(2) input').nth(1).click() + self.course_nav.q(css='fieldset div.field:nth-child(4) input').nth(1).click() # Submit the answer self.course_nav.q(css='button.check.Check').click() diff --git a/common/test/acceptance/tests/lms/test_lms_problems.py b/common/test/acceptance/tests/lms/test_lms_problems.py index daa0fcb64b..209151b559 100644 --- a/common/test/acceptance/tests/lms/test_lms_problems.py +++ b/common/test/acceptance/tests/lms/test_lms_problems.py @@ -51,7 +51,7 @@ class ProblemsTest(UniqueCourseTest): email=self.email, password=self.password, course_id=self.course_id, - staff=False + staff=True ).visit() def get_problem(self): diff --git a/common/test/acceptance/tests/lms/test_problem_types.py b/common/test/acceptance/tests/lms/test_problem_types.py index 6370fd48f8..5e36b67b15 100644 --- a/common/test/acceptance/tests/lms/test_problem_types.py +++ b/common/test/acceptance/tests/lms/test_problem_types.py @@ -324,7 +324,8 @@ class CheckboxProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): 'question_text': 'The correct answer is Choice 0 and Choice 2', 'choice_type': 'checkbox', 'choices': [True, False, True, False], - 'choice_names': ['Choice 0', 'Choice 1', 'Choice 2', 'Choice 3'] + 'choice_names': ['Choice 0', 'Choice 1', 'Choice 2', 'Choice 3'], + 'explanation_text': 'This is explanation text' } def setUp(self, *args, **kwargs): @@ -332,15 +333,6 @@ class CheckboxProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): Additional setup for CheckboxProblemTypeTest """ super(CheckboxProblemTypeTest, self).setUp(*args, **kwargs) - self.problem_page.a11y_audit.config.set_rules({ - 'ignore': [ - 'section', # TODO: AC-491 - 'aria-allowed-attr', # TODO: AC-251 - 'aria-valid-attr', # TODO: AC-251 - 'aria-roles', # TODO: AC-251 - 'checkboxgroup', # TODO: AC-251 - ] - }) def answer_problem(self, correct): """ @@ -352,6 +344,30 @@ class CheckboxProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): else: self.problem_page.click_choice("choice_1") + @attr('shard_7') + def test_can_show_hide_answer(self): + """ + Scenario: Verifies that show/hide answer button is working as expected. + + Given that I am on courseware page + And I can see a CAPA problem with show answer button + When I click "Show Answer" button + Then I should see "Hide Answer" text on button + And I should see question's solution + And I should see correct choices highlighted + When I click "Hide Answer" button + Then I should see "Show Answer" text on button + And I should not see question's solution + And I should not see correct choices highlighted + """ + self.problem_page.click_show_hide_button() + self.assertTrue(self.problem_page.is_solution_tag_present()) + self.assertTrue(self.problem_page.is_correct_choice_highlighted(correct_choices=[1, 3])) + + self.problem_page.click_show_hide_button() + self.assertFalse(self.problem_page.is_solution_tag_present()) + self.assertFalse(self.problem_page.is_correct_choice_highlighted(correct_choices=[1, 3])) + class MultipleChoiceProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): """ @@ -378,13 +394,6 @@ class MultipleChoiceProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): Additional setup for MultipleChoiceProblemTypeTest """ super(MultipleChoiceProblemTypeTest, self).setUp(*args, **kwargs) - self.problem_page.a11y_audit.config.set_rules({ - 'ignore': [ - 'section', # TODO: AC-491 - 'aria-valid-attr', # TODO: AC-251 - 'radiogroup', # TODO: AC-251 - ] - }) def answer_problem(self, correct): """ @@ -422,13 +431,6 @@ class RadioProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): Additional setup for RadioProblemTypeTest """ super(RadioProblemTypeTest, self).setUp(*args, **kwargs) - self.problem_page.a11y_audit.config.set_rules({ - 'ignore': [ - 'section', # TODO: AC-491 - 'aria-valid-attr', # TODO: AC-292 - 'radiogroup', # TODO: AC-292 - ] - }) def answer_problem(self, correct): """ @@ -798,13 +800,6 @@ class RadioTextProblemTypeTest(ChoiceTextProbelmTypeTestBase, ProblemTypeTestMix Additional setup for RadioTextProblemTypeTest """ super(RadioTextProblemTypeTest, self).setUp(*args, **kwargs) - self.problem_page.a11y_audit.config.set_rules({ - 'ignore': [ - 'section', # TODO: AC-491 - 'label', # TODO: AC-285 - 'radiogroup', # TODO: AC-285 - ] - }) class CheckboxTextProblemTypeTest(ChoiceTextProbelmTypeTestBase, ProblemTypeTestMixin): @@ -831,13 +826,6 @@ class CheckboxTextProblemTypeTest(ChoiceTextProbelmTypeTestBase, ProblemTypeTest Additional setup for CheckboxTextProblemTypeTest """ super(CheckboxTextProblemTypeTest, self).setUp(*args, **kwargs) - self.problem_page.a11y_audit.config.set_rules({ - 'ignore': [ - 'section', # TODO: AC-491 - 'label', # TODO: AC-284 - 'checkboxgroup', # TODO: AC-284 - ] - }) class ImageProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): @@ -885,9 +873,9 @@ class SymbolicProblemTypeTest(ProblemTypeTestBase, ProblemTypeTestMixin): } status_indicators = { - 'correct': ['span div.correct'], - 'incorrect': ['span div.incorrect'], - 'unanswered': ['span div.unanswered'], + 'correct': ['div.capa_inputtype div.correct'], + 'incorrect': ['div.capa_inputtype div.incorrect'], + 'unanswered': ['div.capa_inputtype div.unanswered'], } def setUp(self, *args, **kwargs): From 7240b6256c6674b95c032825ac37c026009387e7 Mon Sep 17 00:00:00 2001 From: muhammad-ammar Date: Wed, 20 Jul 2016 18:37:17 +0500 Subject: [PATCH 3/8] Associate descriptions with question text TNL-5014 --- common/lib/capa/capa/capa_problem.py | 82 ++- common/lib/capa/capa/inputtypes.py | 33 +- .../capa/templates/chemicalequationinput.html | 2 +- .../lib/capa/capa/templates/choicegroup.html | 16 +- .../lib/capa/capa/templates/choicetext.html | 6 +- .../capa/capa/templates/filesubmission.html | 2 +- .../capa/templates/formulaequationinput.html | 3 +- .../lib/capa/capa/templates/optioninput.html | 2 +- .../capa/capa/templates/schematicinput.html | 2 +- common/lib/capa/capa/templates/textline.html | 8 +- .../lib/capa/capa/tests/test_capa_problem.py | 319 +++++++++ .../test_files/extended_hints_checkbox.xml | 26 +- .../extended_hints_multiple_choice.xml | 9 +- ...tended_hints_multiple_choice_with_html.xml | 4 +- .../extended_hints_numeric_input.xml | 7 +- .../test_files/extended_hints_text_input.xml | 11 +- .../test_files/extended_hints_with_errors.xml | 3 +- .../lib/capa/capa/tests/test_html_render.py | 4 +- .../capa/capa/tests/test_input_templates.py | 165 ++++- common/lib/capa/capa/tests/test_inputtypes.py | 253 ++++--- common/lib/xmodule/xmodule/capa_base.py | 3 +- .../lib/xmodule/xmodule/css/capa/display.scss | 7 +- .../xmodule/js/spec/problem/edit_spec.coffee | 209 ++++-- .../js/spec/problem/edit_spec_hint.coffee | 663 +++++++++--------- .../xmodule/js/src/problem/edit.coffee | 67 +- .../problem/checkboxes_response.yaml | 8 +- .../problem/checkboxes_response_hint.yaml | 7 +- .../templates/problem/customgrader.yaml | 8 +- .../templates/problem/formularesponse.yaml | 6 +- .../templates/problem/latex_problem.yaml | 12 +- .../templates/problem/multiplechoice.yaml | 5 +- .../problem/multiplechoice_hint.yaml | 5 +- .../templates/problem/numericalresponse.yaml | 12 +- .../problem/numericalresponse_hint.yaml | 5 +- .../templates/problem/optionresponse.yaml | 5 +- .../problem/optionresponse_hint.yaml | 5 +- .../templates/problem/string_response.yaml | 5 +- .../problem/string_response_hint.yaml | 5 +- .../xmodule/xmodule/tests/test_capa_module.py | 54 +- common/test/acceptance/pages/lms/problem.py | 14 + .../tests/lms/test_lms_entrance_exams.py | 4 +- .../acceptance/tests/lms/test_lms_problems.py | 105 ++- 42 files changed, 1474 insertions(+), 697 deletions(-) create mode 100644 common/lib/capa/capa/tests/test_capa_problem.py diff --git a/common/lib/capa/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py index 15dd3f538a..9c9b93891e 100644 --- a/common/lib/capa/capa/capa_problem.py +++ b/common/lib/capa/capa/capa_problem.py @@ -13,6 +13,7 @@ Main module which shows problems (of "capa" type). This is used by capa_module. """ +from collections import OrderedDict from copy import deepcopy from datetime import datetime import logging @@ -35,6 +36,16 @@ from capa.safe_exec import safe_exec # extra things displayed after "show answers" is pressed solution_tags = ['solution'] +# fully accessible capa response types +ACCESSIBLE_CAPA_RESPONSE_TYPES = [ + 'choiceresponse', + 'multiplechoiceresponse', + 'optionresponse', + 'numericalresponse', + 'stringresponse', + 'formularesponse', +] + # these get captured as student responses response_properties = ["codeparam", "responseparam", "answer", "openendedparam"] @@ -61,6 +72,8 @@ log = logging.getLogger(__name__) #----------------------------------------------------------------------------- # main class for this module +DEFAULT_QUESTION_TEXT = "Formatting error: You must explicitly specify the question text." + class LoncapaSystem(object): """ @@ -855,17 +868,76 @@ class LoncapaProblem(object): id=response_id_str ) - # assign one answer_id for each input type or solution type + # assign one answer_id for each input type for entry in inputfields: entry.attrib['response_id'] = str(response_id) entry.attrib['answer_id'] = str(answer_id) entry.attrib['id'] = "%s_%i_%i" % (self.problem_id, response_id, answer_id) answer_id = answer_id + 1 - # Find the label and save it for html transformation step - responsetype_label = response.find('label') - problem_data[self.problem_id + '_' + str(response_id)] = { - 'label': responsetype_label.text if responsetype_label is not None else '' + question_id = u'{}_{}'.format(self.problem_id, response_id) + label = '' + element_to_be_deleted = None + + # Extract label value from
diff --git a/common/lib/capa/capa/templates/formulaequationinput.html b/common/lib/capa/capa/templates/formulaequationinput.html index 1e7d8c0e9f..423c193461 100644 --- a/common/lib/capa/capa/templates/formulaequationinput.html +++ b/common/lib/capa/capa/templates/formulaequationinput.html @@ -5,8 +5,7 @@
- % for option_id, option_description in options:
""").replace('\n', ' ').strip() ) @@ -724,10 +777,13 @@ class MatlabTest(unittest.TestCase):
    """) - state = {'value': 'print "good evening"', - 'status': 'incomplete', - 'input_state': {'queue_msg': queue_msg}, - 'feedback': {'message': '3'}, } + state = { + 'value': 'print "good evening"', + 'status': 'incomplete', + 'input_state': {'queue_msg': queue_msg}, + 'feedback': {'message': '3'}, + 'response_data': RESPONSE_DATA + } elt = etree.fromstring(self.xml) the_input = self.input_class(test_capa_system(), elt, state) @@ -759,6 +815,8 @@ class MatlabTest(unittest.TestCase): 'button_enabled': True, 'queue_len': '3', 'matlab_editor_js': '/dummy-static/js/vendor/CodeMirror/octave.js', + 'response_data': {}, + 'describedby': '' } self.assertEqual(context, expected) @@ -845,8 +903,11 @@ class SchematicTest(unittest.TestCase): element = etree.fromstring(xml_str) value = 'three resistors and an oscilating pendulum' - state = {'value': value, - 'status': 'unsubmitted'} + state = { + 'value': value, + 'status': 'unsubmitted', + 'response_data': RESPONSE_DATA + } the_input = lookup_tag('schematic')(test_capa_system(), element, state) @@ -857,7 +918,6 @@ class SchematicTest(unittest.TestCase): 'id': 'prob_1_2', 'value': value, 'status': inputtypes.Status('unsubmitted'), - 'label': '', 'msg': '', 'initial_value': initial_value, 'width': width, @@ -866,6 +926,8 @@ class SchematicTest(unittest.TestCase): 'setup_script': '/dummy-static/js/capa/schematicinput.js', 'analyses': analyses, 'submit_analyses': submit_analyses, + 'response_data': RESPONSE_DATA, + 'describedby': DESCRIBEDBY } self.assertEqual(context, expected) @@ -889,8 +951,11 @@ class ImageInputTest(unittest.TestCase): element = etree.fromstring(xml_str) - state = {'value': value, - 'status': 'unsubmitted'} + state = { + 'value': value, + 'status': 'unsubmitted', + 'response_data': RESPONSE_DATA + } the_input = lookup_tag('imageinput')(test_capa_system(), element, state) @@ -901,13 +966,14 @@ class ImageInputTest(unittest.TestCase): 'id': 'prob_1_2', 'value': value, 'status': inputtypes.Status('unsubmitted'), - 'label': '', 'width': width, 'height': height, 'src': src, 'gx': egx, 'gy': egy, 'msg': '', + 'response_data': RESPONSE_DATA, + 'describedby': DESCRIBEDBY } self.assertEqual(context, expected) @@ -944,8 +1010,11 @@ class CrystallographyTest(unittest.TestCase): element = etree.fromstring(xml_str) value = 'abc' - state = {'value': value, - 'status': 'unsubmitted'} + state = { + 'value': value, + 'status': 'unsubmitted', + 'response_data': RESPONSE_DATA + } the_input = lookup_tag('crystallography')(test_capa_system(), element, state) @@ -956,10 +1025,11 @@ class CrystallographyTest(unittest.TestCase): 'id': 'prob_1_2', 'value': value, 'status': inputtypes.Status('unsubmitted'), - # 'label': '', 'msg': '', 'width': width, 'height': height, + 'response_data': RESPONSE_DATA, + 'describedby': DESCRIBEDBY } self.assertEqual(context, expected) @@ -986,8 +1056,11 @@ class VseprTest(unittest.TestCase): element = etree.fromstring(xml_str) value = 'abc' - state = {'value': value, - 'status': 'unsubmitted'} + state = { + 'value': value, + 'status': 'unsubmitted', + 'response_data': RESPONSE_DATA + } the_input = lookup_tag('vsepr_input')(test_capa_system(), element, state) @@ -1003,6 +1076,8 @@ class VseprTest(unittest.TestCase): 'height': height, 'molecules': molecules, 'geometries': geometries, + 'response_data': RESPONSE_DATA, + 'describedby': DESCRIBEDBY } self.assertEqual(context, expected) @@ -1019,7 +1094,10 @@ class ChemicalEquationTest(unittest.TestCase): element = etree.fromstring(xml_str) - state = {'value': 'H2OYeah', } + state = { + 'value': 'H2OYeah', + 'response_data': RESPONSE_DATA + } self.the_input = lookup_tag('chemicalequationinput')(test_capa_system(), element, state) def test_rendering(self): @@ -1031,10 +1109,11 @@ class ChemicalEquationTest(unittest.TestCase): 'id': 'prob_1_2', 'value': 'H2OYeah', 'status': inputtypes.Status('unanswered'), - 'label': '', 'msg': '', 'size': self.size, 'previewer': '/dummy-static/js/capa/chemical_equation_preview.js', + 'response_data': RESPONSE_DATA, + 'describedby': DESCRIBEDBY } self.assertEqual(context, expected) @@ -1106,7 +1185,10 @@ class FormulaEquationTest(unittest.TestCase): element = etree.fromstring(xml_str) - state = {'value': 'x^2+1/2'} + state = { + 'value': 'x^2+1/2', + 'response_data': RESPONSE_DATA + } self.the_input = lookup_tag('formulaequationinput')(test_capa_system(), element, state) def test_rendering(self): @@ -1120,12 +1202,13 @@ class FormulaEquationTest(unittest.TestCase): 'id': 'prob_1_2', 'value': 'x^2+1/2', 'status': inputtypes.Status('unanswered'), - 'label': '', 'msg': '', 'size': self.size, 'previewer': '/dummy-static/js/capa/src/formula_equation_preview.js', 'inline': False, 'trailing_text': '', + 'response_data': RESPONSE_DATA, + 'describedby': DESCRIBEDBY } self.assertEqual(context, expected) @@ -1152,7 +1235,10 @@ class FormulaEquationTest(unittest.TestCase): element = etree.fromstring(xml_str) - state = {'value': 'x^2+1/2', } + state = { + 'value': 'x^2+1/2', + 'response_data': RESPONSE_DATA + } the_input = lookup_tag('formulaequationinput')(test_capa_system(), element, state) context = the_input._get_render_context() # pylint: disable=protected-access @@ -1162,12 +1248,13 @@ class FormulaEquationTest(unittest.TestCase): 'id': 'prob_1_2', 'value': 'x^2+1/2', 'status': inputtypes.Status('unanswered'), - 'label': '', 'msg': '', 'size': size, 'previewer': '/dummy-static/js/capa/src/formula_equation_preview.js', 'inline': False, 'trailing_text': expected_text, + 'response_data': RESPONSE_DATA, + 'describedby': DESCRIBEDBY } self.assertEqual(context, expected) @@ -1263,8 +1350,11 @@ class DragAndDropTest(unittest.TestCase): element = etree.fromstring(xml_str) value = 'abc' - state = {'value': value, - 'status': 'unsubmitted'} + state = { + 'value': value, + 'status': 'unsubmitted', + 'response_data': RESPONSE_DATA + } user_input = { # order matters, for string comparison "target_outline": "false", @@ -1293,9 +1383,10 @@ class DragAndDropTest(unittest.TestCase): 'id': 'prob_1_2', 'value': value, 'status': inputtypes.Status('unsubmitted'), - # 'label': '', 'msg': '', - 'drag_and_drop_json': json.dumps(user_input) + 'drag_and_drop_json': json.dumps(user_input), + 'response_data': RESPONSE_DATA, + 'describedby': DESCRIBEDBY } # as we are dumping 'draggables' dicts while dumping user_input, string @@ -1332,7 +1423,8 @@ class AnnotationInputTest(unittest.TestCase): state = { 'value': json_value, 'id': 'annotation_input', - 'status': 'answered' + 'status': 'answered', + 'response_data': RESPONSE_DATA } tag = 'annotationinput' @@ -1345,7 +1437,6 @@ class AnnotationInputTest(unittest.TestCase): 'STATIC_URL': '/dummy-static/', 'id': 'annotation_input', 'status': inputtypes.Status('answered'), - # 'label': '', 'msg': '', 'title': 'foo', 'text': 'bar', @@ -1362,7 +1453,9 @@ class AnnotationInputTest(unittest.TestCase): 'has_options_value': len(value['options']) > 0, 'comment_value': value['comment'], 'debug': False, - 'return_to_annotation': True + 'return_to_annotation': True, + 'response_data': RESPONSE_DATA, + 'describedby': DESCRIBEDBY } self.maxDiff = None @@ -1405,6 +1498,7 @@ class TestChoiceText(unittest.TestCase): 'value': '{}', 'id': 'choicetext_input', 'status': inputtypes.Status('answered'), + 'response_data': RESPONSE_DATA } first_input = self.build_choice_element('numtolerance_input', 'choiceinput_0_textinput_0', 'false', '') @@ -1421,11 +1515,12 @@ class TestChoiceText(unittest.TestCase): expected = { 'STATIC_URL': '/dummy-static/', 'msg': '', - 'label': '', 'input_type': expected_input_type, 'choices': choices, 'show_correctness': 'always', - 'submitted_message': 'Answer received.' + 'submitted_message': 'Answer received.', + 'response_data': RESPONSE_DATA, + 'describedby': DESCRIBEDBY } expected.update(state) the_input = lookup_tag(tag)(test_capa_system(), element, state) diff --git a/common/lib/xmodule/xmodule/capa_base.py b/common/lib/xmodule/xmodule/capa_base.py index 9c6db3adfa..c5ffbd14fb 100644 --- a/common/lib/xmodule/xmodule/capa_base.py +++ b/common/lib/xmodule/xmodule/capa_base.py @@ -1256,7 +1256,6 @@ class CapaMixin(CapaFields): of the problem. If problem related metadata cannot be located it should be replaced with empty strings ''. """ - input_metadata = {} for input_id, internal_answer in answers.iteritems(): answer_input = self.lcp.inputs.get(input_id) @@ -1290,7 +1289,7 @@ class CapaMixin(CapaFields): is_correct = '' input_metadata[input_id] = { - 'question': getattr(answer_input, 'loaded_attributes', {}).get('label', ''), + 'question': answer_input.response_data.get('label', ''), 'answer': user_visible_answer, 'response_type': getattr(getattr(answer_response, 'xml', None), 'tag', ''), 'input_type': getattr(answer_input, 'tag', ''), diff --git a/common/lib/xmodule/xmodule/css/capa/display.scss b/common/lib/xmodule/xmodule/css/capa/display.scss index 4f087eca05..9afc1db0ec 100644 --- a/common/lib/xmodule/xmodule/css/capa/display.scss +++ b/common/lib/xmodule/xmodule/css/capa/display.scss @@ -153,11 +153,8 @@ div.problem { } } - span > label { - display: block; - margin-bottom: $baseline; - font: inherit; - color: inherit; + .question-description { + @include margin(($baseline*0.75), 0); } } diff --git a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee index 6f008fc49d..a411ea78d3 100644 --- a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee @@ -235,7 +235,7 @@ describe 'MarkdownEditingDescriptor', ->

    A multiple choice problem presents radio buttons for student input. Students can only select a single option presented. Multiple Choice questions have been the subject of many areas of research due to the early invention and adoption of bubble sheets.

    One of the main elements that goes into a good multiple choice question is the existence of good distractors. That is, each of the alternate responses presented to the student should be the result of a plausible mistake that a student might make.

    - + The iPad Napster The iPod @@ -488,7 +488,7 @@ describe 'MarkdownEditingDescriptor', -> - +

    Explanation

    @@ -512,28 +512,27 @@ describe 'MarkdownEditingDescriptor', -> (x) Berlin ( ) Donut """) - expect(data).toXMLEqual(""" -

    France is a country in Europe.

    + expect(data).toXMLEqual(""" + +

    France is a country in Europe.

    -

    What is the capital of France?

    - - - + + + + -

    Germany is a country in Europe, too.

    +

    Germany is a country in Europe, too.

    -

    What is the capital of Germany?

    - - - Bonn - Hamburg - Berlin - Donut - - - - -
    """) + + + + Bonn + Hamburg + Berlin + Donut + + +
    """) it 'tests multiple questions with only one label', -> data = MarkdownEditingDescriptor.markdownToXml(""" France is a country in Europe. @@ -549,28 +548,27 @@ describe 'MarkdownEditingDescriptor', -> (x) Berlin ( ) Donut """) - expect(data).toXMLEqual(""" -

    France is a country in Europe.

    + expect(data).toXMLEqual(""" + +

    France is a country in Europe.

    -

    What is the capital of France?

    - - - + + + + -

    Germany is a country in Europe, too.

    +

    Germany is a country in Europe, too.

    -

    What is the capital of Germany?

    - - - Bonn - Hamburg - Berlin - Donut - - - - -
    """) +

    What is the capital of Germany?

    + + + Bonn + Hamburg + Berlin + Donut + + +
    """) it 'adds labels to formulae', -> data = MarkdownEditingDescriptor.markdownToXml(""" @@ -581,7 +579,7 @@ describe 'MarkdownEditingDescriptor', -> - + @@ -752,7 +750,7 @@ describe 'MarkdownEditingDescriptor', ->

    Multiple choice problems allow learners to select only one option. Learners can see all the options along with the problem text.

    - + Brazil timely feedback -- explain why an almost correct answer is wrong Germany @@ -774,7 +772,7 @@ describe 'MarkdownEditingDescriptor', ->

    Checkbox problems allow learners to select multiple options. Learners can see all the options along with the problem text.

    - + Urdu Finnish Marathi @@ -818,7 +816,7 @@ describe 'MarkdownEditingDescriptor', -> - + Brazil timely feedback -- explain why an almost correct answer is wrong Germany @@ -839,9 +837,9 @@ describe 'MarkdownEditingDescriptor', -> """) - it 'can do separation if spaces are prsent around ---', -> + it 'can do separation if spaces are present around ---', -> data = MarkdownEditingDescriptor.markdownToXml(""" - >>The following languages are in the Indo-European family:<< + >>The following languages are in the Indo-European family:||There are three correct choices.<< [x] Urdu [ ] Finnish [x] Marathi @@ -850,7 +848,7 @@ describe 'MarkdownEditingDescriptor', -> --- - >>Which of the following countries has the largest population?<< + >>Which of the following countries has the largest population?||You have only choice.<< ( ) Brazil {{ timely feedback -- explain why an almost correct answer is wrong }} ( ) Germany (x) Indonesia @@ -858,30 +856,99 @@ describe 'MarkdownEditingDescriptor', -> """) expect(data).toXMLEqual(""" - - - - Urdu - Finnish - Marathi - French - Hungarian - - - - - - - - - Brazil timely feedback -- explain why an almost correct answer is wrong - - Germany - Indonesia - Russia - - - + + + There are three correct choices. + + Urdu + Finnish + Marathi + French + Hungarian + + + + + You have only choice. + + Brazil + timely feedback -- explain why an almost correct answer is wrong + + Germany + Indonesia + Russia + + + + """) + + it 'can extract question description', -> + data = MarkdownEditingDescriptor.markdownToXml(""" + >>The following languages are in the Indo-European family:||Choose wisely.<< + [x] Urdu + [ ] Finnish + [x] Marathi + [x] French + [ ] Hungarian + """) + expect(data).toXMLEqual(""" + + + + Choose wisely. + + Urdu + Finnish + Marathi + French + Hungarian + + + + """) + + it 'can handle question and description spanned across multiple lines', -> + data = MarkdownEditingDescriptor.markdownToXml(""" + >>The following languages + are in the + Indo-European family: + || + first second + third + << + [x] Urdu + [ ] Finnish + [x] Marathi + """) + expect(data).toXMLEqual(""" + + + + first second third + + Urdu + Finnish + Marathi + + + + """) + + it 'will not add empty description', -> + data = MarkdownEditingDescriptor.markdownToXml(""" + >>The following languages are in the Indo-European family:||<< + [x] Urdu + [ ] Finnish + """) + expect(data).toXMLEqual(""" + + + + + Urdu + Finnish + + """) diff --git a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.coffee b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.coffee index 296591e445..03e84048fe 100644 --- a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.coffee +++ b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.coffee @@ -119,7 +119,7 @@ describe 'Markdown to xml extended hint dropdown', -> - + @@ -149,7 +149,7 @@ describe 'Markdown to xml extended hint dropdown', -> - +