Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
problem-builder
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
problem-builder
Commits
30e9b3cd
Commit
30e9b3cd
authored
Jul 15, 2015
by
Braden MacDonald
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'clarifications' into fix-hgse-upgrade-merged
parents
caccfd1e
2bde5538
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
205 additions
and
15 deletions
+205
-15
problem_builder/mcq.py
+2
-6
problem_builder/mentoring.py
+7
-3
problem_builder/public/css/problem-builder-edit.css
+0
-0
problem_builder/public/css/problem-builder-tinymce-content.css
+15
-0
problem_builder/public/css/problem-builder.css
+8
-0
problem_builder/public/js/mentoring.js
+2
-0
problem_builder/public/js/mentoring_edit.js
+3
-0
problem_builder/public/js/questionnaire_edit.js
+4
-0
problem_builder/public/js/util.js
+40
-0
problem_builder/questionnaire.py
+9
-1
problem_builder/templates/html/ratingblock.html
+2
-2
problem_builder/templates/html/ratingblock_edit_preview.html
+3
-3
problem_builder/tests/integration/test_clarifications.py
+110
-0
No files found.
problem_builder/mcq.py
View file @
30e9b3cd
...
@@ -115,15 +115,13 @@ class MCQBlock(SubmittingXBlockMixin, QuestionnaireAbstractBlock):
...
@@ -115,15 +115,13 @@ class MCQBlock(SubmittingXBlockMixin, QuestionnaireAbstractBlock):
log
.
debug
(
u'MCQ submission result:
%
s'
,
result
)
log
.
debug
(
u'MCQ submission result:
%
s'
,
result
)
return
result
return
result
def
author_edit_view
(
self
,
context
):
def
get_author_edit_view_fragment
(
self
,
context
):
"""
"""
The options for the 1-5 values of the Likert scale aren't child blocks but we want to
The options for the 1-5 values of the Likert scale aren't child blocks but we want to
show them in the author edit view, for clarity.
show them in the author edit view, for clarity.
"""
"""
fragment
=
Fragment
(
u"<p>{}</p>"
.
format
(
self
.
question
))
fragment
=
Fragment
(
u"<p>{}</p>"
.
format
(
self
.
question
))
self
.
render_children
(
context
,
fragment
,
can_reorder
=
True
,
can_add
=
False
)
self
.
render_children
(
context
,
fragment
,
can_reorder
=
True
,
can_add
=
False
)
fragment
.
add_content
(
loader
.
render_template
(
'templates/html/questionnaire_add_buttons.html'
,
{}))
fragment
.
add_css_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/css/questionnaire-edit.css'
))
return
fragment
return
fragment
def
validate_field_data
(
self
,
validation
,
data
):
def
validate_field_data
(
self
,
validation
,
data
):
...
@@ -194,7 +192,7 @@ class RatingBlock(MCQBlock):
...
@@ -194,7 +192,7 @@ class RatingBlock(MCQBlock):
{
"display_name"
:
dn
,
"value"
:
val
}
for
val
,
dn
in
zip
(
self
.
FIXED_VALUES
,
display_names
)
{
"display_name"
:
dn
,
"value"
:
val
}
for
val
,
dn
in
zip
(
self
.
FIXED_VALUES
,
display_names
)
]
+
super
(
RatingBlock
,
self
)
.
human_readable_choices
]
+
super
(
RatingBlock
,
self
)
.
human_readable_choices
def
author_edit_view
(
self
,
context
):
def
get_author_edit_view_fragment
(
self
,
context
):
"""
"""
The options for the 1-5 values of the Likert scale aren't child blocks but we want to
The options for the 1-5 values of the Likert scale aren't child blocks but we want to
show them in the author edit view, for clarity.
show them in the author edit view, for clarity.
...
@@ -207,6 +205,4 @@ class RatingBlock(MCQBlock):
...
@@ -207,6 +205,4 @@ class RatingBlock(MCQBlock):
'accepted_statuses'
:
[
None
]
+
[
self
.
describe_choice_correctness
(
c
)
for
c
in
"12345"
],
'accepted_statuses'
:
[
None
]
+
[
self
.
describe_choice_correctness
(
c
)
for
c
in
"12345"
],
}))
}))
self
.
render_children
(
context
,
fragment
,
can_reorder
=
True
,
can_add
=
False
)
self
.
render_children
(
context
,
fragment
,
can_reorder
=
True
,
can_add
=
False
)
fragment
.
add_content
(
loader
.
render_template
(
'templates/html/questionnaire_add_buttons.html'
,
{}))
fragment
.
add_css_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/css/questionnaire-edit.css'
))
return
fragment
return
fragment
problem_builder/mentoring.py
View file @
30e9b3cd
...
@@ -314,8 +314,9 @@ class MentoringBlock(XBlock, StepParentMixin, StudioEditableXBlockMixin, StudioC
...
@@ -314,8 +314,9 @@ class MentoringBlock(XBlock, StepParentMixin, StudioEditableXBlockMixin, StudioC
'child_content'
:
child_content
,
'child_content'
:
child_content
,
'missing_dependency_url'
:
self
.
has_missing_dependency
and
self
.
next_step_url
,
'missing_dependency_url'
:
self
.
has_missing_dependency
and
self
.
next_step_url
,
}))
}))
fragment
.
add_css_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/css/
mentoring
.css'
))
fragment
.
add_css_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/css/
problem-builder
.css'
))
fragment
.
add_javascript_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/js/vendor/underscore-min.js'
))
fragment
.
add_javascript_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/js/vendor/underscore-min.js'
))
fragment
.
add_javascript_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/js/util.js'
))
js_file
=
'public/js/mentoring_{}_view.js'
.
format
(
'assessment'
if
self
.
is_assessment
else
'standard'
)
js_file
=
'public/js/mentoring_{}_view.js'
.
format
(
'assessment'
if
self
.
is_assessment
else
'standard'
)
fragment
.
add_javascript_url
(
self
.
runtime
.
local_resource_url
(
self
,
js_file
))
fragment
.
add_javascript_url
(
self
.
runtime
.
local_resource_url
(
self
,
js_file
))
fragment
.
add_javascript_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/js/mentoring.js'
))
fragment
.
add_javascript_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/js/mentoring.js'
))
...
@@ -731,7 +732,7 @@ class MentoringBlock(XBlock, StepParentMixin, StudioEditableXBlockMixin, StudioC
...
@@ -731,7 +732,7 @@ class MentoringBlock(XBlock, StepParentMixin, StudioEditableXBlockMixin, StudioC
fragment
.
add_content
(
loader
.
render_template
(
'templates/html/mentoring_url_name.html'
,
{
fragment
.
add_content
(
loader
.
render_template
(
'templates/html/mentoring_url_name.html'
,
{
"url_name"
:
self
.
url_name
"url_name"
:
self
.
url_name
}))
}))
fragment
.
add_css_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/css/
mentoring_
edit.css'
))
fragment
.
add_css_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/css/
problem-builder-
edit.css'
))
self
.
include_theme_files
(
fragment
)
self
.
include_theme_files
(
fragment
)
return
fragment
return
fragment
...
@@ -746,7 +747,10 @@ class MentoringBlock(XBlock, StepParentMixin, StudioEditableXBlockMixin, StudioC
...
@@ -746,7 +747,10 @@ class MentoringBlock(XBlock, StepParentMixin, StudioEditableXBlockMixin, StudioC
fragment
.
add_content
(
loader
.
render_template
(
'templates/html/mentoring_url_name.html'
,
{
fragment
.
add_content
(
loader
.
render_template
(
'templates/html/mentoring_url_name.html'
,
{
"url_name"
:
self
.
url_name
"url_name"
:
self
.
url_name
}))
}))
fragment
.
add_css_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/css/mentoring_edit.css'
))
fragment
.
add_css_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/css/problem-builder.css'
))
fragment
.
add_css_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/css/problem-builder-edit.css'
))
fragment
.
add_css_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/css/problem-builder-tinymce-content.css'
))
fragment
.
add_javascript_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/js/util.js'
))
fragment
.
add_javascript_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/js/mentoring_edit.js'
))
fragment
.
add_javascript_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/js/mentoring_edit.js'
))
fragment
.
initialize_js
(
'MentoringEditComponents'
)
fragment
.
initialize_js
(
'MentoringEditComponents'
)
return
fragment
return
fragment
...
...
problem_builder/public/css/
mentoring_
edit.css
→
problem_builder/public/css/
problem-builder-
edit.css
View file @
30e9b3cd
File moved
problem_builder/public/css/problem-builder-tinymce-content.css
0 → 100644
View file @
30e9b3cd
/* Some styling to make clarifications stand out a bit in
studio HTML edit view. */
.mce-content-body
.pb-clarification
{
color
:
#999
;
font-size
:
0.75em
;
}
.mce-content-body
.pb-clarification
::before
{
content
:
"(?)["
}
.mce-content-body
.pb-clarification
::after
{
content
:
"]"
}
problem_builder/public/css/
mentoring
.css
→
problem_builder/public/css/
problem-builder
.css
View file @
30e9b3cd
...
@@ -173,3 +173,11 @@
...
@@ -173,3 +173,11 @@
float
:
right
;
float
:
right
;
display
:
none
;
display
:
none
;
}
}
.pb-clarification
span
.clarification
i
{
font-style
:
normal
;
}
.pb-clarification
span
.clarification
i
:hover
{
color
:
rgb
(
0
,
159
,
230
);
}
problem_builder/public/js/mentoring.js
View file @
30e9b3cd
...
@@ -113,6 +113,8 @@ function MentoringBlock(runtime, element) {
...
@@ -113,6 +113,8 @@ function MentoringBlock(runtime, element) {
}
}
}
}
ProblemBuilderUtil
.
transformClarifications
(
element
);
if
(
data
.
mode
===
'standard'
)
{
if
(
data
.
mode
===
'standard'
)
{
MentoringStandardView
(
runtime
,
element
,
mentoring
);
MentoringStandardView
(
runtime
,
element
,
mentoring
);
}
}
...
...
problem_builder/public/js/mentoring_edit.js
View file @
30e9b3cd
...
@@ -17,5 +17,8 @@ function MentoringEditComponents(runtime, element) {
...
@@ -17,5 +17,8 @@ function MentoringEditComponents(runtime, element) {
$
(
this
).
addClass
(
'disabled'
);
$
(
this
).
addClass
(
'disabled'
);
}
}
});
});
ProblemBuilderUtil
.
transformClarifications
(
element
);
runtime
.
listenTo
(
'deleted-child'
,
updateButtons
);
runtime
.
listenTo
(
'deleted-child'
,
updateButtons
);
}
}
problem_builder/public/js/questionnaire_edit.js
0 → 100644
View file @
30e9b3cd
function
QuestionnaireEdit
(
runtime
,
element
)
{
'use strict'
;
ProblemBuilderUtil
.
transformClarifications
(
element
);
}
problem_builder/public/js/util.js
0 → 100644
View file @
30e9b3cd
window
.
ProblemBuilderUtil
=
{
transformClarifications
:
function
(
element
)
{
var
$element
=
$
(
element
);
var
transformExisting
=
function
(
node
)
{
$
(
'.pb-clarification'
,
node
).
each
(
function
()
{
var
item
=
$
(
this
);
var
content
=
item
.
html
();
var
clarification
=
$
(
'<span class="clarification" tabindex="0" role="note" aria-label="Clarification">'
+
'<i data-tooltip-show-on-click="true" class="fa fa-info-circle" aria-hidden="true"></i>'
+
'<span class="sr"></span>'
+
'</span>'
);
clarification
.
find
(
'i'
).
attr
(
'data-tooltip'
,
content
);
clarification
.
find
(
'span.sr'
).
html
(
content
);
item
.
empty
().
append
(
clarification
);
});
};
// Transform all span.pb-clarifications already existing inside the element.
transformExisting
(
$element
);
// Transform all future span.pb-clarifications using mutation observer.
// It's only needed in the Studio when editing xblock children because the
// block's JS init function isn't called after edits in the Studio.
if
(
window
.
MutationObserver
)
{
var
observer
=
new
MutationObserver
(
function
(
mutations
)
{
mutations
.
forEach
(
function
(
mutation
)
{
Array
.
prototype
.
forEach
.
call
(
mutation
.
addedNodes
,
function
(
node
)
{
transformExisting
(
node
);
});
})
});
observer
.
observe
(
$element
[
0
],
{
childList
:
true
,
subtree
:
true
});
}
}
};
problem_builder/questionnaire.py
View file @
30e9b3cd
...
@@ -167,13 +167,21 @@ class QuestionnaireAbstractBlock(StudioEditableXBlockMixin, StudioContainerXBloc
...
@@ -167,13 +167,21 @@ class QuestionnaireAbstractBlock(StudioEditableXBlockMixin, StudioContainerXBloc
return
choice
.
content
return
choice
.
content
return
submission
return
submission
def
get_author_edit_view_fragment
(
self
,
context
):
fragment
=
super
(
QuestionnaireAbstractBlock
,
self
)
.
author_edit_view
(
context
)
return
fragment
def
author_edit_view
(
self
,
context
):
def
author_edit_view
(
self
,
context
):
"""
"""
Add some HTML to the author view that allows authors to add choices and tips.
Add some HTML to the author view that allows authors to add choices and tips.
"""
"""
fragment
=
s
uper
(
QuestionnaireAbstractBlock
,
self
)
.
author_edit_view
(
context
)
fragment
=
s
elf
.
get_author_edit_view_fragment
(
context
)
fragment
.
add_content
(
loader
.
render_template
(
'templates/html/questionnaire_add_buttons.html'
,
{}))
fragment
.
add_content
(
loader
.
render_template
(
'templates/html/questionnaire_add_buttons.html'
,
{}))
fragment
.
add_css_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/css/problem-builder.css'
))
fragment
.
add_css_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/css/questionnaire-edit.css'
))
fragment
.
add_css_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/css/questionnaire-edit.css'
))
fragment
.
add_javascript_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/js/util.js'
))
fragment
.
add_javascript_url
(
self
.
runtime
.
local_resource_url
(
self
,
'public/js/questionnaire_edit.js'
))
fragment
.
initialize_js
(
'QuestionnaireEdit'
)
return
fragment
return
fragment
def
validate_field_data
(
self
,
validation
,
data
):
def
validate_field_data
(
self
,
validation
,
data
):
...
...
problem_builder/templates/html/ratingblock.html
View file @
30e9b3cd
...
@@ -15,8 +15,8 @@
...
@@ -15,8 +15,8 @@
</div>
</div>
<label
class=
"choice-label"
for=
"choice-{{ self.html_id }}-{{i}}"
>
<label
class=
"choice-label"
for=
"choice-{{ self.html_id }}-{{i}}"
>
{{i}}
{{i}}
{% if i == '1' %} - {{ self.low }}{% endif %}
{% if i == '1' %} - {{ self.low
|safe
}}{% endif %}
{% if i == '5' %} - {{ self.high }}{% endif %}
{% if i == '5' %} - {{ self.high
|safe
}}{% endif %}
</label>
</label>
<div
class=
"choice-tips-container"
>
<div
class=
"choice-tips-container"
>
<div
class=
"choice-tips"
></div>
<div
class=
"choice-tips"
></div>
...
...
problem_builder/templates/html/ratingblock_edit_preview.html
View file @
30e9b3cd
{% load i18n %}
{% load i18n %}
<p>
{{ question }}
</p>
<p>
{{ question
|safe
}}
</p>
<h2>
{% trans "Built-in choices:" %}
</h2>
<h2>
{% trans "Built-in choices:" %}
</h2>
<ul>
<ul>
<li>
Choice (1):
<strong>
1 - {{ low }}
</strong>
({{accepted_statuses.1}})
</li>
<li>
Choice (1):
<strong>
1 - {{ low
|safe
}}
</strong>
({{accepted_statuses.1}})
</li>
<li>
Choice (2):
<strong>
2
</strong>
({{accepted_statuses.2}})
</li>
<li>
Choice (2):
<strong>
2
</strong>
({{accepted_statuses.2}})
</li>
<li>
Choice (3):
<strong>
3
</strong>
({{accepted_statuses.3}})
</li>
<li>
Choice (3):
<strong>
3
</strong>
({{accepted_statuses.3}})
</li>
<li>
Choice (4):
<strong>
4
</strong>
({{accepted_statuses.4}})
</li>
<li>
Choice (4):
<strong>
4
</strong>
({{accepted_statuses.4}})
</li>
<li>
Choice (5):
<strong>
5 - {{ high }}
</strong>
({{accepted_statuses.5}})
</li>
<li>
Choice (5):
<strong>
5 - {{ high
|safe
}}
</strong>
({{accepted_statuses.5}})
</li>
</ul>
</ul>
<h2>
{% trans "Additional custom choices and tips:" %}
</h2>
<h2>
{% trans "Additional custom choices and tips:" %}
</h2>
problem_builder/tests/integration/test_clarifications.py
0 → 100644
View file @
30e9b3cd
# -*- coding: utf-8 -*-
#
# Copyright (c) 2014-2015 Harvard, edX & OpenCraft
#
# This software's license gives you freedom; you can copy, convey,
# propagate, redistribute and/or modify this program under the terms of
# the GNU Affero General Public License (AGPL) as published by the Free
# Software Foundation (FSF), either version 3 of the License, or (at your
# option) any later version of the AGPL published by the FSF.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
# General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program in a file in the toplevel directory called
# "AGPLv3". If not, see <http://www.gnu.org/licenses/>.
#
"""
Test that <span class="pb-clarification"> elements are transformed into LMS-like tooltips.
"""
# Imports ###########################################################
import
ddt
from
cgi
import
escape
from
xblockutils.base_test
import
SeleniumXBlockTest
# Classes ###########################################################
@ddt.ddt
class
ClarificationTest
(
SeleniumXBlockTest
):
"""
Test that the content of span.pb-clarification elements is transformed into
tooltip elements.
"""
clarification_text
=
'Let me clarify...'
mcq_template
=
"""
<problem-builder>
<pb-mcq question="Who was your favorite character? {clarify_escaped}">
<pb-choice value="gaius">Gaius Baltar</pb-choice>
<pb-choice value="adama">Admiral William Adama {clarify}</pb-choice>
<pb-choice value="starbuck">Starbuck</pb-choice>
</pb-mcq>
</problem-builder>
"""
mrq_template
=
"""
<problem-builder>
<pb-mrq question="What makes a great {clarify_escaped} MRQ {clarify_escaped}?">
<pb-choice value="1">Lots of choices</pb-choice>
<pb-choice value="2">Funny{clarify} choices</pb-choice>
<pb-choice value="3">Not sure {clarify}</pb-choice>
</pb-mrq>
</problem-builder>
"""
rating_template
=
"""
<problem-builder>
<pb-rating name="rating_1_1" question="How do you rate {clarify_escaped} Battlestar Galactica?">
<pb-choice value="6">More than 5 stars {clarify}</pb-choice>
</pb-rating>
</problem-builder>
"""
long_answer_template
=
"""
<problem-builder>
<pb-answer question="What did you think {clarify_escaped} of the ending?" />
</problem-builder>
"""
html_block_template
=
"""
<problem-builder>
<html_demo><p>This is some raw {clarify} HTML code.</p></html_demo>
</problem-builder>
"""
def
prepare_xml_scenario
(
self
,
xml_template
):
span
=
'<span class="pb-clarification">{}</span>'
.
format
(
self
.
clarification_text
)
escaped_span
=
escape
(
span
,
quote
=
True
)
return
xml_template
.
format
(
clarify
=
span
,
clarify_escaped
=
escaped_span
)
@ddt.data
(
(
mcq_template
,
2
),
(
mrq_template
,
4
),
(
rating_template
,
2
),
(
long_answer_template
,
1
),
(
html_block_template
,
1
),
)
@ddt.unpack
def
test_title
(
self
,
xml_template
,
tooltip_count
):
self
.
set_scenario_xml
(
self
.
prepare_xml_scenario
(
xml_template
))
pb_element
=
self
.
go_to_view
()
clarifications
=
pb_element
.
find_elements_by_css_selector
(
'span.pb-clarification'
)
self
.
assertEqual
(
len
(
clarifications
),
tooltip_count
)
for
clarification
in
clarifications
:
tooltip
=
clarification
.
find_element_by_css_selector
(
'i[data-tooltip]'
)
self
.
assertEqual
(
tooltip
.
get_attribute
(
'data-tooltip'
),
self
.
clarification_text
)
sr
=
clarification
.
find_element_by_css_selector
(
'span.sr'
)
self
.
assertEqual
(
sr
.
text
,
self
.
clarification_text
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment