Commit 34cc112c by Arthur Barrett

Saving work in progress on annotations v2 with classification problems.

parent 72d9c1d7
......@@ -73,19 +73,25 @@ class AnnotatableModule(XModule):
def _set_problem(self, span, index, xmltree):
""" Sets the associated problem. """
problem = span.find('problem')
if problem is not None:
problem_el = span.find('problem')
if problem_el is not None:
problem_id = str(index + 1)
problem.set('problem_id', problem_id)
problem_el.set('problem_id', problem_id)
span.set('data-problem-id', problem_id)
parsed_problem = self._parse_problem(problem)
parsed_problem = self._parse_problem(problem_el)
parsed_problem['discussion_id'] = span.get('data-discussion-id')
if parsed_problem is not None:
self.problems.append(parsed_problem)
span.remove(problem_el)
def _parse_problem(self, problem):
prompt_el = problem.find('prompt')
answer_el = problem.find('answer')
tags_el = problem.find('tags')
def _parse_problem(self, problem_el):
""" Returns the problem XML as a dict. """
prompt_el = problem_el.find('prompt')
answer_el = problem_el.find('answer')
tags_el = problem_el.find('tags')
if any(v is None for v in (prompt_el, answer_el, tags_el)):
return None
tags = []
for tag_el in tags_el.iterchildren('tag'):
......@@ -96,20 +102,14 @@ class AnnotatableModule(XModule):
'answer': tag_el.get('answer', 'n') == 'y'
})
parsed = {
'problem_id': problem.get('problem_id'),
result = {
'problem_id': problem_el.get('problem_id'),
'prompt': prompt_el.text,
'answer': answer_el.text,
'tags': tags
}
log.debug('parsed problem id = ' + parsed['problem_id'])
log.debug("problem keys: " + ", ".join(parsed.keys()))
log.debug('prompt = ' + parsed['prompt'])
log.debug('answer = ' + parsed['answer'])
log.debug('num tags = ' + str(len(parsed['tags'])))
return parsed
return result
def _get_marker_color(self, span):
""" Returns the name of the marker/highlight color for the span if it is valid, otherwise none."""
......@@ -151,16 +151,48 @@ class AnnotatableModule(XModule):
return etree.tostring(xmltree)
def _render_items(self):
items = []
if self.render_as_problems:
discussions = {}
for child in self.get_display_items():
discussions[child.discussion_id] = child.get_html()
for problem in self.problems:
discussion = None
discussion_id = problem['discussion_id']
if discussion_id in discussions:
discussion = {
'discussion_id': discussion_id,
'content': discussions[discussion_id]
}
items.append({
'problem': problem,
'discussion': discussion
})
else:
for child in self.get_display_items():
items.append({ 'discussion': {
'discussion_id': child.discussion_id,
'content': child.get_html()
}})
return items
def get_html(self):
""" Renders parameters to template. """
html_content = self._render_content()
items = self._render_items()
context = {
'display_name': self.display_name,
'problem_name': self.problem_name,
'element_id': self.element_id,
'html_content': self._render_content(),
'has_problems': self.has_problems,
'problems': self.problems
'html_content': html_content,
'render_as_problems': self.render_as_problems,
'items': items
}
return self.system.render_template('annotatable.html', context)
......@@ -175,7 +207,7 @@ class AnnotatableModule(XModule):
self.element_id = self.location.html_id();
self.content = self.definition['data']
self.problem_type = xmltree.get('problem_type')
self.has_problems = (self.problem_type == 'classification')
self.render_as_problems = (self.problem_type == 'classification')
self.problem_name = self._get_problem_name(self.problem_type)
self.problems = []
......@@ -184,3 +216,38 @@ class AnnotatableDescriptor(RawDescriptor):
module_class = AnnotatableModule
stores_state = True
template_dir_name = "annotatable"
@classmethod
def definition_from_xml(cls, xml_object, system):
children = []
for child in xml_object.findall('discussion'):
try:
children.append(system.process_xml(etree.tostring(child, encoding='unicode')).location.url())
xml_object.remove(child)
except Exception as e:
log.exception("Unable to load child when parsing Sequence. Continuing...")
if system.error_tracker is not None:
system.error_tracker("ERROR: " + str(e))
continue
return {
'data': etree.tostring(xml_object, pretty_print=True, encoding='unicode'),
'children': children
}
def definition_to_xml(self, resource_fs):
try:
root = etree.fromstring(self.definition['data'])
for child in self.get_children():
root.append(etree.fromstring(child.export_to_xml(resource_fs)))
return root
except etree.XMLSyntaxError as err:
# Can't recover here, so just add some info and
# re-raise
lines = self.definition['data'].split('\n')
line, offset = err.position
msg = ("Unable to create xml for problem {loc}. "
"Context: '{context}'".format(
context=lines[line - 1][offset - 40:offset + 40],
loc=self.location))
raise Exception, msg, sys.exc_info()[2]
\ No newline at end of file
......@@ -62,6 +62,9 @@
.annotatable-problems {
margin: 25px 0 0 0;
.annotatable-discussion {
display: none;
}
}
.annotatable-problem {
border: 1px solid #ccc;
......@@ -88,11 +91,15 @@
margin: 1em 0;
padding: 0;
li {
cursor: pointer;
display: inline;
padding: .5em;
margin: 0 .5em 0 0;
background-color: #ccc;
border: 1px solid #000;
&.selected {
background-color: rgba(255,255,10,0.3);
}
}
}
.annotatable-problem-controls {
......
......@@ -8,6 +8,9 @@ class @Annotatable
replySelector: '.annotatable-reply'
helpSelector: '.annotatable-help-icon'
returnSelector: '.annotatable-return'
problemSelector: '.annotatable-problem'
problemSubmitSelector: '.annotatable-problem-submit'
problemTagSelector: '.annotatable-problem-tags > li'
discussionXModuleSelector: '.xmodule_DiscussionModule'
discussionSelector: '.discussion-module'
......@@ -25,7 +28,6 @@ class @Annotatable
init: () ->
@initEvents()
@initTips()
@initDiscussionReturnLinks()
initEvents: () ->
@annotationsHidden = false
......@@ -33,6 +35,13 @@ class @Annotatable
@$(@wrapperSelector).delegate @replySelector, 'click', @onClickReply
$(@discussionXModuleSelector).delegate @returnSelector, 'click', @onClickReturn
problemSelector = @problemSelector
@$(@problemSubmitSelector).bind 'click', (e) ->
$(this).closest(problemSelector).next().show()
@$(@problemTagSelector).bind 'click', (e) ->
$(this).toggleClass('selected')
initTips: () ->
@savedTips = []
@$(@spanSelector).each (index, el) => $(el).qtip(@getTipOptions el)
......@@ -45,10 +54,6 @@ class @Annotatable
title: 'Annotated Reading'
text: true # use title attribute of this element
initDiscussionReturnLinks: () ->
$(@discussionXModuleSelector).find(@discussionSelector).each (index, el) =>
$(el).before @createReturnLink(@getDiscussionId el)
getTipOptions: (el) ->
content:
title:
......
<%namespace name="annotatable" file="annotatable_problem.html"/>
<div class="annotatable-wrapper" id="${element_id}-wrapper">
<div class="annotatable-header">
% if display_name is not UNDEFINED and display_name is not None:
......@@ -12,32 +14,23 @@
<div class="annotatable-content">${html_content}</div>
% if has_problems:
% if render_as_problems:
<div class="annotatable-problems">
% for problem in problems:
<div class="annotatable-problem" data-problem-id="${problem['problem_id']}">
<div class="annotatable-problem-header">
Classification Exercise: <span class="annotatable-problem-index">(${loop.index + 1} / ${len(problems)}) </span>
</div>
<div class="annotatable-problem-body">
<div class="annotatable-problem-prompt">${problem['prompt']}</div>
<ul class="annotatable-problem-tags">
% for tag in problem['tags']:
<li>${tag['name']}</li>
% endfor
</ul>
Explain the rationale for your tag selections:<br/>
<textarea></textarea>
<div class="annotatable-problem-controls">
<button class="button annotatable-problem-save">Save</button>
<button class="button annotatable-problem-submit">Submit</button>
<a class="annotatable-problem-return" href="javascript:void(0);">Return to annotation</a>
</div>
</div>
<div class="annotatable-problem-footer">
</div>
</div>
% for item in items:
${annotatable.render_problem(item['problem'],loop.index,len(items))}
% if item['discussion']:
<div class="annotatable-discussion">${item['discussion']['content']}</div>
% endif
% endfor
</div>
% else:
<div class="annotatable-discussions">
% for item in items:
<div class="annotatable-discussion">
<a class="annotatable-return" href="javascript:void(0);" data-discussion-id="${item['discussion']['discussion_id']}">Return to annotation</a>
${item['discussion']['content']}
</div>
% endfor
</div>
% endif
</div>
<div class="annotatable-problem" data-problem-id="${problem_id}">
<%def name="render_problem(problem,index,total)">
<div class="annotatable-problem" data-problem-id="${problem['problem_id']}">
<div class="annotatable-problem-header">
Classification Exercise:
<span class="annotatable-problem-index">
${problem_index} / ${total_problems}
</span>
Classification Exercise: <span class="annotatable-problem-index">(${index + 1} / ${total}) </span>
</div>
<div class="annotatable-problem-body">
<div class="annotatable-problem-prompt">${problem_prompt}</div>
<div class="annotatable-problem-prompt">${problem['prompt']}</div>
<ul class="annotatable-problem-tags">
% for tag in problem_tags:
<li>${tag.name}</li>
% for tag in problem['tags']:
<li>${tag['name']}</li>
% endfor
</ul>
Explain the rationale for your tag selections:<br/>
<textarea></textarea>
<div class="annotatable-problem-controls">
<button class="button annotatable-problem-save">Save</button>
<button class="button annotatable-problem-submit">Submit</button>
<a class="annotatable-problem-return" href="javascript:void(0);" data-discussion-id="${problem['discussion_id']}">Return to annotation</a>
</div>
</div>
<div class="annotatable-problem-footer">
<button class="button">Save</button>
<button class="button">Submit</button>
<a href="javascript:void(0);">Return to annotation</a>
</div>
</div>
</%def>
\ No newline at end of file
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