Commit a9773eb8 by Arthur Barrett

Updated markup, styling, and tooltip behavior for displaying instructor…

Updated markup, styling, and tooltip behavior for displaying instructor comments. Added drag/drop to the comments so the user can organize them as they wish after clicking on the span. When the user hides the annotations, their positions on the screen are remembered so they can be restored later. Also modified the markup so that block content can be displayed.
parent 7ea87793
...@@ -30,20 +30,20 @@ class AnnotatableModule(XModule): ...@@ -30,20 +30,20 @@ class AnnotatableModule(XModule):
def _is_span(self, element): def _is_span(self, element):
""" Returns true if the element is a valid annotation span, false otherwise. """ """ Returns true if the element is a valid annotation span, false otherwise. """
return element.tag == 'span' and element.get('class') == 'annotatable' return element.get('class') == 'annotatable'
def _iterspans(self, xmltree, callbacks): def _iterspans(self, xmltree, callbacks):
""" Iterates over span elements and invokes each callback on the span. """ """ Iterates over elements and invokes each callback on the span. """
index = 0 index = 0
for element in xmltree.iter('span'): for element in xmltree.iter():
if self._is_span(element): if self._is_span(element):
for callback in callbacks: for callback in callbacks:
callback(element, index, xmltree) callback(element, index, xmltree)
index += 1 index += 1
def _set_span_data(self, span, index, xmltree): def _set_span_data(self, span, index, xmltree):
""" Sets an ID and discussion anchor for the span. """ """ Sets the discussion anchor for the span. """
if 'anchor' in span.attrib: if 'anchor' in span.attrib:
span.set('data-discussion-anchor', span.get('anchor')) span.set('data-discussion-anchor', span.get('anchor'))
...@@ -52,13 +52,12 @@ class AnnotatableModule(XModule): ...@@ -52,13 +52,12 @@ class AnnotatableModule(XModule):
def _decorate_span(self, span, index, xmltree): def _decorate_span(self, span, index, xmltree):
""" Decorates the span with an icon and highlight. """ """ Decorates the span with an icon and highlight. """
cls = ['annotatable', ] cls = ['annotatable-span', 'highlight']
marker = self._get_marker_color(span) marker = self._get_marker_color(span)
if marker is None: if marker is not None:
cls.append('highlight-yellow')
else:
cls.append('highlight-'+marker) cls.append('highlight-'+marker)
span.tag = 'div'
span.set('class', ' '.join(cls)) span.set('class', ' '.join(cls))
span_icon = etree.Element('span', { 'class': 'annotatable-icon'} ) span_icon = etree.Element('span', { 'class': 'annotatable-icon'} )
span_icon.text = ''; span_icon.text = '';
...@@ -76,9 +75,12 @@ class AnnotatableModule(XModule): ...@@ -76,9 +75,12 @@ class AnnotatableModule(XModule):
break break
if comment is not None: if comment is not None:
comment.tag = 'div'
comment.set('class', 'annotatable-comment') comment.set('class', 'annotatable-comment')
def _get_marker_color(self, span): def _get_marker_color(self, span):
""" Returns the name of the marker color for the span if it is valid, otherwise none."""
valid_markers = ['yellow', 'orange', 'purple', 'blue', 'green'] valid_markers = ['yellow', 'orange', 'purple', 'blue', 'green']
if 'marker' in span.attrib: if 'marker' in span.attrib:
marker = span.attrib['marker'] marker = span.attrib['marker']
......
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
font-size: $body-font-size; font-size: $body-font-size;
} }
span.annotatable { .annotatable-span {
display: inline;
cursor: pointer; cursor: pointer;
@each $highlight in ( @each $highlight in (
(yellow rgb(239, 255, 0)), (yellow rgb(239, 255, 0)),
...@@ -27,9 +28,10 @@ span.annotatable { ...@@ -27,9 +28,10 @@ span.annotatable {
(purple rgb(255,0,197)), (purple rgb(255,0,197)),
(blue rgb(0,90,255)), (blue rgb(0,90,255)),
(green rgb(111,255,9))) { (green rgb(111,255,9))) {
&.highlight-#{nth($highlight,1)} { $marker: nth($highlight,1);
background-color: #{lighten(nth($highlight,2), 20%)}; $color: lighten(nth($highlight,2), 20%);
} @if $marker == yellow { &.highlight { background-color: $color; } }
&.highlight-#{$marker} { background-color: $color; }
} }
&.hide { &.hide {
cursor: none; cursor: none;
...@@ -50,7 +52,7 @@ span.annotatable { ...@@ -50,7 +52,7 @@ span.annotatable {
.annotatable-icon { .annotatable-icon {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
width: 16px; width: 17px;
height: 17px; height: 17px;
background: url(../images/link-icon.png) no-repeat; background: url(../images/link-icon.png) no-repeat;
} }
...@@ -60,12 +62,12 @@ span.annotatable { ...@@ -60,12 +62,12 @@ span.annotatable {
margin: 1em 0 .5em 0; margin: 1em 0 .5em 0;
} }
.help-icon { .annotatable-help-icon {
display: block; display: block;
position: absolute; position: absolute;
right: 0; right: 0;
top: 33%; top: 33%;
width: 16px; width: 17px;
height: 17px; height: 17px;
margin: 0 7px 0 0; margin: 0 7px 0 0;
background: url(../images/info-icon.png) no-repeat; background: url(../images/info-icon.png) no-repeat;
...@@ -80,11 +82,14 @@ span.annotatable { ...@@ -80,11 +82,14 @@ span.annotatable {
background: rgba(255, 255, 255, 0.9); background: rgba(255, 255, 255, 0.9);
border: 1px solid $border-color; border: 1px solid $border-color;
color: #000; color: #000;
font-weight: normal;
margin-bottom: 6px; margin-bottom: 6px;
margin-right: 0; margin-right: 0;
overflow: visible;
padding: 4px; padding: 4px;
text-align: left; text-align: left;
max-width: 300px;
max-height: 300px;
overflow: auto;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
} }
} }
\ No newline at end of file
...@@ -3,64 +3,89 @@ class @Annotatable ...@@ -3,64 +3,89 @@ class @Annotatable
wrapperSelector: '.annotatable-wrapper' wrapperSelector: '.annotatable-wrapper'
toggleSelector: '.annotatable-toggle' toggleSelector: '.annotatable-toggle'
spanSelector: 'span.annotatable' spanSelector: '.annotatable-span'
commentSelector: '.annotatable-comment' commentSelector: '.annotatable-comment'
replySelector: 'a.annotatable-reply' replySelector: '.annotatable-reply'
helpSelector: '.annotatable-help-icon'
constructor: (el) -> constructor: (el) ->
console.log 'loaded Annotatable' if @_debug console.log 'loaded Annotatable' if @_debug
@init(el) @el = el
@init()
$: (selector) -> $: (selector) ->
$(selector, @el) $(selector, @el)
init: (el) -> init: () ->
@el = el
@hideAnnotations = false
@initEvents() @initEvents()
@initToolTips() @initTips()
initEvents: () -> initEvents: () ->
@annotationsHidden = false
@$(@toggleSelector).bind 'click', @onClickToggleAnnotations @$(@toggleSelector).bind 'click', @onClickToggleAnnotations
@$(@wrapperSelector).delegate @replySelector, 'click', @onClickReply @$(@wrapperSelector).delegate @replySelector, 'click', @onClickReply
initToolTips: () -> initTips: () ->
@visibleTips = []
@$(@spanSelector).each (index, el) => @$(@spanSelector).each (index, el) =>
$(el).qtip(@getTipOptions el) $(el).qtip(@getTipOptions el)
@$(@helpSelector).qtip
position:
my: 'right top'
at: 'bottom left'
content:
title: 'Annotated Reading Help'
text: "To reveal annotations in the reading, click the highlighted areas.
Discuss the annotations in the forums using the reply link at the
end of the annotation.<br/><br/>
To conceal annotations, use the <i>Hide Annotations</i> button."
getTipOptions: (el) -> getTipOptions: (el) ->
content: content:
title: title:
text: @makeTipTitle(el) text: @makeTipTitle(el)
button: 'Close' button: 'Close'
text: @makeTipComment(el) text: @makeTipContent(el)
position: position:
my: 'bottom center' # of tooltip my: 'bottom center' # of tooltip
at: 'top center' # of target at: 'top center' # of target
target: 'mouse' target: 'mouse'
container: @$(@wrapperSelector) container: @$(@wrapperSelector)
adjust: adjust:
mouse: false # dont follow the mouse mouse: false # dont follow the mouse
method: 'shift none' show:
show:
event: 'click' event: 'click'
hide: hide:
event: 'click' event: 'click'
style: style:
classes: 'ui-tooltip-annotatable' classes: 'ui-tooltip-annotatable'
events: events:
show: @onShowTipComment render: @onRenderTip
show: @onShowTip
onRenderTip: (event, api) =>
$(api.elements.tooltip).draggable
handle: '.ui-tooltip-title'
cursor: 'move'
onShowTipComment: (event, api) => onShowTip: (event, api) =>
event.preventDefault() if @hideAnnotations event.preventDefault() if @annotationsHidden
onClickToggleAnnotations: (e) => onClickToggleAnnotations: (e) =>
@hideAnnotations = !@hideAnnotations toggle = @$(@toggleSelector)
hide = @hideAnnotations spans = @$(@spanSelector)
@hideAllTips() if hide @annotationsHidden = !@annotationsHidden
@$(@spanSelector).toggleClass('hide', hide) if @annotationsHidden
@$(@toggleSelector).text((if hide then 'Show' else 'Hide') + ' Annotations') spans.toggleClass('hide', true)
toggle.text('Show Annotations')
@visibleTips = @getVisibleTips()
@hideTips(@visibleTips)
else
spans.toggleClass('hide', false)
toggle.text('Hide Annotations')
@showTips(@visibleTips)
onClickReply: (e) => onClickReply: (e) =>
hash = $(e.currentTarget).attr('href') hash = $(e.currentTarget).attr('href')
...@@ -70,11 +95,16 @@ class @Annotatable ...@@ -70,11 +95,16 @@ class @Annotatable
@scrollTo(anchor) if anchor.length == 1 @scrollTo(anchor) if anchor.length == 1
scrollTo: (el, padding = 20) -> scrollTo: (el, padding = 20) ->
scrollTop = el.offset().top - padding props =
$('html,body').animate(scrollTop: scrollTop, 500, 'swing') scrollTop: (el.offset().top - padding)
opts =
duration: 500
complete: @_once -> el.effect 'highlight', {}, 2000
makeTipComment: (el) -> $('html,body').animate(props, opts)
return (api) =>
makeTipContent: (el) ->
(api) =>
comment = $(@commentSelector, el).first().clone() comment = $(@commentSelector, el).first().clone()
anchor = $(el).data('discussion-anchor') anchor = $(el).data('discussion-anchor')
if anchor if anchor
...@@ -82,13 +112,36 @@ class @Annotatable ...@@ -82,13 +112,36 @@ class @Annotatable
comment.contents() comment.contents()
makeTipTitle: (el) -> makeTipTitle: (el) ->
return (api) => (api) =>
comment = $(@commentSelector, el).first() comment = $(@commentSelector, el).first()
title = comment.attr('title') title = comment.attr('title')
(if title then title else 'Commentary') (if title then title else 'Commentary')
createReplyLink: (anchor) -> createReplyLink: (anchor) ->
$("<a class=\"annotatable-reply\" href=\"##{anchor}\">Reply to Comment</a>") $("<a class=\"annotatable-reply\" href=\"##{anchor}\">Reply to this comment</a>")
getVisibleTips: () ->
visible = []
@$(@spanSelector).each (index, el) ->
api = $(el).qtip('api')
tip = $(api?.elements.tooltip)
if tip.is(':visible')
visible.push [el, tip.offset()]
visible
hideAllTips: () -> hideTips: (items) ->
@$(@spanSelector).each (index, el) -> $(el).qtip('api').hide() elements = (pair[0] for pair in items)
\ No newline at end of file $(elements).qtip('hide')
showTips: (items) ->
$.each items, (index, item) ->
[el, offset] = item
api = $(el).qtip('api')
api?.show()
$(api?.elements.tooltip).offset(offset)
_once: (fn) ->
done = false
return =>
fn.call this unless done
done = true
<div class="annotatable-wrapper" id="${element_id}-wrapper"> <div class="annotatable-wrapper" id="${element_id}-wrapper">
<div class="annotatable-header"> <div class="annotatable-header">
<div class="help-icon"></div> <div class="annotatable-help-icon"></div>
% if display_name is not UNDEFINED and display_name is not None: % if display_name is not UNDEFINED and display_name is not None:
<div class="annotatable-title">${display_name} </div> <div class="annotatable-title">${display_name} </div>
% endif % endif
......
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