added ability to hide/show instructions, if present
This commit is contained in:
@@ -93,6 +93,7 @@ class AnnotatableModule(XModule):
|
||||
'display_name': self.display_name,
|
||||
'element_id': self.element_id,
|
||||
'discussion_id': self.discussion_id,
|
||||
'instructions_html': self.instructions_html,
|
||||
'content_html': self._render_content()
|
||||
}
|
||||
|
||||
@@ -103,11 +104,25 @@ class AnnotatableModule(XModule):
|
||||
XModule.__init__(self, system, location, definition, descriptor,
|
||||
instance_state, shared_state, **kwargs)
|
||||
|
||||
self.element_id = self.location.html_id()
|
||||
|
||||
xmltree = etree.fromstring(self.definition['data'])
|
||||
|
||||
# extract discussion id
|
||||
self.discussion_id = xmltree.get('discussion', '')
|
||||
del xmltree.attrib['discussion']
|
||||
|
||||
# extract instructions text (if any)
|
||||
instructions = xmltree.find('instructions')
|
||||
instructions_html = None
|
||||
if instructions is not None:
|
||||
instructions.tag = 'div'
|
||||
instructions_html = etree.tostring(instructions, encoding='unicode')
|
||||
xmltree.remove(instructions)
|
||||
self.instructions_html = instructions_html
|
||||
|
||||
# everything else is annotatable content
|
||||
self.content = etree.tostring(xmltree, encoding='unicode')
|
||||
self.element_id = self.location.html_id()
|
||||
|
||||
class AnnotatableDescriptor(RawDescriptor):
|
||||
module_class = AnnotatableModule
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
.annotatable-header {
|
||||
margin-bottom: 1em;
|
||||
margin-bottom: .5em;
|
||||
.annotatable-title {
|
||||
font-size: em(22);
|
||||
text-transform: uppercase;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
.annotatable-description {
|
||||
position: relative;
|
||||
font-size: $body-font-size;
|
||||
padding: 2px 4px;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 3px;
|
||||
.annotatable-toggle {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin: 2px 7px 2px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.annotatable-description {
|
||||
position: relative;
|
||||
padding: 2px 4px;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 3px;
|
||||
margin-bottom: .5em;
|
||||
.annotatable-toggle {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin: 2px 7px 2px 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,62 +51,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.annotatable-problems {
|
||||
margin: 25px 0 0 0;
|
||||
.annotatable-discussion {
|
||||
display: none;
|
||||
}
|
||||
.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 {
|
||||
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 {
|
||||
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;
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
class @Annotatable
|
||||
_debug: false
|
||||
|
||||
wrapperSelector: '.annotatable-wrapper'
|
||||
toggleSelector: '.annotatable-toggle'
|
||||
spanSelector: '.annotatable-span'
|
||||
replySelector: '.annotatable-reply'
|
||||
wrapperSelector: '.annotatable-wrapper'
|
||||
toggleAnnotationsSelector: '.annotatable-toggle-annotations'
|
||||
toggleInstructionsSelector: '.annotatable-toggle-instructions'
|
||||
instructionsSelector: '.annotatable-instructions'
|
||||
spanSelector: '.annotatable-span'
|
||||
replySelector: '.annotatable-reply'
|
||||
|
||||
problemXModuleSelector: '.xmodule_CapaModule'
|
||||
problemSelector: 'section.problem'
|
||||
problemInputSelector: '.annotation-input'
|
||||
problemReturnSelector: 'section.problem .annotation-return'
|
||||
problemXModuleSelector: '.xmodule_CapaModule'
|
||||
problemSelector: 'section.problem'
|
||||
problemInputSelector: 'section.problem .annotation-input'
|
||||
problemReturnSelector: 'section.problem .annotation-return'
|
||||
|
||||
constructor: (el) ->
|
||||
console.log 'loaded Annotatable' if @_debug
|
||||
@@ -24,9 +26,12 @@ class @Annotatable
|
||||
@initTips()
|
||||
|
||||
initEvents: () ->
|
||||
# For handling hide/show of annotations
|
||||
# For handling hide/show of annotations and instructions
|
||||
@annotationsHidden = false
|
||||
@$(@toggleSelector).bind 'click', @onClickToggleAnnotations
|
||||
@$(@toggleAnnotationsSelector).bind 'click', @onClickToggleAnnotations
|
||||
|
||||
@instructionsHidden = false
|
||||
@$(@toggleInstructionsSelector).bind 'click', @onClickToggleInstructions
|
||||
|
||||
# For handling 'reply to annotation' events that scroll to the associated capa problem.
|
||||
# These are contained in the tooltips, which should be rendered somewhere in the wrapper
|
||||
@@ -68,29 +73,15 @@ class @Annotatable
|
||||
events:
|
||||
show: @onShowTip
|
||||
|
||||
onShowTip: (event, api) =>
|
||||
event.preventDefault() if @annotationsHidden
|
||||
onShowTip: (event, api) => event.preventDefault() if @annotationsHidden
|
||||
|
||||
onClickToggleAnnotations: (e) =>
|
||||
@toggleAnnotations()
|
||||
onClickToggleAnnotations: (e) => @toggleAnnotations()
|
||||
|
||||
onClickReply: (e) =>
|
||||
e.preventDefault()
|
||||
offset = -20
|
||||
el = @getProblem e.currentTarget
|
||||
if el.length > 0
|
||||
@scrollTo(el, @afterScrollToProblem, offset)
|
||||
else
|
||||
console.log('problem not found. event: ', e) if @_debug
|
||||
onClickToggleInstructions: (e) => @toggleInstructions()
|
||||
|
||||
onClickReturn: (e) =>
|
||||
e.preventDefault()
|
||||
offset = -200
|
||||
el = @getSpanForProblemReturn e.currentTarget
|
||||
if el.length > 0
|
||||
@scrollTo(el, @afterScrollToSpan, offset)
|
||||
else
|
||||
console.log('span not found. event:', e) if @_debug
|
||||
onClickReply: (e) => @replyTo(e.currentTarget)
|
||||
|
||||
onClickReturn: (e) => @returnFrom(e.currentTarget)
|
||||
|
||||
getSpanForProblemReturn: (el) ->
|
||||
problem_id = $(@problemReturnSelector).index(el)
|
||||
@@ -105,24 +96,48 @@ class @Annotatable
|
||||
|
||||
toggleAnnotations: () ->
|
||||
hide = (@annotationsHidden = not @annotationsHidden)
|
||||
@toggleButtonText hide
|
||||
@toggleAnnotationButtonText hide
|
||||
@toggleSpans hide
|
||||
@toggleReturnLinks hide
|
||||
@toggleTips hide
|
||||
|
||||
toggleTips: (hide) ->
|
||||
if hide then @closeAndSaveTips() else @openSavedTips()
|
||||
|
||||
toggleReturnLinks: (hide) ->
|
||||
$(@returnSelector)[if hide then 'hide' else 'show']()
|
||||
|
||||
toggleButtonText: (hide) ->
|
||||
toggleAnnotationButtonText: (hide) ->
|
||||
buttonText = (if hide then 'Show' else 'Hide')+' Annotations'
|
||||
@$(@toggleSelector).text(buttonText)
|
||||
@$(@toggleAnnotationsSelector).text(buttonText)
|
||||
|
||||
toggleInstructions: () ->
|
||||
hide = (@instructionsHidden = not @instructionsHidden)
|
||||
@toggleInstructionsButtonText hide
|
||||
@toggleInstructionsText hide
|
||||
|
||||
toggleInstructionsButtonText: (hide) ->
|
||||
buttonText = (if hide then 'Show' else 'Hide')+' Instructions'
|
||||
@$(@toggleInstructionsSelector).text(buttonText)
|
||||
|
||||
toggleInstructionsText: (hide) ->
|
||||
@$(@instructionsSelector)[if hide then 'slideUp' else 'slideDown']()
|
||||
|
||||
toggleSpans: (hide) ->
|
||||
@$(@spanSelector).toggleClass 'hide', hide, 250
|
||||
|
||||
replyTo: (buttonEl) ->
|
||||
offset = -20
|
||||
el = @getProblem buttonEl
|
||||
if el.length > 0
|
||||
@scrollTo(el, @afterScrollToProblem, offset)
|
||||
else
|
||||
console.log('problem not found. event: ', e) if @_debug
|
||||
|
||||
returnFrom: (buttonEl) ->
|
||||
offset = -200
|
||||
el = @getSpanForProblemReturn buttonEl
|
||||
if el.length > 0
|
||||
@scrollTo(el, @afterScrollToSpan, offset)
|
||||
else
|
||||
console.log('span not found. event:', e) if @_debug
|
||||
|
||||
scrollTo: (el, after, offset = -20) ->
|
||||
$('html,body').scrollTo(el, {
|
||||
duration: 500
|
||||
|
||||
@@ -23,18 +23,18 @@
|
||||
},
|
||||
onChangeComment: function(e) {
|
||||
var value_el = this.findValueEl(e.target);
|
||||
var current_value = this.currentValue(value_el);
|
||||
var current_value = this.loadValue(value_el);
|
||||
var target_value = $(e.target).val();
|
||||
|
||||
current_value.comment = target_value;
|
||||
this.setValue(value_el, current_value);
|
||||
this.storeValue(value_el, current_value);
|
||||
},
|
||||
onClickTag: function(e) {
|
||||
var target_el = e.target, target_value, target_index;
|
||||
var value_el, current_value;
|
||||
|
||||
value_el = this.findValueEl(e.target);
|
||||
current_value = this.currentValue(value_el);
|
||||
current_value = this.loadValue(value_el);
|
||||
target_value = $(e.target).data('id');
|
||||
|
||||
if(!$(target_el).hasClass('selected')) {
|
||||
@@ -46,14 +46,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
this.setValue(value_el, current_value);
|
||||
this.storeValue(value_el, current_value);
|
||||
$(target_el).toggleClass('selected');
|
||||
},
|
||||
findValueEl: function(target_el) {
|
||||
var input_el = $(target_el).closest(this.inputSelector);
|
||||
return $(this.valueSelector, input_el);
|
||||
},
|
||||
currentValue: function(value_el) {
|
||||
loadValue: function(value_el) {
|
||||
var json = $(value_el).val();
|
||||
|
||||
var result = JSON.parse(json);
|
||||
@@ -69,7 +69,7 @@
|
||||
|
||||
return result;
|
||||
},
|
||||
setValue: function(value_el, new_value) {
|
||||
storeValue: function(value_el, new_value) {
|
||||
var json = JSON.stringify(new_value);
|
||||
$(value_el).val(json);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,19 @@
|
||||
% if display_name is not UNDEFINED and display_name is not None:
|
||||
<div class="annotatable-title">${display_name}</div>
|
||||
% endif
|
||||
<div class="annotatable-description">
|
||||
Guided Discussion
|
||||
<a class="annotatable-toggle" href="javascript:void(0)">Hide Annotations</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
% if instructions_html is not UNDEFINED and instructions_html is not None:
|
||||
<div class="annotatable-description">
|
||||
Instructions
|
||||
<a class="annotatable-toggle annotatable-toggle-instructions" href="javascript:void(0)">Hide Instructions</a>
|
||||
</div>
|
||||
<div class="annotatable-instructions">${instructions_html}</div>
|
||||
% endif
|
||||
|
||||
<div class="annotatable-description">
|
||||
Guided Discussion
|
||||
<a class="annotatable-toggle annotatable-toggle-annotations" href="javascript:void(0)">Hide Annotations</a>
|
||||
</div>
|
||||
<div class="annotatable-content">${content_html}</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user