Commit 09d86c22 by Adam

Merge pull request #4832 from edx/hotfix/2014-08-14

Hotfix/2014 08 14
parents 9b53c809 b5aaf8b0
...@@ -248,10 +248,19 @@ def create_unit_from_course_outline(): ...@@ -248,10 +248,19 @@ def create_unit_from_course_outline():
world.wait_for_mathjax() world.wait_for_mathjax()
world.wait_for_xmodule() world.wait_for_xmodule()
world.wait_for_loading()
assert world.is_css_present('ul.new-component-type') assert world.is_css_present('ul.new-component-type')
@world.absorb
def wait_for_loading():
"""
Waits for the loading indicator to be hidden.
"""
world.wait_for(lambda _driver: len(world.browser.find_by_css('div.ui-loading.is-hidden')) > 0)
@step('I have clicked the new unit button$') @step('I have clicked the new unit button$')
@step(u'I am in Studio editing a new unit$') @step(u'I am in Studio editing a new unit$')
def edit_new_unit(step): def edit_new_unit(step):
......
...@@ -6,7 +6,6 @@ from nose.tools import assert_equal, assert_in # pylint: disable=E0611 ...@@ -6,7 +6,6 @@ from nose.tools import assert_equal, assert_in # pylint: disable=E0611
from terrain.steps import reload_the_page from terrain.steps import reload_the_page
from common import type_in_codemirror from common import type_in_codemirror
from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.keys import Keys
from cms.envs.common import FEATURES
@world.absorb @world.absorb
...@@ -123,6 +122,9 @@ def ensure_settings_visible(): ...@@ -123,6 +122,9 @@ def ensure_settings_visible():
@world.absorb @world.absorb
def edit_component(index=0): def edit_component(index=0):
# Verify that the "loading" indication has been hidden.
world.wait_for_loading()
# Verify that the "edit" button is present.
world.wait_for(lambda _driver: world.css_visible('a.edit-button')) world.wait_for(lambda _driver: world.css_visible('a.edit-button'))
world.css_click('a.edit-button', index) world.css_click('a.edit-button', index)
world.wait_for_ajax_complete() world.wait_for_ajax_complete()
......
...@@ -371,6 +371,23 @@ PIPELINE_CSS = { ...@@ -371,6 +371,23 @@ PIPELINE_CSS = {
], ],
'output_filename': 'css/cms-style-xmodule.css', 'output_filename': 'css/cms-style-xmodule.css',
}, },
'style-xmodule-annotations': {
'source_filenames': [
'css/vendor/ova/annotator.css',
'css/vendor/ova/edx-annotator.css',
'css/vendor/ova/video-js.min.css',
'css/vendor/ova/rangeslider.css',
'css/vendor/ova/share-annotator.css',
'css/vendor/ova/richText-annotator.css',
'css/vendor/ova/tags-annotator.css',
'css/vendor/ova/flagging-annotator.css',
'css/vendor/ova/diacritic-annotator.css',
'css/vendor/ova/grouping-annotator.css',
'css/vendor/ova/ova.css',
'js/vendor/ova/catch/css/main.css'
],
'output_filename': 'css/cms-style-xmodule-annotations.css',
},
} }
# test_order: Determines the position of this chunk of javascript on # test_order: Determines the position of this chunk of javascript on
...@@ -549,7 +566,10 @@ INSTALLED_APPS = ( ...@@ -549,7 +566,10 @@ INSTALLED_APPS = (
'monitoring', 'monitoring',
# Course action state # Course action state
'course_action_state' 'course_action_state',
# Additional problem types
'edx_jsme', # Molecular Structure
) )
......
...@@ -82,6 +82,27 @@ ...@@ -82,6 +82,27 @@
"URI": "js/vendor/URI.min", "URI": "js/vendor/URI.min",
"ieshim": "js/src/ie_shim", "ieshim": "js/src/ie_shim",
"tooltip_manager": "js/src/tooltip_manager", "tooltip_manager": "js/src/tooltip_manager",
// Files needed for Annotations feature
"annotator": "js/vendor/ova/annotator-full",
"annotator-harvardx": "js/vendor/ova/annotator-full-firebase-auth",
"video.dev": "js/vendor/ova/video.dev",
"vjs.youtube": 'js/vendor/ova/vjs.youtube',
"rangeslider": 'js/vendor/ova/rangeslider',
"share-annotator": 'js/vendor/ova/share-annotator',
"richText-annotator": 'js/vendor/ova/richText-annotator',
"reply-annotator": 'js/vendor/ova/reply-annotator',
"grouping-annotator": 'js/vendor/ova/grouping-annotator',
"tags-annotator": 'js/vendor/ova/tags-annotator',
"diacritic-annotator": 'js/vendor/ova/diacritic-annotator',
"flagging-annotator": 'js/vendor/ova/flagging-annotator',
"jquery-Watch": 'js/vendor/ova/jquery-Watch',
"openseadragon": 'js/vendor/ova/openseadragon',
"osda": 'js/vendor/ova/OpenSeaDragonAnnotation',
"ova": 'js/vendor/ova/ova',
"catch": 'js/vendor/ova/catch/js/catch',
"handlebars": 'js/vendor/ova/catch/js/handlebars-1.1.2',
// end of Annotation tool files
// externally hosted files // externally hosted files
"tender": [ "tender": [
...@@ -217,6 +238,9 @@ ...@@ -217,6 +238,9 @@
"tooltip_manager": { "tooltip_manager": {
deps: ["jquery", "underscore"] deps: ["jquery", "underscore"]
}, },
"jquery.immediateDescendents": {
deps: ["jquery"]
},
"xblock/core": { "xblock/core": {
exports: "XBlock", exports: "XBlock",
deps: ["jquery", "jquery.immediateDescendents"] deps: ["jquery", "jquery.immediateDescendents"]
...@@ -232,7 +256,54 @@ ...@@ -232,7 +256,54 @@
"coffee/src/logger": { "coffee/src/logger": {
exports: "Logger", exports: "Logger",
deps: ["coffee/src/ajax_prefix"] deps: ["coffee/src/ajax_prefix"]
} },
// the following are all needed for annotation tools
"video.dev": {
exports:"videojs"
},
"vjs.youtube": {
deps: ["video.dev"]
},
"rangeslider": {
deps: ["video.dev"]
},
"annotator": {
exports: "Annotator"
},
"annotator-harvardx":{
deps: ["annotator"]
},
"share-annotator": {
deps: ["annotator"]
},
"richText-annotator": {
deps: ["annotator", "tinymce"]
},
"reply-annotator": {
deps: ["annotator"]
},
"tags-annotator": {
deps: ["annotator"]
},
"diacritic-annotator": {
deps: ["annotator"]
},
"flagging-annotator": {
deps: ["annotator"]
},
"grouping-annotator": {
deps: ["annotator"]
},
"ova":{
exports: "ova",
deps: ["annotator", "annotator-harvardx", "video.dev", "vjs.youtube", "rangeslider", "share-annotator", "richText-annotator", "reply-annotator", "tags-annotator", "flagging-annotator", "grouping-annotator", "diacritic-annotator", "jquery-Watch", "catch", "handlebars", "URI"]
},
"osda":{
exports: "osda",
deps: ["annotator", "annotator-harvardx", "video.dev", "vjs.youtube", "rangeslider", "share-annotator", "richText-annotator", "reply-annotator", "tags-annotator", "flagging-annotator", "grouping-annotator", "diacritic-annotator", "openseadragon", "jquery-Watch", "catch", "handlebars", "URI"]
},
// end of annotation tool files
}, },
// load jquery and gettext automatically // load jquery and gettext automatically
deps: ["jquery", "gettext"], deps: ["jquery", "gettext"],
......
...@@ -92,7 +92,7 @@ def render_to_string(template_name, dictionary, context=None, namespace='main'): ...@@ -92,7 +92,7 @@ def render_to_string(template_name, dictionary, context=None, namespace='main'):
context_instance['marketing_link'] = marketing_link context_instance['marketing_link'] = marketing_link
# In various testing contexts, there might not be a current request context. # In various testing contexts, there might not be a current request context.
if edxmako.middleware.REQUEST_CONTEXT.context is not None: if getattr(edxmako.middleware.REQUEST_CONTEXT, "context", None):
for d in edxmako.middleware.REQUEST_CONTEXT.context: for d in edxmako.middleware.REQUEST_CONTEXT.context:
context_dictionary.update(d) context_dictionary.update(d)
for d in context_instance: for d in context_instance:
......
...@@ -48,7 +48,7 @@ class Template(MakoTemplate): ...@@ -48,7 +48,7 @@ class Template(MakoTemplate):
context_dictionary = {} context_dictionary = {}
# In various testing contexts, there might not be a current request context. # In various testing contexts, there might not be a current request context.
if edxmako.middleware.REQUEST_CONTEXT.context is not None: if getattr(edxmako.middleware.REQUEST_CONTEXT, "context", None):
for d in edxmako.middleware.REQUEST_CONTEXT.context: for d in edxmako.middleware.REQUEST_CONTEXT.context:
context_dictionary.update(d) context_dictionary.update(d)
for d in context_instance: for d in context_instance:
......
from mock import patch, Mock from mock import patch, Mock
import unittest
from django.conf import settings
from django.http import HttpResponse from django.http import HttpResponse
from django.test import TestCase from django.test import TestCase
from django.test.utils import override_settings from django.test.utils import override_settings
...@@ -7,7 +10,7 @@ from django.test.client import RequestFactory ...@@ -7,7 +10,7 @@ from django.test.client import RequestFactory
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
import edxmako.middleware import edxmako.middleware
from edxmako import add_lookup, LOOKUP from edxmako import add_lookup, LOOKUP
from edxmako.shortcuts import marketing_link from edxmako.shortcuts import marketing_link, render_to_string
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
from util.testing import UrlResetMixin from util.testing import UrlResetMixin
...@@ -71,6 +74,26 @@ class MakoMiddlewareTest(TestCase): ...@@ -71,6 +74,26 @@ class MakoMiddlewareTest(TestCase):
# requestcontext should be None. # requestcontext should be None.
self.assertIsNone(edxmako.middleware.REQUEST_CONTEXT.context) self.assertIsNone(edxmako.middleware.REQUEST_CONTEXT.context)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
@patch("edxmako.middleware.REQUEST_CONTEXT")
def test_render_to_string_when_no_global_context_lms(self, context_mock):
"""
Test render_to_string() when makomiddleware has not initialized
the threadlocal REQUEST_CONTEXT.context. This is meant to run in LMS.
"""
del context_mock.context
self.assertIn("this module is temporarily unavailable", render_to_string("courseware/error-message.html", None))
@unittest.skipUnless(settings.ROOT_URLCONF == 'cms.urls', 'Test only valid in cms')
@patch("edxmako.middleware.REQUEST_CONTEXT")
def test_render_to_string_when_no_global_context_cms(self, context_mock):
"""
Test render_to_string() when makomiddleware has not initialized
the threadlocal REQUEST_CONTEXT.context. This is meant to run in CMS.
"""
del context_mock.context
self.assertIn("We're having trouble rendering your component", render_to_string("html_error.html", None))
def mako_middleware_process_request(request): def mako_middleware_process_request(request):
""" """
......
...@@ -130,8 +130,8 @@ class ImageAnnotationModule(AnnotatableFields, XModule): ...@@ -130,8 +130,8 @@ class ImageAnnotationModule(AnnotatableFields, XModule):
'annotation_mode': self.annotation_mode, 'annotation_mode': self.annotation_mode,
} }
fragment = Fragment(self.system.render_template('imageannotation.html', context)) fragment = Fragment(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(self.runtime.STATIC_URL + "js/vendor/tinymce/js/tinymce/tinymce.full.min.js")
fragment.add_javascript_url("/static/js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js") fragment.add_javascript_url(self.runtime.STATIC_URL + "js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js")
return fragment return fragment
......
...@@ -106,7 +106,7 @@ class MongoModulestoreBuilder(object): ...@@ -106,7 +106,7 @@ class MongoModulestoreBuilder(object):
db.connection.close() db.connection.close()
# Delete the created directory on the filesystem # Delete the created directory on the filesystem
rmtree(fs_root) rmtree(fs_root, ignore_errors=True)
def __repr__(self): def __repr__(self):
return 'MongoModulestoreBuilder()' return 'MongoModulestoreBuilder()'
...@@ -152,7 +152,7 @@ class VersioningModulestoreBuilder(object): ...@@ -152,7 +152,7 @@ class VersioningModulestoreBuilder(object):
db.connection.close() db.connection.close()
# Delete the created directory on the filesystem # Delete the created directory on the filesystem
rmtree(fs_root) rmtree(fs_root, ignore_errors=True)
def __repr__(self): def __repr__(self):
return 'SplitModulestoreBuilder()' return 'SplitModulestoreBuilder()'
...@@ -248,7 +248,7 @@ class CrossStoreXMLRoundtrip(CourseComparisonTest): ...@@ -248,7 +248,7 @@ class CrossStoreXMLRoundtrip(CourseComparisonTest):
def setUp(self): def setUp(self):
super(CrossStoreXMLRoundtrip, self).setUp() super(CrossStoreXMLRoundtrip, self).setUp()
self.export_dir = mkdtemp() self.export_dir = mkdtemp()
self.addCleanup(rmtree, self.export_dir) self.addCleanup(rmtree, self.export_dir, ignore_errors=True)
@ddt.data(*itertools.product( @ddt.data(*itertools.product(
MODULESTORE_SETUPS, MODULESTORE_SETUPS,
......
...@@ -127,8 +127,8 @@ class TextAnnotationModule(AnnotatableFields, XModule): ...@@ -127,8 +127,8 @@ class TextAnnotationModule(AnnotatableFields, XModule):
'annotation_mode': self.annotation_mode, 'annotation_mode': self.annotation_mode,
} }
fragment = Fragment(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(self.runtime.STATIC_URL + "js/vendor/tinymce/js/tinymce/tinymce.full.min.js")
fragment.add_javascript_url("/static/js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js") fragment.add_javascript_url(self.runtime.STATIC_URL + "js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js")
return fragment return fragment
......
...@@ -133,8 +133,8 @@ class VideoAnnotationModule(AnnotatableFields, XModule): ...@@ -133,8 +133,8 @@ class VideoAnnotationModule(AnnotatableFields, XModule):
'annotation_mode': self.annotation_mode, 'annotation_mode': self.annotation_mode,
} }
fragment = Fragment(self.system.render_template('videoannotation.html', context)) fragment = Fragment(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(self.runtime.STATIC_URL + "js/vendor/tinymce/js/tinymce/tinymce.full.min.js")
fragment.add_javascript_url("/static/js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js") fragment.add_javascript_url(self.runtime.STATIC_URL + "js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js")
return fragment return fragment
......
...@@ -352,7 +352,7 @@ CatchAnnotation.prototype = { ...@@ -352,7 +352,7 @@ CatchAnnotation.prototype = {
// if the default tab is instructor, we must refresh the catch to pull the ones // if the default tab is instructor, we must refresh the catch to pull the ones
// under the instructor's email. Calling changeUserId will update this.options.userId // under the instructor's email. Calling changeUserId will update this.options.userId
// and most importantly refresh not only the highlights (from Annotator) // and most importantly refresh not only the highlights (from Annotator)
// but also the table below from the annotations database server (called Catch). // but also the table below from the annotations database server (called Catch).
if(this.options.default_tab.toLowerCase() === 'instructor') { if(this.options.default_tab.toLowerCase() === 'instructor') {
this.changeUserId(this.options.instructor_email); this.changeUserId(this.options.instructor_email);
} }
...@@ -717,7 +717,7 @@ CatchAnnotation.prototype = { ...@@ -717,7 +717,7 @@ CatchAnnotation.prototype = {
var isInList = false; var isInList = false;
var list = $('#mainCatch .annotationList .annotationRow.item'); var list = $('#mainCatch .annotationList .annotationRow.item');
for (_i = 0, _len = list.length; _i < _len; _i++) { for (_i = 0, _len = list.length; _i < _len; _i++) {
if ($(list[_i]).parent().attr('annotationid') === an.id) if (parseInt($(list[_i]).parent().attr('annotationid'), 10) === an.id)
isInList = true; isInList = true;
} }
return isInList; return isInList;
...@@ -800,7 +800,7 @@ CatchAnnotation.prototype = { ...@@ -800,7 +800,7 @@ CatchAnnotation.prototype = {
$(evt.target).parents('.detailHeader:first').find('#myLocationMap .map').html(imgSrc); $(evt.target).parents('.detailHeader:first').find('#myLocationMap .map').html(imgSrc);
}, },
_onPlaySelectionClick: function(evt) { _onPlaySelectionClick: function(evt) {
var id = $(evt.target).find('.idAnnotation').html(); var id = parseInt($(evt.target).find('.idAnnotation').html(), 10);
var uri = $(evt.target).find('.uri').html(); var uri = $(evt.target).find('.uri').html();
var container = $(evt.target).find('.container').html(); var container = $(evt.target).find('.container').html();
if (this.options.externalLink) { if (this.options.externalLink) {
...@@ -858,7 +858,7 @@ CatchAnnotation.prototype = { ...@@ -858,7 +858,7 @@ CatchAnnotation.prototype = {
}, },
_onZoomToImageBoundsButtonClick: function(evt){ _onZoomToImageBoundsButtonClick: function(evt){
var zoomToBounds = $(evt.target).hasClass('zoomToImageBounds')?$(evt.target):$(evt.target).parents('.zoomToImageBounds:first'); var zoomToBounds = $(evt.target).hasClass('zoomToImageBounds')?$(evt.target):$(evt.target).parents('.zoomToImageBounds:first');
var osdaId = zoomToBounds.find('.idAnnotation').html(); var osdaId = parseInt(zoomToBounds.find('.idAnnotation').html(), 10);
var uri = zoomToBounds.find('.uri').html(); var uri = zoomToBounds.find('.uri').html();
var allannotations = this.annotator.plugins['Store'].annotations; var allannotations = this.annotator.plugins['Store'].annotations;
...@@ -887,7 +887,7 @@ CatchAnnotation.prototype = { ...@@ -887,7 +887,7 @@ CatchAnnotation.prototype = {
}, },
_onQuoteMediaButton: function(evt) { _onQuoteMediaButton: function(evt) {
var quote = $(evt.target).hasClass('quote')?$(evt.target):$(evt.target).parents('.quote:first'); var quote = $(evt.target).hasClass('quote')?$(evt.target):$(evt.target).parents('.quote:first');
var id = quote.find('.idAnnotation').html(); var id = parseInt(quote.find('.idAnnotation').html(), 10);
var uri = quote.find('.uri').html(); var uri = quote.find('.uri').html();
if (typeof id === 'undefined' || id === ''){ if (typeof id === 'undefined' || id === ''){
this.refreshCatch(); this.refreshCatch();
...@@ -927,7 +927,7 @@ CatchAnnotation.prototype = { ...@@ -927,7 +927,7 @@ CatchAnnotation.prototype = {
}, },
_refreshReplies: function(evt) { _refreshReplies: function(evt) {
var item = $(evt.target).parents('.annotationItem:first'); var item = $(evt.target).parents('.annotationItem:first');
var anId = item.attr('annotationId'); var anId = parseInt(item.attr('annotationId'), 10);
var replyElem = $(evt.target).parents('.annotationItem:first').find('.replies'); var replyElem = $(evt.target).parents('.annotationItem:first').find('.replies');
var annotator = this.annotator; var annotator = this.annotator;
...@@ -954,7 +954,7 @@ CatchAnnotation.prototype = { ...@@ -954,7 +954,7 @@ CatchAnnotation.prototype = {
if (typeof replyItems !== 'undefined' && replyItems.length > 0) { if (typeof replyItems !== 'undefined' && replyItems.length > 0) {
annotations.forEach(function(ann) { annotations.forEach(function(ann) {
replyItems.each(function(item) { replyItems.each(function(item) {
var id = $(replyItems[item]).attr('annotationid'); var id = parseInt($(replyItems[item]).attr('annotationid'), 10);
if (id === ann.id) { if (id === ann.id) {
var perm = self.annotator.plugins.Permissions; var perm = self.annotator.plugins.Permissions;
if (!perm.options.userAuthorize('delete', ann, perm.user)) { if (!perm.options.userAuthorize('delete', ann, perm.user)) {
...@@ -1031,7 +1031,7 @@ CatchAnnotation.prototype = { ...@@ -1031,7 +1031,7 @@ CatchAnnotation.prototype = {
if (confirm("Would you like to delete the annotation?")) { if (confirm("Would you like to delete the annotation?")) {
var annotator = this.annotator; var annotator = this.annotator;
var item = $(evt.target).parents('.annotationItem:first'); var item = $(evt.target).parents('.annotationItem:first');
var id = item.attr('annotationId'); var id = parseInt(item.attr('annotationId'), 10);
var store = annotator.plugins.Store; var store = annotator.plugins.Store;
var annotations = store.annotations; var annotations = store.annotations;
var permissions = annotator.plugins.Permissions; var permissions = annotator.plugins.Permissions;
...@@ -1048,7 +1048,7 @@ CatchAnnotation.prototype = { ...@@ -1048,7 +1048,7 @@ CatchAnnotation.prototype = {
var annotator = this.annotator; var annotator = this.annotator;
var item = $(evt.target).parents('.annotationItem:first'); var item = $(evt.target).parents('.annotationItem:first');
var id = item.attr('annotationId'); var id = parseInt(item.attr('annotationId'), 10);
var store = annotator.plugins.Store; var store = annotator.plugins.Store;
var annotations = store.annotations; var annotations = store.annotations;
var permissions = annotator.plugins.Permissions; var permissions = annotator.plugins.Permissions;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -433,5 +433,8 @@ ADVANCED_SECURITY_CONFIG = ENV_TOKENS.get('ADVANCED_SECURITY_CONFIG', {}) ...@@ -433,5 +433,8 @@ ADVANCED_SECURITY_CONFIG = ENV_TOKENS.get('ADVANCED_SECURITY_CONFIG', {})
GOOGLE_ANALYTICS_ACCOUNT = AUTH_TOKENS.get('GOOGLE_ANALYTICS_ACCOUNT') GOOGLE_ANALYTICS_ACCOUNT = AUTH_TOKENS.get('GOOGLE_ANALYTICS_ACCOUNT')
GOOGLE_ANALYTICS_LINKEDIN = AUTH_TOKENS.get('GOOGLE_ANALYTICS_LINKEDIN') GOOGLE_ANALYTICS_LINKEDIN = AUTH_TOKENS.get('GOOGLE_ANALYTICS_LINKEDIN')
##### OPTIMIZELY PROJECT ID #####
OPTIMIZELY_PROJECT_ID = AUTH_TOKENS.get('OPTIMIZELY_PROJECT_ID', OPTIMIZELY_PROJECT_ID)
#### Course Registration Code length #### #### Course Registration Code length ####
REGISTRATION_CODE_LENGTH = ENV_TOKENS.get('REGISTRATION_CODE_LENGTH', 8) REGISTRATION_CODE_LENGTH = ENV_TOKENS.get('REGISTRATION_CODE_LENGTH', 8)
...@@ -148,10 +148,7 @@ FEATURES = { ...@@ -148,10 +148,7 @@ FEATURES = {
# Staff Debug tool. # Staff Debug tool.
'ENABLE_STUDENT_HISTORY_VIEW': True, 'ENABLE_STUDENT_HISTORY_VIEW': True,
# Optimizely for the LMS--need to explicitly turn on for production. # Segment.io for LMS--need to explicitly turn it on for production.
'OPTIMIZELY_LMS': False,
# Segment.io for LMS--need to explicitly turn on for production.
'SEGMENT_IO_LMS': False, 'SEGMENT_IO_LMS': False,
# Provide a UI to allow users to submit feedback from the LMS (left-hand help modal) # Provide a UI to allow users to submit feedback from the LMS (left-hand help modal)
...@@ -474,6 +471,9 @@ if FEATURES.get('ENABLE_SQL_TRACKING_LOGS'): ...@@ -474,6 +471,9 @@ if FEATURES.get('ENABLE_SQL_TRACKING_LOGS'):
GOOGLE_ANALYTICS_ACCOUNT = None GOOGLE_ANALYTICS_ACCOUNT = None
GOOGLE_ANALYTICS_LINKEDIN = 'GOOGLE_ANALYTICS_LINKEDIN_DUMMY' GOOGLE_ANALYTICS_LINKEDIN = 'GOOGLE_ANALYTICS_LINKEDIN_DUMMY'
######################## OPTIMIZELY ###########################
OPTIMIZELY_PROJECT_ID = None
######################## subdomain specific settings ########################### ######################## subdomain specific settings ###########################
COURSE_LISTINGS = {} COURSE_LISTINGS = {}
SUBDOMAIN_BRANDING = {} SUBDOMAIN_BRANDING = {}
...@@ -934,18 +934,6 @@ PIPELINE_CSS = { ...@@ -934,18 +934,6 @@ PIPELINE_CSS = {
'css/vendor/jquery.qtip.min.css', 'css/vendor/jquery.qtip.min.css',
'css/vendor/responsive-carousel/responsive-carousel.css', 'css/vendor/responsive-carousel/responsive-carousel.css',
'css/vendor/responsive-carousel/responsive-carousel.slide.css', 'css/vendor/responsive-carousel/responsive-carousel.slide.css',
'css/vendor/ova/annotator.css',
'css/vendor/ova/edx-annotator.css',
'css/vendor/ova/video-js.min.css',
'css/vendor/ova/rangeslider.css',
'css/vendor/ova/share-annotator.css',
'css/vendor/ova/richText-annotator.css',
'css/vendor/ova/tags-annotator.css',
'css/vendor/ova/flagging-annotator.css',
'css/vendor/ova/diacritic-annotator.css',
'css/vendor/ova/grouping-annotator.css',
'css/vendor/ova/ova.css',
'js/vendor/ova/catch/css/main.css'
], ],
'output_filename': 'css/lms-style-vendor.css', 'output_filename': 'css/lms-style-vendor.css',
}, },
...@@ -995,6 +983,23 @@ PIPELINE_CSS = { ...@@ -995,6 +983,23 @@ PIPELINE_CSS = {
], ],
'output_filename': 'css/lms-style-course.css', 'output_filename': 'css/lms-style-course.css',
}, },
'style-xmodule-annotations': {
'source_filenames': [
'css/vendor/ova/annotator.css',
'css/vendor/ova/edx-annotator.css',
'css/vendor/ova/video-js.min.css',
'css/vendor/ova/rangeslider.css',
'css/vendor/ova/share-annotator.css',
'css/vendor/ova/richText-annotator.css',
'css/vendor/ova/tags-annotator.css',
'css/vendor/ova/flagging-annotator.css',
'css/vendor/ova/diacritic-annotator.css',
'css/vendor/ova/grouping-annotator.css',
'css/vendor/ova/ova.css',
'js/vendor/ova/catch/css/main.css'
],
'output_filename': 'css/lms-style-xmodule-annotations.css',
},
} }
...@@ -1326,7 +1331,10 @@ INSTALLED_APPS = ( ...@@ -1326,7 +1331,10 @@ INSTALLED_APPS = (
'monitoring', 'monitoring',
# Course action state # Course action state
'course_action_state' 'course_action_state',
# Additional problem types
'edx_jsme', # Molecular Structure
) )
######################### MARKETING SITE ############################### ######################### MARKETING SITE ###############################
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
<%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)}
${static.css(group='style-xmodule-annotations', raw=True)}
</div> </div>
<div id="catchDIV"> <div id="catchDIV">
<div class="annotationListContainer">${_('Note: only instructors may annotate.')}</div> <div class="annotationListContainer">${_('Note: only instructors may annotate.')}</div>
...@@ -181,23 +182,23 @@ ...@@ -181,23 +182,23 @@
}; };
var imgURLRoot = "${settings.STATIC_URL}" + "js/vendor/ova/catch/img/"; var imgURLRoot = "${settings.STATIC_URL}" + "js/vendor/ova/catch/img/";
var osda, annotator, catchOptions, Catch;
if (typeof Annotator != 'undefined'){ var startosda = function() {
//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); osda = new OpenSeadragonAnnotation($('#imageHolder'),options);
var userId = ('${default_tab}'.toLowerCase() === 'instructor') ? var userId = ('${default_tab}'.toLowerCase() === 'instructor') ?
'${instructor_email}': '${instructor_email}':
'${user.email}'; '${user.email}';
//Catch //Catch
var annotator = osda.annotator; annotator = osda.annotator;
var catchOptions = { catchOptions = {
media:'image', media:'image',
externalLink:false, externalLink:false,
imageUrlRoot:imgURLRoot, imageUrlRoot:imgURLRoot,
...@@ -214,10 +215,23 @@ ...@@ -214,10 +215,23 @@
// if annotations are opened to everyone (2) or if they want to create no annotations (1 with no instructor) // 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 // then the table at the bottom of the source should be displayed
if ("${annotation_mode}" == "everyone" || ("${annotation_mode}" == "instructor" && "${instructor_email}" != "")) if ("${annotation_mode}" == "everyone" || ("${annotation_mode}" == "instructor" && "${instructor_email}" != ""))
var Catch = new CatchAnnotation($('#catchDIV'),catchOptions); Catch = new CatchAnnotation($('#catchDIV'),catchOptions);
// if it is in instructor mode only (1), the annotator should be destroyed for all except the instructor // 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) if ("${annotation_mode}" == "instructor" && "${instructor_email}" == "" && !is_staff)
osda.annotator.destroy(); osda.annotator.destroy();
} }
// if the following is true, template is being rendered in LMS, otherwise it is in Studio
if (typeof Annotator !== 'undefined') {
startosda();
} else {
try {
require(["osda"], function(osda){
startosda();
});
} catch(error) {
console.log("Error: " + error.message + " - Annotator not loaded in LMS.");
}
}
</script> </script>
\ No newline at end of file
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
<%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)}
${static.css(group='style-xmodule-annotations', raw=True)}
<div class="annotatable-wrapper"> <div class="annotatable-wrapper">
<div class="annotatable-header"> <div class="annotatable-header">
...@@ -168,36 +169,51 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)} ...@@ -168,36 +169,51 @@ ${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/";
var ova, Catch, annotator, catchOptions;
var startova = function(){
//remove old instances
if (Annotator._instances.length !== 0) {
$('#textHolder').annotator("destroy");
}
delete ova;
//Load the plugin Video/Text Annotation
ova = new OpenVideoAnnotation.Annotator($('#textHolder'),options);
//remove old instances if (typeof Annotator.Plugin["Grouping"] === 'function')
if (Annotator._instances.length !== 0) { ova.annotator.addPlugin("Grouping");
$('#textHolder').annotator("destroy");
}
delete ova;
//Load the plugin Video/Text Annotation
var ova = new OpenVideoAnnotation.Annotator($('#textHolder'),options);
if (typeof Annotator.Plugin["Grouping"] === 'function') var userId = ('${default_tab}'.toLowerCase() === 'instructor') ?
ova.annotator.addPlugin("Grouping"); '${instructor_email}':
'${user.email}';
var userId = ('${default_tab}'.toLowerCase() === 'instructor') ? //Catch
'${instructor_email}': annotator = ova.annotator;
'${user.email}'; catchOptions = {
media:'text',
externalLink:false,
imageUrlRoot:imgURLRoot,
showMediaSelector: false,
showPublicPrivate: true,
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}",
};
Catch = new CatchAnnotation($('#catchDIV'),catchOptions);
}
//Catch // if the following is true, template is being rendered in LMS, otherwise it is in Studio
var annotator = ova.annotator; if (typeof Annotator !== 'undefined') {
var catchOptions = { startova();
media:'text', } else {
externalLink:false, try {
imageUrlRoot:imgURLRoot, require(["ova"], function(ova) {
showMediaSelector: false, startova();
showPublicPrivate: true, });
userId:userId, } catch(error) {
pagination:pagination,//Number of Annotations per load in the pagination, console.log("Error: " + error.message + " - Annotator not loaded in LMS.");
flags:is_staff, }
default_tab: "${default_tab}", }
instructor_email: "${instructor_email}",
annotation_mode: "${annotation_mode}",
};
var Catch = new CatchAnnotation($('#catchDIV'),catchOptions);
</script> </script>
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
<%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)}
${static.css(group='style-xmodule-annotations', raw=True)}
<div class="annotatable-wrapper"> <div class="annotatable-wrapper">
<div class="annotatable-header"> <div class="annotatable-header">
...@@ -165,34 +166,47 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)} ...@@ -165,34 +166,47 @@ ${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/";
var ova, Catch, annotator, catchOptions;
var startova = function() {
//remove old instances
if (Annotator._instances.length !== 0) {
$('#videoHolder').annotator("destroy");
}
delete ova;
//Load the plugin Video/Text Annotation
ova = new OpenVideoAnnotation.Annotator($('#videoHolder'),options);
//remove old instances ova.annotator.addPlugin('Tags');
if (Annotator._instances.length !== 0) { var userId = ('${default_tab}'.toLowerCase() === 'instructor') ?
$('#videoHolder').annotator("destroy"); '${instructor_email}':
} '${user.email}';
delete ova;
//Load the plugin Video/Text Annotation
var ova = new OpenVideoAnnotation.Annotator($('#videoHolder'),options);
ova.annotator.addPlugin('Tags');
var userId = ('${default_tab}'.toLowerCase() === 'instructor') ?
'${instructor_email}':
'${user.email}';
//Catch //Catch
var annotator = ova.annotator; annotator = ova.annotator;
var catchOptions = { catchOptions = {
media:'video', media:'video',
externalLink:false, externalLink:false,
imageUrlRoot:imgURLRoot, imageUrlRoot:imgURLRoot,
showMediaSelector: false, showMediaSelector: false,
showPublicPrivate: true, showPublicPrivate: true,
userId:userId, 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}", default_tab: "${default_tab}",
instructor_email: "${instructor_email}", instructor_email: "${instructor_email}",
annotation_mode: "${annotation_mode}", annotation_mode: "${annotation_mode}",
}; };
var Catch = new CatchAnnotation($('#catchDIV'),catchOptions); Catch = new CatchAnnotation($('#catchDIV'),catchOptions);
}
if (typeof Annotator !== 'undefined') {
startova();
} else {
try {
require(["ova"], function(ova) {
startova();
});
} catch(error) {
console.log("Error: " + error.message + " - Annotator not loaded in LMS.");
}
}
</script> </script>
% if settings.FEATURES.get('OPTIMIZELY_LMS'): % if settings.OPTIMIZELY_PROJECT_ID:
<script src="//cdn.optimizely.com/js/1706490390.js"></script> <script src=${'//cdn.optimizely.com/js/{}.js'.format(settings.OPTIMIZELY_PROJECT_ID)}></script>
% endif % endif
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
-e git+https://github.com/eventbrite/zendesk.git@d53fe0e81b623f084e91776bcf6369f8b7b63879#egg=zendesk -e git+https://github.com/eventbrite/zendesk.git@d53fe0e81b623f084e91776bcf6369f8b7b63879#egg=zendesk
-e git+https://github.com/un33k/django-ipware.git@42cb1bb1dc680a60c6452e8bb2b843c2a0382c90#egg=django-ipware -e git+https://github.com/un33k/django-ipware.git@42cb1bb1dc680a60c6452e8bb2b843c2a0382c90#egg=django-ipware
-e git+https://github.com/appliedsec/pygeoip.git@95e69341cebf5a6a9fbf7c4f5439d458898bdc3b#egg=pygeoip -e git+https://github.com/appliedsec/pygeoip.git@95e69341cebf5a6a9fbf7c4f5439d458898bdc3b#egg=pygeoip
-e git+https://github.com/jazkarta/edx-jsme.git@813079fd5218ed275248d2a1fcae2fcbf20a0838#egg=edx-jsme
# Our libraries: # Our libraries:
-e git+https://github.com/edx/XBlock.git@aed7a2c51a59836e435259ad0fb41f8e865fa530#egg=XBlock -e git+https://github.com/edx/XBlock.git@aed7a2c51a59836e435259ad0fb41f8e865fa530#egg=XBlock
......
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