Commit 2e36fb29 by Sarina Canelake

Merge pull request #4046 from edx/hotfix/2014-06-11

Hotfix 2014-06-11
parents 21a784b4 13ec3698
from course_modes.models import CourseMode from course_modes.models import CourseMode
from factory.django import DjangoModelFactory from factory.django import DjangoModelFactory
from xmodule.modulestore.locations import SlashSeparatedCourseKey
# Factories don't have __init__ methods, and are self documenting # Factories don't have __init__ methods, and are self documenting
...@@ -7,9 +8,10 @@ from factory.django import DjangoModelFactory ...@@ -7,9 +8,10 @@ from factory.django import DjangoModelFactory
class CourseModeFactory(DjangoModelFactory): class CourseModeFactory(DjangoModelFactory):
FACTORY_FOR = CourseMode FACTORY_FOR = CourseMode
course_id = u'MITx/999/Robot_Super_Course' course_id = SlashSeparatedCourseKey('MITx', '999', 'Robot_Super_Course')
mode_slug = 'audit' mode_slug = 'audit'
mode_display_name = 'audit course' mode_display_name = 'audit course'
min_price = 0 min_price = 0
currency = 'usd' currency = 'usd'
expiration_datetime = None expiration_datetime = None
suggested_prices = ''
import ddt
import unittest
from django.test import TestCase
from django.conf import settings
from django.core.urlresolvers import reverse
from mock import patch, Mock
from course_modes.tests.factories import CourseModeFactory
from student.tests.factories import CourseEnrollmentFactory, UserFactory
from xmodule.modulestore.locations import SlashSeparatedCourseKey
@ddt.ddt
class CourseModeViewTest(TestCase):
def setUp(self):
self.course_id = SlashSeparatedCourseKey('org', 'course', 'run')
for mode in ('audit', 'verified', 'honor'):
CourseModeFactory(mode_slug=mode, course_id=self.course_id)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
@ddt.data(
# is_active?, enrollment_mode, upgrade?, redirect?
(True, 'verified', True, True), # User is already verified
(True, 'verified', False, True), # User is already verified
(True, 'honor', True, False), # User isn't trying to upgrade
(True, 'honor', False, True), # User is trying to upgrade
(True, 'audit', True, False), # User isn't trying to upgrade
(True, 'audit', False, True), # User is trying to upgrade
(False, 'verified', True, False), # User isn't active
(False, 'verified', False, False), # User isn't active
(False, 'honor', True, False), # User isn't active
(False, 'honor', False, False), # User isn't active
(False, 'audit', True, False), # User isn't active
(False, 'audit', False, False), # User isn't active
)
@ddt.unpack
@patch('course_modes.views.modulestore', Mock())
def test_reregister_redirect(self, is_active, enrollment_mode, upgrade, redirect):
enrollment = CourseEnrollmentFactory(
is_active=is_active,
mode=enrollment_mode,
course_id=self.course_id
)
self.client.login(
username=enrollment.user.username,
password='test'
)
if upgrade:
get_params = {'upgrade': True}
else:
get_params = {}
response = self.client.get(
reverse('course_modes_choose', args=[self.course_id.to_deprecated_string()]),
get_params,
follow=False,
)
if redirect:
self.assertEquals(response.status_code, 302)
self.assertTrue(response['Location'].endswith(reverse('dashboard')))
else:
self.assertEquals(response.status_code, 200)
# TODO: Fix it so that response.templates works w/ mako templates, and then assert
# that the right template rendered
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
@ddt.data(
'',
'1,,2',
'1, ,2',
'1, 2, 3'
)
@patch('course_modes.views.modulestore', Mock())
def test_suggested_prices(self, price_list):
course_id = SlashSeparatedCourseKey('org', 'course', 'price_course')
user = UserFactory()
for mode in ('audit', 'honor'):
CourseModeFactory(mode_slug=mode, course_id=course_id)
CourseModeFactory(mode_slug='verified', course_id=course_id, suggested_prices=price_list)
self.client.login(
username=user.username,
password='test'
)
response = self.client.get(
reverse('course_modes_choose', args=[self.course_id.to_deprecated_string()]),
follow=False,
)
self.assertEquals(response.status_code, 200)
# TODO: Fix it so that response.templates works w/ mako templates, and then assert
# that the right template rendered
...@@ -36,16 +36,14 @@ class ChooseModeView(View): ...@@ -36,16 +36,14 @@ class ChooseModeView(View):
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
enrollment_mode = CourseEnrollment.enrollment_mode_for_user(request.user, course_key) enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user(request.user, course_key)
upgrade = request.GET.get('upgrade', False) upgrade = request.GET.get('upgrade', False)
request.session['attempting_upgrade'] = upgrade request.session['attempting_upgrade'] = upgrade
# Inactive users always need to re-register
# verified users do not need to register or upgrade # verified users do not need to register or upgrade
if enrollment_mode == 'verified':
return redirect(reverse('dashboard'))
# registered users who are not trying to upgrade do not need to re-register # registered users who are not trying to upgrade do not need to re-register
if enrollment_mode is not None and upgrade is False: if is_active and (upgrade is False or enrollment_mode == 'verified'):
return redirect(reverse('dashboard')) return redirect(reverse('dashboard'))
modes = CourseMode.modes_for_course_dict(course_key) modes = CourseMode.modes_for_course_dict(course_key)
...@@ -64,7 +62,11 @@ class ChooseModeView(View): ...@@ -64,7 +62,11 @@ class ChooseModeView(View):
"upgrade": upgrade, "upgrade": upgrade,
} }
if "verified" in modes: if "verified" in modes:
context["suggested_prices"] = [decimal.Decimal(x) for x in modes["verified"].suggested_prices.split(",")] context["suggested_prices"] = [
decimal.Decimal(x.strip())
for x in modes["verified"].suggested_prices.split(",")
if x.strip()
]
context["currency"] = modes["verified"].currency.upper() context["currency"] = modes["verified"].currency.upper()
context["min_price"] = modes["verified"].min_price context["min_price"] = modes["verified"].min_price
......
...@@ -880,18 +880,15 @@ class CourseEnrollment(models.Model): ...@@ -880,18 +880,15 @@ class CourseEnrollment(models.Model):
`user` is a Django User object `user` is a Django User object
`course_id` is our usual course_id string (e.g. "edX/Test101/2013_Fall) `course_id` is our usual course_id string (e.g. "edX/Test101/2013_Fall)
Returns the mode for both inactive and active users. Returns (mode, is_active) where mode is the enrollment mode of the student
Returns None if the courseenrollment record does not exist. and is_active is whether the enrollment is active.
Returns (None, None) if the courseenrollment record does not exist.
""" """
try: try:
record = CourseEnrollment.objects.get(user=user, course_id=course_id) record = CourseEnrollment.objects.get(user=user, course_id=course_id)
return (record.mode, record.is_active)
if hasattr(record, 'mode'):
return record.mode
else:
return None
except cls.DoesNotExist: except cls.DoesNotExist:
return None return (None, None)
@classmethod @classmethod
def enrollments_for_user(cls, user): def enrollments_for_user(cls, user):
......
...@@ -10,6 +10,7 @@ import factory ...@@ -10,6 +10,7 @@ import factory
from factory.django import DjangoModelFactory from factory.django import DjangoModelFactory
from uuid import uuid4 from uuid import uuid4
from pytz import UTC from pytz import UTC
from xmodule.modulestore.locations import SlashSeparatedCourseKey
# Factories don't have __init__ methods, and are self documenting # Factories don't have __init__ methods, and are self documenting
# pylint: disable=W0232, C0111 # pylint: disable=W0232, C0111
...@@ -109,14 +110,14 @@ class CourseEnrollmentFactory(DjangoModelFactory): ...@@ -109,14 +110,14 @@ class CourseEnrollmentFactory(DjangoModelFactory):
FACTORY_FOR = CourseEnrollment FACTORY_FOR = CourseEnrollment
user = factory.SubFactory(UserFactory) user = factory.SubFactory(UserFactory)
course_id = u'edX/toy/2012_Fall' course_id = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')
class CourseEnrollmentAllowedFactory(DjangoModelFactory): class CourseEnrollmentAllowedFactory(DjangoModelFactory):
FACTORY_FOR = CourseEnrollmentAllowed FACTORY_FOR = CourseEnrollmentAllowed
email = 'test@edx.org' email = 'test@edx.org'
course_id = 'edX/test/2012_Fall' course_id = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')
class PendingEmailChangeFactory(DjangoModelFactory): class PendingEmailChangeFactory(DjangoModelFactory):
......
...@@ -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
......
...@@ -226,7 +226,7 @@ class SplitTestModule(SplitTestFields, XModule): ...@@ -226,7 +226,7 @@ class SplitTestModule(SplitTestFields, XModule):
Record in the tracking logs which child was rendered Record in the tracking logs which child was rendered
""" """
# TODO: use publish instead, when publish is wired to the tracking logs # TODO: use publish instead, when publish is wired to the tracking logs
self.system.track_function('xblock.split_test.child_render', {'child-id': self.child.scope_ids.usage_id}) self.system.track_function('xblock.split_test.child_render', {'child-id': self.child.scope_ids.usage_id.to_deprecated_string()})
return Response() return Response()
def get_icon_class(self): def get_icon_class(self):
......
...@@ -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,7 +380,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ...@@ -380,7 +380,7 @@ 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 ){
...@@ -394,6 +394,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ...@@ -394,6 +394,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
{anchor: $.ControlAnchor.TOP_LEFT} {anchor: $.ControlAnchor.TOP_LEFT}
); );
} }
}
}, },
_reset: function(){ _reset: function(){
//Find and remove DrawingRect. This is the previous rectangle //Find and remove DrawingRect. This is the previous rectangle
......
...@@ -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('/');
......
...@@ -181,7 +181,7 @@ class XQueueCertInterface(object): ...@@ -181,7 +181,7 @@ class XQueueCertInterface(object):
course_name = course.display_name or course_id.to_deprecated_string() course_name = course.display_name or course_id.to_deprecated_string()
is_whitelisted = self.whitelist.filter(user=student, course_id=course_id, whitelist=True).exists() is_whitelisted = self.whitelist.filter(user=student, course_id=course_id, whitelist=True).exists()
grade = grades.grade(student, self.request, course) grade = grades.grade(student, self.request, course)
enrollment_mode = CourseEnrollment.enrollment_mode_for_user(student, course_id) enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(student, course_id)
mode_is_verified = (enrollment_mode == GeneratedCertificate.MODES.verified) mode_is_verified = (enrollment_mode == GeneratedCertificate.MODES.verified)
user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(student) user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(student)
user_is_reverified = SoftwareSecurePhotoVerification.user_is_reverified_for_all(course_id, student) user_is_reverified = SoftwareSecurePhotoVerification.user_is_reverified_for_all(course_id, student)
......
...@@ -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)
...@@ -65,7 +65,7 @@ class VerifyView(View): ...@@ -65,7 +65,7 @@ class VerifyView(View):
reverse('verify_student_verified', reverse('verify_student_verified',
kwargs={'course_id': course_id.to_deprecated_string()}) + "?upgrade={}".format(upgrade) kwargs={'course_id': course_id.to_deprecated_string()}) + "?upgrade={}".format(upgrade)
) )
elif CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified': elif CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == ('verified', True):
return redirect(reverse('dashboard')) return redirect(reverse('dashboard'))
else: else:
# If they haven't completed a verification attempt, we have to # If they haven't completed a verification attempt, we have to
...@@ -119,7 +119,7 @@ class VerifiedView(View): ...@@ -119,7 +119,7 @@ class VerifiedView(View):
""" """
upgrade = request.GET.get('upgrade', False) upgrade = request.GET.get('upgrade', False)
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id) course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified': if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == ('verified', True):
return redirect(reverse('dashboard')) return redirect(reverse('dashboard'))
verify_mode = CourseMode.mode_for_course(course_id, "verified") verify_mode = CourseMode.mode_for_course(course_id, "verified")
...@@ -284,7 +284,7 @@ def show_requirements(request, course_id): ...@@ -284,7 +284,7 @@ def show_requirements(request, course_id):
Show the requirements necessary for the verification flow. Show the requirements necessary for the verification flow.
""" """
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id) course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified': if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == ('verified', True):
return redirect(reverse('dashboard')) return redirect(reverse('dashboard'))
upgrade = request.GET.get('upgrade', False) upgrade = request.GET.get('upgrade', False)
......
...@@ -31,12 +31,9 @@ ...@@ -31,12 +31,9 @@
<%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>
...@@ -74,7 +71,7 @@ ...@@ -74,7 +71,7 @@
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:{
...@@ -174,13 +171,14 @@ ...@@ -174,13 +171,14 @@
}, },
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'){
...@@ -192,19 +190,33 @@ ...@@ -192,19 +190,33 @@
//Load the plugin Image/Text Annotation //Load the plugin Image/Text Annotation
var osda = new OpenSeadragonAnnotation($('#imageHolder'),options); var osda = new OpenSeadragonAnnotation($('#imageHolder'),options);
var userId = ('${default_tab}'.toLowerCase() === 'instructor') ?
'${instructor_email}':
'${user.email}';
//Catch //Catch
var annotator = osda.annotator, var annotator = osda.annotator;
catchOptions = { var catchOptions = {
media:'image', media:'image',
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}",
};
// 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
...@@ -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,14 +162,12 @@ ...@@ -158,14 +162,12 @@
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: { auth: {
token: "${token}" token: "${token}"
...@@ -184,11 +186,10 @@ ...@@ -184,11 +186,10 @@
destroy: '/delete/:id', destroy: '/delete/:id',
search: '/search' 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