Commit dc338972 by Julia Hansbrough

Merge pull request #4053 from edx/harvard-annotations-on-hotfix

Harvard annotations on hotfix
parents 0df70376 e48cc16d
...@@ -7,7 +7,6 @@ from urlparse import urlparse ...@@ -7,7 +7,6 @@ from urlparse import urlparse
from os.path import splitext, basename from os.path import splitext, basename
from HTMLParser import HTMLParser from HTMLParser import HTMLParser
def get_instructions(xmltree): def get_instructions(xmltree):
""" Removes <instructions> from the xmltree and returns them as a string, otherwise None. """ """ Removes <instructions> from the xmltree and returns them as a string, otherwise None. """
instructions = xmltree.find('instructions') instructions = xmltree.find('instructions')
......
...@@ -9,13 +9,19 @@ from xmodule.raw_module import RawDescriptor ...@@ -9,13 +9,19 @@ from xmodule.raw_module import RawDescriptor
from xblock.core import Scope, String from xblock.core import Scope, String
from xmodule.annotator_mixin import get_instructions, html_to_text from xmodule.annotator_mixin import get_instructions, html_to_text
from xmodule.annotator_token import retrieve_token from xmodule.annotator_token import retrieve_token
from xblock.fragment import Fragment
import textwrap import textwrap
# Make '_' a no-op so we can scrape strings
_ = lambda text: text
class AnnotatableFields(object): class AnnotatableFields(object):
""" Fields for `ImageModule` and `ImageDescriptor`. """ """ Fields for `ImageModule` and `ImageDescriptor`. """
data = String(help="XML data for the annotation", scope=Scope.content, default=textwrap.dedent("""\ data = String(help=_("XML data for the annotation"),
scope=Scope.content,
default=textwrap.dedent("""\
<annotatable> <annotatable>
<instructions> <instructions>
<p> <p>
...@@ -36,28 +42,47 @@ class AnnotatableFields(object): ...@@ -36,28 +42,47 @@ class AnnotatableFields(object):
</annotatable> </annotatable>
""")) """))
display_name = String( display_name = String(
display_name="Display Name", display_name=_("Display Name"),
help="Display name for this module", help=_("Display name for this module"),
scope=Scope.settings, scope=Scope.settings,
default='Image Annotation', default='Image Annotation',
) )
instructor_tags = String( instructor_tags = String(
display_name="Tags for Assignments", display_name=_("Tags for Assignments"),
help="Add tags that automatically highlight in a certain color using the comma-separated form, i.e. imagery:red,parallelism:blue", help=_("Add tags that automatically highlight in a certain color using the comma-separated form, i.e. imagery:red,parallelism:blue"),
scope=Scope.settings, scope=Scope.settings,
default='professor:green,teachingAssistant:blue', default='professor:green,teachingAssistant:blue',
) )
annotation_storage_url = String( annotation_storage_url = String(
help="Location of Annotation backend", help=_("Location of Annotation backend"),
scope=Scope.settings, scope=Scope.settings,
default="http://your_annotation_storage.com", default="http://your_annotation_storage.com",
display_name="Url for Annotation Storage" display_name=_("Url for Annotation Storage")
) )
annotation_token_secret = String( annotation_token_secret = String(
help="Secret string for annotation storage", help=_("Secret string for annotation storage"),
scope=Scope.settings, scope=Scope.settings,
default="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", default="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
display_name="Secret Token String for Annotation" display_name=_("Secret Token String for Annotation")
)
default_tab = String(
display_name=_("Default Annotations Tab"),
help=_("Select which tab will be the default in the annotations table: myNotes, Instructor, or Public."),
scope=Scope.settings,
default="myNotes",
)
# currently only supports one instructor, will build functionality for multiple later
instructor_email = String(
display_name=_("Email for 'Instructor' Annotations"),
help=_("Email of the user that will be attached to all annotations that will be found in 'Instructor' tab."),
scope=Scope.settings,
default="",
)
annotation_mode = String(
display_name=_("Mode for Annotation Tool"),
help=_("Type in number corresponding to following modes: 'instructor' or 'everyone'"),
scope=Scope.settings,
default="everyone",
) )
...@@ -91,18 +116,23 @@ class ImageAnnotationModule(AnnotatableFields, XModule): ...@@ -91,18 +116,23 @@ class ImageAnnotationModule(AnnotatableFields, XModule):
""" Removes <instructions> from the xmltree and returns them as a string, otherwise None. """ """ Removes <instructions> from the xmltree and returns them as a string, otherwise None. """
return get_instructions(xmltree) return get_instructions(xmltree)
def get_html(self): def student_view(self, context):
""" Renders parameters to template. """ """ Renders parameters to template. """
context = { context = {
'display_name': self.display_name_with_default, 'display_name': self.display_name_with_default,
'instructions_html': self.instructions, 'instructions_html': self.instructions,
'annotation_storage': self.annotation_storage_url,
'token': retrieve_token(self.user, self.annotation_token_secret), 'token': retrieve_token(self.user, self.annotation_token_secret),
'tag': self.instructor_tags, 'tag': self.instructor_tags,
'openseadragonjson': self.openseadragonjson, 'openseadragonjson': self.openseadragonjson,
'annotation_storage': self.annotation_storage_url,
'default_tab': self.default_tab,
'instructor_email': self.instructor_email,
'annotation_mode': self.annotation_mode,
} }
fragment = Fragment(self.system.render_template('imageannotation.html', context))
return self.system.render_template('imageannotation.html', context) fragment.add_javascript_url("/static/js/vendor/tinymce/js/tinymce/tinymce.full.min.js")
fragment.add_javascript_url("/static/js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js")
return fragment
class ImageAnnotationDescriptor(AnnotatableFields, RawDescriptor): # pylint: disable=abstract-method class ImageAnnotationDescriptor(AnnotatableFields, RawDescriptor): # pylint: disable=abstract-method
......
...@@ -69,10 +69,10 @@ class ImageAnnotationModuleTestCase(unittest.TestCase): ...@@ -69,10 +69,10 @@ class ImageAnnotationModuleTestCase(unittest.TestCase):
actual = self.mod._extract_instructions(xmltree) # pylint: disable=protected-access actual = self.mod._extract_instructions(xmltree) # pylint: disable=protected-access
self.assertIsNone(actual) self.assertIsNone(actual)
def test_get_html(self): def test_student_view(self):
""" """
Tests the function that passes in all the information in the context that will be used in templates/textannotation.html Tests the function that passes in all the information in the context that will be used in templates/textannotation.html
""" """
context = self.mod.get_html() context = self.mod.student_view({}).content
for key in ['display_name', 'instructions_html', 'annotation_storage', 'token', 'tag', 'openseadragonjson']: for key in ['display_name', 'instructions_html', 'annotation_storage', 'token', 'tag', 'openseadragonjson']:
self.assertIn(key, context) self.assertIn(key, context)
...@@ -54,10 +54,10 @@ class TextAnnotationModuleTestCase(unittest.TestCase): ...@@ -54,10 +54,10 @@ class TextAnnotationModuleTestCase(unittest.TestCase):
actual = self.mod._extract_instructions(xmltree) # pylint: disable=W0212 actual = self.mod._extract_instructions(xmltree) # pylint: disable=W0212
self.assertIsNone(actual) self.assertIsNone(actual)
def test_get_html(self): def test_student_view(self):
""" """
Tests the function that passes in all the information in the context that will be used in templates/textannotation.html Tests the function that passes in all the information in the context that will be used in templates/textannotation.html
""" """
context = self.mod.get_html() context = self.mod.student_view({}).content
for key in ['display_name', 'tag', 'source', 'instructions_html', 'content_html', 'annotation_storage', 'token']: for key in ['display_name', 'tag', 'source', 'instructions_html', 'content_html', 'annotation_storage', 'token']:
self.assertIn(key, context) self.assertIn(key, context)
...@@ -62,10 +62,10 @@ class VideoAnnotationModuleTestCase(unittest.TestCase): ...@@ -62,10 +62,10 @@ class VideoAnnotationModuleTestCase(unittest.TestCase):
self.assertEqual(expectedyoutube, result2) self.assertEqual(expectedyoutube, result2)
self.assertEqual(expectednotyoutube, result1) self.assertEqual(expectednotyoutube, result1)
def test_get_html(self): def test_student_view(self):
""" """
Tests to make sure variables passed in truly exist within the html once it is all rendered. Tests to make sure variables passed in truly exist within the html once it is all rendered.
""" """
context = self.mod.get_html() context = self.mod.student_view({}).content
for key in ['display_name', 'instructions_html', 'sourceUrl', 'typeSource', 'poster', 'annotation_storage']: for key in ['display_name', 'instructions_html', 'sourceUrl', 'typeSource', 'poster', 'annotation_storage']:
self.assertIn(key, context) self.assertIn(key, context)
...@@ -8,7 +8,7 @@ from xmodule.raw_module import RawDescriptor ...@@ -8,7 +8,7 @@ from xmodule.raw_module import RawDescriptor
from xblock.core import Scope, String from xblock.core import Scope, String
from xmodule.annotator_mixin import get_instructions from xmodule.annotator_mixin import get_instructions
from xmodule.annotator_token import retrieve_token from xmodule.annotator_token import retrieve_token
from xblock.fragment import Fragment
import textwrap import textwrap
# Make '_' a no-op so we can scrape strings # Make '_' a no-op so we can scrape strings
...@@ -17,7 +17,9 @@ _ = lambda text: text ...@@ -17,7 +17,9 @@ _ = lambda text: text
class AnnotatableFields(object): class AnnotatableFields(object):
"""Fields for `TextModule` and `TextDescriptor`.""" """Fields for `TextModule` and `TextDescriptor`."""
data = String(help=_("XML data for the annotation"), scope=Scope.content, default=textwrap.dedent("""\ data = String(help=_("XML data for the annotation"),
scope=Scope.content,
default=textwrap.dedent("""\
<annotatable> <annotatable>
<instructions> <instructions>
<p> <p>
...@@ -47,8 +49,43 @@ class AnnotatableFields(object): ...@@ -47,8 +49,43 @@ class AnnotatableFields(object):
scope=Scope.settings, scope=Scope.settings,
default='None', default='None',
) )
annotation_storage_url = String(help=_("Location of Annotation backend"), scope=Scope.settings, default="http://your_annotation_storage.com", display_name=_("Url for Annotation Storage")) diacritics = String(
annotation_token_secret = String(help=_("Secret string for annotation storage"), scope=Scope.settings, default="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", display_name=_("Secret Token String for Annotation")) display_name=_("Diacritic Marks"),
help=_("Add diacritic marks to be added to a text using the comma-separated form, i.e. markname;urltomark;baseline,markname2;urltomark2;baseline2"),
scope=Scope.settings,
default='',
)
annotation_storage_url = String(
help=_("Location of Annotation backend"),
scope=Scope.settings,
default="http://your_annotation_storage.com",
display_name=_("Url for Annotation Storage")
)
annotation_token_secret = String(
help=_("Secret string for annotation storage"),
scope=Scope.settings,
default="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
display_name=_("Secret Token String for Annotation")
)
default_tab = String(
display_name=_("Default Annotations Tab"),
help=_("Select which tab will be the default in the annotations table: myNotes, Instructor, or Public."),
scope=Scope.settings,
default="myNotes",
)
# currently only supports one instructor, will build functionality for multiple later
instructor_email = String(
display_name=_("Email for 'Instructor' Annotations"),
help=_("Email of the user that will be attached to all annotations that will be found in 'Instructor' tab."),
scope=Scope.settings,
default="",
)
annotation_mode = String(
display_name=_("Mode for Annotation Tool"),
help=_("Type in number corresponding to following modes: 'instructor' or 'everyone'"),
scope=Scope.settings,
default="everyone",
)
class TextAnnotationModule(AnnotatableFields, XModule): class TextAnnotationModule(AnnotatableFields, XModule):
...@@ -73,7 +110,7 @@ class TextAnnotationModule(AnnotatableFields, XModule): ...@@ -73,7 +110,7 @@ class TextAnnotationModule(AnnotatableFields, XModule):
""" Removes <instructions> from the xmltree and returns them as a string, otherwise None. """ """ Removes <instructions> from the xmltree and returns them as a string, otherwise None. """
return get_instructions(xmltree) return get_instructions(xmltree)
def get_html(self): def student_view(self, context):
""" Renders parameters to template. """ """ Renders parameters to template. """
context = { context = {
'course_key': self.runtime.course_id, 'course_key': self.runtime.course_id,
...@@ -82,10 +119,17 @@ class TextAnnotationModule(AnnotatableFields, XModule): ...@@ -82,10 +119,17 @@ class TextAnnotationModule(AnnotatableFields, XModule):
'source': self.source, 'source': self.source,
'instructions_html': self.instructions, 'instructions_html': self.instructions,
'content_html': self.content, 'content_html': self.content,
'annotation_storage': self.annotation_storage_url,
'token': retrieve_token(self.user_email, self.annotation_token_secret), 'token': retrieve_token(self.user_email, self.annotation_token_secret),
'diacritic_marks': self.diacritics,
'annotation_storage': self.annotation_storage_url,
'default_tab': self.default_tab,
'instructor_email': self.instructor_email,
'annotation_mode': self.annotation_mode,
} }
return self.system.render_template('textannotation.html', context) fragment = Fragment(self.system.render_template('textannotation.html', context))
fragment.add_javascript_url("/static/js/vendor/tinymce/js/tinymce/tinymce.full.min.js")
fragment.add_javascript_url("/static/js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js")
return fragment
class TextAnnotationDescriptor(AnnotatableFields, RawDescriptor): class TextAnnotationDescriptor(AnnotatableFields, RawDescriptor):
......
...@@ -9,6 +9,7 @@ from xmodule.raw_module import RawDescriptor ...@@ -9,6 +9,7 @@ from xmodule.raw_module import RawDescriptor
from xblock.core import Scope, String from xblock.core import Scope, String
from xmodule.annotator_mixin import get_instructions, get_extension from xmodule.annotator_mixin import get_instructions, get_extension
from xmodule.annotator_token import retrieve_token from xmodule.annotator_token import retrieve_token
from xblock.fragment import Fragment
import textwrap import textwrap
...@@ -18,7 +19,9 @@ _ = lambda text: text ...@@ -18,7 +19,9 @@ _ = lambda text: text
class AnnotatableFields(object): class AnnotatableFields(object):
""" Fields for `VideoModule` and `VideoDescriptor`. """ """ Fields for `VideoModule` and `VideoDescriptor`. """
data = String(help=_("XML data for the annotation"), scope=Scope.content, default=textwrap.dedent("""\ data = String(help=_("XML data for the annotation"),
scope=Scope.content,
default=textwrap.dedent("""\
<annotatable> <annotatable>
<instructions> <instructions>
<p> <p>
...@@ -31,12 +34,51 @@ class AnnotatableFields(object): ...@@ -31,12 +34,51 @@ class AnnotatableFields(object):
display_name=_("Display Name"), display_name=_("Display Name"),
help=_("Display name for this module"), help=_("Display name for this module"),
scope=Scope.settings, scope=Scope.settings,
default='Video Annotation', default=_('Video Annotation'),
)
sourceurl = String(
help=_("The external source URL for the video."),
display_name=_("Source URL"),
scope=Scope.settings, default="http://video-js.zencoder.com/oceans-clip.mp4"
)
poster_url = String(
help=_("Poster Image URL"),
display_name=_("Poster URL"),
scope=Scope.settings,
default=""
)
annotation_storage_url = String(
help=_("Location of Annotation backend"),
scope=Scope.settings,
default="http://your_annotation_storage.com",
display_name=_("Url for Annotation Storage")
)
annotation_token_secret = String(
help=_("Secret string for annotation storage"),
scope=Scope.settings,
default="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
display_name=_("Secret Token String for Annotation")
)
default_tab = String(
display_name=_("Default Annotations Tab"),
help=_("Select which tab will be the default in the annotations table: myNotes, Instructor, or Public."),
scope=Scope.settings,
default="myNotes",
)
# currently only supports one instructor, will build functionality for multiple later
instructor_email = String(
display_name=_("Email for 'Instructor' Annotations"),
help=_("Email of the user that will be attached to all annotations that will be found in 'Instructor' tab."),
scope=Scope.settings,
default="",
)
annotation_mode = String(
display_name=_("Mode for Annotation Tool"),
help=_("Type in number corresponding to following modes: 'instructor' or 'everyone'"),
scope=Scope.settings,
default="everyone",
) )
sourceurl = String(help=_("The external source URL for the video."), display_name=_("Source URL"), scope=Scope.settings, default="http://video-js.zencoder.com/oceans-clip.mp4")
poster_url = String(help=_("Poster Image URL"), display_name=_("Poster URL"), scope=Scope.settings, default="")
annotation_storage_url = String(help=_("Location of Annotation backend"), scope=Scope.settings, default="http://your_annotation_storage.com", display_name=_("Url for Annotation Storage"))
annotation_token_secret = String(help=_("Secret string for annotation storage"), scope=Scope.settings, default="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", display_name=_("Secret Token String for Annotation"))
class VideoAnnotationModule(AnnotatableFields, XModule): class VideoAnnotationModule(AnnotatableFields, XModule):
'''Video Annotation Module''' '''Video Annotation Module'''
...@@ -72,7 +114,7 @@ class VideoAnnotationModule(AnnotatableFields, XModule): ...@@ -72,7 +114,7 @@ class VideoAnnotationModule(AnnotatableFields, XModule):
''' get the extension of a given url ''' ''' get the extension of a given url '''
return get_extension(src_url) return get_extension(src_url)
def get_html(self): def student_view(self, context):
""" Renders parameters to template. """ """ Renders parameters to template. """
extension = self._get_extension(self.sourceurl) extension = self._get_extension(self.sourceurl)
...@@ -84,11 +126,16 @@ class VideoAnnotationModule(AnnotatableFields, XModule): ...@@ -84,11 +126,16 @@ class VideoAnnotationModule(AnnotatableFields, XModule):
'typeSource': extension, 'typeSource': extension,
'poster': self.poster_url, 'poster': self.poster_url,
'content_html': self.content, 'content_html': self.content,
'annotation_storage': self.annotation_storage_url,
'token': retrieve_token(self.user_email, self.annotation_token_secret), 'token': retrieve_token(self.user_email, self.annotation_token_secret),
'annotation_storage': self.annotation_storage_url,
'default_tab': self.default_tab,
'instructor_email': self.instructor_email,
'annotation_mode': self.annotation_mode,
} }
fragment = Fragment(self.system.render_template('videoannotation.html', context))
return self.system.render_template('videoannotation.html', context) fragment.add_javascript_url("/static/js/vendor/tinymce/js/tinymce/tinymce.full.min.js")
fragment.add_javascript_url("/static/js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js")
return fragment
class VideoAnnotationDescriptor(AnnotatableFields, RawDescriptor): class VideoAnnotationDescriptor(AnnotatableFields, RawDescriptor):
......
...@@ -380,19 +380,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ...@@ -380,19 +380,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
clickTimeThreshold: viewer.clickTimeThreshold, clickTimeThreshold: viewer.clickTimeThreshold,
clickDistThreshold: viewer.clickDistThreshold clickDistThreshold: viewer.clickDistThreshold
}); });
if(this.options.viewer.annotation_mode == "everyone" || this.options.viewer.flags){
/* Set elements to the control menu */ /* Set elements to the control menu */
viewer.annotatorControl = viewer.wrapperAnnotation.element; viewer.annotatorControl = viewer.wrapperAnnotation.element;
if( viewer.toolbar ){ if( viewer.toolbar ){
viewer.toolbar.addControl( viewer.toolbar.addControl(
viewer.annotatorControl, viewer.annotatorControl,
{anchor: $.ControlAnchor.BOTTOM_RIGHT} {anchor: $.ControlAnchor.BOTTOM_RIGHT}
); );
}else{ }else{
viewer.addControl( viewer.addControl(
viewer.annotatorControl, viewer.annotatorControl,
{anchor: $.ControlAnchor.TOP_LEFT} {anchor: $.ControlAnchor.TOP_LEFT}
); );
}
} }
}, },
_reset: function(){ _reset: function(){
......
...@@ -379,14 +379,14 @@ ...@@ -379,14 +379,14 @@
display:inline-block; display:inline-block;
color:#302f2f; color:#302f2f;
font-family:arial; font-family:arial;
font-size:15px; font-size:14px;
font-weight:bold; font-weight:bold;
padding:6px 24px; padding:6px 24px;
text-decoration:none; text-decoration:none;
margin: 0px 0px 10px 0px; margin: 0px 0px 10px 0px;
cursor:pointer; cursor:pointer;
width:140px; width:115px;
text-align:center; text-align:center;
} }
...@@ -468,7 +468,7 @@ ...@@ -468,7 +468,7 @@
#mainCatch .searchbox input{ #mainCatch .searchbox input{
margin: 0; margin: 0;
padding: 0; padding: 0;
width: 60%; width: 50%;
margin-left: 10px; margin-left: 10px;
display: inline; display: inline;
float: left; float: left;
...@@ -493,19 +493,28 @@ ...@@ -493,19 +493,28 @@
cursor:pointer; cursor:pointer;
} }
#mainCatch .searchbox .clear-search-icon{
font-size: 12px;
text-decoration: underline;
float: right;
margin-top: 10px;
padding-right: 3px;
cursor:pointer;
}
#mainCatch .searchbox .search-icon:hover{ #mainCatch .searchbox .search-icon:hover{
opacity:0.5; opacity:0.5;
box-shadow: 2px 4px 5px #888888; box-shadow: 2px 4px 5px #888888;
} }
#mainCatch .selectors{ #mainCatch .selectors{
width:40%; width:45%;
position:relative; position:relative;
float:left; float:left;
} }
#mainCatch .searchbox{ #mainCatch .searchbox{
width:60%; width:52%;
position:relative; position:relative;
float:right; float:right;
} }
...@@ -515,6 +524,7 @@ ...@@ -515,6 +524,7 @@
position:relative; position:relative;
padding-right:5px; padding-right:5px;
margin-top:8px; margin-top:8px;
font-size:14px;
} }
#mainCatch .replies .replyItem .deleteReply{ #mainCatch .replies .replyItem .deleteReply{
......
...@@ -7872,14 +7872,14 @@ $.extend( $.IIIF1_1TileSource.prototype, $.TileSource.prototype, { ...@@ -7872,14 +7872,14 @@ $.extend( $.IIIF1_1TileSource.prototype, $.TileSource.prototype, {
uri; uri;
if ( level_width < this.tile_width && level_height < this.tile_height ){ if ( level_width < this.tile_width && level_height < this.tile_height ){
iiif_size = level_width + "," + level_height; iiif_size = level_width + ",";
iiif_region = 'full'; iiif_region = 'full';
} else { } else {
iiif_tile_x = x * iiif_tile_size_width; iiif_tile_x = x * iiif_tile_size_width;
iiif_tile_y = y * iiif_tile_size_height; iiif_tile_y = y * iiif_tile_size_height;
iiif_tile_w = Math.min( iiif_tile_size_width, this.width - iiif_tile_x ); iiif_tile_w = Math.min( iiif_tile_size_width, this.width - iiif_tile_x );
iiif_tile_h = Math.min( iiif_tile_size_height, this.height - iiif_tile_y ); iiif_tile_h = Math.min( iiif_tile_size_height, this.height - iiif_tile_y );
iiif_size = Math.ceil(iiif_tile_w * scale) + "," + Math.ceil(iiif_tile_h * scale); iiif_size = Math.ceil(iiif_tile_w * scale) + ",";
iiif_region = [ iiif_tile_x, iiif_tile_y, iiif_tile_w, iiif_tile_h ].join(','); iiif_region = [ iiif_tile_x, iiif_tile_y, iiif_tile_w, iiif_tile_h ].join(',');
} }
uri = [ this['@id'], iiif_region, iiif_size, IIIF_ROTATION, IIIF_QUALITY ].join('/'); uri = [ this['@id'], iiif_region, iiif_size, IIIF_ROTATION, IIIF_QUALITY ].join('/');
......
...@@ -11,9 +11,7 @@ from xmodule.modulestore.locations import SlashSeparatedCourseKey ...@@ -11,9 +11,7 @@ from xmodule.modulestore.locations import SlashSeparatedCourseKey
@login_required @login_required
def notes(request, course_id): def notes(request, course_id):
''' Displays the student's notes. ''' ''' Displays the student's notes. '''
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
course = get_course_with_access(request.user, 'load', course_key) course = get_course_with_access(request.user, 'load', course_key)
if not notes_enabled_for_course(course): if not notes_enabled_for_course(course):
raise Http404 raise Http404
...@@ -28,6 +26,7 @@ def notes(request, course_id): ...@@ -28,6 +26,7 @@ def notes(request, course_id):
'student': student, 'student': student,
'storage': storage, 'storage': storage,
'token': retrieve_token(student.email, course.annotation_token_secret), 'token': retrieve_token(student.email, course.annotation_token_secret),
'default_tab': 'myNotes',
} }
return render_to_response('notes.html', context) return render_to_response('notes.html', context)
...@@ -9,72 +9,69 @@ ...@@ -9,72 +9,69 @@
</style> </style>
<div class="annotatable-wrapper"> <div class="annotatable-wrapper">
<div class="annotatable-header"> <div class="annotatable-header">
% 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
</div> </div>
% if instructions_html is not UNDEFINED and instructions_html is not None: % if instructions_html is not UNDEFINED and instructions_html is not None:
<div class="annotatable-section shaded"> <div class="annotatable-section shaded">
<div class="annotatable-section-title"> <div class="annotatable-section-title">
${_('Instructions')} ${_('Instructions')}
<a class="annotatable-toggle annotatable-toggle-instructions expanded" href="javascript:void(0)">${_('Collapse Instructions')}</a> <a class="annotatable-toggle annotatable-toggle-instructions expanded" href="javascript:void(0)">${_('Collapse Instructions')}</a>
</div> </div>
<div class="annotatable-section-body annotatable-instructions"> <div class="annotatable-section-body annotatable-instructions">
${instructions_html} ${instructions_html}
</div> </div>
</div> </div>
% endif % endif
<div class="annotatable-section"> <div class="annotatable-section">
<div class="annotatable-content"> <div class="annotatable-content">
<div id="imageHolder" class="openseadragon1"> <div id="imageHolder" class="openseadragon1">
<%namespace name='static' file='/static_content.html'/> <%namespace name='static' file='/static_content.html'/>
${static.css(group='style-vendor-tinymce-content', raw=True)} ${static.css(group='style-vendor-tinymce-content', raw=True)}
${static.css(group='style-vendor-tinymce-skin', raw=True)} ${static.css(group='style-vendor-tinymce-skin', raw=True)}
<script type="text/javascript" src="${static.url('js/vendor/tinymce/js/tinymce/tinymce.full.min.js', raw=True)}" />
<script type="text/javascript" src="${static.url('js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js', raw=True)}" />
</div> </div>
<div id="catchDIV"> <div id="catchDIV">
## Translators: Notes below refer to annotations. They wil later be put under a "Notes" section. <div class="annotationListContainer">${_('Note: only instructors may annotate.')}</div>
<div class="annotationListContainer">${_('You do not have any notes.')}</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
<script> <script>
function onClickHideInstructions(){ function onClickHideInstructions(){
//Reset function if there is more than one event handler //Reset function if there is more than one event handler
$(this).off(); $(this).off();
$(this).on('click',onClickHideInstructions); $(this).on('click',onClickHideInstructions);
var hide = $(this).html()=='Collapse Instructions'?true:false, var hide = $(this).html()=='Collapse Instructions'?true:false,
cls, txt,slideMethod; cls, txt,slideMethod;
txt = (hide ? 'Expand' : 'Collapse') + ' Instructions'; txt = (hide ? 'Expand' : 'Collapse') + ' Instructions';
cls = (hide ? ['expanded', 'collapsed'] : ['collapsed', 'expanded']); cls = (hide ? ['expanded', 'collapsed'] : ['collapsed', 'expanded']);
slideMethod = (hide ? 'slideUp' : 'slideDown'); slideMethod = (hide ? 'slideUp' : 'slideDown');
$(this).text(txt).removeClass(cls[0]).addClass(cls[1]); $(this).text(txt).removeClass(cls[0]).addClass(cls[1]);
$(this).parents('.annotatable-section:first').find('.annotatable-instructions')[slideMethod](); $(this).parents('.annotatable-section:first').find('.annotatable-instructions')[slideMethod]();
} }
$('.annotatable-toggle-instructions').on('click', onClickHideInstructions); $('.annotatable-toggle-instructions').on('click', onClickHideInstructions);
//Grab uri of the course //Grab uri of the course
var parts = window.location.href.split("/"), var parts = window.location.href.split("/"),
uri = '', uri = '',
courseid; courseid;
for (var index = 0; index <= 9; index += 1) uri += parts[index]+"/"; //Get the unit url for (var index = 0; index <= 9; index += 1) uri += parts[index]+"/"; //Get the unit url
courseid = parts[4] + "/" + parts[5] + "/" + parts[6]; courseid = parts[4] + "/" + parts[5] + "/" + parts[6];
//Change uri in cms //Change uri in cms
var lms_location = $('.sidebar .preview-button').attr('href'); var lms_location = $('.sidebar .preview-button').attr('href');
if (typeof lms_location!='undefined'){ if (typeof lms_location!='undefined'){
courseid = parts[4].split(".").join("/"); courseid = parts[4].split(".").join("/");
uri = window.location.protocol; uri = window.location.protocol;
for (var index = 0; index <= 9; index += 1) uri += lms_location.split("/")[index]+"/"; //Get the unit url for (var index = 0; index <= 9; index += 1) uri += lms_location.split("/")[index]+"/"; //Get the unit url
} }
var unit_id = $('#sequence-list').find('.active').attr("data-element"); var unit_id = $('#sequence-list').find('.active').attr("data-element");
uri += unit_id; uri += unit_id;
var pagination = 100, var pagination = 100,
is_staff = !('${user.is_staff}'=='False'), is_staff = ('${user.email}'=='${instructor_email}'),
options = { options = {
optionsAnnotator: { optionsAnnotator: {
permissions:{ permissions:{
...@@ -105,7 +102,7 @@ ...@@ -105,7 +102,7 @@
if (annotation.permissions) { if (annotation.permissions) {
tokens = annotation.permissions[action] || []; tokens = annotation.permissions[action] || [];
if (is_staff){ if (is_staff){
return true; return true;
} }
if (tokens.length === 0) { if (tokens.length === 0) {
return true; return true;
...@@ -155,7 +152,7 @@ ...@@ -155,7 +152,7 @@
offset:0, offset:0,
uri:uri, uri:uri,
media:'image', media:'image',
userid:'${user.email}', userid:'${user.email}',
} }
}, },
highlightTags:{ highlightTags:{
...@@ -174,37 +171,52 @@ ...@@ -174,37 +171,52 @@
}, },
optionsOpenSeadragon:{ optionsOpenSeadragon:{
id: "imageHolder", id: "imageHolder",
annotation_mode: "${annotation_mode}",
flags: is_staff,
prefixUrl: "${settings.STATIC_URL}" + "js/vendor/ova/images/", prefixUrl: "${settings.STATIC_URL}" + "js/vendor/ova/images/",
${openseadragonjson} ${openseadragonjson}
}, },
optionsOSDA:{}, optionsOSDA:{},
}; };
tinymce.baseURL = "${settings.STATIC_URL}" + "js/vendor/tinymce/js/tinymce";
var imgURLRoot = "${settings.STATIC_URL}" + "js/vendor/ova/catch/img/"; var imgURLRoot = "${settings.STATIC_URL}" + "js/vendor/ova/catch/img/";
if (typeof Annotator != 'undefined'){ if (typeof Annotator != 'undefined'){
//remove old instances //remove old instances
if (Annotator._instances.length !== 0) { if (Annotator._instances.length !== 0) {
$('#imageHolder').annotator("destroy"); $('#imageHolder').annotator("destroy");
} }
delete osda; delete osda;
//Load the plugin Image/Text Annotation //Load the plugin Image/Text Annotation
var osda = new OpenSeadragonAnnotation($('#imageHolder'),options); var osda = new OpenSeadragonAnnotation($('#imageHolder'),options);
//Catch var userId = ('${default_tab}'.toLowerCase() === 'instructor') ?
var annotator = osda.annotator, '${instructor_email}':
catchOptions = { '${user.email}';
media:'image',
externalLink:false, //Catch
imageUrlRoot:imgURLRoot, var annotator = osda.annotator;
showMediaSelector: false, var catchOptions = {
showPublicPrivate: true, media:'image',
userId:'${user.email}', externalLink:false,
pagination:pagination,//Number of Annotations per load in the pagination, imageUrlRoot:imgURLRoot,
flags:is_staff showMediaSelector: false,
}, showPublicPrivate: true,
Catch = new CatchAnnotation($('#catchDIV'),catchOptions); userId:userId,
pagination:pagination,//Number of Annotations per load in the pagination,
flags:is_staff,
default_tab: "${default_tab}",
instructor_email: "${instructor_email}",
annotation_mode: "${annotation_mode}",
};
// if annotations are opened to everyone (2) or if they want to create no annotations (1 with no instructor)
// then the table at the bottom of the source should be displayed
if ("${annotation_mode}" == "everyone" || ("${annotation_mode}" == "instructor" && "${instructor_email}" != ""))
var Catch = new CatchAnnotation($('#catchDIV'),catchOptions);
// if it is in instructor mode only (1), the annotator should be destroyed for all except the instructor
if ("${annotation_mode}" == "instructor" && "${instructor_email}" == "" && !is_staff)
osda.annotator.destroy();
} }
</script> </script>
\ No newline at end of file
<%! from django.utils.translation import ugettext as _ %> <%! from django.utils.translation import ugettext as _ %>
<%namespace name='static' file='static_content.html'/> <%namespace name='static' file='static_content.html'/>
${static.css(group='style-vendor-tinymce-content', raw=True)}
${static.css(group='style-vendor-tinymce-skin', raw=True)}
<script type="text/javascript" src="${static.url('js/vendor/tinymce/js/tinymce/tinymce.full.min.js', raw=True)}"></script>
<script type="text/javascript" src="${static.url('js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js', raw=True)}" ></script>
<%inherit file="main.html" /> <%inherit file="main.html" />
<%! <%!
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
...@@ -102,7 +106,7 @@ ...@@ -102,7 +106,7 @@
if (annotation.permissions) { if (annotation.permissions) {
tokens = annotation.permissions[action] || []; tokens = annotation.permissions[action] || [];
if (is_staff){ if (is_staff){
return true; return true;
} }
if (tokens.length === 0) { if (tokens.length === 0) {
return true; return true;
...@@ -128,7 +132,7 @@ ...@@ -128,7 +132,7 @@
}, },
}, },
auth: { auth: {
tokenUrl: location.protocol+'//'+location.host+"/token?course_id=${course.id.to_deprecated_string()}" token: "${token}"
}, },
store: { store: {
// The endpoint of the store on your server. // The endpoint of the store on your server.
...@@ -158,37 +162,34 @@ ...@@ -158,37 +162,34 @@
optionsRichText: { optionsRichText: {
tinymce:{ tinymce:{
selector: "li.annotator-item textarea", selector: "li.annotator-item textarea",
plugins: "media image insertdatetime link code", plugins: "media image codemirror",
menubar: false, menubar: false,
toolbar_items_size: 'small', toolbar_items_size: 'small',
extended_valid_elements : "iframe[src|frameborder|style|scrolling|class|width|height|name|align|id]", extended_valid_elements : "iframe[src|frameborder|style|scrolling|class|width|height|name|align|id]",
toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image media rubric | code ", toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | image rubric | code ",
} }
return true;
},
},
auth: {
token: "${token}"
},
store: {
// The endpoint of the store on your server.
prefix: "${storage}",
annotationData: {},
urls: {
// These are the default URLs.
create: '/create',
read: '/read/:id',
update: '/update/:id',
destroy: '/delete/:id',
search: '/search'
}, },
auth: {
token: "${token}"
},
store: {
// The endpoint of the store on your server.
prefix: "${storage}",
annotationData: {},
urls: {
// These are the default URLs.
create: '/create',
read: '/read/:id',
update: '/update/:id',
destroy: '/delete/:id',
search: '/search'
},
}
}; };
tinyMCE.baseURL = "${settings.STATIC_URL}" + "js/vendor/ova";
var imgURLRoot = "${settings.STATIC_URL}" + "js/vendor/ova/catch/img/"; var imgURLRoot = "${settings.STATIC_URL}" + "js/vendor/ova/catch/img/";
//remove old instances //remove old instances
if (Annotator._instances.length !== 0) { if (Annotator._instances.length !== 0) {
$('#notesHolder').annotator("destroy"); $('#notesHolder').annotator("destroy");
...@@ -207,7 +208,8 @@ ...@@ -207,7 +208,8 @@
showMediaSelector: true, showMediaSelector: true,
showPublicPrivate: true, showPublicPrivate: true,
pagination:pagination,//Number of Annotations per load in the pagination, pagination:pagination,//Number of Annotations per load in the pagination,
flags:is_staff flags:is_staff,
default_tab: "${default_tab}",
}, },
Catch = new CatchAnnotation($('#catchDIV'),catchOptions); Catch = new CatchAnnotation($('#catchDIV'),catchOptions);
</script> </script>
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
<%namespace name='static' file='/static_content.html'/> <%namespace name='static' file='/static_content.html'/>
${static.css(group='style-vendor-tinymce-content', raw=True)} ${static.css(group='style-vendor-tinymce-content', raw=True)}
${static.css(group='style-vendor-tinymce-skin', raw=True)} ${static.css(group='style-vendor-tinymce-skin', raw=True)}
<script type="text/javascript" src="${static.url('js/vendor/tinymce/js/tinymce/tinymce.full.min.js', raw=True)}" />
<script type="text/javascript" src="${static.url('js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js', raw=True)}" />
<div class="annotatable-wrapper"> <div class="annotatable-wrapper">
<div class="annotatable-header"> <div class="annotatable-header">
...@@ -167,7 +165,6 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)} ...@@ -167,7 +165,6 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)}
}; };
var imgURLRoot = "${settings.STATIC_URL}" + "js/vendor/ova/catch/img/"; var imgURLRoot = "${settings.STATIC_URL}" + "js/vendor/ova/catch/img/";
tinymce.baseURL = "${settings.STATIC_URL}" + "js/vendor/tinymce/js/tinymce";
//remove old instances //remove old instances
if (Annotator._instances.length !== 0) { if (Annotator._instances.length !== 0) {
...@@ -177,17 +174,24 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)} ...@@ -177,17 +174,24 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)}
//Load the plugin Video/Text Annotation //Load the plugin Video/Text Annotation
var ova = new OpenVideoAnnotation.Annotator($('#textHolder'),options); var ova = new OpenVideoAnnotation.Annotator($('#textHolder'),options);
var userId = ('${default_tab}'.toLowerCase() === 'instructor') ?
'${instructor_email}':
'${user.email}';
//Catch //Catch
var annotator = ova.annotator, var annotator = ova.annotator;
catchOptions = { var catchOptions = {
media:'text', media:'text',
externalLink:false, externalLink:false,
imageUrlRoot:imgURLRoot, imageUrlRoot:imgURLRoot,
showMediaSelector: false, showMediaSelector: false,
showPublicPrivate: true, showPublicPrivate: true,
userId:'${user.email}', userId:userId,
pagination:pagination,//Number of Annotations per load in the pagination, pagination:pagination,//Number of Annotations per load in the pagination,
flags:is_staff flags:is_staff,
}, default_tab: "${default_tab}",
Catch = new CatchAnnotation($('#catchDIV'),catchOptions); instructor_email: "${instructor_email}",
annotation_mode: "${annotation_mode}",
};
var Catch = new CatchAnnotation($('#catchDIV'),catchOptions);
</script> </script>
...@@ -2,9 +2,6 @@ ...@@ -2,9 +2,6 @@
<%namespace name='static' file='/static_content.html'/> <%namespace name='static' file='/static_content.html'/>
${static.css(group='style-vendor-tinymce-content', raw=True)} ${static.css(group='style-vendor-tinymce-content', raw=True)}
${static.css(group='style-vendor-tinymce-skin', raw=True)} ${static.css(group='style-vendor-tinymce-skin', raw=True)}
<script type="text/javascript" src="${static.url('js/vendor/tinymce/js/tinymce/tinymce.full.min.js', raw=True)}" />
<script type="text/javascript" src="${static.url('js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js', raw=True)}" />
<div class="annotatable-wrapper"> <div class="annotatable-wrapper">
<div class="annotatable-header"> <div class="annotatable-header">
...@@ -168,7 +165,6 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)} ...@@ -168,7 +165,6 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)}
}; };
var imgURLRoot = "${settings.STATIC_URL}" + "js/vendor/ova/catch/img/"; var imgURLRoot = "${settings.STATIC_URL}" + "js/vendor/ova/catch/img/";
tinymce.baseURL = "${settings.STATIC_URL}" + "js/vendor/tinymce/js/tinymce";
//remove old instances //remove old instances
if (Annotator._instances.length !== 0) { if (Annotator._instances.length !== 0) {
...@@ -179,18 +175,24 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)} ...@@ -179,18 +175,24 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)}
var ova = new OpenVideoAnnotation.Annotator($('#videoHolder'),options); var ova = new OpenVideoAnnotation.Annotator($('#videoHolder'),options);
ova.annotator.addPlugin('Tags'); ova.annotator.addPlugin('Tags');
var userId = ('${default_tab}'.toLowerCase() === 'instructor') ?
'${instructor_email}':
'${user.email}';
//Catch //Catch
var annotator = ova.annotator, var annotator = ova.annotator;
catchOptions = { var catchOptions = {
media:'video', media:'video',
externalLink:false, externalLink:false,
imageUrlRoot:imgURLRoot, imageUrlRoot:imgURLRoot,
showMediaSelector: false, showMediaSelector: false,
showPublicPrivate: true, showPublicPrivate: true,
userId:'${user.email}', userId:userId,
pagination:pagination,//Number of Annotations per load in the pagination, pagination:pagination,//Number of Annotations per load in the pagination,
flags:is_staff flags:is_staff,
}, default_tab: "${default_tab}",
Catch = new CatchAnnotation($('#catchDIV'),catchOptions); instructor_email: "${instructor_email}",
annotation_mode: "${annotation_mode}",
};
var Catch = new CatchAnnotation($('#catchDIV'),catchOptions);
</script> </script>
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