Commit 30781d01 by Xavier Antoviaque

Merge pull request #71 from dragonfi/description-and-frame

Add a shared header text and number assessment questions
parents 595f6a2f 31ec9efb
...@@ -82,6 +82,7 @@ elements: ...@@ -82,6 +82,7 @@ elements:
* `<title>` - Renders the title of the block. * `<title>` - Renders the title of the block.
* `<html>` - May contain arbitrary HTML to be displayed in the block. * `<html>` - May contain arbitrary HTML to be displayed in the block.
* `<shared-header>` - A specialized HTML block, displayed together with the title as a shared header for every step in assessment mode.
* `<answer>` - Represents a free-form answer, rendered as a textarea * `<answer>` - Represents a free-form answer, rendered as a textarea
element. element.
* `<mcq>` - Multiple choice question, rendered as radio buttons. * `<mcq>` - Multiple choice question, rendered as radio buttons.
......
...@@ -9,3 +9,4 @@ from .message import MentoringMessageBlock ...@@ -9,3 +9,4 @@ from .message import MentoringMessageBlock
from .table import MentoringTableBlock, MentoringTableColumnBlock, MentoringTableColumnHeaderBlock from .table import MentoringTableBlock, MentoringTableColumnBlock, MentoringTableColumnHeaderBlock
from .tip import TipBlock from .tip import TipBlock
from .title import TitleBlock from .title import TitleBlock
from .header import SharedHeaderBlock
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 Harvard
#
# Authors:
# Xavier Antoviaque <xavier@antoviaque.org>
# David Gabor Bodor <david.gabor.bodor@gmail.com>
#
# 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/>.
#
import logging
from lxml import etree
from xblock.fragment import Fragment
from .light_children import LightChild, Scope, String
log = logging.getLogger(__name__)
class SharedHeaderBlock(LightChild):
"""
A shared header block shown under the title.
"""
content = String(help="HTML content of the header", scope=Scope.content, default="")
@classmethod
def init_block_from_node(cls, block, node, attr):
block.light_children = []
node.tag = 'div'
block.content = unicode(etree.tostring(node))
node.tag = 'shared-header'
return block
def student_view(self, context=None):
return Fragment(u"<script type='text/template' id='{}'>\n{}\n</script>".format(
'light-child-template',
self.content
))
def mentoring_view(self, context=None):
return self.student_view(context)
def mentoring_table_view(self, context=None):
return self.student_view(context)
...@@ -35,6 +35,7 @@ from xblock.fragment import Fragment ...@@ -35,6 +35,7 @@ from xblock.fragment import Fragment
from .light_children import XBlockWithLightChildren from .light_children import XBlockWithLightChildren
from .title import TitleBlock from .title import TitleBlock
from .header import SharedHeaderBlock
from .html import HTMLBlock from .html import HTMLBlock
from .message import MentoringMessageBlock from .message import MentoringMessageBlock
from .utils import get_scenarios_from_path, load_resource, render_template from .utils import get_scenarios_from_path, load_resource, render_template
...@@ -97,7 +98,7 @@ class MentoringBlock(XBlockWithLightChildren): ...@@ -97,7 +98,7 @@ class MentoringBlock(XBlockWithLightChildren):
@property @property
def steps(self): def steps(self):
return [child for child in self.get_children_objects() if return [child for child in self.get_children_objects() if
not isinstance(child, (HTMLBlock, TitleBlock, MentoringMessageBlock))] not isinstance(child, (HTMLBlock, TitleBlock, MentoringMessageBlock, SharedHeaderBlock))]
@property @property
def score(self): def score(self):
...@@ -112,12 +113,28 @@ class MentoringBlock(XBlockWithLightChildren): ...@@ -112,12 +113,28 @@ class MentoringBlock(XBlockWithLightChildren):
return (score, int(round(score*100)), correct, incorrect) return (score, int(round(score*100)), correct, incorrect)
def _index_steps(self):
steps = self.steps
if len(steps) == 1:
steps[0].index = ""
return
index = 1
for child in steps:
child.index = index
index += 1
def student_view(self, context): def student_view(self, context):
self._index_steps()
fragment, named_children = self.get_children_fragment( fragment, named_children = self.get_children_fragment(
context, view_name='mentoring_view', context, view_name='mentoring_view',
not_instance_of=(MentoringMessageBlock, TitleBlock) not_instance_of=(MentoringMessageBlock, TitleBlock, SharedHeaderBlock)
) )
fragment.add_content(render_template('templates/html/mentoring.html', { fragment.add_content(render_template('templates/html/mentoring.html', {
'self': self, 'self': self,
'named_children': named_children, 'named_children': named_children,
...@@ -150,7 +167,7 @@ class MentoringBlock(XBlockWithLightChildren): ...@@ -150,7 +167,7 @@ class MentoringBlock(XBlockWithLightChildren):
except KeyError as e: except KeyError as e:
return {'result': 'error', 'message': 'Missing event_type in JSON data'} return {'result': 'error', 'message': 'Missing event_type in JSON data'}
self._publish_event(event_type, data) return self._publish_event(event_type, data)
def _publish_event(self, event_type, data): def _publish_event(self, event_type, data):
data['user_id'] = self.scope_ids.user_id data['user_id'] = self.scope_ids.user_id
...@@ -170,6 +187,16 @@ class MentoringBlock(XBlockWithLightChildren): ...@@ -170,6 +187,16 @@ class MentoringBlock(XBlockWithLightChildren):
return None return None
@property @property
def header(self):
"""
Return the header child.
"""
for child in self.get_children_objects():
if isinstance(child, SharedHeaderBlock):
return child
return None
@property
def has_missing_dependency(self): def has_missing_dependency(self):
""" """
Returns True if the student needs to complete another step before being able to complete Returns True if the student needs to complete another step before being able to complete
...@@ -265,7 +292,7 @@ class MentoringBlock(XBlockWithLightChildren): ...@@ -265,7 +292,7 @@ class MentoringBlock(XBlockWithLightChildren):
completed = False completed = False
current_child = None current_child = None
children = [child for child in self.get_children_objects() \ children = [child for child in self.get_children_objects() \
if not isinstance(child, TitleBlock)] if not isinstance(child, (TitleBlock, SharedHeaderBlock))]
for child in children: for child in children:
if child.name and child.name in submissions: if child.name and child.name in submissions:
......
...@@ -95,6 +95,11 @@ ...@@ -95,6 +95,11 @@
height:33.33px; height:33.33px;
} }
.mentoring .assessment-question-block {
border: 5px solid #e5ebee;
padding: 20px;
}
.mentoring .assessment-checkmark { .mentoring .assessment-checkmark {
margin-right: 10px; margin-right: 10px;
} }
......
<fieldset class="choices questionnaire"> <fieldset class="choices questionnaire">
<legend class="question"> <legend class="question">
<h3>QUESTION</h3> <h3 class="question-title">QUESTION {{ self.index }}</h3>
<p>{{ self.question }}</p> <p>{{ self.question }}</p>
</legend> </legend>
<div class="choices-list"> <div class="choices-list">
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<div class="choice"> <div class="choice">
<div class="choice-result icon-2x"></div> <div class="choice-result icon-2x"></div>
<label class="choice-label"> <label class="choice-label">
<input class="choice-selector" type="radio" name="{{ self.name }}" value="{{ choice.value }}"{% if self.student_choice == choice.value %} checked{% endif %}> {{ choice.content }} <input class="choice-selector" type="radio" name="{{ self.name }}" value="{{ choice.value }}"{% if self.student_choice == choice.value %} checked{% endif %} />{{ choice.content }}
</label> </label>
<div class="choice-tips"></div> <div class="choice-tips"></div>
</div> </div>
......
<fieldset class="rating questionnaire"> <fieldset class="rating questionnaire">
<legend class="question">{{ self.question }}</legend> <legend class="question">
<h3 class="question-title">QUESTION {{ self.index }}</h3>
<p>{{ self.question }}</p>
</legend>
<div class="choices-list"> <div class="choices-list">
<div class="choice"> <div class="choice">
<div class="choice-result icon-2x"></div> <div class="choice-result icon-2x"></div>
<label><input class="choice-selector" type="radio" name="{{ self.name }}" value="1"{% if self.student_choice == '1' %} checked{% endif %}>1</label> <label><input class="choice-selector" type="radio" name="{{ self.name }}" value="1"{% if self.student_choice == '1' %} checked{% endif %} />1</label>
<span class="low"> - {{ self.low }}</span> <span class="low"> - {{ self.low }}</span>
<div class="choice-tips"></div> <div class="choice-tips"></div>
</div> </div>
<div class="choice"> <div class="choice">
<div class="choice-result icon-2x"></div> <div class="choice-result icon-2x"></div>
<label><input class="choice-selector" type="radio" name="{{ self.name }}" value="2"{% if self.student_choice == '2' %} checked{% endif %}>2</label> <label><input class="choice-selector" type="radio" name="{{ self.name }}" value="2"{% if self.student_choice == '2' %} checked{% endif %} />2</label>
<div class="choice-tips"></div> <div class="choice-tips"></div>
</div> </div>
<div class="choice"> <div class="choice">
<div class="choice-result icon-2x"></div> <div class="choice-result icon-2x"></div>
<label><input class="choice-selector" type="radio" name="{{ self.name }}" value="3"{% if self.student_choice == '3' %} checked{% endif %}>3</label> <label><input class="choice-selector" type="radio" name="{{ self.name }}" value="3"{% if self.student_choice == '3' %} checked{% endif %} />3</label>
<div class="choice-tips"></div> <div class="choice-tips"></div>
</div> </div>
<div class="choice"> <div class="choice">
<div class="choice-result icon-2x"></div> <div class="choice-result icon-2x"></div>
<label><input class="choice-selector" type="radio" name="{{ self.name }}" value="4"{% if self.student_choice == '4' %} checked{% endif %}>4</label> <label><input class="choice-selector" type="radio" name="{{ self.name }}" value="4"{% if self.student_choice == '4' %} checked{% endif %} />4</label>
<div class="choice-tips"></div> <div class="choice-tips"></div>
</div> </div>
<div class="choice"> <div class="choice">
<div class="choice-result icon-2x"></div> <div class="choice-result icon-2x"></div>
<label><input class="choice-selector" type="radio" name="{{ self.name }}" value="5"{% if self.student_choice == '5' %} checked{% endif %}>5</label> <label><input class="choice-selector" type="radio" name="{{ self.name }}" value="5"{% if self.student_choice == '5' %} checked{% endif %} />5</label>
<span class="low"> - {{ self.high }}</span> <span class="low"> - {{ self.high }}</span>
<div class="choice-tips"></div> <div class="choice-tips"></div>
</div> </div>
{% for choice in custom_choices %} {% for choice in custom_choices %}
<div class="choice"> <div class="choice">
<div class="choice-result icon-2x"></div> <div class="choice-result icon-2x"></div>
<label><input type="radio" name="{{ self.name }}" value="{{ choice.value }}"{% if self.student_choice == '{{ choice.value }}' %} checked{% endif %}> {{ choice.content }}</label> <label><input type="radio" name="{{ self.name }}" value="{{ choice.value }}"{% if self.student_choice == '{{ choice.value }}' %} checked{% endif %} />{{ choice.content }}</label>
<div class="choice-tips"></div> <div class="choice-tips"></div>
</div> </div>
{% endfor %} {% endfor %}
......
...@@ -3,38 +3,44 @@ ...@@ -3,38 +3,44 @@
You need to complete <a href="{{ missing_dependency_url }}">the previous step</a> before You need to complete <a href="{{ missing_dependency_url }}">the previous step</a> before
attempting this step. attempting this step.
</div> </div>
{% if self.title %}
{% if self.title or self.header %}
<div class="title"> <div class="title">
<h2 class="main">{{ self.title.content }}</h2> {% if self.title %} <h2 class="main">{{ self.title.content }}</h2> {% endif %}
{% if self.header %} <div class="header">{{ self.header.content|safe }}</div> {% endif %}
</div> </div>
{% endif %} {% endif %}
{% for name, c in named_children %}
{{c.body_html|safe}}
{% endfor %}
{% if self.display_submit %}
<div class="grade" data-score="{{ self.score.1 }}"
data-correct_answer="{{ self.score.2 }}"
data-incorrect_answer="{{ self.score.3 }}"
data-max_attempts="{{ self.max_attempts }}"
data-num_attempts="{{ self.num_attempts }}">
</div>
<div class="submit"> <div class="{{self.mode}}-question-block">
{% if self.mode == 'assessment' %} {% for name, c in named_children %}
<span class="assessment-checkmark icon-2x"></span> {{c.body_html|safe}}
{% endif %} {% endfor %}
<input type="button" class="input-main" value="Submit" disabled="disabled"></input> {% if self.display_submit %}
{% if self.mode == 'assessment' %} <div class="grade" data-score="{{ self.score.1 }}"
<input type="button" class="input-next" value="Next Question" disabled="disabled"></input> data-correct_answer="{{ self.score.2 }}"
<input type="button" class="input-review" value="Review grade" disabled="disabled"></input> data-incorrect_answer="{{ self.score.3 }}"
<input type="button" class="input-try-again" value="Try again" disabled="disabled"></input> data-max_attempts="{{ self.max_attempts }}"
{% endif %} data-num_attempts="{{ self.num_attempts }}">
</div>
<div class="submit">
{% if self.mode == 'assessment' %}
<span class="assessment-checkmark icon-2x"></span>
{% endif %}
<div class="attempts" data-max_attempts="{{ self.max_attempts }}" data-num_attempts="{{ self.num_attempts }}"></div> <input type="button" class="input-main" value="Submit" disabled="disabled" />
{% if self.mode == 'assessment' %}
<input type="button" class="input-next" value="Next Question" disabled="disabled" />
<input type="button" class="input-review" value="Review grade" disabled="disabled" />
<input type="button" class="input-try-again" value="Try again" disabled="disabled" />
{% endif %}
<div class="attempts" data-max_attempts="{{ self.max_attempts }}" data-num_attempts="{{ self.num_attempts }}"></div>
</div>
{% endif %}
<div class="messages"></div>
</div> </div>
{% endif %}
<div class="messages"></div>
</div> </div>
<fieldset class="choices questionnaire" data-hide_results="{{self.hide_results}}"> <fieldset class="choices questionnaire" data-hide_results="{{self.hide_results}}">
<legend class="question"> <legend class="question">
<h3>QUESTION</h3> <h3 class="question-title">QUESTION {{ self.index }}</h3>
<p>{{ self.question }}</p> <p>{{ self.question }}</p>
</legend> </legend>
<div class="choices-list"> <div class="choices-list">
...@@ -11,9 +10,8 @@ ...@@ -11,9 +10,8 @@
<label class="choice-label"> <label class="choice-label">
<input class="choice-selector" type="checkbox" name="{{ self.name }}" <input class="choice-selector" type="checkbox" name="{{ self.name }}"
value="{{ choice.value }}" value="{{ choice.value }}"
{% if choice.value in self.student_choices %} checked{% endif %}> {% if choice.value in self.student_choices %} checked{% endif %} />
{{ choice.content }} {{ choice.content }}
</input>
</label> </label>
<div class="choice-tips"></div> <div class="choice-tips"></div>
</div> </div>
......
<mentoring url_name="{{ url_name }}" display_name="Nav tooltip title" weight="1" mode="assessment"> <mentoring url_name="{{ url_name }}" display_name="Nav tooltip title" weight="1" mode="assessment">
<title>Default Title</title> <title>Default Title</title>
<shared-header>
<p>This paragraph is shared between <strong>all</strong> questions.</p>
</shared-header>
<html> <html>
<p>What is your goal?</p> <p>What is your goal?</p>
</html> </html>
......
...@@ -59,7 +59,8 @@ BLOCKS_CHILDREN = [ ...@@ -59,7 +59,8 @@ BLOCKS_CHILDREN = [
'tip = mentoring:TipBlock', 'tip = mentoring:TipBlock',
'choice = mentoring:ChoiceBlock', 'choice = mentoring:ChoiceBlock',
'html = mentoring:HTMLBlock', 'html = mentoring:HTMLBlock',
'title = mentoring:TitleBlock' 'title = mentoring:TitleBlock',
'shared-header = mentoring:SharedHeaderBlock',
] ]
setup( setup(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment