Commit af43a26d by Braden MacDonald

Refactor Answer and Table. Changed <answer read_only="true"> to <answer-recap>

parent 3736fa36
from .answer import AnswerBlock from .answer import AnswerBlock, AnswerRecapBlock
from .choice import ChoiceBlock from .choice import ChoiceBlock
from .mcq import MCQBlock, RatingBlock from .mcq import MCQBlock, RatingBlock
from .mrq import MRQBlock from .mrq import MRQBlock
from .message import MentoringMessageBlock from .message import MentoringMessageBlock
from .table import MentoringTableBlock, MentoringTableColumnBlock, MentoringTableColumnHeaderBlock from .table import MentoringTableBlock, MentoringTableColumn
from .tip import TipBlock from .tip import TipBlock
...@@ -29,9 +29,10 @@ from lazy import lazy ...@@ -29,9 +29,10 @@ from lazy import lazy
from mentoring.models import Answer from mentoring.models import Answer
from xblock.core import XBlock from xblock.core import XBlock
from xblock.fields import Scope, Boolean, Float, Integer, String from xblock.fields import Scope, Float, Integer, String
from xblock.fragment import Fragment from xblock.fragment import Fragment
from xblockutils.resources import ResourceLoader from xblockutils.resources import ResourceLoader
from xblockutils.studio_editable import StudioEditableXBlockMixin
from .step import StepMixin from .step import StepMixin
...@@ -43,7 +44,51 @@ loader = ResourceLoader(__name__) ...@@ -43,7 +44,51 @@ loader = ResourceLoader(__name__)
# Classes ########################################################### # Classes ###########################################################
class AnswerBlock(XBlock, StepMixin): class AnswerMixin(object):
"""
Mixin to give an XBlock the ability to read/write data to the Answers DB table.
"""
name = String(
display_name="Answer ID",
help="The ID of the long answer. Should be unique unless you want the answer to be used in multiple places.",
default="",
scope=Scope.content,
)
def _get_course_id(self):
""" Get a course ID if available """
return getattr(self.runtime, 'course_id', 'all')
def _get_student_id(self):
""" Get student anonymous ID or normal ID """
try:
return self.runtime.anonymous_student_id
except AttributeError:
return self.scope_ids.user_id
def get_model_object(self, name=None):
"""
Fetches the Answer model object for the answer named `name`
"""
# By default, get the model object for the current answer's name
if not name:
name = self.name
# Consistency check - we should have a name by now
if not name:
raise ValueError('AnswerBlock.name field need to be set to a non-null/empty value')
student_id = self._get_student_id()
course_id = self._get_course_id()
answer_data, _ = Answer.objects.get_or_create(
student_id=student_id,
course_id=course_id,
name=name,
)
return answer_data
class AnswerBlock(AnswerMixin, StepMixin, StudioEditableXBlockMixin, XBlock):
""" """
A field where the student enters an answer A field where the student enters an answer
...@@ -55,11 +100,6 @@ class AnswerBlock(XBlock, StepMixin): ...@@ -55,11 +100,6 @@ class AnswerBlock(XBlock, StepMixin):
default="", default="",
scope=Scope.content scope=Scope.content
) )
read_only = Boolean(
help="Display as a read-only field",
default=False,
scope=Scope.content
)
default_from = String( default_from = String(
help="If specified, get the default value from this answer.", help="If specified, get the default value from this answer.",
default=None, default=None,
...@@ -82,32 +122,11 @@ class AnswerBlock(XBlock, StepMixin): ...@@ -82,32 +122,11 @@ class AnswerBlock(XBlock, StepMixin):
enforce_type=True enforce_type=True
) )
@classmethod editable_fields = ('question', 'name', 'min_characters', 'weight', 'default_from')
def parse_xml(cls, node, runtime, keys, id_generator):
block = runtime.construct_xblock_from_class(cls, keys)
# Load XBlock properties from the XML attributes: @property
for name, value in node.items(): def display_name(self):
setattr(block, name, value) return u"Question {}".format(self.step_number) if not self.lonely_step else u"Question"
for xml_child in node:
if xml_child.tag == 'question':
block.question = xml_child.text
else:
block.runtime.add_node_as_child(block, xml_child, id_generator)
return block
def _get_course_id(self):
""" Get a course ID if available """
return getattr(self.runtime, 'course_id', 'all')
def _get_student_id(self):
""" Get student anonymous ID or normal ID """
try:
return self.runtime.anonymous_student_id
except AttributeError:
return self.scope_ids.user_id
@lazy @lazy
def student_input(self): def student_input(self):
...@@ -129,14 +148,9 @@ class AnswerBlock(XBlock, StepMixin): ...@@ -129,14 +148,9 @@ class AnswerBlock(XBlock, StepMixin):
return student_input return student_input
def mentoring_view(self, context=None): def mentoring_view(self, context=None):
if not self.read_only: context = context or {}
html = loader.render_template('templates/html/answer_editable.html', { context['self'] = self
'self': self, html = loader.render_template('templates/html/answer_editable.html', context)
})
else:
html = loader.render_template('templates/html/answer_read_only.html', {
'self': self,
})
fragment = Fragment(html) fragment = Fragment(html)
fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/answer.css')) fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/answer.css'))
...@@ -144,19 +158,10 @@ class AnswerBlock(XBlock, StepMixin): ...@@ -144,19 +158,10 @@ class AnswerBlock(XBlock, StepMixin):
fragment.initialize_js('AnswerBlock') fragment.initialize_js('AnswerBlock')
return fragment return fragment
def mentoring_table_view(self, context=None):
html = loader.render_template('templates/html/answer_table.html', {
'self': self,
})
fragment = Fragment(html)
fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/answer_table.css'))
return fragment
def submit(self, submission): def submit(self, submission):
if not self.read_only: self.student_input = submission[0]['value'].strip()
self.student_input = submission[0]['value'].strip() self.save()
self.save() log.info(u'Answer submitted for`{}`: "{}"'.format(self.name, self.student_input))
log.info(u'Answer submitted for`{}`: "{}"'.format(self.name, self.student_input))
return { return {
'student_input': self.student_input, 'student_input': self.student_input,
'status': self.status, 'status': self.status,
...@@ -170,7 +175,7 @@ class AnswerBlock(XBlock, StepMixin): ...@@ -170,7 +175,7 @@ class AnswerBlock(XBlock, StepMixin):
if self.min_characters > 0: if self.min_characters > 0:
answer_length_ok = len(self.student_input.strip()) >= self.min_characters answer_length_ok = len(self.student_input.strip()) >= self.min_characters
return 'correct' if (self.read_only or answer_length_ok) else 'incorrect' return 'correct' if answer_length_ok else 'incorrect'
@property @property
def completed(self): def completed(self):
...@@ -189,27 +194,42 @@ class AnswerBlock(XBlock, StepMixin): ...@@ -189,27 +194,42 @@ class AnswerBlock(XBlock, StepMixin):
# Only attempt to locate a model object for this block when the answer has a name # Only attempt to locate a model object for this block when the answer has a name
if self.name: if self.name:
answer_data = self.get_model_object() answer_data = self.get_model_object()
if answer_data.student_input != self.student_input and not self.read_only: if answer_data.student_input != self.student_input:
answer_data.student_input = self.student_input answer_data.student_input = self.student_input
answer_data.save() answer_data.save()
def get_model_object(self, name=None):
"""
Fetches the Answer model object for the answer named `name`
"""
# By default, get the model object for the current answer's name
if not name:
name = self.name
# Consistency check - we should have a name by now
if not name:
raise ValueError('AnswerBlock.name field need to be set to a non-null/empty value')
student_id = self._get_student_id() class AnswerRecapBlock(AnswerMixin, StudioEditableXBlockMixin, XBlock):
course_id = self._get_course_id() """
A block that displays an answer previously entered by the student (read-only).
"""
display_name = String(
display_name="Title",
help="Title of this answer recap section",
scope=Scope.content,
default="",
)
description = String(
help="Description of this answer (optional). Can include HTML.",
scope=Scope.content,
default="",
display_name="Description",
)
editable_fields = ('name', 'display_name', 'description')
answer_data, _ = Answer.objects.get_or_create( @property
student_id=student_id, def student_input(self):
course_id=course_id, if self.name:
name=name, return self.get_model_object().student_input
) return ''
return answer_data
def fallback_view(self, view_name, context=None):
context = context or {}
context['title'] = self.display_name
context['description'] = self.description
context['student_input'] = self.student_input
html = loader.render_template('templates/html/answer_read_only.html', context)
fragment = Fragment(html)
fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/answer.css'))
return fragment
...@@ -25,3 +25,7 @@ ...@@ -25,3 +25,7 @@
margin-right: 13px; margin-right: 13px;
vertical-align: -25px; vertical-align: -25px;
} }
.answer-table {
margin-bottom: 20px;
}
...@@ -25,13 +25,14 @@ ...@@ -25,13 +25,14 @@
import errno import errno
from .utils import child_isinstance
from xblock.core import XBlock from xblock.core import XBlock
from xblock.exceptions import NoSuchViewError
from xblock.fields import Scope, String from xblock.fields import Scope, String
from xblock.fragment import Fragment from xblock.fragment import Fragment
from xblockutils.resources import ResourceLoader from xblockutils.resources import ResourceLoader
from xblockutils.studio_editable import StudioEditableXBlockMixin, StudioContainerXBlockMixin
# Globals ########################################################### # Globals ###########################################################
...@@ -40,47 +41,61 @@ loader = ResourceLoader(__name__) ...@@ -40,47 +41,61 @@ loader = ResourceLoader(__name__)
# Classes ########################################################### # Classes ###########################################################
class MentoringTableBlock(XBlock): class MentoringTableBlock(StudioEditableXBlockMixin, StudioContainerXBlockMixin, XBlock):
""" """
Table-type display of information from mentoring blocks Table-type display of information from mentoring blocks
Used to present summary of information entered by the students in mentoring blocks. Used to present summary of information entered by the students in mentoring blocks.
Supports different types of formatting through the `type` parameter. Supports different types of formatting through the `type` parameter.
""" """
type = String(help="Variant of the table to display", scope=Scope.content, default='') display_name = String(
display_name="Display name",
help="Title of the table",
default="Answers Table",
scope=Scope.settings
)
type = String(
display_name="Special Mode",
help="Variant of the table that will display a specific background image.",
scope=Scope.content,
default='',
values=[
{"display_name": "Normal", "value": ""},
{"display_name": "Immunity Map Assumptions", "value": "immunity-map-assumptions"},
{"display_name": "Immunity Map", "value": "immunity-map"},
],
)
editable_fields = ("type", )
has_children = True has_children = True
def student_view(self, context): def student_view(self, context):
context = context or {}
fragment = Fragment() fragment = Fragment()
columns_frags = [] header_values = []
header_frags = [] content_values = []
for child_id in self.children: for child_id in self.children:
child = self.runtime.get_block(child_id) child = self.runtime.get_block(child_id)
column_fragment = child.render('mentoring_table_view', context) # Child should be an instance of MentoringTableColumn
fragment.add_frag_resources(column_fragment) header_values.append(child.header)
columns_frags.append((child.name, column_fragment)) child_frag = child.render('mentoring_view', context)
header_fragment = child.render('mentoring_table_header_view', context) content_values.append(child_frag.content)
fragment.add_frag_resources(header_fragment) fragment.add_frag_resources(child_frag)
header_frags.append((child.name, header_fragment)) context['header_values'] = header_values if any(header_values) else None
context['content_values'] = content_values
bg_image_url = self.runtime.local_resource_url(self, 'public/img/{}-bg.png'.format(self.type))
if self.type:
# Load an optional description for the background image, for accessibility # Load an optional background image:
try: context['bg_image_url'] = self.runtime.local_resource_url(self, 'public/img/{}-bg.png'.format(self.type))
bg_image_description = loader.load_unicode('static/text/table-{}.txt'.format(self.type)) # Load an optional description for the background image, for accessibility
except IOError as e: try:
if e.errno == errno.ENOENT: context['bg_image_description'] = loader.load_unicode('static/text/table-{}.txt'.format(self.type))
bg_image_description = '' except IOError as e:
else: if e.errno == errno.ENOENT:
raise pass
else:
fragment.add_content(loader.render_template('templates/html/mentoring-table.html', { raise
'self': self,
'columns_frags': columns_frags, fragment.add_content(loader.render_template('templates/html/mentoring-table.html', context))
'header_frags': header_frags,
'bg_image_url': bg_image_url,
'bg_image_description': bg_image_description,
}))
fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/mentoring-table.css')) fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/mentoring-table.css'))
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/vendor/jquery-shorten.js')) fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/vendor/jquery-shorten.js'))
fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/mentoring-table.js')) fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/mentoring-table.js'))
...@@ -92,58 +107,57 @@ class MentoringTableBlock(XBlock): ...@@ -92,58 +107,57 @@ class MentoringTableBlock(XBlock):
# Allow to render within mentoring blocks, or outside # Allow to render within mentoring blocks, or outside
return self.student_view(context) return self.student_view(context)
def author_edit_view(self, context):
"""
Add some HTML to the author view that allows authors to add choices and tips.
"""
fragment = super(MentoringTableBlock, self).author_edit_view(context)
fragment.add_content(loader.render_template('templates/html/mentoring-table-add-button.html', {}))
# Share styles with the questionnaire edit CSS:
fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/questionnaire-edit.css'))
return fragment
class MentoringTableColumnBlock(XBlock): class MentoringTableColumn(StudioEditableXBlockMixin, StudioContainerXBlockMixin, XBlock):
""" """
Individual column of a mentoring table A column in a mentoring table. Has a header and can contain HTML and AnswerRecapBlocks.
""" """
header = String(help="Header of the column", scope=Scope.content, default=None) display_name = String(display_name="Display Name", default="Column")
header = String(
display_name="Header",
help="Header of this column",
default="",
scope=Scope.content,
multiline_editor="html",
)
editable_fields = ("header", )
has_children = True has_children = True
def _render_table_view(self, view_name, id_filter, template, context): def fallback_view(self, view_name, context):
context = context or {}
fragment = Fragment() fragment = Fragment()
named_children = []
for child_id in self.children: for child_id in self.children:
if id_filter(child_id): child = self.runtime.get_block(child_id)
child = self.runtime.get_block(child_id) if child.scope_ids.block_type == "html":
# HTML block current doesn't support "mentoring_view" and if "student_view" is used, it gets wrapped
# with HTML we don't want. So just grab its HTML directly.
child_frag = Fragment(child.data)
else:
child_frag = child.render(view_name, context) child_frag = child.render(view_name, context)
fragment.add_frag_resources(child_frag) fragment.add_content(child_frag.content)
named_children.append((child.name, child_frag)) fragment.add_frag_resources(child_frag)
fragment.add_content(loader.render_template('templates/html/{}'.format(template), {
'self': self,
'named_children': named_children,
}))
return fragment return fragment
def mentoring_table_view(self, context): def author_preview_view(self, context):
""" return self.author_edit_view(context)
The content of the column
""" def author_edit_view(self, context):
return self._render_table_view(
view_name='mentoring_table_view',
id_filter=lambda child_id: not child_isinstance(self, child_id, MentoringTableColumnHeaderBlock),
template='mentoring-table-column.html',
context=context
)
def mentoring_table_header_view(self, context):
""" """
The content of the column's header Add some HTML to the author view that allows authors to add choices and tips.
""" """
return self._render_table_view( fragment = super(MentoringTableColumn, self).author_edit_view(context)
view_name='mentoring_table_header_view', fragment.content = u"<div style=\"font-weight: bold;\">{}</div>".format(self.header) + fragment.content
id_filter=lambda child_id: child_isinstance(self, child_id, MentoringTableColumnHeaderBlock), fragment.add_content(loader.render_template('templates/html/mentoring-column-add-button.html', {}))
template='mentoring-table-header.html', # Share styles with the questionnaire edit CSS:
context=context fragment.add_css_url(self.runtime.local_resource_url(self, 'public/css/questionnaire-edit.css'))
) return fragment
class MentoringTableColumnHeaderBlock(XBlock):
"""
Header content for a given column
"""
content = String(help="Body of the header", scope=Scope.content, default='')
def mentoring_table_header_view(self, context):
return Fragment(unicode(self.content))
<div class="xblock-answer" data-completed="{{ self.completed }}"> <div class="xblock-answer" data-completed="{{ self.completed }}">
<h3 class="question-title">QUESTION {% if not self.lonely_step %}{{ self.step_number }}{% endif %}</h3> {% if not hide_header %}<h3 class="question-title">{{ self.display_name }}</h3>{% endif %}
<p>{{ self.question }}</p> <p>{{ self.question }}</p>
<textarea <textarea
class="answer editable" cols="50" rows="10" name="input" class="answer editable" cols="50" rows="10" name="input"
......
<div class="xblock-answer" data-completed="{{ self.completed }}"> {% load i18n %}
<h3 class="question-title">QUESTION {% if not self.lonely_step %}{{ self.step_number }}{% endif %}</h3> <div class="xblock-answer" data-completed="{{ student_input|yesno:"true,false" }}">
<p>{{ self.question }}</p> {% if not hide_header %}<h3 class="question-title">{{ title }}</h3>{% endif %}
{% if description %}<p>{{ description|safe }}</p>{% endif %}
<blockquote class="answer read_only"> <blockquote class="answer read_only">
{{ self.student_input|linebreaksbr }} {% if student_input %}
{{ student_input|linebreaksbr }}
{% else %}
<em>{% trans "No answer yet." %}</em>
{% endif %}
</blockquote> </blockquote>
</div> </div>
<div class="answer-table">
{{ self.student_input|linebreaksbr }}
</div>
{% load i18n %}
<div class="add-xblock-component new-component-item adding">
<div class="new-component">
<ul class="new-component-type">
<li><a href="#" class="single-template add-xblock-component-button" data-category="html">{% trans "Add HTML" %}</a></li>
<li><a href="#" class="single-template add-xblock-component-button" data-category="mentoring-answer-recap">{% trans "Add Answer Recap" %}</a></li>
</ul>
</div>
</div>
{% load i18n %}
<div class="add-xblock-component new-component-item adding">
<div class="new-component">
<ul class="new-component-type">
<li><a href="#" class="single-template add-xblock-component-button" data-category="mentoring-column">{% trans "Add Answer Recap Column" %}</a></li>
</ul>
</div>
</div>
<td>
<div class="mentoring-column">
{% for name, c in named_children %}
{{c.body_html|safe}}
{% endfor %}
</div>
</td>
<th>
{% for name, c in named_children %}
{{c.body_html|safe}}
{% endfor %}
</th>
<div class="mentoring-table {{ self.type }}" style="background-image: url({{ bg_image_url }})"> <div class="mentoring-table {{ self.type }}" style="background-image: url({{ bg_image_url }})">
<div class="cont-text-sr">{{ bg_image_description }}</div> <div class="cont-text-sr">{{ bg_image_description }}</div>
<table> <table>
{% if header_frags %} {% if header_values %}
<thead> <thead>
{% for name, c in header_frags %} {% for header in header_values %}
{{c.body_html|safe}} <th>{{ header|safe }}</th>
{% endfor %} {% endfor %}
</thead> </thead>
{% endif %} {% endif %}
<tbody> <tbody>
<tr> <tr>
{% for name, c in columns_frags %} {% for content in content_values %}
{{c.body_html|safe}} <td>
<div class="mentoring-column">
{{content|safe}}
</div>
</td>
{% endfor %} {% endfor %}
</tr> </tr>
</tbody> </tbody>
......
...@@ -5,8 +5,7 @@ ...@@ -5,8 +5,7 @@
<p>Please answer the questions below.</p> <p>Please answer the questions below.</p>
</html_demo> </html_demo>
<answer name="goal"> <answer name="goal" question="What is your goal?">
<question>What is your goal?</question>
</answer> </answer>
<mcq name="mcq_1_1" question="Do you like this MCQ?" correct_choices="yes"> <mcq name="mcq_1_1" question="Do you like this MCQ?" correct_choices="yes">
......
...@@ -8,8 +8,7 @@ ...@@ -8,8 +8,7 @@
<p>Please answer the question below.</p> <p>Please answer the question below.</p>
</html_demo> </html_demo>
<answer name="goal"> <answer name="goal" question="What is your goal?">
<question>What is your goal?</question>
</answer> </answer>
</mentoring> </mentoring>
<mentoring display_name="Mentoring Block 2 (Assessment)" mode="assessment"> <mentoring display_name="Mentoring Block 2 (Assessment)" mode="assessment">
...@@ -17,11 +16,9 @@ ...@@ -17,11 +16,9 @@
<p>Please answer the question below.</p> <p>Please answer the question below.</p>
</html_demo> </html_demo>
<answer name="inspired"> <answer name="inspired" question="Who has inspired you the most?">
<question>Who has inspired you the most?</question>
</answer> </answer>
<answer name="meaning"> <answer name="meaning" question="What is the meaning of life?">
<question>What is the meaning of life?</question>
</answer> </answer>
</mentoring> </mentoring>
......
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
<p>Please answer the questions below.</p> <p>Please answer the questions below.</p>
</html_demo> </html_demo>
<answer name="goal"> <answer name="goal" question="What is your goal?">
<question>What is your goal?</question>
</answer> </answer>
<mcq name="mcq_1_1" question="Do you like this MCQ?" correct_choices="yes"> <mcq name="mcq_1_1" question="Do you like this MCQ?" correct_choices="yes">
......
...@@ -39,7 +39,7 @@ class AnswerBlockTest(MentoringBaseTest): ...@@ -39,7 +39,7 @@ class AnswerBlockTest(MentoringBaseTest):
answer1_bis = mentoring.find_element_by_css_selector('textarea') answer1_bis = mentoring.find_element_by_css_selector('textarea')
answer1_readonly = mentoring.find_element_by_css_selector('blockquote.answer.read_only') answer1_readonly = mentoring.find_element_by_css_selector('blockquote.answer.read_only')
self.assertEqual(answer1_bis.get_attribute('value'), '') self.assertEqual(answer1_bis.get_attribute('value'), '')
self.assertEqual(answer1_readonly.text, '') self.assertEqual(answer1_readonly.text, 'No answer yet.')
# Another answer with the same name # Another answer with the same name
mentoring = self.go_to_page('Answer Edit 1') mentoring = self.go_to_page('Answer Edit 1')
...@@ -89,7 +89,7 @@ class AnswerBlockTest(MentoringBaseTest): ...@@ -89,7 +89,7 @@ class AnswerBlockTest(MentoringBaseTest):
# Check initial state # Check initial state
mentoring = self.go_to_page('Answer Blank Read Only') mentoring = self.go_to_page('Answer Blank Read Only')
answer = mentoring.find_element_by_css_selector('blockquote.answer.read_only') answer = mentoring.find_element_by_css_selector('blockquote.answer.read_only')
self.assertEqual(answer.text, '') self.assertEqual(answer.text, 'No answer yet.')
# Submit should allow to complete # Submit should allow to complete
submit = mentoring.find_element_by_css_selector('.submit input.input-main') submit = mentoring.find_element_by_css_selector('.submit input.input-main')
......
...@@ -40,8 +40,8 @@ class MentoringTableBlockTest(MentoringBaseTest): ...@@ -40,8 +40,8 @@ class MentoringTableBlockTest(MentoringBaseTest):
rows = table.find_elements_by_css_selector('td') rows = table.find_elements_by_css_selector('td')
self.assertEqual(len(rows), 2) self.assertEqual(len(rows), 2)
self.assertEqual(rows[0].text, '') self.assertEqual(rows[0].text, 'No answer yet.')
self.assertEqual(rows[1].text, '') self.assertEqual(rows[1].text, 'No answer yet.')
# Fill the answers - they should appear in the table # Fill the answers - they should appear in the table
mentoring = self.go_to_page('Table 1') mentoring = self.go_to_page('Table 1')
......
<vertical_demo> <vertical_demo>
<mentoring url_name="answer_blank_read_only" enforce_dependency="false"> <mentoring url_name="answer_blank_read_only" enforce_dependency="false">
<answer name="answer_blank" read_only="true" /> <answer-recap name="answer_blank" />
</mentoring> </mentoring>
</vertical_demo> </vertical_demo>
<vertical_demo> <vertical_demo>
<mentoring url_name="answer_edit_2" enforce_dependency="false"> <mentoring url_name="answer_edit_2" enforce_dependency="false">
<answer name="answer_1" read_only="true" /> <answer-recap name="answer_1" />
<answer name="answer_1" /> <answer name="answer_1" />
</mentoring> </mentoring>
</vertical_demo> </vertical_demo>
...@@ -8,21 +8,15 @@ ...@@ -8,21 +8,15 @@
<p>Please answer the question below.</p> <p>Please answer the question below.</p>
</html_demo> </html_demo>
<answer name="goal"> <answer name="goal" question="What is your goal?" />
<question>What is your goal?</question>
</answer>
</mentoring> </mentoring>
<mentoring display_name="Mentoring Block 2 (Assessment)" mode="assessment"> <mentoring display_name="Mentoring Block 2 (Assessment)" mode="assessment">
<html_demo> <html_demo>
<p>Please answer the question below.</p> <p>Please answer the question below.</p>
</html_demo> </html_demo>
<answer name="inspired"> <answer name="inspired" question="Who has inspired you the most?"/>
<question>Who has inspired you the most?</question> <answer name="meaning" question="What is the meaning of life?" />
</answer>
<answer name="meaning">
<question>What is the meaning of life?</question>
</answer>
</mentoring> </mentoring>
<mentoring-dataexport display_name="Data Export Test" /> <mentoring-dataexport display_name="Data Export Test" />
......
<vertical_demo> <vertical_demo>
<mentoring display_submit="false" enforce_dependency="false"> <mentoring display_submit="false" enforce_dependency="false">
<mentoring-table type="table_test" url_name="table_2"> <mentoring-table>
<column> <column header="Header Test 1">
<header>Header Test 1</header> <answer-recap name="table_1_answer_1"/>
<answer name="table_1_answer_1" />
</column> </column>
<column header="Header Test 2">
<column> <answer-recap name="table_1_answer_2"/>
<header>Header Test 2</header>
<answer name="table_1_answer_2" />
</column> </column>
</mentoring-table> </mentoring-table>
</mentoring> </mentoring>
......
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