Skip to content
Snippets Groups Projects
Commit 72d9c1d7 authored by Arthur Barrett's avatar Arthur Barrett
Browse files

Saving work-in-progress of guided classification exercise.

parent 9fb80ec3
No related branches found
No related tags found
No related merge requests found
import pprint
import json
import logging
import re
......@@ -42,14 +43,7 @@ class AnnotatableModule(XModule):
callback(element, index, xmltree)
index += 1
def _set_span_data(self, span, index, xmltree):
""" Sets the associated discussion id for the span. """
if 'discussion' in span.attrib:
span.set('data-discussion-id', span.get('discussion'))
del span.attrib['discussion']
def _decorate_span(self, span, index, xmltree):
def _set_span_highlight(self, span, index, xmltree):
""" Adds a highlight class to the span. """
cls = ['annotatable-span', 'highlight']
......@@ -60,19 +54,63 @@ class AnnotatableModule(XModule):
span.set('class', ' '.join(cls))
span.tag = 'div'
def _decorate_comment(self, span, index, xmltree):
def _set_span_comment(self, span, index, xmltree):
""" Sets the comment class. """
comment = None
for child in span.iterchildren():
if child.get('class') == 'comment':
comment = child
break
comment = span.find('comment')
if comment is not None:
comment.tag = 'div'
comment.set('class', 'annotatable-comment')
def _set_span_discussion(self, span, index, xmltree):
""" Sets the associated discussion id for the span. """
if 'discussion' in span.attrib:
discussion = span.get('discussion')
span.set('data-discussion-id', discussion)
del span.attrib['discussion']
def _set_problem(self, span, index, xmltree):
""" Sets the associated problem. """
problem = span.find('problem')
if problem is not None:
problem_id = str(index + 1)
problem.set('problem_id', problem_id)
span.set('data-problem-id', problem_id)
parsed_problem = self._parse_problem(problem)
if parsed_problem is not None:
self.problems.append(parsed_problem)
def _parse_problem(self, problem):
prompt_el = problem.find('prompt')
answer_el = problem.find('answer')
tags_el = problem.find('tags')
tags = []
for tag_el in tags_el.iterchildren('tag'):
tags.append({
'name': tag_el.get('name', ''),
'display_name': tag_el.get('display_name', ''),
'weight': tag_el.get('weight', 0),
'answer': tag_el.get('answer', 'n') == 'y'
})
parsed = {
'problem_id': problem.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
def _get_marker_color(self, span):
""" Returns the name of the marker/highlight color for the span if it is valid, otherwise none."""
......@@ -84,17 +122,33 @@ class AnnotatableModule(XModule):
return marker
return None
def _render(self):
def _get_problem_name(self, problem_type):
""" Returns the display name for the problem type. Defaults to annotated reading if none given. """
problem_types = {
'classification': 'Classification Exercise + Guided Discussion',
'annotated_reading': 'Annotated Reading + Guided Discussion'
}
if problem_type is not None and problem_type in problem_types.keys():
return problem_types[problem_type]
return problem_types['annotated_reading']
def _render_content(self):
""" Renders annotatable content by transforming spans and adding discussions. """
callbacks = [
self._set_span_highlight,
self._set_span_comment,
self._set_span_discussion,
self._set_problem
]
xmltree = etree.fromstring(self.content)
self._iterspans(xmltree, [
self._set_span_data,
self._decorate_span,
self._decorate_comment
])
xmltree.tag = 'div'
self._iterspans(xmltree, callbacks)
return etree.tostring(xmltree)
def get_html(self):
......@@ -102,20 +156,29 @@ class AnnotatableModule(XModule):
context = {
'display_name': self.display_name,
'problem_name': self.problem_name,
'element_id': self.element_id,
'html_content': self._render()
'html_content': self._render_content(),
'has_problems': self.has_problems,
'problems': self.problems
}
# template dir: lms/templates
return self.system.render_template('annotatable.html', context)
def __init__(self, system, location, definition, descriptor,
instance_state=None, shared_state=None, **kwargs):
XModule.__init__(self, system, location, definition, descriptor,
instance_state, shared_state, **kwargs)
xmltree = etree.fromstring(self.definition['data'])
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.problem_name = self._get_problem_name(self.problem_type)
self.problems = []
class AnnotatableDescriptor(RawDescriptor):
module_class = AnnotatableModule
......
from lxml import etree
class AnnotatableSource:
def __init__(self, source, **kwargs):
self._source = source
self._annotations = []
def render(self):
result = { 'html': None, 'json': None }
return result
def problems(self):
return []
def annotations(self):
return self.annotations
class Annotation:
def __init__(self, target, body, **kwargs):
self.target = target
self.body = body
self.problems = []
class Problem:
def __init__(self, definition, **kwargs):
self.definition = definition
TEXT = """
<annotatable problem_type="classification">
<div style="float:left">
<img src="/static/toy/images/mantony.jpg" width="300"/>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<span class="annotatable" discussion="Toy_Fall_2012_Caesar0">
Pellentesque id mauris sit amet lectus interdum tincidunt quis at mi.
<comment title="On Lorem Ipsum">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum massa enim, sollicitudin id rutrum non, laoreet quis massa. Donec pharetra porta est id feugiat. Suspendisse aliquet cursus augue, at placerat magna adipiscing sit amet. Suspendisse velit dolor, congue in venenatis eget, consectetur pharetra massa. Vivamus facilisis tincidunt mi, nec imperdiet nibh vehicula sit amet. Donec lectus nisl, interdum sit amet faucibus et, porttitor in est.</comment>
<problem><prompt>Instructor prompt here...</prompt><tags><tag name="foo" display_name="Foo" weight="1" answer="y"/><tag name="bar" display_name="Bar" weight="0"/><tag name="green" display_name="Green" weight="-1"/><tag name="eggs" display_name="Eggs" weight="2" answer="y"/><tag name="ham" display_name="Ham" weight="-2"/></tags><answer>Explanation here...</answer></problem>
</span>
Sed semper malesuada est et mattis. Mauris vel aliquet dolor. Vivamus rhoncus tristique dictum. Duis eu neque et enim euismod venenatis. Praesent porttitor commodo erat, hendrerit interdum risus sollicitudin a. Fusce neque augue, volutpat vitae vestibulum sit amet, gravida ut urna. Vivamus rutrum laoreet turpis, a gravida velit fringilla a.</p>
<p>
Nullam quis nisi non erat auctor tristique. Suspendisse a elit tellus. In consectetur mauris quis erat consectetur eu porta turpis sodales.
<span class="annotatable" discussion="Toy_Fall_2012_Caesar1"><comment>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque egestas aliquam dignissim. Suspendisse fringilla, ante facilisis molestie ullamcorper, nisl erat elementum orci, a convallis ante massa id tellus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam nec leo eget enim imperdiet congue eget et quam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aenean a vulputate dui. Quisque gravida volutpat dolor eu porttitor. Sed varius aliquam dictum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla dictum ligula cursus nisl volutpat consectetur. Nunc iaculis tellus orci, id aliquet purus. Sed ac justo tellus. Mauris at lacus nisi. In tincidunt nisl sit amet nisi interdum non malesuada nulla pulvinar. Aliquam scelerisque ligula ut urna fermentum tincidunt. Aenean lacinia blandit metus et interdum. Phasellus porttitor porttitor consequat. Cras ultrices dictum velit, sit amet turpis duis.</comment>
Maecenas eu volutpat lacus.
</span>
Morbi luctus est
<span class="annotatable" discussion="Toy_Fall_2012_Caesar2">
tincidunt
<comment title="What is this?">Ignore this for now. It's not important.</comment>
</span>
mauris dictum sit amet ornare augue eleifend. Quisque sagittis varius enim vulputate congue.
<span class="annotatable" discussion="Toy_Fall_2012_Caesar3"><comment title="Lorem Ipsum TItle">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque egestas aliquam dignissim. Suspendisse fringilla, ante facilisis molestie ullamcorper, nisl erat elementum orci, a convallis ante massa id tellus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam nec leo eget enim imperdiet congue eget et quam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aenean a vulputate dui. Quisque gravida volutpat dolor eu porttitor. Sed varius aliquam dictum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla dictum ligula cursus nisl volutpat consectetur. Nunc iaculis tellus orci, id aliquet purus. Sed ac justo tellus. Mauris at lacus nisi. In tincidunt nisl sit amet nisi interdum non malesuada nulla pulvinar. Aliquam scelerisque ligula ut urna fermentum tincidunt. Aenean lacinia blandit metus et interdum. Phasellus porttitor porttitor consequat. Cras ultrices dictum velit, sit amet turpis duis.</comment>
Mauris facilisis mauris id nunc euismod vehicula. Mauris dictum nisi ac ligula posuere ultricies. Maecenas eros nisl, aliquet non eleifend ac, posuere in ante. Aliquam erat volutpat. Mauris consequat fringilla cursus. Suspendisse euismod eros et mauris imperdiet a placerat sapien semper.
</span>
Sed molestie laoreet magna in pharetra. Nunc mattis eleifend ultrices. Aenean ut quam vitae risus tincidunt tempor vitae sed arcu.
</p>
<p>
In adipiscing metus sit amet quam sollicitudin sed suscipit diam gravida. Maecenas aliquet ante id nunc scelerisque pulvinar. Praesent ante erat, condimentum vel scelerisque non, aliquam vel urna. Cras euismod, mi at congue dignissim, velit velit aliquet est, vel vestibulum sem turpis a dui. Donec vel rutrum felis. Fusce nulla risus, volutpat sit amet molestie non, sollicitudin quis felis. Maecenas a turpis mauris. Donec vel pulvinar nulla.
<span class="annotatable" discussion="Toy_Fall_2012_Caesar4"><comment>Chicken tenderloin boudin pig pork chop. Biltong rump frankfurter swine jowl turducken. Venison ham hock chuck pork chop, jowl chicken meatball doner meatloaf beef ribs ball tip ham. Pork drumstick fatback ribeye chicken pork chop frankfurter andouille ball tip strip steak spare ribs biltong capicola.</comment>
Vivamus nec mi quam, non gravida erat. Fusce iaculis eros eget mi tempus vitae cursus nulla ornare. Donec a nibh purus.
</span>
Ut id risus quis nibh tincidunt consectetur sed ac metus. Praesent accumsan scelerisque neque, eu imperdiet justo pharetra euismod. Suspendisse potenti. Suspendisse turpis lectus, fermentum id pellentesque eu, iaculis ut tortor. Nullam ut accumsan diam.
</p>
<p>
<span class="annotatable" discussion="Toy_Fall_2012_Caesar5"><comment>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque egestas aliquam dignissim. Suspendisse fringilla, ante facilisis molestie ullamcorper, nisl erat elementum orci, a convallis ante massa id tellus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam nec leo eget enim imperdiet congue eget et quam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aenean a vulputate dui. Quisque gravida volutpat dolor eu porttitor. Sed varius aliquam dictum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla dictum ligula cursus nisl volutpat consectetur. Nunc iaculis tellus orci, id aliquet purus. Sed ac justo tellus. Mauris at lacus nisi. In tincidunt nisl sit amet nisi interdum non malesuada nulla pulvinar. Aliquam scelerisque ligula ut urna fermentum tincidunt. Aenean lacinia blandit metus et interdum. Phasellus porttitor porttitor consequat. Cras ultrices dictum velit, sit amet turpis duis.</comment>
Duis nisl nunc, iaculis et pretium vel, bibendum eget diam. Vestibulum consectetur facilisis pretium. Morbi tristique dui a dui tempus vitae fermentum nunc dapibus. Vestibulum bibendum nunc nec dui sollicitudin viverra. Cras quam justo, consectetur fringilla varius vitae, malesuada eu lacus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec nisi lacus, feugiat sed lobortis nec, sodales sit amet tortor.
</span>
<span class="annotatable">
Vestibulum lobortis mollis cursus.
<comment>foo!</comment>
</span>
</p>
</annotatable>
"""
source = AnnotatableSource(TEXT)
rendered = source.render()
print ", ".join(rendered.keys())
......@@ -60,6 +60,54 @@
}
}
.annotatable-problems {
margin: 25px 0 0 0;
}
.annotatable-problem {
border: 1px solid #ccc;
border-radius: 1em;
margin: 0 0 1em 0;
}
.annotatable-problem-header {
font-weight: bold;
border-bottom: 1px solid #ccc;
.annotatable-problem-index { font-weight: normal; }
}
.annotatable-problem-body {
position: relative;
textarea {
display: inline-block;
width: 55%;
}
.annotatable-problem-prompt {
font-style: italic;
}
ul.annotatable-problem-tags {
display: block;
list-style-type: none;
margin: 1em 0;
padding: 0;
li {
display: inline;
padding: .5em;
margin: 0 .5em 0 0;
background-color: #ccc;
border: 1px solid #000;
}
}
.annotatable-problem-controls {
display: inline-block;
margin: 0 4px 0 8px;
}
}
.annotatable-problem-footer {}
.annotatable-problem-header,
.annotatable-problem-body,
.annotatable-problem-footer {
padding: .5em 1em;
}
.ui-tooltip.qtip.ui-tooltip {
font-size: $body-font-size;
border: 1px solid #333;
......@@ -137,3 +185,5 @@
border-top-color: rgba(0, 0, 0, .85);
}
}
......@@ -77,7 +77,7 @@ if Backbone?
if @$('section.discussion').length
@$('section.discussion').replaceWith($discussion)
else
$(".discussion-module").append($discussion)
@$el.append($discussion)
@newPostForm = $('.new-post-article')
@threadviews = @discussion.map (thread) ->
new DiscussionThreadInlineView el: @$("article#thread_#{thread.id}"), model: thread
......
......@@ -4,13 +4,40 @@
<div class="annotatable-title">${display_name} </div>
% endif
<div class="annotatable-description">
Annotated Reading + Guided Discussion
${problem_name}
<a href="javascript:void(0)" class="annotatable-toggle">Hide Annotations</a>
<div class="annotatable-help-icon" title="Move your cursor over the highlighted areas to display annotations. Discuss the annotations in the forums using the link at the bottom of the annotation. You may hide annotations at any time by using the button at the top of the section."></div>
</div>
</div>
<div class="annotatable-content">
${html_content}
</div>
<div class="annotatable-content">${html_content}</div>
% if has_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>
% endfor
</div>
% endif
</div>
<div class="annotatable-problem" data-problem-id="${problem_id}">
<div class="annotatable-problem-header">
Classification Exercise:
<span class="annotatable-problem-index">
${problem_index} / ${total_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>
<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>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment