diff --git a/.gitignore b/.gitignore
index 89313581c5..78cd1732dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,6 +73,7 @@ bin/
lms/static/css/
lms/static/certificates/css/
cms/static/css/
+common/static/common/js/vendor/
### Styling generated from templates
lms/static/sass/*.css
diff --git a/cms/djangoapps/contentstore/features/course-export.feature b/cms/djangoapps/contentstore/features/course-export.feature
deleted file mode 100644
index 581992e6e4..0000000000
--- a/cms/djangoapps/contentstore/features/course-export.feature
+++ /dev/null
@@ -1,12 +0,0 @@
-@shard_1
-Feature: Course export
- I want to export my course to a tar.gz file to share with others or check into source control
-
- # Disabling due to failure on master. 05/21/2014 TODO: fix
- # Scenario: User is directed to problem with & in it when export fails
- # Given I am in Studio editing a new unit
- # When I add a "Blank Advanced Problem" "Advanced Problem" component
- # And I edit and enter an ampersand
- # And I export the course
- # Then I get an error dialog
- # And I can click to go to the unit with the error
diff --git a/cms/djangoapps/contentstore/features/course-export.py b/cms/djangoapps/contentstore/features/course-export.py
deleted file mode 100644
index ae30100382..0000000000
--- a/cms/djangoapps/contentstore/features/course-export.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# pylint: disable=missing-docstring
-# pylint: disable=redefined-outer-name
-# pylint: disable=unused-argument
-
-from lettuce import world, step
-from component_settings_editor_helpers import enter_xml_in_advanced_problem
-from nose.tools import assert_true, assert_equal
-from contentstore.utils import reverse_usage_url
-
-
-@step('I go to the export page$')
-def i_go_to_the_export_page(step):
- world.click_tools()
- link_css = 'li.nav-course-tools-export a'
- world.css_click(link_css)
-
-
-@step('I export the course$')
-def i_export_the_course(step):
- step.given('I go to the export page')
- world.css_click('a.action-export')
-
-
-@step('I edit and enter bad XML$')
-def i_enter_bad_xml(step):
- enter_xml_in_advanced_problem(
- step,
- """
Smallest Canvas
-
You want to make the smallest canvas you can.
-
-
-
-
-
-
- """
- )
-
-
-@step('I edit and enter an ampersand$')
-def i_enter_an_ampersand(step):
- enter_xml_in_advanced_problem(step, "&")
-
-
-@step('I get an error dialog$')
-def get_an_error_dialog(step):
- assert_true(world.is_css_present("div.prompt.error"))
-
-
-@step('I can click to go to the unit with the error$')
-def i_click_on_error_dialog(step):
- world.css_click("button.action-primary")
-
- problem_string = unicode(world.scenario_dict['COURSE'].id.make_usage_key("problem", 'ignore'))
- problem_string = u"Problem {}".format(problem_string[:problem_string.rfind('ignore')])
- css_selector = "span.inline-error"
- world.wait_for_visible(css_selector)
- assert_true(
- world.css_html(css_selector).startswith(problem_string),
- u"{} does not start with {}".format(
- world.css_html(css_selector), problem_string
- ))
- # we don't know the actual ID of the vertical. So just check that we did go to a
- # vertical page in the course (there should only be one).
- vertical_usage_key = world.scenario_dict['COURSE'].id.make_usage_key("vertical", "test")
- vertical_url = reverse_usage_url('container_handler', vertical_usage_key)
- # Remove the trailing "/None" from the URL - we don't know the course ID, so we just want to
- # check that we visited a vertical URL.
- if vertical_url.endswith("/test") or vertical_url.endswith("@test"):
- vertical_url = vertical_url[:-5]
- assert_equal(1, world.browser.url.count(vertical_url))
diff --git a/cms/djangoapps/contentstore/features/problem-editor.feature b/cms/djangoapps/contentstore/features/problem-editor.feature
index 0891e9de99..026504ca7f 100644
--- a/cms/djangoapps/contentstore/features/problem-editor.feature
+++ b/cms/djangoapps/contentstore/features/problem-editor.feature
@@ -101,27 +101,3 @@ Feature: CMS.Problem Editor
Then I can see Reply to Annotation link
And I see that page has scrolled "down" when I click on "annotatable-reply" link
And I see that page has scrolled "up" when I click on "annotation-return" link
-
- # Disabled 11/13/2013 after failing in master
- # The screenshot showed that the LaTeX editor had the text "hi",
- # but Selenium timed out waiting for the text to appear.
- # It also caused later tests to fail with "UnexpectedAlertPresent"
- #
- # This feature will work in Firefox only when Firefox is the active window
- # IE will not interact with the high level source in sauce labs
- #@skip_internetexplorer
- #Scenario: High Level source is persisted for LaTeX problem (bug STUD-280)
- # Given I have created a LaTeX Problem
- # When I edit and compile the High Level Source
- # Then my change to the High Level Source is persisted
- # And when I view the High Level Source I see my changes
-
- # Disabled 10/28/13 due to flakiness observed in master
- # Scenario: Exceptions don't cause problem to be uneditable (bug STUD-786)
- #Given I have an empty course
- #And I go to the import page
- #And I import the file "get_html_exception_test.tar.gz"
- #When I go to the unit "Probability and BMI"
- #And I click on "edit a draft"
- #Then I see a message that says "We're having trouble rendering your component"
- #And I can edit the problem
diff --git a/cms/djangoapps/contentstore/features/video.feature b/cms/djangoapps/contentstore/features/video.feature
deleted file mode 100644
index 59dc89f6eb..0000000000
--- a/cms/djangoapps/contentstore/features/video.feature
+++ /dev/null
@@ -1,57 +0,0 @@
-@shard_2 @requires_stub_youtube
-Feature: CMS Video Component
- As a course author, I want to be able to view my created videos in Studio
-
- # 2
- # Disabled 2/19/14 after intermittent failures in master
- #Scenario: Check that position is stored on page refresh, position within start-end range
- # Given I have created a Video component with subtitles
- # And Make sure captions are closed
- # And I edit the component
- # And I open tab "Advanced"
- # And I set value "00:00:12" to the field "Video Start Time"
- # And I set value "00:00:24" to the field "Video Stop Time"
- # And I save changes
- # And I click video button "play"
- # Then I see a range on slider
- # Then I seek video to "16" seconds
- # And I click video button "pause"
- # And I reload the page
- # And I click video button "play"
- # Then I see video starts playing from "0:16" position
-
- # 3
-# Disabled 2/18/14 after intermittent failures in master
-# Scenario: Check that position is stored on page refresh, position before start-end range
-# Given I have created a Video component with subtitles
-# And Make sure captions are closed
-# And I edit the component
-# And I open tab "Advanced"
-# And I set value "00:00:12" to the field "Video Start Time"
-# And I set value "00:00:24" to the field "Video Stop Time"
-# And I save changes
-# And I click video button "play"
-# Then I see a range on slider
-# Then I seek video to "5" seconds
-# And I click video button "pause"
-# And I reload the page
-# And I click video button "play"
-# Then I see video starts playing from "0:12" position
-
- # 4
-# Disabled 2/18/14 after intermittent failures in master
-# Scenario: Check that position is stored on page refresh, position after start-end range
-# Given I have created a Video component with subtitles
-# And Make sure captions are closed
-# And I edit the component
-# And I open tab "Advanced"
-# And I set value "00:00:12" to the field "Video Start Time"
-# And I set value "00:00:24" to the field "Video Stop Time"
-# And I save changes
-# And I click video button "play"
-# Then I see a range on slider
-# Then I seek video to "30" seconds
-# And I click video button "pause"
-# And I reload the page
-# And I click video button "play"
-# Then I see video starts playing from "0:12" position
diff --git a/cms/djangoapps/contentstore/features/video_editor.py b/cms/djangoapps/contentstore/features/video_editor.py
deleted file mode 100644
index cf96e099c9..0000000000
--- a/cms/djangoapps/contentstore/features/video_editor.py
+++ /dev/null
@@ -1,321 +0,0 @@
-# -*- coding: utf-8 -*-
-# disable missing docstring
-# pylint: disable=missing-docstring
-
-import requests
-from lettuce import world, step
-from nose.tools import assert_true, assert_equal, assert_in, assert_not_equal
-from terrain.steps import reload_the_page
-from django.conf import settings
-from common import upload_file, attach_file
-
-TEST_ROOT = settings.COMMON_TEST_DATA_ROOT
-
-DISPLAY_NAME = "Component Display Name"
-NATIVE_LANGUAGES = {lang: label for lang, label in settings.LANGUAGES if len(lang) == 2}
-LANGUAGES = {
- lang: NATIVE_LANGUAGES.get(lang, display)
- for lang, display in settings.ALL_LANGUAGES
-}
-
-LANGUAGES.update({
- 'table': 'Table of Contents'
-})
-
-TRANSLATION_BUTTONS = {
- 'add': '.metadata-video-translations .create-action',
- 'upload': '.metadata-video-translations .upload-action',
- 'download': '.metadata-video-translations .download-action',
- 'remove': '.metadata-video-translations .remove-action',
- 'clear': '.metadata-video-translations .setting-clear',
-}
-
-VIDEO_MENUS = {
- 'language': '.lang .menu',
-}
-
-
-class RequestHandlerWithSessionId(object):
- def get(self, url):
- """
- Sends a request.
- """
- kwargs = dict()
-
- session_id = [{i['name']:i['value']} for i in world.browser.cookies.all() if i['name'] == u'sessionid']
- if session_id:
- kwargs.update({
- 'cookies': session_id[0]
- })
-
- response = requests.get(url, **kwargs)
- self.response = response
- self.status_code = response.status_code
- self.headers = response.headers
- self.content = response.content
-
- return self
-
- def is_success(self):
- """
- Returns `True` if the response was succeed, otherwise, returns `False`.
- """
- if self.status_code < 400:
- return True
- return False
-
- def check_header(self, name, value):
- """
- Returns `True` if the response header exist and has appropriate value,
- otherwise, returns `False`.
- """
- if value in self.headers.get(name, ''):
- return True
- return False
-
-
-def success_upload_file(filename):
- upload_file(filename, sub_path="uploads/")
- world.css_has_text('#upload_confirm', 'Success!')
- world.is_css_not_present('.wrapper-modal-window-assetupload', wait_time=30)
-
-
-def get_translations_container():
- return world.browser.find_by_xpath('//label[text()="Transcript Languages"]/following-sibling::div')
-
-
-def get_setting_container(lang_code):
- try:
- get_xpath = lambda value: './/descendant::a[@data-lang="{}" and contains(@class,"remove-setting")]/parent::*'.format(value)
- return get_translations_container().find_by_xpath(get_xpath(lang_code)).first
- except Exception:
- return None
-
-
-def get_last_dropdown():
- return get_translations_container().find_by_xpath('.//descendant::select[last()]').last
-
-
-def choose_option(dropdown, value):
- dropdown.find_by_value(value)[0].click()
-
-
-def choose_new_lang(lang_code):
- world.css_click(TRANSLATION_BUTTONS['add'])
- choose_option(get_last_dropdown(), lang_code)
- assert_equal(get_last_dropdown().value, lang_code, "Option with provided value is not available or was not selected")
-
-
-def open_menu(menu):
- world.browser.execute_script("$('{selector}').parent().addClass('is-opened')".format(
- selector=VIDEO_MENUS[menu]
- ))
-
-
-@step('I have set "transcript display" to (.*)$')
-def set_show_captions(step, setting):
- # Prevent cookies from overriding course settings
- world.browser.cookies.delete('hide_captions')
-
- world.edit_component()
- world.select_editor_tab('Advanced')
- world.browser.select('Show Transcript', setting)
- world.save_component()
-
-
-@step('when I view the video it (.*) show the captions$')
-def shows_captions(_step, show_captions):
- world.wait_for_js_variable_truthy("Video")
- world.wait(0.5)
- if show_captions == 'does not':
- assert_true(world.is_css_present('div.video.closed'))
- else:
- assert_true(world.is_css_not_present('div.video.closed'))
-
- # Prevent cookies from overriding course settings
- world.browser.cookies.delete('hide_captions')
- world.browser.cookies.delete('current_player_mode')
-
-
-@step('I see the correct video settings and default values$')
-def correct_video_settings(_step):
- expected_entries = [
- # basic
- [DISPLAY_NAME, 'Video', False],
- ['Default Video URL', 'http://youtu.be/3_yD_cEKoCk, , ', False],
-
- # advanced
- [DISPLAY_NAME, 'Video', False],
- ['Default Timed Transcript', '', False],
- ['Download Transcript Allowed', 'False', False],
- ['Downloadable Transcript URL', '', False],
- ['Show Transcript', 'True', False],
- ['Transcript Languages', '', False],
- ['Upload Handout', '', False],
- ['Video Available on Web Only', 'False', False],
- ['Video Download Allowed', 'False', False],
- ['Video File URLs', '', False],
- ['Video Start Time', '00:00:00', False],
- ['Video Stop Time', '00:00:00', False],
- ['YouTube ID', '3_yD_cEKoCk', False],
- ['YouTube ID for .75x speed', '', False],
- ['YouTube ID for 1.25x speed', '', False],
- ['YouTube ID for 1.5x speed', '', False]
- ]
- world.verify_all_setting_entries(expected_entries)
-
-
-@step('my video display name change is persisted on save$')
-def video_name_persisted(step):
- world.save_component()
- reload_the_page(step)
- world.wait_for_xmodule()
- world.edit_component()
-
- world.verify_setting_entry(
- world.get_setting_entry(DISPLAY_NAME),
- DISPLAY_NAME, '3.4', True
- )
-
-
-@step('I can modify video display name')
-def i_can_modify_video_display_name(_step):
- index = world.get_setting_entry_index(DISPLAY_NAME)
- world.set_field_value(index, '3.4')
- world.verify_setting_entry(world.get_setting_entry(DISPLAY_NAME), DISPLAY_NAME, '3.4', True)
-
-
-@step('I upload transcript file(?:s)?:$')
-def upload_transcript(step):
- input_hidden = '.metadata-video-translations .input'
- # Number of previously added translations
- initial_index = len(world.css_find(TRANSLATION_BUTTONS['download']))
-
- if step.hashes:
- for i, item in enumerate(step.hashes):
- lang_code = item['lang_code']
- filename = item['filename']
- index = initial_index + i
-
- choose_new_lang(lang_code)
-
- expected_text = world.css_text(TRANSLATION_BUTTONS['upload'], index=index)
- assert_equal(expected_text, "Upload")
- assert_equal(world.css_find(input_hidden).last.value, "")
-
- world.css_click(TRANSLATION_BUTTONS['upload'], index=index)
- success_upload_file(filename)
-
- world.wait_for_visible(TRANSLATION_BUTTONS['download'], index=index)
- assert_equal(world.css_find(TRANSLATION_BUTTONS['upload']).last.text, "Replace")
- assert_equal(world.css_find(input_hidden).last.value, filename)
-
-
-@step('I try to upload transcript file "([^"]*)"$')
-def try_to_upload_transcript(step, filename):
- world.css_click(TRANSLATION_BUTTONS['upload'])
- attach_file(filename, 'uploads/')
-
-
-@step('I upload transcript file "([^"]*)" for "([^"]*)" language code$')
-def upload_transcript_for_lang(step, filename, lang_code):
- get_xpath = lambda value: './/div/a[contains(@class, "upload-action")]'.format(value)
- container = get_setting_container(lang_code)
-
- # If translation isn't uploaded, prepare drop-down and try to find container again
- choose_new_lang(lang_code)
- container = get_setting_container(lang_code)
-
- button = container.find_by_xpath(get_xpath(lang_code)).first
- button.click()
- success_upload_file(filename)
-
-
-@step('I replace transcript file for "([^"]*)" language code by "([^"]*)"$')
-def replace_transcript_for_lang(step, lang_code, filename):
- get_xpath = lambda value: './/div/a[contains(@class, "upload-action")]'.format(value)
- container = get_setting_container(lang_code)
-
- button = container.find_by_xpath(get_xpath(lang_code)).first
- button.click()
- success_upload_file(filename)
-
-
-@step('I see validation error "([^"]*)"$')
-def verify_validation_error_message(step, error_message):
- assert_equal(world.css_text('#upload_error'), error_message)
-
-
-@step('I can download transcript for "([^"]*)" language code, that contains text "([^"]*)"$')
-def i_can_download_transcript(_step, lang_code, text):
- MIME_TYPE = 'application/x-subrip'
- get_xpath = lambda value: './/div/a[contains(text(), "Download")]'.format(value)
- container = get_setting_container(lang_code)
- assert container
- button = container.find_by_xpath(get_xpath(lang_code)).first
- url = button['href']
- request = RequestHandlerWithSessionId()
- assert_true(request.get(url).is_success())
- assert_true(request.check_header('content-type', MIME_TYPE))
- assert_in(text.encode('utf-8'), request.content)
-
-
-@step('I remove translation for "([^"]*)" language code$')
-def i_can_remove_transcript(_step, lang_code):
- get_xpath = lambda value: './/descendant::a[@data-lang="{}" and contains(@class,"remove-setting")]'.format(value)
- container = get_setting_container(lang_code)
- assert container
- button = container.find_by_xpath(get_xpath(lang_code)).first
- button.click()
-
-
-@step('I see translations for "([^"]*)"$')
-def verify_translations(_step, lang_codes_string):
- expected = [l.strip() for l in lang_codes_string.split(',')]
- actual = [l['data-lang'] for l in world.css_find('.metadata-video-translations .remove-setting')]
- assert_equal(set(expected), set(actual))
-
-
-@step('I do not see translations$')
-def no_translations(_step):
- assert_true(world.is_css_not_present('.metadata-video-translations .remove-setting'))
-
-
-@step('I confirm prompt$')
-def confirm_prompt(_step):
- world.confirm_studio_prompt()
-
-
-@step('I (cannot )?choose "([^"]*)" language code$')
-def i_choose_lang_code(_step, cannot, lang_code):
- choose_option(get_last_dropdown(), lang_code)
- if cannot:
- assert_not_equal(get_last_dropdown().value, lang_code, "Option with provided value was selected, but shouldn't")
- else:
- assert_equal(get_last_dropdown().value, lang_code, "Option with provided value is not available or was not selected")
-
-
-@step('I click button "([^"]*)"$')
-def click_button(_step, button):
- world.css_click(TRANSLATION_BUTTONS[button.lower()])
-
-
-@step('video language menu has "([^"]*)" translations$')
-def i_see_correct_langs(_step, langs):
- menu_name = 'language'
- open_menu(menu_name)
- items = world.css_find(VIDEO_MENUS[menu_name] + ' li')
- translations = {t.strip(): LANGUAGES[t.strip()] for t in langs.split(',')}
-
- assert_equal(len(translations), len(items))
- for lang_code, label in translations.items():
- assert_true(any([i.text == label for i in items]))
- assert_true(any([i['data-lang-code'] == lang_code for i in items]))
-
-
-@step('video language with code "([^"]*)" at position "(\d+)"$')
-def i_see_lang_at_position(_step, code, position):
- menu_name = 'language'
- open_menu(menu_name)
- item = world.css_find(VIDEO_MENUS[menu_name] + ' li')[int(position)]
- assert_equal(item['data-lang-code'], code)
diff --git a/cms/djangoapps/contentstore/features/video_handout.py b/cms/djangoapps/contentstore/features/video_handout.py
deleted file mode 100644
index 233ea30b56..0000000000
--- a/cms/djangoapps/contentstore/features/video_handout.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# -*- coding: utf-8 -*-
-# disable missing docstring
-# pylint: disable=missing-docstring
-
-from lettuce import world, step
-from nose.tools import assert_true
-from video_editor import RequestHandlerWithSessionId, success_upload_file
-
-
-@step('I (?:upload|replace) handout file(?: by)? "([^"]*)"$')
-def upload_handout(step, filename):
- world.css_click('.wrapper-comp-setting.file-uploader .upload-action')
- success_upload_file(filename)
-
-
-@step('I can download handout file( in editor)? with mime type "([^"]*)"$')
-def i_can_download_handout_with_mime_type(_step, is_editor, mime_type):
- if is_editor:
- selector = '.wrapper-comp-setting.file-uploader .download-action'
- else:
- selector = '.video-handout.video-download-button a'
-
- button = world.css_find(selector).first
- url = button['href']
- request = RequestHandlerWithSessionId()
- assert_true(request.get(url).is_success())
- assert_true(request.check_header('content-type', mime_type))
-
-
-@step('I clear handout$')
-def clear_handout(_step):
- world.css_click('.wrapper-comp-setting.file-uploader .setting-clear')
-
-
-@step('I have created a Video component with handout file "([^"]*)"')
-def create_video_with_handout(_step, filename):
- _step.given('I have created a Video component')
- _step.given('I edit the component')
- _step.given('I open tab "Advanced"')
- _step.given('I upload handout file "{0}"'.format(filename))
diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py
index 9670ee3cf5..00cf07215f 100644
--- a/cms/djangoapps/contentstore/views/course.py
+++ b/cms/djangoapps/contentstore/views/course.py
@@ -90,6 +90,7 @@ from util.organizations_helpers import (
organizations_enabled,
)
from util.string_utils import _has_non_ascii_characters
+from util.course_key_utils import from_string_or_404
from xmodule.contentstore.content import StaticContent
from xmodule.course_module import CourseFields
from xmodule.course_module import DEFAULT_START_DATE
@@ -868,10 +869,7 @@ def course_info_handler(request, course_key_string):
GET
html: return html for editing the course info handouts and updates.
"""
- try:
- course_key = CourseKey.from_string(course_key_string)
- except InvalidKeyError:
- raise Http404
+ course_key = from_string_or_404(course_key_string)
with modulestore().bulk_operations(course_key):
course_module = get_course_and_check_access(course_key, request.user)
diff --git a/cms/envs/aws.py b/cms/envs/aws.py
index cc45b632e1..a924de3018 100644
--- a/cms/envs/aws.py
+++ b/cms/envs/aws.py
@@ -283,6 +283,17 @@ else:
DATABASES = AUTH_TOKENS['DATABASES']
MODULESTORE = convert_module_store_setting_if_needed(AUTH_TOKENS.get('MODULESTORE', MODULESTORE))
+
+MODULESTORE_FIELD_OVERRIDE_PROVIDERS = ENV_TOKENS.get(
+ 'MODULESTORE_FIELD_OVERRIDE_PROVIDERS',
+ MODULESTORE_FIELD_OVERRIDE_PROVIDERS
+)
+
+XBLOCK_FIELD_DATA_WRAPPERS = ENV_TOKENS.get(
+ 'XBLOCK_FIELD_DATA_WRAPPERS',
+ XBLOCK_FIELD_DATA_WRAPPERS
+)
+
CONTENTSTORE = AUTH_TOKENS['CONTENTSTORE']
DOC_STORE_CONFIG = AUTH_TOKENS['DOC_STORE_CONFIG']
# Datadog for events!
diff --git a/cms/envs/common.py b/cms/envs/common.py
index de6db81d21..dff2231171 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -383,6 +383,9 @@ XBLOCK_MIXINS = (
XBLOCK_SELECT_FUNCTION = prefer_xmodules
+# Paths to wrapper methods which should be applied to every XBlock's FieldData.
+XBLOCK_FIELD_DATA_WRAPPERS = ()
+
############################ Modulestore Configuration ################################
MODULESTORE_BRANCH = 'draft-preferred'
@@ -417,6 +420,10 @@ MODULESTORE = {
}
}
+# Modulestore-level field override providers. These field override providers don't
+# require student context.
+MODULESTORE_FIELD_OVERRIDE_PROVIDERS = ()
+
#################### Python sandbox ############################################
CODE_JAIL = {
diff --git a/cms/static/cms/js/require-config.js b/cms/static/cms/js/require-config.js
index 43a497049e..a91819ace7 100644
--- a/cms/static/cms/js/require-config.js
+++ b/cms/static/cms/js/require-config.js
@@ -50,7 +50,7 @@
"moment": "js/vendor/moment.min",
"moment-with-locales": "js/vendor/moment-with-locales.min",
"text": 'js/vendor/requirejs/text',
- "underscore": "js/vendor/underscore-min",
+ "underscore": "common/js/vendor/underscore",
"underscore.string": "js/vendor/underscore.string.min",
"backbone": "js/vendor/backbone-min",
"backbone-relational" : "js/vendor/backbone-relational.min",
diff --git a/cms/static/coffee/spec/main.coffee b/cms/static/coffee/spec/main.coffee
index 985f5e67ad..638bf9a51d 100644
--- a/cms/static/coffee/spec/main.coffee
+++ b/cms/static/coffee/spec/main.coffee
@@ -26,7 +26,7 @@ requirejs.config({
"moment": "xmodule_js/common_static/js/vendor/moment.min",
"moment-with-locales": "xmodule_js/common_static/js/vendor/moment-with-locales.min",
"text": "xmodule_js/common_static/js/vendor/requirejs/text",
- "underscore": "xmodule_js/common_static/js/vendor/underscore-min",
+ "underscore": "xmodule_js/common_static/common/js/vendor/underscore",
"underscore.string": "xmodule_js/common_static/js/vendor/underscore.string.min",
"backbone": "xmodule_js/common_static/js/vendor/backbone-min",
"backbone.associations": "xmodule_js/common_static/js/vendor/backbone-associations-min",
diff --git a/cms/static/coffee/spec/main_squire.coffee b/cms/static/coffee/spec/main_squire.coffee
index d09cdfd393..a46474744e 100644
--- a/cms/static/coffee/spec/main_squire.coffee
+++ b/cms/static/coffee/spec/main_squire.coffee
@@ -22,7 +22,7 @@ requirejs.config({
"datepair": "xmodule_js/common_static/js/vendor/timepicker/datepair",
"date": "xmodule_js/common_static/js/vendor/date",
"text": "xmodule_js/common_static/js/vendor/requirejs/text",
- "underscore": "xmodule_js/common_static/js/vendor/underscore-min",
+ "underscore": "xmodule_js/common_static/common/js/vendor/underscore",
"underscore.string": "xmodule_js/common_static/js/vendor/underscore.string.min",
"backbone": "xmodule_js/common_static/js/vendor/backbone-min",
"backbone.associations": "xmodule_js/common_static/js/vendor/backbone-associations-min",
diff --git a/cms/static/edx-pattern-library b/cms/static/edx-pattern-library
new file mode 120000
index 0000000000..0d3ed215ee
--- /dev/null
+++ b/cms/static/edx-pattern-library
@@ -0,0 +1 @@
+../../common/static/edx-pattern-library
\ No newline at end of file
diff --git a/cms/static/edx-ui-toolkit b/cms/static/edx-ui-toolkit
new file mode 120000
index 0000000000..32e7d34a2c
--- /dev/null
+++ b/cms/static/edx-ui-toolkit
@@ -0,0 +1 @@
+../../common/static/edx-ui-toolkit
\ No newline at end of file
diff --git a/cms/static/js/certificates/views/signatory_editor.js b/cms/static/js/certificates/views/signatory_editor.js
index 2bd6e2f890..d446ea630f 100644
--- a/cms/static/js/certificates/views/signatory_editor.js
+++ b/cms/static/js/certificates/views/signatory_editor.js
@@ -129,9 +129,9 @@ function ($, _, Backbone, gettext,
if (event && event.preventDefault) { event.preventDefault(); }
var model = this.model;
var self = this;
- var titleText = gettext('Delete "<%= signatoryName %>" from the list of signatories?');
+ var titleTextTemplate = _.template(gettext('Delete "<%= signatoryName %>" from the list of signatories?'));
var confirm = new PromptView.Warning({
- title: _.template(titleText, {signatoryName: model.get('name')}),
+ title: titleTextTemplate({signatoryName: model.get('name')}),
message: gettext('This action cannot be undone.'),
actions: {
primary: {
diff --git a/cms/static/js/i18n/ar/djangojs.js b/cms/static/js/i18n/ar/djangojs.js
index 514d05b4af..03dc3c3018 100644
--- a/cms/static/js/i18n/ar/djangojs.js
+++ b/cms/static/js/i18n/ar/djangojs.js
@@ -1605,6 +1605,7 @@
"Update post": "\u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0645\u0646\u0634\u0648\u0631 ",
"Update response": "\u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0631\u062f ",
"Update team.": "\u0639\u062f\u0651\u0644 \u0641\u0631\u064a\u0642.",
+ "Updating Tags": "\u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0634\u064e\u0627\u0631\u0627\u062a",
"Updating with latest library content": "\u062c\u0627\u0631\u064a \u0627\u0644\u062a\u062d\u062f\u064a\u062b \u0645\u0639 \u0645\u0633\u062a\u062c\u062f\u0651\u0627\u062a \u0645\u062d\u062a\u0648\u0649 \u0627\u0644\u0645\u0643\u062a\u0628\u0629",
"Upgrade Deadline": "\u0627\u0644\u0645\u0648\u0639\u062f \u0627\u0644\u0646\u0647\u0627\u0626\u064a \u0644\u0644\u062a\u062d\u062f\u064a\u062b ",
"Upgrade to a Verified Certificate for %(courseName)s": "\u0642\u0645 \u0628\u0627\u0644\u062a\u0631\u0642\u064a\u0629 \u0644\u062a\u062d\u0635\u0644 \u0639\u0644\u0649 \u0634\u0647\u0627\u062f\u0629 \u0645\u0648\u062b\u0651\u0642\u0629 \u0644\u0644\u0645\u0633\u0627\u0642 %(courseName)s",
diff --git a/cms/static/js/i18n/eo/djangojs.js b/cms/static/js/i18n/eo/djangojs.js
index 87442010b0..2975f803f4 100644
--- a/cms/static/js/i18n/eo/djangojs.js
+++ b/cms/static/js/i18n/eo/djangojs.js
@@ -301,7 +301,7 @@
"Cancel team updating.": "\u00c7\u00e4n\u00e7\u00e9l t\u00e9\u00e4m \u00fcpd\u00e4t\u00efng. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, #",
"Cannot delete when in use by a unit": "\u00c7\u00e4nn\u00f6t d\u00e9l\u00e9t\u00e9 wh\u00e9n \u00efn \u00fcs\u00e9 \u00df\u00fd \u00e4 \u00fcn\u00eft \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442#",
"Cannot delete when in use by an experiment": "\u00c7\u00e4nn\u00f6t d\u00e9l\u00e9t\u00e9 wh\u00e9n \u00efn \u00fcs\u00e9 \u00df\u00fd \u00e4n \u00e9xp\u00e9r\u00efm\u00e9nt \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f #",
- "Cannot drop more <% attrs.types %> than will assigned.": "\u00c7\u00e4nn\u00f6t dr\u00f6p m\u00f6r\u00e9 <% attrs.types %> th\u00e4n w\u00efll \u00e4ss\u00efgn\u00e9d. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f#",
+ "Cannot drop more <%= types %> assignments than are assigned.": "\u00c7\u00e4nn\u00f6t dr\u00f6p m\u00f6r\u00e9 <%= types %> \u00e4ss\u00efgnm\u00e9nts th\u00e4n \u00e4r\u00e9 \u00e4ss\u00efgn\u00e9d. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f \u03b1#",
"Caption": "\u00c7\u00e4pt\u00ef\u00f6n \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c #",
"Caution: The last published version of this unit is live. By publishing changes you will change the student experience.": "\u00c7\u00e4\u00fct\u00ef\u00f6n: Th\u00e9 l\u00e4st p\u00fc\u00dfl\u00efsh\u00e9d v\u00e9rs\u00ef\u00f6n \u00f6f th\u00efs \u00fcn\u00eft \u00efs l\u00efv\u00e9. B\u00fd p\u00fc\u00dfl\u00efsh\u00efng \u00e7h\u00e4ng\u00e9s \u00fd\u00f6\u00fc w\u00efll \u00e7h\u00e4ng\u00e9 th\u00e9 st\u00fcd\u00e9nt \u00e9xp\u00e9r\u00ef\u00e9n\u00e7\u00e9. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c#",
"Cell": "\u00c7\u00e9ll \u2c60'\u03c3\u044f\u0454\u043c \u03b9#",
@@ -385,7 +385,6 @@
"Cohorts Disabled": "\u00c7\u00f6h\u00f6rts D\u00efs\u00e4\u00dfl\u00e9d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c#",
"Cohorts Enabled": "\u00c7\u00f6h\u00f6rts \u00c9n\u00e4\u00dfl\u00e9d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1#",
"Collapse All": "\u00c7\u00f6ll\u00e4ps\u00e9 \u00c0ll \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#",
- "Collapse All Sections": "\u00c7\u00f6ll\u00e4ps\u00e9 \u00c0ll S\u00e9\u00e7t\u00ef\u00f6ns \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, #",
"Collapse Instructions": "\u00c7\u00f6ll\u00e4ps\u00e9 \u00ccnstr\u00fc\u00e7t\u00ef\u00f6ns \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, #",
"Collapse discussion": "\u00c7\u00f6ll\u00e4ps\u00e9 d\u00efs\u00e7\u00fcss\u00ef\u00f6n \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442,#",
"Collapse/Expand this %(xblock_type)s": "\u00c7\u00f6ll\u00e4ps\u00e9/\u00c9xp\u00e4nd th\u00efs %(xblock_type)s \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7#",
@@ -550,7 +549,6 @@
"Edit Team": "\u00c9d\u00eft T\u00e9\u00e4m \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142#",
"Edit Your Name": "\u00c9d\u00eft \u00dd\u00f6\u00fcr N\u00e4m\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442#",
"Edit post title": "\u00c9d\u00eft p\u00f6st t\u00eftl\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1#",
- "Edit section release date": "\u00c9d\u00eft s\u00e9\u00e7t\u00ef\u00f6n r\u00e9l\u00e9\u00e4s\u00e9 d\u00e4t\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455#",
"Edit the name": "\u00c9d\u00eft th\u00e9 n\u00e4m\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9#",
"Edit this certificate?": "\u00c9d\u00eft th\u00efs \u00e7\u00e9rt\u00eff\u00ef\u00e7\u00e4t\u00e9? \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2#",
"Editable": "\u00c9d\u00eft\u00e4\u00dfl\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202#",
@@ -639,7 +637,6 @@
"Exception Granted": "\u00c9x\u00e7\u00e9pt\u00ef\u00f6n Gr\u00e4nt\u00e9d \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454#",
"Exit full browser": "\u00c9x\u00eft f\u00fcll \u00dfr\u00f6ws\u00e9r \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454#",
"Expand All": "\u00c9xp\u00e4nd \u00c0ll \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3#",
- "Expand All Sections": "\u00c9xp\u00e4nd \u00c0ll S\u00e9\u00e7t\u00ef\u00f6ns \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442,#",
"Expand Instructions": "\u00c9xp\u00e4nd \u00ccnstr\u00fc\u00e7t\u00ef\u00f6ns \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442,#",
"Expand discussion": "\u00c9xp\u00e4nd d\u00efs\u00e7\u00fcss\u00ef\u00f6n \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454#",
"Explain if other.": "\u00c9xpl\u00e4\u00efn \u00eff \u00f6th\u00e9r. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454#",
@@ -1085,7 +1082,6 @@
"Release Date:": "R\u00e9l\u00e9\u00e4s\u00e9 D\u00e4t\u00e9: \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9#",
"Release Status:": "R\u00e9l\u00e9\u00e4s\u00e9 St\u00e4t\u00fcs: \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1#",
"Release Time in UTC:": "R\u00e9l\u00e9\u00e4s\u00e9 T\u00efm\u00e9 \u00efn \u00dbT\u00c7: \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, #",
- "Release date:": "R\u00e9l\u00e9\u00e4s\u00e9 d\u00e4t\u00e9: \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9#",
"Release:": "R\u00e9l\u00e9\u00e4s\u00e9: \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202#",
"Released:": "R\u00e9l\u00e9\u00e4s\u00e9d: \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142#",
"Removal is in progress. To avoid errors, stay on this page until the process is complete.": "R\u00e9m\u00f6v\u00e4l \u00efs \u00efn pr\u00f6gr\u00e9ss. T\u00f6 \u00e4v\u00f6\u00efd \u00e9rr\u00f6rs, st\u00e4\u00fd \u00f6n th\u00efs p\u00e4g\u00e9 \u00fcnt\u00efl th\u00e9 pr\u00f6\u00e7\u00e9ss \u00efs \u00e7\u00f6mpl\u00e9t\u00e9. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455#",
@@ -1291,7 +1287,7 @@
"Task Type": "T\u00e4sk T\u00fdp\u00e9 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142#",
"Task inputs": "T\u00e4sk \u00efnp\u00fcts \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f #",
"Teaching Assistant": "T\u00e9\u00e4\u00e7h\u00efng \u00c0ss\u00efst\u00e4nt \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442#",
- "Team \"%(team)s\" successfully deleted.": "T\u00e9\u00e4m \"%(team)s\" s\u00fc\u00e7\u00e7\u00e9ssf\u00fcll\u00fd d\u00e9l\u00e9t\u00e9d. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454#",
+ "Team \"{team}\" successfully deleted.": "T\u00e9\u00e4m \"{team}\" s\u00fc\u00e7\u00e7\u00e9ssf\u00fcll\u00fd d\u00e9l\u00e9t\u00e9d. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454#",
"Team Description (Required) *": "T\u00e9\u00e4m D\u00e9s\u00e7r\u00efpt\u00ef\u00f6n (R\u00e9q\u00fc\u00efr\u00e9d) * \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2#",
"Team Details": "T\u00e9\u00e4m D\u00e9t\u00e4\u00efls \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455#",
"Team Name (Required) *": "T\u00e9\u00e4m N\u00e4m\u00e9 (R\u00e9q\u00fc\u00efr\u00e9d) * \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2#",
@@ -1818,7 +1814,6 @@
"with %(section_or_subsection)s": "w\u00efth %(section_or_subsection)s \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202#",
"{browse_span_start}Browse teams in other topics{span_end} or {search_span_start}search teams{span_end} in this topic. If you still can't find a team to join, {create_span_start}create a new team in this topic{span_end}.": "{browse_span_start}Br\u00f6ws\u00e9 t\u00e9\u00e4ms \u00efn \u00f6th\u00e9r t\u00f6p\u00ef\u00e7s{span_end} \u00f6r {search_span_start}s\u00e9\u00e4r\u00e7h t\u00e9\u00e4ms{span_end} \u00efn th\u00efs t\u00f6p\u00ef\u00e7. \u00ccf \u00fd\u00f6\u00fc st\u00efll \u00e7\u00e4n't f\u00efnd \u00e4 t\u00e9\u00e4m t\u00f6 j\u00f6\u00efn, {create_span_start}\u00e7r\u00e9\u00e4t\u00e9 \u00e4 n\u00e9w t\u00e9\u00e4m \u00efn th\u00efs t\u00f6p\u00ef\u00e7{span_end}. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442\u03c5\u044f \u03b1\u2202\u03b9\u03c1\u03b9\u0455\u03b9\u00a2\u03b9\u03b7g \u0454\u0142\u03b9\u0442, \u0455\u0454\u2202 \u2202\u03c3 \u0454\u03b9\u03c5\u0455\u043c\u03c3\u2202 \u0442\u0454\u043c\u03c1\u03c3\u044f \u03b9\u03b7\u00a2\u03b9\u2202\u03b9\u2202\u03c5\u03b7\u0442 \u03c5\u0442 \u0142\u03b1\u0432\u03c3\u044f\u0454 \u0454\u0442 \u2202\u03c3\u0142\u03c3\u044f\u0454 \u043c\u03b1g\u03b7\u03b1 \u03b1\u0142\u03b9q\u03c5\u03b1. \u03c5\u0442 \u0454\u03b7\u03b9\u043c \u03b1\u2202 \u043c\u03b9\u03b7\u03b9\u043c \u03bd\u0454\u03b7\u03b9\u03b1\u043c, q\u03c5\u03b9\u0455 \u03b7\u03c3\u0455\u0442\u044f\u03c5\u2202 \u0454\u03c7\u0454\u044f\u00a2\u03b9\u0442\u03b1\u0442\u03b9\u03c3\u03b7 \u03c5\u0142\u0142\u03b1\u043c\u00a2\u03c3 \u0142\u03b1\u0432\u03c3\u044f\u03b9\u0455 \u03b7\u03b9\u0455\u03b9 \u03c5\u0442 \u03b1\u0142\u03b9q\u03c5\u03b9\u03c1 \u0454\u03c7 \u0454\u03b1 \u00a2\u03c3\u043c\u043c\u03c3\u2202\u03c3 \u00a2\u03c3\u03b7\u0455\u0454q\u03c5\u03b1\u0442. \u2202\u03c5\u03b9\u0455 \u03b1\u03c5\u0442\u0454 \u03b9\u044f\u03c5\u044f\u0454 \u2202\u03c3\u0142\u03c3\u044f \u03b9\u03b7 \u044f\u0454\u03c1\u044f\u0454\u043d\u0454\u03b7\u2202\u0454\u044f\u03b9\u0442 \u03b9\u03b7 \u03bd\u03c3\u0142\u03c5\u03c1\u0442\u03b1\u0442\u0454 \u03bd\u0454\u0142\u03b9\u0442 \u0454\u0455\u0455\u0454 \u00a2\u03b9\u0142\u0142\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f\u0454 \u0454\u03c5 \u0192\u03c5g\u03b9\u03b1\u0442 \u03b7\u03c5\u0142\u0142\u03b1 \u03c1\u03b1\u044f\u03b9\u03b1\u0442\u03c5\u044f. \u0454\u03c7\u00a2\u0454\u03c1\u0442\u0454\u03c5\u044f \u0455\u03b9\u03b7\u0442 \u03c3\u00a2\u00a2\u03b1\u0454\u00a2\u03b1\u0442 \u00a2\u03c5\u03c1\u03b9\u2202\u03b1\u0442\u03b1\u0442 \u03b7\u03c3\u03b7 \u03c1\u044f\u03c3\u03b9\u2202\u0454\u03b7\u0442, \u0455\u03c5\u03b7\u0442 \u03b9\u03b7 \u00a2\u03c5\u0142\u03c1\u03b1 q\u03c5\u03b9 \u03c3\u0192\u0192\u03b9\u00a2\u03b9\u03b1 \u2202\u0454\u0455\u0454\u044f\u03c5\u03b7\u0442 \u043c\u03c3\u0142\u0142\u03b9\u0442 \u03b1\u03b7#",
"{email} is already on the {container} team. Recheck the email address if you want to add a new member.": "{email} \u00efs \u00e4lr\u00e9\u00e4d\u00fd \u00f6n th\u00e9 {container} t\u00e9\u00e4m. R\u00e9\u00e7h\u00e9\u00e7k th\u00e9 \u00e9m\u00e4\u00efl \u00e4ddr\u00e9ss \u00eff \u00fd\u00f6\u00fc w\u00e4nt t\u00f6 \u00e4dd \u00e4 n\u00e9w m\u00e9m\u00df\u00e9r. \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455#",
- "{month}/{day}/{year} at {hour}:{minute} UTC": "{month}/{day}/{year} \u00e4t {hour}:{minute} \u00dbT\u00c7 \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455#",
"{numMoved} student was removed from {oldCohort}": [
"{numMoved} st\u00fcd\u00e9nt w\u00e4s r\u00e9m\u00f6v\u00e9d fr\u00f6m {oldCohort} \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454#",
"{numMoved} st\u00fcd\u00e9nts w\u00e9r\u00e9 r\u00e9m\u00f6v\u00e9d fr\u00f6m {oldCohort} \u2c60'\u03c3\u044f\u0454\u043c \u03b9\u03c1\u0455\u03c5\u043c \u2202\u03c3\u0142\u03c3\u044f \u0455\u03b9\u0442 \u03b1\u043c\u0454\u0442, \u00a2\u03c3\u03b7\u0455\u0454\u00a2\u0442\u0454\u0442#"
diff --git a/cms/static/js/i18n/fake2/djangojs.js b/cms/static/js/i18n/fake2/djangojs.js
index aed68ad55a..28b4763e83 100644
--- a/cms/static/js/i18n/fake2/djangojs.js
+++ b/cms/static/js/i18n/fake2/djangojs.js
@@ -301,7 +301,7 @@
"Cancel team updating.": "\u023b\u0250n\u0254\u01ddl \u0287\u01dd\u0250\u026f ndd\u0250\u0287\u1d09n\u0183.",
"Cannot delete when in use by a unit": "\u023b\u0250nn\u00f8\u0287 d\u01ddl\u01dd\u0287\u01dd \u028d\u0265\u01ddn \u1d09n ns\u01dd b\u028e \u0250 nn\u1d09\u0287",
"Cannot delete when in use by an experiment": "\u023b\u0250nn\u00f8\u0287 d\u01ddl\u01dd\u0287\u01dd \u028d\u0265\u01ddn \u1d09n ns\u01dd b\u028e \u0250n \u01ddxd\u01dd\u0279\u1d09\u026f\u01ddn\u0287",
- "Cannot drop more <% attrs.types %> than will assigned.": "\u023b\u0250nn\u00f8\u0287 d\u0279\u00f8d \u026f\u00f8\u0279\u01dd <% attrs.types %> \u0287\u0265\u0250n \u028d\u1d09ll \u0250ss\u1d09\u0183n\u01ddd.",
+ "Cannot drop more <%= types %> assignments than are assigned.": "\u023b\u0250nn\u00f8\u0287 d\u0279\u00f8d \u026f\u00f8\u0279\u01dd <%= types %> \u0250ss\u1d09\u0183n\u026f\u01ddn\u0287s \u0287\u0265\u0250n \u0250\u0279\u01dd \u0250ss\u1d09\u0183n\u01ddd.",
"Caption": "\u023b\u0250d\u0287\u1d09\u00f8n",
"Caution: The last published version of this unit is live. By publishing changes you will change the student experience.": "\u023b\u0250n\u0287\u1d09\u00f8n: \u0166\u0265\u01dd l\u0250s\u0287 dnbl\u1d09s\u0265\u01ddd \u028c\u01dd\u0279s\u1d09\u00f8n \u00f8\u025f \u0287\u0265\u1d09s nn\u1d09\u0287 \u1d09s l\u1d09\u028c\u01dd. \u0243\u028e dnbl\u1d09s\u0265\u1d09n\u0183 \u0254\u0265\u0250n\u0183\u01dds \u028e\u00f8n \u028d\u1d09ll \u0254\u0265\u0250n\u0183\u01dd \u0287\u0265\u01dd s\u0287nd\u01ddn\u0287 \u01ddxd\u01dd\u0279\u1d09\u01ddn\u0254\u01dd.",
"Cell": "\u023b\u01ddll",
@@ -385,7 +385,6 @@
"Cohorts Disabled": "\u023b\u00f8\u0265\u00f8\u0279\u0287s \u0110\u1d09s\u0250bl\u01ddd",
"Cohorts Enabled": "\u023b\u00f8\u0265\u00f8\u0279\u0287s \u0246n\u0250bl\u01ddd",
"Collapse All": "\u023b\u00f8ll\u0250ds\u01dd \u023all",
- "Collapse All Sections": "\u023b\u00f8ll\u0250ds\u01dd \u023all S\u01dd\u0254\u0287\u1d09\u00f8ns",
"Collapse Instructions": "\u023b\u00f8ll\u0250ds\u01dd \u0197ns\u0287\u0279n\u0254\u0287\u1d09\u00f8ns",
"Collapse discussion": "\u023b\u00f8ll\u0250ds\u01dd d\u1d09s\u0254nss\u1d09\u00f8n",
"Collapse/Expand this %(xblock_type)s": "\u023b\u00f8ll\u0250ds\u01dd/\u0246xd\u0250nd \u0287\u0265\u1d09s %(xblock_type)s",
@@ -550,7 +549,6 @@
"Edit Team": "\u0246d\u1d09\u0287 \u0166\u01dd\u0250\u026f",
"Edit Your Name": "\u0246d\u1d09\u0287 \u024e\u00f8n\u0279 N\u0250\u026f\u01dd",
"Edit post title": "\u0246d\u1d09\u0287 d\u00f8s\u0287 \u0287\u1d09\u0287l\u01dd",
- "Edit section release date": "\u0246d\u1d09\u0287 s\u01dd\u0254\u0287\u1d09\u00f8n \u0279\u01ddl\u01dd\u0250s\u01dd d\u0250\u0287\u01dd",
"Edit the name": "\u0246d\u1d09\u0287 \u0287\u0265\u01dd n\u0250\u026f\u01dd",
"Edit this certificate?": "\u0246d\u1d09\u0287 \u0287\u0265\u1d09s \u0254\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dd?",
"Editable": "\u0246d\u1d09\u0287\u0250bl\u01dd",
@@ -639,7 +637,6 @@
"Exception Granted": "\u0246x\u0254\u01ddd\u0287\u1d09\u00f8n \u01e4\u0279\u0250n\u0287\u01ddd",
"Exit full browser": "\u0246x\u1d09\u0287 \u025fnll b\u0279\u00f8\u028ds\u01dd\u0279",
"Expand All": "\u0246xd\u0250nd \u023all",
- "Expand All Sections": "\u0246xd\u0250nd \u023all S\u01dd\u0254\u0287\u1d09\u00f8ns",
"Expand Instructions": "\u0246xd\u0250nd \u0197ns\u0287\u0279n\u0254\u0287\u1d09\u00f8ns",
"Expand discussion": "\u0246xd\u0250nd d\u1d09s\u0254nss\u1d09\u00f8n",
"Explain if other.": "\u0246xdl\u0250\u1d09n \u1d09\u025f \u00f8\u0287\u0265\u01dd\u0279.",
@@ -1085,7 +1082,6 @@
"Release Date:": "\u024c\u01ddl\u01dd\u0250s\u01dd \u0110\u0250\u0287\u01dd:",
"Release Status:": "\u024c\u01ddl\u01dd\u0250s\u01dd S\u0287\u0250\u0287ns:",
"Release Time in UTC:": "\u024c\u01ddl\u01dd\u0250s\u01dd \u0166\u1d09\u026f\u01dd \u1d09n \u0244\u0166\u023b:",
- "Release date:": "\u024c\u01ddl\u01dd\u0250s\u01dd d\u0250\u0287\u01dd:",
"Release:": "\u024c\u01ddl\u01dd\u0250s\u01dd:",
"Released:": "\u024c\u01ddl\u01dd\u0250s\u01ddd:",
"Removal is in progress. To avoid errors, stay on this page until the process is complete.": "\u024c\u01dd\u026f\u00f8\u028c\u0250l \u1d09s \u1d09n d\u0279\u00f8\u0183\u0279\u01ddss. \u0166\u00f8 \u0250\u028c\u00f8\u1d09d \u01dd\u0279\u0279\u00f8\u0279s, s\u0287\u0250\u028e \u00f8n \u0287\u0265\u1d09s d\u0250\u0183\u01dd nn\u0287\u1d09l \u0287\u0265\u01dd d\u0279\u00f8\u0254\u01ddss \u1d09s \u0254\u00f8\u026fdl\u01dd\u0287\u01dd.",
@@ -1291,7 +1287,7 @@
"Task Type": "\u0166\u0250s\u029e \u0166\u028ed\u01dd",
"Task inputs": "\u0166\u0250s\u029e \u1d09ndn\u0287s",
"Teaching Assistant": "\u0166\u01dd\u0250\u0254\u0265\u1d09n\u0183 \u023ass\u1d09s\u0287\u0250n\u0287",
- "Team \"%(team)s\" successfully deleted.": "\u0166\u01dd\u0250\u026f \"%(team)s\" sn\u0254\u0254\u01ddss\u025fnll\u028e d\u01ddl\u01dd\u0287\u01ddd.",
+ "Team \"{team}\" successfully deleted.": "\u0166\u01dd\u0250\u026f \"{team}\" sn\u0254\u0254\u01ddss\u025fnll\u028e d\u01ddl\u01dd\u0287\u01ddd.",
"Team Description (Required) *": "\u0166\u01dd\u0250\u026f \u0110\u01dds\u0254\u0279\u1d09d\u0287\u1d09\u00f8n (\u024c\u01ddbn\u1d09\u0279\u01ddd) *",
"Team Details": "\u0166\u01dd\u0250\u026f \u0110\u01dd\u0287\u0250\u1d09ls",
"Team Name (Required) *": "\u0166\u01dd\u0250\u026f N\u0250\u026f\u01dd (\u024c\u01ddbn\u1d09\u0279\u01ddd) *",
@@ -1818,7 +1814,6 @@
"with %(section_or_subsection)s": "\u028d\u1d09\u0287\u0265 %(section_or_subsection)s",
"{browse_span_start}Browse teams in other topics{span_end} or {search_span_start}search teams{span_end} in this topic. If you still can't find a team to join, {create_span_start}create a new team in this topic{span_end}.": "{browse_span_start}\u0243\u0279\u00f8\u028ds\u01dd \u0287\u01dd\u0250\u026fs \u1d09n \u00f8\u0287\u0265\u01dd\u0279 \u0287\u00f8d\u1d09\u0254s{span_end} \u00f8\u0279 {search_span_start}s\u01dd\u0250\u0279\u0254\u0265 \u0287\u01dd\u0250\u026fs{span_end} \u1d09n \u0287\u0265\u1d09s \u0287\u00f8d\u1d09\u0254. \u0197\u025f \u028e\u00f8n s\u0287\u1d09ll \u0254\u0250n'\u0287 \u025f\u1d09nd \u0250 \u0287\u01dd\u0250\u026f \u0287\u00f8 \u027e\u00f8\u1d09n, {create_span_start}\u0254\u0279\u01dd\u0250\u0287\u01dd \u0250 n\u01dd\u028d \u0287\u01dd\u0250\u026f \u1d09n \u0287\u0265\u1d09s \u0287\u00f8d\u1d09\u0254{span_end}.",
"{email} is already on the {container} team. Recheck the email address if you want to add a new member.": "{email} \u1d09s \u0250l\u0279\u01dd\u0250d\u028e \u00f8n \u0287\u0265\u01dd {container} \u0287\u01dd\u0250\u026f. \u024c\u01dd\u0254\u0265\u01dd\u0254\u029e \u0287\u0265\u01dd \u01dd\u026f\u0250\u1d09l \u0250dd\u0279\u01ddss \u1d09\u025f \u028e\u00f8n \u028d\u0250n\u0287 \u0287\u00f8 \u0250dd \u0250 n\u01dd\u028d \u026f\u01dd\u026fb\u01dd\u0279.",
- "{month}/{day}/{year} at {hour}:{minute} UTC": "{month}/{day}/{year} \u0250\u0287 {hour}:{minute} \u0244\u0166\u023b",
"{numMoved} student was removed from {oldCohort}": [
"{numMoved} s\u0287nd\u01ddn\u0287 \u028d\u0250s \u0279\u01dd\u026f\u00f8\u028c\u01ddd \u025f\u0279\u00f8\u026f {oldCohort}",
"{numMoved} s\u0287nd\u01ddn\u0287s \u028d\u01dd\u0279\u01dd \u0279\u01dd\u026f\u00f8\u028c\u01ddd \u025f\u0279\u00f8\u026f {oldCohort}"
diff --git a/cms/static/js/i18n/rtl/djangojs.js b/cms/static/js/i18n/rtl/djangojs.js
index 99b2d8525e..43cace494c 100644
--- a/cms/static/js/i18n/rtl/djangojs.js
+++ b/cms/static/js/i18n/rtl/djangojs.js
@@ -301,7 +301,7 @@
"Cancel team updating.": "\u0630\u0634\u0631\u0630\u062b\u0645 \u0641\u062b\u0634\u0648 \u0639\u062d\u064a\u0634\u0641\u0647\u0631\u0644.",
"Cannot delete when in use by a unit": "\u0630\u0634\u0631\u0631\u062e\u0641 \u064a\u062b\u0645\u062b\u0641\u062b \u0635\u0627\u062b\u0631 \u0647\u0631 \u0639\u0633\u062b \u0632\u063a \u0634 \u0639\u0631\u0647\u0641",
"Cannot delete when in use by an experiment": "\u0630\u0634\u0631\u0631\u062e\u0641 \u064a\u062b\u0645\u062b\u0641\u062b \u0635\u0627\u062b\u0631 \u0647\u0631 \u0639\u0633\u062b \u0632\u063a \u0634\u0631 \u062b\u0637\u062d\u062b\u0642\u0647\u0648\u062b\u0631\u0641",
- "Cannot drop more <% attrs.types %> than will assigned.": "\u0630\u0634\u0631\u0631\u062e\u0641 \u064a\u0642\u062e\u062d \u0648\u062e\u0642\u062b <% attrs.types %> \u0641\u0627\u0634\u0631 \u0635\u0647\u0645\u0645 \u0634\u0633\u0633\u0647\u0644\u0631\u062b\u064a.",
+ "Cannot drop more <%= types %> assignments than are assigned.": "\u0630\u0634\u0631\u0631\u062e\u0641 \u064a\u0642\u062e\u062d \u0648\u062e\u0642\u062b <%= types %> \u0634\u0633\u0633\u0647\u0644\u0631\u0648\u062b\u0631\u0641\u0633 \u0641\u0627\u0634\u0631 \u0634\u0642\u062b \u0634\u0633\u0633\u0647\u0644\u0631\u062b\u064a.",
"Caption": "\u0630\u0634\u062d\u0641\u0647\u062e\u0631",
"Caution: The last published version of this unit is live. By publishing changes you will change the student experience.": "\u0630\u0634\u0639\u0641\u0647\u062e\u0631: \u0641\u0627\u062b \u0645\u0634\u0633\u0641 \u062d\u0639\u0632\u0645\u0647\u0633\u0627\u062b\u064a \u062f\u062b\u0642\u0633\u0647\u062e\u0631 \u062e\u0628 \u0641\u0627\u0647\u0633 \u0639\u0631\u0647\u0641 \u0647\u0633 \u0645\u0647\u062f\u062b. \u0632\u063a \u062d\u0639\u0632\u0645\u0647\u0633\u0627\u0647\u0631\u0644 \u0630\u0627\u0634\u0631\u0644\u062b\u0633 \u063a\u062e\u0639 \u0635\u0647\u0645\u0645 \u0630\u0627\u0634\u0631\u0644\u062b \u0641\u0627\u062b \u0633\u0641\u0639\u064a\u062b\u0631\u0641 \u062b\u0637\u062d\u062b\u0642\u0647\u062b\u0631\u0630\u062b.",
"Cell": "\u0630\u062b\u0645\u0645",
@@ -385,7 +385,6 @@
"Cohorts Disabled": "\u0630\u062e\u0627\u062e\u0642\u0641\u0633 \u064a\u0647\u0633\u0634\u0632\u0645\u062b\u064a",
"Cohorts Enabled": "\u0630\u062e\u0627\u062e\u0642\u0641\u0633 \u062b\u0631\u0634\u0632\u0645\u062b\u064a",
"Collapse All": "\u0630\u062e\u0645\u0645\u0634\u062d\u0633\u062b \u0634\u0645\u0645",
- "Collapse All Sections": "\u0630\u062e\u0645\u0645\u0634\u062d\u0633\u062b \u0634\u0645\u0645 \u0633\u062b\u0630\u0641\u0647\u062e\u0631\u0633",
"Collapse Instructions": "\u0630\u062e\u0645\u0645\u0634\u062d\u0633\u062b \u0647\u0631\u0633\u0641\u0642\u0639\u0630\u0641\u0647\u062e\u0631\u0633",
"Collapse discussion": "\u0630\u062e\u0645\u0645\u0634\u062d\u0633\u062b \u064a\u0647\u0633\u0630\u0639\u0633\u0633\u0647\u062e\u0631",
"Collapse/Expand this %(xblock_type)s": "\u0630\u062e\u0645\u0645\u0634\u062d\u0633\u062b/\u062b\u0637\u062d\u0634\u0631\u064a \u0641\u0627\u0647\u0633 %(xblock_type)s",
@@ -550,7 +549,6 @@
"Edit Team": "\u062b\u064a\u0647\u0641 \u0641\u062b\u0634\u0648",
"Edit Your Name": "\u062b\u064a\u0647\u0641 \u063a\u062e\u0639\u0642 \u0631\u0634\u0648\u062b",
"Edit post title": "\u062b\u064a\u0647\u0641 \u062d\u062e\u0633\u0641 \u0641\u0647\u0641\u0645\u062b",
- "Edit section release date": "\u062b\u064a\u0647\u0641 \u0633\u062b\u0630\u0641\u0647\u062e\u0631 \u0642\u062b\u0645\u062b\u0634\u0633\u062b \u064a\u0634\u0641\u062b",
"Edit the name": "\u062b\u064a\u0647\u0641 \u0641\u0627\u062b \u0631\u0634\u0648\u062b",
"Edit this certificate?": "\u062b\u064a\u0647\u0641 \u0641\u0627\u0647\u0633 \u0630\u062b\u0642\u0641\u0647\u0628\u0647\u0630\u0634\u0641\u062b?",
"Editable": "\u062b\u064a\u0647\u0641\u0634\u0632\u0645\u062b",
@@ -639,7 +637,6 @@
"Exception Granted": "\u062b\u0637\u0630\u062b\u062d\u0641\u0647\u062e\u0631 \u0644\u0642\u0634\u0631\u0641\u062b\u064a",
"Exit full browser": "\u062b\u0637\u0647\u0641 \u0628\u0639\u0645\u0645 \u0632\u0642\u062e\u0635\u0633\u062b\u0642",
"Expand All": "\u062b\u0637\u062d\u0634\u0631\u064a \u0634\u0645\u0645",
- "Expand All Sections": "\u062b\u0637\u062d\u0634\u0631\u064a \u0634\u0645\u0645 \u0633\u062b\u0630\u0641\u0647\u062e\u0631\u0633",
"Expand Instructions": "\u062b\u0637\u062d\u0634\u0631\u064a \u0647\u0631\u0633\u0641\u0642\u0639\u0630\u0641\u0647\u062e\u0631\u0633",
"Expand discussion": "\u062b\u0637\u062d\u0634\u0631\u064a \u064a\u0647\u0633\u0630\u0639\u0633\u0633\u0647\u062e\u0631",
"Explain if other.": "\u062b\u0637\u062d\u0645\u0634\u0647\u0631 \u0647\u0628 \u062e\u0641\u0627\u062b\u0642.",
@@ -1085,7 +1082,6 @@
"Release Date:": "\u0642\u062b\u0645\u062b\u0634\u0633\u062b \u064a\u0634\u0641\u062b:",
"Release Status:": "\u0642\u062b\u0645\u062b\u0634\u0633\u062b \u0633\u0641\u0634\u0641\u0639\u0633:",
"Release Time in UTC:": "\u0642\u062b\u0645\u062b\u0634\u0633\u062b \u0641\u0647\u0648\u062b \u0647\u0631 \u0639\u0641\u0630:",
- "Release date:": "\u0642\u062b\u0645\u062b\u0634\u0633\u062b \u064a\u0634\u0641\u062b:",
"Release:": "\u0642\u062b\u0645\u062b\u0634\u0633\u062b:",
"Released:": "\u0642\u062b\u0645\u062b\u0634\u0633\u062b\u064a:",
"Removal is in progress. To avoid errors, stay on this page until the process is complete.": "\u0642\u062b\u0648\u062e\u062f\u0634\u0645 \u0647\u0633 \u0647\u0631 \u062d\u0642\u062e\u0644\u0642\u062b\u0633\u0633. \u0641\u062e \u0634\u062f\u062e\u0647\u064a \u062b\u0642\u0642\u062e\u0642\u0633, \u0633\u0641\u0634\u063a \u062e\u0631 \u0641\u0627\u0647\u0633 \u062d\u0634\u0644\u062b \u0639\u0631\u0641\u0647\u0645 \u0641\u0627\u062b \u062d\u0642\u062e\u0630\u062b\u0633\u0633 \u0647\u0633 \u0630\u062e\u0648\u062d\u0645\u062b\u0641\u062b.",
@@ -1291,7 +1287,7 @@
"Task Type": "\u0641\u0634\u0633\u0646 \u0641\u063a\u062d\u062b",
"Task inputs": "\u0641\u0634\u0633\u0646 \u0647\u0631\u062d\u0639\u0641\u0633",
"Teaching Assistant": "\u0641\u062b\u0634\u0630\u0627\u0647\u0631\u0644 \u0634\u0633\u0633\u0647\u0633\u0641\u0634\u0631\u0641",
- "Team \"%(team)s\" successfully deleted.": "\u0641\u062b\u0634\u0648 \"%(team)s\" \u0633\u0639\u0630\u0630\u062b\u0633\u0633\u0628\u0639\u0645\u0645\u063a \u064a\u062b\u0645\u062b\u0641\u062b\u064a.",
+ "Team \"{team}\" successfully deleted.": "\u0641\u062b\u0634\u0648 \"{team}\" \u0633\u0639\u0630\u0630\u062b\u0633\u0633\u0628\u0639\u0645\u0645\u063a \u064a\u062b\u0645\u062b\u0641\u062b\u064a.",
"Team Description (Required) *": "\u0641\u062b\u0634\u0648 \u064a\u062b\u0633\u0630\u0642\u0647\u062d\u0641\u0647\u062e\u0631 (\u0642\u062b\u0636\u0639\u0647\u0642\u062b\u064a) *",
"Team Details": "\u0641\u062b\u0634\u0648 \u064a\u062b\u0641\u0634\u0647\u0645\u0633",
"Team Name (Required) *": "\u0641\u062b\u0634\u0648 \u0631\u0634\u0648\u062b (\u0642\u062b\u0636\u0639\u0647\u0642\u062b\u064a) *",
@@ -1818,7 +1814,6 @@
"with %(section_or_subsection)s": "\u0635\u0647\u0641\u0627 %(section_or_subsection)s",
"{browse_span_start}Browse teams in other topics{span_end} or {search_span_start}search teams{span_end} in this topic. If you still can't find a team to join, {create_span_start}create a new team in this topic{span_end}.": "{browse_span_start}\u0632\u0642\u062e\u0635\u0633\u062b \u0641\u062b\u0634\u0648\u0633 \u0647\u0631 \u062e\u0641\u0627\u062b\u0642 \u0641\u062e\u062d\u0647\u0630\u0633{span_end} \u062e\u0642 {search_span_start}\u0633\u062b\u0634\u0642\u0630\u0627 \u0641\u062b\u0634\u0648\u0633{span_end} \u0647\u0631 \u0641\u0627\u0647\u0633 \u0641\u062e\u062d\u0647\u0630. \u0647\u0628 \u063a\u062e\u0639 \u0633\u0641\u0647\u0645\u0645 \u0630\u0634\u0631'\u0641 \u0628\u0647\u0631\u064a \u0634 \u0641\u062b\u0634\u0648 \u0641\u062e \u062a\u062e\u0647\u0631, {create_span_start}\u0630\u0642\u062b\u0634\u0641\u062b \u0634 \u0631\u062b\u0635 \u0641\u062b\u0634\u0648 \u0647\u0631 \u0641\u0627\u0647\u0633 \u0641\u062e\u062d\u0647\u0630{span_end}.",
"{email} is already on the {container} team. Recheck the email address if you want to add a new member.": "{email} \u0647\u0633 \u0634\u0645\u0642\u062b\u0634\u064a\u063a \u062e\u0631 \u0641\u0627\u062b {container} \u0641\u062b\u0634\u0648. \u0642\u062b\u0630\u0627\u062b\u0630\u0646 \u0641\u0627\u062b \u062b\u0648\u0634\u0647\u0645 \u0634\u064a\u064a\u0642\u062b\u0633\u0633 \u0647\u0628 \u063a\u062e\u0639 \u0635\u0634\u0631\u0641 \u0641\u062e \u0634\u064a\u064a \u0634 \u0631\u062b\u0635 \u0648\u062b\u0648\u0632\u062b\u0642.",
- "{month}/{day}/{year} at {hour}:{minute} UTC": "{month}/{day}/{year} \u0634\u0641 {hour}:{minute} \u0639\u0641\u0630",
"{numMoved} student was removed from {oldCohort}": [
"{numMoved} \u0633\u0641\u0639\u064a\u062b\u0631\u0641 \u0635\u0634\u0633 \u0642\u062b\u0648\u062e\u062f\u062b\u064a \u0628\u0642\u062e\u0648 {oldCohort}",
"{numMoved} \u0633\u0641\u0639\u064a\u062b\u0631\u0641\u0633 \u0635\u062b\u0642\u062b \u0642\u062b\u0648\u062e\u062f\u062b\u064a \u0628\u0642\u062e\u0648 {oldCohort}"
diff --git a/cms/static/js/i18n/ru/djangojs.js b/cms/static/js/i18n/ru/djangojs.js
index ec6859d4b8..8a2c109a24 100644
--- a/cms/static/js/i18n/ru/djangojs.js
+++ b/cms/static/js/i18n/ru/djangojs.js
@@ -649,6 +649,7 @@
"Error deleting entrance exam state for student '{student_id}'. Make sure student identifier is correct.": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u0432\u0441\u0442\u0443\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u044f \u0434\u043b\u044f '{student_id}'. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.",
"Error deleting student '<%= student_id %>'s state on problem '<%= problem_id %>'. Make sure that the problem and student identifiers are complete and correct.": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f '<%= problem_id %>' \u0434\u043b\u044f '<%= student_id %>'. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u0438 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044f \u0432\u0432\u0435\u0434\u0435\u043d\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0438 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e.",
"Error enrolling/unenrolling users.": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438/\u043e\u0442\u043c\u0435\u043d\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439:",
+ "Error generating ORA data report. Please try again.": "\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043e\u0442\u0447\u0435\u0442\u0430 \u043f\u043e \u0437\u0430\u0434\u0430\u043d\u0438\u044e \u0441 \u043e\u0442\u0432\u0435\u0442\u0430\u043c\u0438 \u0432 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437.",
"Error generating grades. Please try again.": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0440\u0430\u0441\u0447\u0451\u0442\u0430 \u043e\u0446\u0435\u043d\u043e\u043a. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437.",
"Error generating list of students who may enroll. Please try again.": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043a\u0443\u0440\u0441. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437.",
"Error generating problem grade report. Please try again.": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0433\u043e \u043e\u0446\u0435\u043d\u043e\u0447\u043d\u043e\u0433\u043e \u043b\u0438\u0441\u0442\u0430. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437.",
diff --git a/cms/static/js/models/settings/course_grader.js b/cms/static/js/models/settings/course_grader.js
index 7f7716eb8b..f31e832bac 100644
--- a/cms/static/js/models/settings/course_grader.js
+++ b/cms/static/js/models/settings/course_grader.js
@@ -66,9 +66,10 @@ var CourseGrader = Backbone.Model.extend({
else attrs.drop_count = intDropCount;
}
if (_.has(attrs, 'min_count') && _.has(attrs, 'drop_count') && !_.has(errors, 'min_count') && !_.has(errors, 'drop_count') && attrs.drop_count > attrs.min_count) {
- errors.drop_count = _.template(
- gettext("Cannot drop more <% attrs.types %> than will assigned."),
- attrs, {variable: 'attrs'});
+ var template = _.template(
+ gettext("Cannot drop more <%= types %> assignments than are assigned.")
+ );
+ errors.drop_count = template({types: attrs.type});
}
if (!_.isEmpty(errors)) return errors;
}
diff --git a/cms/static/js/models/uploads.js b/cms/static/js/models/uploads.js
index 7a19b3c4bd..6eaf020f60 100644
--- a/cms/static/js/models/uploads.js
+++ b/cms/static/js/models/uploads.js
@@ -15,8 +15,7 @@ var FileUpload = Backbone.Model.extend({
validate: function(attrs, options) {
if(attrs.selectedFile && !this.checkTypeValidity(attrs.selectedFile)) {
return {
- message: _.template(
- gettext("Only <%= fileTypes %> files can be uploaded. Please select a file ending in <%= fileExtensions %> to upload."),
+ message: _.template(gettext("Only <%= fileTypes %> files can be uploaded. Please select a file ending in <%= fileExtensions %> to upload."))( // jshint ignore:line
this.formatValidTypes()
),
attributes: {selectedFile: true}
@@ -64,7 +63,7 @@ var FileUpload = Backbone.Model.extend({
}
var or = gettext('or');
var formatTypes = function(types) {
- return _.template('<%= initial %> <%= or %> <%= last %>', {
+ return _.template('<%= initial %> <%= or %> <%= last %>')({
initial: _.initial(types).join(', '),
or: or,
last: _.last(types)
diff --git a/cms/static/js/utils/drag_and_drop.js b/cms/static/js/utils/drag_and_drop.js
index 6228a32019..1393c870a3 100644
--- a/cms/static/js/utils/drag_and_drop.js
+++ b/cms/static/js/utils/drag_and_drop.js
@@ -359,12 +359,12 @@ define(["jquery", "jquery.ui", "underscore", "gettext", "draggabilly",
makeDraggable: function (element, options) {
var draggable;
options = _.defaults({
- type: null,
- handleClass: null,
- droppableClass: null,
- parentLocationSelector: null,
- refresh: null,
- ensureChildrenRendered: null
+ type: undefined,
+ handleClass: undefined,
+ droppableClass: undefined,
+ parentLocationSelector: undefined,
+ refresh: undefined,
+ ensureChildrenRendered: undefined
}, options);
if ($(element).data('droppable-class') !== options.droppableClass) {
diff --git a/cms/static/js/views/assets.js b/cms/static/js/views/assets.js
index 0a1c4967eb..f9694096d3 100644
--- a/cms/static/js/views/assets.js
+++ b/cms/static/js/views/assets.js
@@ -67,7 +67,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/models/asset
ViewUtils.hideLoadingIndicator();
// Create the table
- this.$el.html(_.template(asset_library_template, {typeData: this.typeData}));
+ this.$el.html(_.template(asset_library_template)({typeData: this.typeData}));
tableBody = this.$('#asset-table-body');
this.tableBody = tableBody;
this.pagingHeader = new PagingHeader({view: this, el: $('#asset-paging-header')});
diff --git a/cms/static/js/views/content_group_details.js b/cms/static/js/views/content_group_details.js
index 4357b04aaa..4b6ed76820 100644
--- a/cms/static/js/views/content_group_details.js
+++ b/cms/static/js/views/content_group_details.js
@@ -75,18 +75,18 @@ define([
},
getOutlineAnchorMessage: function () {
- var message = gettext(
+ var message = _.escape(gettext(
/*
Translators: 'outlineAnchor' is an anchor pointing to
the course outline page.
*/
'This content group is not in use. Add a content group to any unit from the %(outlineAnchor)s.'
- ),
+ )),
anchor = str.sprintf(
'%(text)s',
{
url: this.model.collection.parents[0].outlineUrl,
- text: gettext('Course Outline')
+ text: _.escape(gettext('Course Outline'))
}
);
diff --git a/cms/static/js/views/edit_chapter.js b/cms/static/js/views/edit_chapter.js
index f70839c2d4..895e932f34 100644
--- a/cms/static/js/views/edit_chapter.js
+++ b/cms/static/js/views/edit_chapter.js
@@ -1,3 +1,5 @@
+/*global course */
+
define(["js/views/baseview", "underscore", "underscore.string", "jquery", "gettext", "js/models/uploads", "js/views/uploads"],
function(BaseView, _, str, $, gettext, FileUploadModel, UploadDialogView) {
_.str = str; // used in template
@@ -52,10 +54,8 @@ define(["js/views/baseview", "underscore", "underscore.string", "jquery", "gette
asset_path: this.$("input.chapter-asset-path").val()
});
var msg = new FileUploadModel({
- title: _.template(
- gettext("Upload a new PDF to “<%= name %>”"),
- {name: window.course.escape('name')}
- ),
+ title: _.template(gettext("Upload a new PDF to “<%= name %>”"))(
+ {name: course.escape('name')}),
message: gettext("Please select a PDF file to upload."),
mimeTypes: ['application/pdf']
});
diff --git a/cms/static/js/views/manage_users_and_roles.js b/cms/static/js/views/manage_users_and_roles.js
index dc22023158..f9d154696e 100644
--- a/cms/static/js/views/manage_users_and_roles.js
+++ b/cms/static/js/views/manage_users_and_roles.js
@@ -54,8 +54,8 @@ define(['jquery', 'underscore', 'gettext', "js/views/baseview",
title: messages.alreadyMember.title,
message: _.template(
messages.alreadyMember.messageTpl,
- {email: email, container: containerName},
- {interpolate: /\{(.+?)}/g}
+ {interpolate: /\{(.+?)}/g})(
+ {email: email, container: containerName}
),
actions: {
primary: {
@@ -140,7 +140,9 @@ define(['jquery', 'underscore', 'gettext', "js/views/baseview",
roles = _.object(_.pluck(this.roles, 'key'), _.pluck(this.roles, "name")),
adminRoleCount = this.getAdminRoleCount(),
viewHelpers = {
- format: function (template, data) { return _.template(template, data, {interpolate: /\{(.+?)}/g}); }
+ format: function (template, data) {
+ return _.template(template, {interpolate: /\{(.+?)}/g})(data);
+ }
};
for (var i = 0; i < this.users.length; i++) {
var user = this.users[i],
@@ -284,8 +286,8 @@ define(['jquery', 'underscore', 'gettext', "js/views/baseview",
title: self.messages.deleteUser.title,
message: _.template(
self.messages.deleteUser.messageTpl,
- {email: email, container: self.containerName},
- {interpolate: /\{(.+?)}/g}
+ {interpolate: /\{(.+?)}/g})(
+ {email: email, container: self.containerName}
),
actions: {
primary: {
diff --git a/cms/static/js/views/overview.js b/cms/static/js/views/overview.js
deleted file mode 100644
index 12e6728063..0000000000
--- a/cms/static/js/views/overview.js
+++ /dev/null
@@ -1,242 +0,0 @@
-define(["domReady", "jquery", "jquery.ui", "underscore", "gettext", "common/js/components/views/feedback_notification",
- "js/utils/cancel_on_escape", "js/utils/date_utils", "js/utils/module", "common/js/components/utils/view_utils"],
- function (domReady, $, ui, _, gettext, NotificationView, CancelOnEscape,
- DateUtils, ModuleUtils, ViewUtils) {
-
- var modalSelector = '.edit-section-publish-settings';
-
- var toggleSections = function(e) {
- e.preventDefault();
-
- var $section = $('.courseware-section');
- var $button = $(this);
- var $labelCollapsed = $(' ' +
- gettext('Collapse All Sections') + '');
- var $labelExpanded = $(' ' +
- gettext('Expand All Sections') + '');
-
- var buttonLabel = $button.hasClass('is-activated') ? $labelCollapsed : $labelExpanded;
- $button.toggleClass('is-activated').html(buttonLabel);
-
- if ($button.hasClass('is-activated')) {
- $section.addClass('collapsed');
- // first child in order to avoid the icons on the subsection lists which are not in the first child
- $section.find('header .expand-collapse').removeClass('collapse').addClass('expand');
- } else {
- $section.removeClass('collapsed');
- // first child in order to avoid the icons on the subsection lists which are not in the first child
- $section.find('header .expand-collapse').removeClass('expand').addClass('collapse');
- }
- };
-
- var toggleSubmodules = function(e) {
- e.preventDefault();
- $(this).toggleClass('expand collapse');
- $(this).closest('.is-collapsible, .window').toggleClass('collapsed');
- };
-
-
- var closeModalNew = function (e) {
- if (e) {
- e.preventDefault();
- }
- $('body').removeClass('modal-window-is-shown');
- $('.edit-section-publish-settings').removeClass('is-shown');
- };
-
- var editSectionPublishDate = function (e) {
- e.preventDefault();
- var $modal = $(modalSelector);
- $modal.attr('data-locator', $(this).attr('data-locator'));
- $modal.find('.start-date').val($(this).attr('data-date'));
- $modal.find('.start-time').val($(this).attr('data-time'));
- if ($modal.find('.start-date').val() == '' && $modal.find('.start-time').val() == '') {
- $modal.find('.save-button').hide();
- }
- $modal.find('.section-name').html('"' + $(this).closest('.courseware-section').find('.section-name-span').text() + '"');
- $('body').addClass('modal-window-is-shown');
- $('.edit-section-publish-settings').addClass('is-shown');
- };
-
- var saveSetSectionScheduleDate = function (e) {
- e.preventDefault();
-
- var datetime = DateUtils.getDate(
- $('.edit-section-publish-settings .start-date'),
- $('.edit-section-publish-settings .start-time')
- );
-
- var locator = $(modalSelector).attr('data-locator');
-
- analytics.track('Edited Section Release Date', {
- 'course': course_location_analytics,
- 'id': locator,
- 'start': datetime
- });
-
- var saving = new NotificationView.Mini({
- title: gettext("Saving")
- });
- saving.show();
- // call into server to commit the new order
- $.ajax({
- url: ModuleUtils.getUpdateUrl(locator),
- type: "PUT",
- dataType: "json",
- contentType: "application/json",
- data: JSON.stringify({
- 'metadata': {
- 'start': datetime
- }
- })
- }).success(function() {
- var pad2 = function(number) {
- // pad a number to two places: useful for formatting months, days, hours, etc
- // when displaying a date/time
- return (number < 10 ? '0' : '') + number;
- };
-
- var $thisSection = $('.courseware-section[data-locator="' + locator + '"]');
- var html = _.template(
- '' +
- '' + gettext("Release date:") + ' ' +
- gettext("{month}/{day}/{year} at {hour}:{minute} UTC") +
- '' +
- '' +
- gettext("Edit section release date") +
- '',
- {year: datetime.getUTCFullYear(), month: pad2(datetime.getUTCMonth() + 1), day: pad2(datetime.getUTCDate()),
- hour: pad2(datetime.getUTCHours()), minute: pad2(datetime.getUTCMinutes()),
- locator: locator},
- {interpolate: /\{(.+?)\}/g});
- $thisSection.find('.section-published-date').html(html);
- saving.hide();
- closeModalNew();
- });
- };
-
- var addNewSection = function (e) {
- e.preventDefault();
-
- $(e.target).addClass('disabled');
-
- var $newSection = $($('#new-section-template').html());
- var $cancelButton = $newSection.find('.new-section-name-cancel');
- $('.courseware-overview').prepend($newSection);
- $newSection.find('.new-section-name').focus().select();
- $newSection.find('.section-name-form').bind('submit', saveNewSection);
- $cancelButton.bind('click', cancelNewSection);
- CancelOnEscape($cancelButton);
- };
-
- var saveNewSection = function (e) {
- e.preventDefault();
-
- var $saveButton = $(this).find('.new-section-name-save');
- var parent = $saveButton.data('parent');
- var category = $saveButton.data('category');
- var display_name = $(this).find('.new-section-name').val();
-
- analytics.track('Created a Section', {
- 'course': course_location_analytics,
- 'display_name': display_name
- });
-
- $.postJSON(ModuleUtils.getUpdateUrl(), {
- 'parent_locator': parent,
- 'category': category,
- 'display_name': display_name
- },
-
- function(data) {
- if (data.locator != undefined) location.reload();
- });
- };
-
- var cancelNewSection = function (e) {
- e.preventDefault();
- $('.new-courseware-section-button').removeClass('disabled');
- $(this).parents('section.new-section').remove();
- };
-
- var addNewSubsection = function (e) {
- e.preventDefault();
- var $section = $(this).closest('.courseware-section');
- var $newSubsection = $($('#new-subsection-template').html());
- $section.find('.subsection-list > ol').append($newSubsection);
- $section.find('.new-subsection-name-input').focus().select();
-
- var $saveButton = $newSubsection.find('.new-subsection-name-save');
- var $cancelButton = $newSubsection.find('.new-subsection-name-cancel');
-
- var parent = $(this).parents("section.courseware-section").data("locator");
-
- $saveButton.data('parent', parent);
- $saveButton.data('category', $(this).data('category'));
-
- $newSubsection.find('.new-subsection-form').bind('submit', saveNewSubsection);
- $cancelButton.bind('click', cancelNewSubsection);
- CancelOnEscape($cancelButton);
- };
-
- var saveNewSubsection = function (e) {
- e.preventDefault();
-
- var parent = $(this).find('.new-subsection-name-save').data('parent');
- var category = $(this).find('.new-subsection-name-save').data('category');
- var display_name = $(this).find('.new-subsection-name-input').val();
-
- analytics.track('Created a Subsection', {
- 'course': course_location_analytics,
- 'display_name': display_name
- });
-
-
- $.postJSON(ModuleUtils.getUpdateUrl(), {
- 'parent_locator': parent,
- 'category': category,
- 'display_name': display_name
- },
-
- function(data) {
- if (data.locator != undefined) {
- location.reload();
- }
- });
- };
-
- var cancelNewSubsection = function (e) {
- e.preventDefault();
- $(this).parents('li.courseware-subsection').remove();
- };
-
-
-
- domReady(function() {
- // toggling overview section details
- $(function() {
- if ($('.courseware-section').length > 0) {
- $('.toggle-button-sections').addClass('is-shown');
- }
- });
- $('.toggle-button-sections').bind('click', toggleSections);
- $('.expand-collapse').bind('click', toggleSubmodules);
-
- $('.dismiss-button').bind('click', ViewUtils.deleteNotificationHandler(function () {
- $('.wrapper-alert-announcement').remove();
- }));
-
- var $body = $('body');
- $body.on('click', '.section-published-date .edit-release-date', editSectionPublishDate);
- $body.on('click', '.edit-section-publish-settings .action-save', saveSetSectionScheduleDate);
- $body.on('click', '.edit-section-publish-settings .action-cancel', closeModalNew);
-
- $('.new-courseware-section-button').bind('click', addNewSection);
- $('.new-subsection-item').bind('click', addNewSubsection);
-
- });
-
- return {
- saveSetSectionScheduleDate: saveSetSectionScheduleDate
- };
- });
diff --git a/cms/static/js/views/paging_header.js b/cms/static/js/views/paging_header.js
index 25c23acf48..662faf2139 100644
--- a/cms/static/js/views/paging_header.js
+++ b/cms/static/js/views/paging_header.js
@@ -22,9 +22,7 @@ define(["underscore", "backbone", "gettext", "text!templates/paging-header.under
currentPage = collection.currentPage,
lastPage = collection.totalPages - 1,
messageHtml = this.messageHtml();
- this.$el.html(_.template(paging_header_template, {
- messageHtml: messageHtml
- }));
+ this.$el.html(_.template(paging_header_template)({ messageHtml: messageHtml}));
this.$(".previous-page-link").toggleClass("is-disabled", currentPage === 0).attr('aria-disabled', currentPage === 0);
this.$(".next-page-link").toggleClass("is-disabled", currentPage === lastPage).attr('aria-disabled', currentPage === lastPage);
return this;
diff --git a/cms/static/js/views/show_textbook.js b/cms/static/js/views/show_textbook.js
index 2dcc470154..9f0ecd316a 100644
--- a/cms/static/js/views/show_textbook.js
+++ b/cms/static/js/views/show_textbook.js
@@ -27,10 +27,9 @@ define(["js/views/baseview", "underscore", "gettext", "common/js/components/view
},
confirmDelete: function(e) {
if(e && e.preventDefault) { e.preventDefault(); }
- var textbook = this.model, collection = this.model.collection;
- var msg = new PromptView.Warning({
- title: _.template(
- gettext("Delete “<%= name %>”?"),
+ var textbook = this.model;
+ new PromptView.Warning({
+ title: _.template(gettext("Delete “<%= name %>”?"))(
{name: textbook.get('name')}
),
message: gettext("Deleting a textbook cannot be undone and once deleted any reference to it in your courseware's navigation will also be removed."),
diff --git a/cms/static/js/views/video/transcripts/file_uploader.js b/cms/static/js/views/video/transcripts/file_uploader.js
index 77e967ce92..41f69dd3b7 100644
--- a/cms/static/js/views/video/transcripts/file_uploader.js
+++ b/cms/static/js/views/video/transcripts/file_uploader.js
@@ -18,7 +18,9 @@ function($, Backbone, _, Utils) {
uploadTpl: '#file-upload',
initialize: function () {
- _.bindAll(this);
+ _.bindAll(this,
+ 'changeHandler', 'clickHandler', 'xhrResetProgressBar', 'xhrProgressHandler', 'xhrCompleteHandler'
+ );
this.file = false;
this.render();
diff --git a/cms/static/js/views/video/transcripts/message_manager.js b/cms/static/js/views/video/transcripts/message_manager.js
index ef15c9d304..d405b713e2 100644
--- a/cms/static/js/views/video/transcripts/message_manager.js
+++ b/cms/static/js/views/video/transcripts/message_manager.js
@@ -29,7 +29,9 @@ function($, Backbone, _, Utils, FileUploader, gettext) {
},
initialize: function () {
- _.bindAll(this);
+ _.bindAll(this,
+ 'importHandler', 'replaceHandler', 'chooseHandler', 'useExistingHandler', 'showError', 'hideError'
+ );
this.component_locator = this.$el.closest('[data-locator]').data('locator');
diff --git a/cms/static/js_test.yml b/cms/static/js_test.yml
index 25f2adc05c..42685123a5 100644
--- a/cms/static/js_test.yml
+++ b/cms/static/js_test.yml
@@ -35,7 +35,7 @@ lib_paths:
- xmodule_js/common_static/js/vendor/jquery-ui.min.js
- xmodule_js/common_static/js/vendor/jquery.cookie.js
- xmodule_js/common_static/js/vendor/jquery.simulate.js
- - xmodule_js/common_static/js/vendor/underscore-min.js
+ - xmodule_js/common_static/common/js/vendor/underscore.js
- xmodule_js/common_static/js/vendor/underscore.string.min.js
- xmodule_js/common_static/js/vendor/backbone-min.js
- xmodule_js/common_static/js/vendor/backbone-associations-min.js
@@ -78,6 +78,8 @@ src_paths:
- js/certificates
- js/factories
- common/js
+ - edx-pattern-library/js
+ - edx-ui-toolkit/js
# Paths to spec (test) JavaScript files
# We should define the custom path mapping in /coffee/spec/main.coffee as well e.g. certificates etc.
diff --git a/cms/static/js_test_squire.yml b/cms/static/js_test_squire.yml
index 122505d073..62a93331f2 100644
--- a/cms/static/js_test_squire.yml
+++ b/cms/static/js_test_squire.yml
@@ -34,7 +34,7 @@ lib_paths:
- xmodule_js/common_static/js/vendor/jquery.min.js
- xmodule_js/common_static/js/vendor/jquery-ui.min.js
- xmodule_js/common_static/js/vendor/jquery.cookie.js
- - xmodule_js/common_static/js/vendor/underscore-min.js
+ - xmodule_js/common_static/common/js/vendor/underscore.js
- xmodule_js/common_static/js/vendor/underscore.string.min.js
- xmodule_js/common_static/js/vendor/backbone-min.js
- xmodule_js/common_static/js/vendor/backbone-associations-min.js
@@ -73,6 +73,8 @@ src_paths:
- js/utils
- js/views
- common/js
+ - edx-pattern-library/js
+ - edx-ui-toolkit/js
# Paths to spec (test) JavaScript files
spec_paths:
diff --git a/cms/templates/404.html b/cms/templates/404.html
index 455bd5ce14..8753d39ee1 100644
--- a/cms/templates/404.html
+++ b/cms/templates/404.html
@@ -1,4 +1,8 @@
-<%! from django.utils.translation import ugettext as _ %>
+<%page expression_filter="h"/>
+<%!
+from django.utils.translation import ugettext as _
+from openedx.core.djangolib.markup import Text, HTML
+%>
<%inherit file="base.html" />
<%block name="title">${_("Page Not Found")}%block>
<%block name="bodyclass">view-util util-404%block>
@@ -11,12 +15,14 @@
${_("Page not found")}
-
${_('The page that you were looking for was not found.')}
- ${_('Go back to the {homepage} or let us know about any pages that may have been moved at {email}.').format(
- homepage='homepage',
- email=u'{address}'.format(
- address=settings.TECH_SUPPORT_EMAIL,
- ))}
+
+ ${_('The page that you were looking for was not found.')}
+ ${Text(_('Go back to the {homepage} or let us know about any pages that may have been moved at {email}.')).format(
+ homepage=HTML('homepage'),
+ email=HTML('{address}'.format(
+ address=Text(settings.TECH_SUPPORT_EMAIL)
+ ))
+ )}
diff --git a/cms/templates/500.html b/cms/templates/500.html
index 31ec1dd958..6b77cda024 100644
--- a/cms/templates/500.html
+++ b/cms/templates/500.html
@@ -1,6 +1,14 @@
-<%! from django.utils.translation import ugettext as _ %>
+<%page expression_filter="h"/>
+<%!
+from openedx.core.djangolib.markup import Text, HTML
+from django.utils.translation import ugettext as _
+%>
<%inherit file="base.html" />
-<%block name="title">${_("{studio_name} Server Error").format(studio_name=settings.STUDIO_SHORT_NAME)}%block>
+<%block name="title">
+${Text(_("{studio_name} Server Error")).format(
+ studio_name=Text(settings.STUDIO_SHORT_NAME)
+)}
+%block>
<%block name="bodyclass">view-util util-500%block>
<%block name="content">
@@ -8,20 +16,24 @@
- ${_("An error occurred in {studio_name} and the page could not be loaded. Please try again in a few moments.").format(studio_name=settings.STUDIO_SHORT_NAME)}
+ ${Text(_("An error occurred in {studio_name} and the page could not be loaded. Please try again in a few moments.")).format(
+ studio_name=Text(settings.STUDIO_SHORT_NAME),
+ )}
${_("We've logged the error and our staff is currently working to resolve this error as soon as possible.")}
- ${_('If the problem persists, please email us at {email_link}.').format(
- email_link=u'{email_address}'.format(
- email_address=settings.TECH_SUPPORT_EMAIL,
- )
- )}
+ ${Text(_(u'If the problem persists, please email us at {email_link}.')).format(
+ email_link=HTML(u'{email_address}'.format(
+ email_address=Text(settings.TECH_SUPPORT_EMAIL),
+ ))
+ )}
diff --git a/cms/templates/activation_complete.html b/cms/templates/activation_complete.html
index 135f15764d..fa39f13ac8 100644
--- a/cms/templates/activation_complete.html
+++ b/cms/templates/activation_complete.html
@@ -1,10 +1,18 @@
-<%! from django.utils.translation import ugettext as _ %>
+<%!
+from openedx.core.djangolib.markup import Text
+from django.utils.translation import ugettext as _
+%>
+<%page expression_filter="h"/>
<%inherit file="base.html" />
<%block name="content">
${_("Thank you for activating your account. You may now sign in and start using {studio_name} to author courses.").format(studio_name=settings.STUDIO_NAME)}
+
+ ${Text(_("Thank you for activating your account. You may now sign in and start using {studio_name} to author courses.")).format(
+ studio_name=Text(settings.STUDIO_NAME)
+ )}
+
${_("We're sorry. Something went wrong with your activation. Check to make sure the URL you went to was correct, as e-mail programs will sometimes split it into two lines.")}
-
${_("If you still have issues, contact {platform_name} Support. In the meantime, you can also return to {link_start}the {studio_name} homepage.{link_end}").format(
- platform_name=settings.PLATFORM_NAME, studio_name=settings.STUDIO_NAME,
- link_start='', link_end=""
- )}
+
+ ${Text(_("If you still have issues, contact {platform_name} Support. In the meantime, you can also return to {link_start}the {studio_name} homepage.{link_end}")).format(
+ platform_name=Text(settings.PLATFORM_NAME),
+ studio_name=Text(settings.STUDIO_NAME),
+ link_start=HTML(''),
+ link_end=HTML('')
+ )}
+
<%= _.template(
- ngettext(
- "There was {strong_start}{num_errors} validation error{strong_end} while trying to save the course settings in the database.",
- "There were {strong_start}{num_errors} validation errors{strong_end} while trying to save the course settings in the database.",
- num_errors
- ),
- {
- strong_start:'',
- num_errors: num_errors,
- strong_end: ''
- },
- {interpolate: /\{(.+?)\}/g})%>
+ ngettext(
+ "There was {strong_start}{num_errors} validation error{strong_end} while trying to save the course settings in the database.",
+ "There were {strong_start}{num_errors} validation errors{strong_end} while trying to save the course settings in the database.",
+ num_errors
+ ),
+ {interpolate: /\{(.+?)\}/g})(
+ {
+ strong_start:'',
+ num_errors: num_errors,
+ strong_end: ''
+ })%>
<%= gettext("Please check the following validation feedbacks and reflect them in your course settings:")%>
${_("You were most recently in {section_link}. If you\'re done with that, choose another section on the left.").format(
- section_link=u'{section_name}'.format(
+
${Text(_("You were most recently in {section_link}. If you're done with that, choose another section on the left.")).format(
+ section_link=HTML('{section_name}').format(
url=prev_section_url,
- section_name=prev_section.display_name_with_default_escaped,
+ section_name=prev_section.display_name_with_default,
)
)}
- ${_(u"Congratulations! You are eligible to receive course credit for successfully completing your {platform_name} course! {link_start}Get your credit now.{link_end}").format(
- link_start=u''.format(
- dashboard_url=dashboard_link
- ),
- link_end=u'',
- platform_name=settings.PLATFORM_NAME
- )}
+
+ % if providers:
+ ${_(u"Congratulations! You are eligible to receive course credit from {providers} for successfully completing your {platform_name} course! {link_start}Get your credit now.{link_end}").format(
+ link_start=u''.format(
+ dashboard_url=dashboard_link
+ ),
+ link_end=u'',
+ platform_name=settings.PLATFORM_NAME,
+ providers=providers
+ )}
+ % else:
+ ${_(u"Congratulations! You are eligible to receive course credit for successfully completing your {platform_name} course! {link_start}Get your credit now.{link_end}").format(
+ link_start=u''.format(
+ dashboard_url=dashboard_link
+ ),
+ link_end=u'',
+ platform_name=settings.PLATFORM_NAME
+ )}
+ % endif
diff --git a/lms/templates/credit_notifications/credit_eligibility_email.txt b/lms/templates/credit_notifications/credit_eligibility_email.txt
index c0e6284497..76b794652d 100644
--- a/lms/templates/credit_notifications/credit_eligibility_email.txt
+++ b/lms/templates/credit_notifications/credit_eligibility_email.txt
@@ -5,7 +5,11 @@ ${_(u"Hi {name},").format(name=full_name)}
${_(u"Hi,")}
% endif
-${_(u"Congratulations! You are eligible to receive course credit for successfully completing your edX course!")}
+% if providers:
+ ${_(u"Congratulations! You are eligible to receive course credit from {providers} for successfully completing your edX course!").format(providers=providers)}
+% else:
+ ${_(u"Congratulations! You are eligible to receive course credit for successfully completing your edX course!")}
+% endif
${_(u"Click on the link below to get your credit now:")}
diff --git a/lms/templates/dashboard/_dashboard_certificate_information.html b/lms/templates/dashboard/_dashboard_certificate_information.html
index 13109ea82e..a07acf823f 100644
--- a/lms/templates/dashboard/_dashboard_certificate_information.html
+++ b/lms/templates/dashboard/_dashboard_certificate_information.html
@@ -1,7 +1,8 @@
-<%page args="cert_status, course_overview, enrollment" />
+<%page expression_filter="h" args="cert_status, course_overview, enrollment" />
<%!
from django.utils.translation import ugettext as _
+from openedx.core.djangolib.markup import Text, HTML
from course_modes.models import CourseMode
%>
<%namespace name='static' file='../static_content.html'/>
@@ -41,11 +42,11 @@ else:
${"{0:.0f}%".format(float(course_overview.lowest_passing_grade)*100)}.
% elif cert_status['status'] == 'restricted' and enrollment.mode == 'verified':
- ${_("Your verified {cert_name_long} is being held pending confirmation that the issuance of your {cert_name_short} is in compliance with strict U.S. embargoes on Iran, Cuba, Syria and Sudan. If you think our system has mistakenly identified you as being connected with one of those countries, please let us know by contacting {email}. If you would like a refund on your {cert_name_long}, please contact our billing address {billing_email}").format(email='{email}.'.format(email=settings.CONTACT_EMAIL), billing_email='{email}'.format(email=settings.PAYMENT_SUPPORT_EMAIL), cert_name_short=cert_name_short, cert_name_long=cert_name_long)}
+ ${Text(_("Your verified {cert_name_long} is being held pending confirmation that the issuance of your {cert_name_short} is in compliance with strict U.S. embargoes on Iran, Cuba, Syria and Sudan. If you think our system has mistakenly identified you as being connected with one of those countries, please let us know by contacting {email}. If you would like a refund on your {cert_name_long}, please contact our billing address {billing_email}")).format(email=HTML('{email}.').format(email=settings.CONTACT_EMAIL), billing_email=HTML('{email}').format(email=settings.PAYMENT_SUPPORT_EMAIL), cert_name_short=cert_name_short, cert_name_long=cert_name_long)}
% elif cert_status['status'] == 'restricted':
- ${_("Your {cert_name_long} is being held pending confirmation that the issuance of your {cert_name_short} is in compliance with strict U.S. embargoes on Iran, Cuba, Syria and Sudan. If you think our system has mistakenly identified you as being connected with one of those countries, please let us know by contacting {email}.").format(email='{email}.'.format(email=settings.CONTACT_EMAIL), cert_name_short=cert_name_short, cert_name_long=cert_name_long)}
+ ${Text(_("Your {cert_name_long} is being held pending confirmation that the issuance of your {cert_name_short} is in compliance with strict U.S. embargoes on Iran, Cuba, Syria and Sudan. If you think our system has mistakenly identified you as being connected with one of those countries, please let us know by contacting {email}.")).format(email=HTML('{email}.').format(email=settings.CONTACT_EMAIL), cert_name_short=cert_name_short, cert_name_long=cert_name_long)}
- <%= gettext("To invalidate a certificate for a particular learner, add the username or email address below.") %>
+ <%- gettext("To invalidate a certificate for a particular learner, add the username or email address below.") %>
diff --git a/lms/templates/instructor/instructor_dashboard_2/certificates.html b/lms/templates/instructor/instructor_dashboard_2/certificates.html
index 0a90da2b12..1c599355bb 100644
--- a/lms/templates/instructor/instructor_dashboard_2/certificates.html
+++ b/lms/templates/instructor/instructor_dashboard_2/certificates.html
@@ -1,18 +1,19 @@
+<%page args="section_data" expression_filter="h"/>
<%namespace name='static' file='../../static_content.html'/>
-<%! from django.utils.translation import ugettext as _
-import json
+<%!
+from django.utils.translation import ugettext as _
+from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_string
%>
<%static:require_module module_name="js/certificates/factories/certificate_whitelist_factory" class_name="CertificateWhitelistFactory">
- CertificateWhitelistFactory('${json.dumps(certificate_white_list)}', "${generate_certificate_exceptions_url}", "${certificate_exception_view_url}", "${generate_bulk_certificate_exceptions_url}");
+ CertificateWhitelistFactory('${certificate_white_list | n, dump_js_escaped_json}', '${generate_certificate_exceptions_url | n, js_escaped_string}', '${certificate_exception_view_url | n, js_escaped_string}', '${generate_bulk_certificate_exceptions_url | n, js_escaped_string}');
%static:require_module>
<%static:require_module module_name="js/certificates/factories/certificate_invalidation_factory" class_name="CertificateInvalidationFactory">
- CertificateInvalidationFactory('${json.dumps(certificate_invalidations)}', '${certificate_invalidation_view_url}');
+ CertificateInvalidationFactory('${certificate_invalidations | n, dump_js_escaped_json}', '${certificate_invalidation_view_url | n, js_escaped_string}');
%static:require_module>
-<%page args="section_data"/>
diff --git a/lms/templates/instructor/instructor_dashboard_2/cohort_management.html b/lms/templates/instructor/instructor_dashboard_2/cohort_management.html
index 71d5fe0dfc..81fe4c4221 100644
--- a/lms/templates/instructor/instructor_dashboard_2/cohort_management.html
+++ b/lms/templates/instructor/instructor_dashboard_2/cohort_management.html
@@ -2,6 +2,7 @@
<%namespace name='static' file='../../static_content.html'/>
<%!
from django.utils.translation import ugettext as _
+from openedx.core.djangolib.js_utils import js_escaped_string
from courseware.courses import get_studio_url
from openedx.core.djangoapps.course_groups.partition_scheme import get_cohorted_user_partition
%>
@@ -27,7 +28,7 @@ from openedx.core.djangoapps.course_groups.partition_scheme import get_cohorted_
% for content_group in content_groups:
{
id: ${content_group.id},
- name: "${content_group.name | h}",
+ name: "${content_group.name | n, js_escaped_string}",
user_partition_id: cohortUserPartitionId
},
% endfor
diff --git a/lms/templates/instructor/instructor_dashboard_2/e-commerce.html b/lms/templates/instructor/instructor_dashboard_2/e-commerce.html
index b763e85fb6..42e3e4312d 100644
--- a/lms/templates/instructor/instructor_dashboard_2/e-commerce.html
+++ b/lms/templates/instructor/instructor_dashboard_2/e-commerce.html
@@ -1,9 +1,10 @@
+<%page args="section_data" expression_filter="h"/>
<%!
from django.utils.translation import ugettext as _
from datetime import datetime, timedelta
+from openedx.core.djangolib.js_utils import js_escaped_string
import pytz
%>
-<%page args="section_data"/>
<%include file="add_coupon_modal.html" args="section_data=section_data" />
<%include file="edit_coupon_modal.html" args="section_data=section_data" />
<%include file="set_course_mode_price_modal.html" args="section_data=section_data" />
@@ -239,7 +240,7 @@ import pytz
$.ajax({
type: "POST",
- url: "${section_data['get_user_invoice_preference_url']}",
+ url: "${section_data['get_user_invoice_preference_url'] | n, js_escaped_string}",
success: function (data) {
$('#invoice-copy').prop('checked', data.invoice_copy);
$('#registration_code_generation_link-trigger').click();
@@ -255,13 +256,13 @@ import pytz
}
if($('#invoice_number').val() == "") {
$('#error-msg').attr('class','error-msgs')
- $('#error-msg').html("${_('The Invoice Number field cannot be empty.')}").show();
+ $('#error-msg').html("${_('The Invoice Number field cannot be empty.') | n, h, js_escaped_string}").show();
return
}
$.ajax({
type: "POST",
data: {invoice_number: $('#invoice_number').val(), event_type:event_type},
- url: "${section_data['sale_validation_url']}",
+ url: "${section_data['sale_validation_url'] | n, js_escaped_string}",
success: function (data) {
$('#error-msg').attr('class','success-msgs')
$('#error-msg').html(data.message).show();
@@ -287,7 +288,7 @@ import pytz
$.ajax({
type: "POST",
data: {id: coupon_id},
- url: "${section_data['ajax_get_coupon_info']}",
+ url: "${section_data['ajax_get_coupon_info'] | n, js_escaped_string}",
success: function (data) {
$('#error-msg').val('');
$('#error-msg').hide()
@@ -299,7 +300,7 @@ import pytz
$('input#edit_coupon_expiration_date').val(data.expiry_date);
}
else {
- $('input#edit_coupon_expiration_date').val("${_('No Expiration Date')}");
+ $('input#edit_coupon_expiration_date').val("${_('No Expiration Date') | n, js_escaped_string}");
}
$('#edit-modal-trigger').click();
},
@@ -323,7 +324,7 @@ import pytz
$.ajax({
type: "POST",
data: {id: $(this).data('item-id')},
- url: "${section_data['ajax_remove_coupon_url']}",
+ url: "${section_data['ajax_remove_coupon_url'] | n, js_escaped_string}",
success: function (data) {
anchor.removeData("disabled");
location.reload(true);
@@ -359,91 +360,91 @@ import pytz
if (company_name == '') {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('Enter the company name.')}");
+ registration_code_error.text("${_('Enter the company name.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (($.isNumeric(company_name))) {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('The company name cannot be a number.')}");
+ registration_code_error.text("${_('The company name cannot be a number.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (company_contact_name == '') {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('Enter the company contact name.')}");
+ registration_code_error.text("${_('Enter the company contact name.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (($.isNumeric(company_contact_name))) {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('The company contact name cannot be a number.')}");
+ registration_code_error.text("${_('The company contact name cannot be a number.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (company_contact_email == '') {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('Enter the email address for the company contact.')}");
+ registration_code_error.text("${_('Enter the email address for the company contact.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (!(validateEmail(company_contact_email))) {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('Enter a valid email address.')}");
+ registration_code_error.text("${_('Enter a valid email address.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (recipient_name == '') {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('Enter the recipient name.')}");
+ registration_code_error.text("${_('Enter the recipient name.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (($.isNumeric(recipient_name))) {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('The recipient name cannot be a number.')}");
+ registration_code_error.text("${_('The recipient name cannot be a number.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (recipient_email == '') {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('Enter the recipient email address.')}");
+ registration_code_error.text("${_('Enter the recipient email address.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (!(validateEmail(recipient_email))) {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('Enter a valid email address.')}");
+ registration_code_error.text("${_('Enter a valid email address.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (address_line == '') {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('Enter the billing address.')}");
+ registration_code_error.text("${_('Enter the billing address.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (unit_price == '') {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('Enter the price per course seat.')}");
+ registration_code_error.text("${_('Enter the price per course seat.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false
}
if (!($.isNumeric(unit_price))) {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('Enter a numeric value for the price per course seat. Do not include currency symbols.')}");
+ registration_code_error.text("${_('Enter a numeric value for the price per course seat. Do not include currency symbols.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false
}
if (total_registration_codes == '') {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('Enter the number of enrollment codes.')}");
+ registration_code_error.text("${_('Enter the number of enrollment codes.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false
}
if (!($.isNumeric(total_registration_codes))) {
registration_code_error.attr('style', 'display: block !important');
- registration_code_error.text("${_('Enter a numeric value for the number of enrollment codes.')}");
+ registration_code_error.text("${_('Enter a numeric value for the number of enrollment codes.') | n, js_escaped_string}");
generate_registration_button.removeAttr('disabled');
return false;
}
@@ -464,7 +465,7 @@ import pytz
"coupon_id" : coupon_id,
"description": description
},
- url: "${section_data['ajax_update_coupon']}",
+ url: "${section_data['ajax_update_coupon'] | n, js_escaped_string}",
success: function (data) {
location.reload(true);
},
@@ -498,19 +499,19 @@ import pytz
// Check if empty of not
if (course_price === '') {
$('#set_price_form #course_form_error').attr('style', 'display: block !important');
- $('#set_price_form #course_form_error').text("${_('Enter the price per course seat.')}");
+ $('#set_price_form #course_form_error').text("${_('Enter the price per course seat.') | n, js_escaped_string}");
$("#set_course_button").removeAttr('disabled');
return false;
}
if (!$.isNumeric(course_price)) {
$("#set_course_button").removeAttr('disabled');
$('#set_price_form #course_form_error').attr('style', 'display: block !important');
- $('#set_price_form #course_form_error').text("${_('Enter a numeric value for the price per course seat. Do not include currency symbols.')}");
+ $('#set_price_form #course_form_error').text("${_('Enter a numeric value for the price per course seat. Do not include currency symbols.') | n, js_escaped_string}");
return false;
}
if (currency == '') {
$('#set_price_form #course_form_error').attr('style', 'display: block !important');
- $('#set_price_form #course_form_error').text("${_('Select a currency.')}");
+ $('#set_price_form #course_form_error').text("${_('Select a currency.') | n, js_escaped_string}");
$("#set_course_button").removeAttr('disabled');
return false;
}
@@ -520,7 +521,7 @@ import pytz
"course_price" : course_price,
"currency": currency
},
- url: "${section_data['set_course_mode_url']}",
+ url: "${section_data['set_course_mode_url'] | n, js_escaped_string}",
success: function (data) {
location.reload(true);
},
@@ -545,19 +546,19 @@ import pytz
if (code === '') {
$("#add_coupon_button").removeAttr('disabled');
$('#add_coupon_form #coupon_form_error').attr('style', 'display: block !important');
- $('#add_coupon_form #coupon_form_error').text("${_('Enter a coupon code.')}");
+ $('#add_coupon_form #coupon_form_error').text("${_('Enter a coupon code.') | n, js_escaped_string}");
return false;
}
if (parseInt(coupon_discount) > 100) {
$('#add_coupon_form #coupon_form_error').attr('style', 'display: block !important');
- $('#add_coupon_form #coupon_form_error').text("${_('The discount percentage must be less than or equal to 100.')}");
+ $('#add_coupon_form #coupon_form_error').text("${_('The discount percentage must be less than or equal to 100.') | n, js_escaped_string}");
$("#add_coupon_button").removeAttr('disabled');
return false;
}
if (!$.isNumeric(coupon_discount)) {
$("#add_coupon_button").removeAttr('disabled');
$('#add_coupon_form #coupon_form_error').attr('style', 'display: block !important');
- $('#add_coupon_form #coupon_form_error').text("${_('Enter a numeric value for the discount amount. Do not include the percent sign.')}");
+ $('#add_coupon_form #coupon_form_error').text("${_('Enter a numeric value for the discount amount. Do not include the percent sign.') | n, js_escaped_string}");
return false;
}
$.ajax({
@@ -569,7 +570,7 @@ import pytz
"description": description,
"expiration_date": expiration_date
},
- url: "${section_data['ajax_add_coupon']}",
+ url: "${section_data['ajax_add_coupon'] | n, js_escaped_string}",
success: function (data) {
location.reload(true);
},
diff --git a/lms/templates/instructor/instructor_dashboard_2/edit_coupon_modal.html b/lms/templates/instructor/instructor_dashboard_2/edit_coupon_modal.html
index bf2dc000f4..de1fb662d2 100644
--- a/lms/templates/instructor/instructor_dashboard_2/edit_coupon_modal.html
+++ b/lms/templates/instructor/instructor_dashboard_2/edit_coupon_modal.html
@@ -1,8 +1,8 @@
+<%page args="section_data" expression_filter="h"/>
<%!
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
%>
-<%page args="section_data"/>