Merge pull request #12232 from edx/rc/2016-04-26

Release Candidate rc/2016-04-26
This commit is contained in:
David Ormsbee
2016-04-27 12:23:34 -04:00
413 changed files with 18098 additions and 7511 deletions

1
.gitignore vendored
View File

@@ -58,6 +58,7 @@ jscover.log
jscover.log.*
.tddium*
common/test/data/test_unicode/static/
test_root/courses/
django-pyfs
### Installation artifacts

View File

@@ -52,6 +52,18 @@ class CourseSettingsEncoderTest(CourseTestCase):
self.assertIsNone(jsondetails['effort'], "effort somehow initialized")
self.assertIsNone(jsondetails['language'], "language somehow initialized")
def test_pre_1900_date(self):
"""
Tests that the encoder can handle a pre-1900 date, since strftime
doesn't work for these dates.
"""
details = CourseDetails.fetch(self.course.id)
pre_1900 = datetime.datetime(1564, 4, 23, 1, 1, 1, tzinfo=UTC())
details.enrollment_start = pre_1900
dumped_jsondetails = json.dumps(details, cls=CourseSettingsEncoder)
loaded_jsondetails = json.loads(dumped_jsondetails)
self.assertEqual(loaded_jsondetails['enrollment_start'], pre_1900.isoformat())
def test_ooc_encoder(self):
"""
Test the encoder out of its original constrained purpose to see if it functions for general use

View File

@@ -91,7 +91,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 util.course_key_utils import course_key_from_string_or_404
from xmodule.contentstore.content import StaticContent
from xmodule.course_module import CourseFields
from xmodule.course_module import DEFAULT_START_DATE
@@ -875,7 +875,7 @@ def course_info_handler(request, course_key_string):
GET
html: return html for editing the course info handouts and updates.
"""
course_key = from_string_or_404(course_key_string)
course_key = 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)

View File

@@ -16,7 +16,7 @@ from django.contrib.auth.decorators import login_required
from django.core.exceptions import SuspiciousOperation, PermissionDenied
from django.core.files.temp import NamedTemporaryFile
from django.core.servers.basehttp import FileWrapper
from django.http import HttpResponse, HttpResponseNotFound
from django.http import HttpResponse, HttpResponseNotFound, Http404
from django.utils.translation import ugettext as _
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.decorators.http import require_http_methods, require_GET
@@ -489,6 +489,8 @@ def export_handler(request, course_key_string):
}
else:
courselike_module = modulestore().get_course(course_key)
if courselike_module is None:
raise Http404
context = {
'context_course': courselike_module,
'courselike_home_url': reverse_course_url("course_handler", course_key),

View File

@@ -14,7 +14,8 @@ from edxmako.shortcuts import render_to_response
from xmodule.modulestore.django import modulestore
from xmodule.modulestore import ModuleStoreEnum
from xmodule.tabs import CourseTabList, CourseTab, InvalidTabsException, StaticTab
from opaque_keys.edx.keys import CourseKey, UsageKey
from opaque_keys.edx.keys import UsageKey
from util.course_key_utils import course_key_from_string_or_404
from ..utils import get_lms_link_for_item
@@ -39,7 +40,7 @@ def tabs_handler(request, course_key_string):
Creating a tab, deleting a tab, or changing its contents is not supported through this method.
Instead use the general xblock URL (see item.xblock_handler).
"""
course_key = CourseKey.from_string(course_key_string)
course_key = course_key_from_string_or_404(course_key_string)
if not has_course_author_access(request.user, course_key):
raise PermissionDenied()

View File

@@ -510,6 +510,7 @@ class ImportTestCase(CourseTestCase):
@override_settings(CONTENTSTORE=TEST_DATA_CONTENTSTORE)
@ddt.ddt
class ExportTestCase(CourseTestCase):
"""
Tests for export_handler.
@@ -630,6 +631,17 @@ class ExportTestCase(CourseTestCase):
self.test_export_targz_urlparam()
@ddt.data(
'/export/non.1/existence_1/Run_1', # For mongo
'/export/course-v1:non1+existence1+Run1', # For split
)
def test_export_course_doest_not_exist(self, url):
"""
Export failure if course is not exist
"""
resp = self.client.get_html(url)
self.assertEquals(resp.status_code, 404)
@override_settings(CONTENTSTORE=TEST_DATA_CONTENTSTORE)
class TestLibraryImportExport(CourseTestCase):

View File

@@ -7,9 +7,12 @@ from contentstore.tests.utils import CourseTestCase
from contentstore.utils import reverse_course_url
from xmodule.x_module import STUDENT_VIEW
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from django.test.client import RequestFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.tabs import CourseTabList
from xmodule.modulestore.django import modulestore
from django.http import Http404
from contentstore.views.tabs import tabs_handler
class TabsPageTests(CourseTestCase):
@@ -191,6 +194,14 @@ class TabsPageTests(CourseTestCase):
self.assertIn('<span class="sr">Delete this component</span>', html)
self.assertIn('<span data-tooltip="Drag to reorder" class="drag-handle action"></span>', html)
def test_invalid_course_id(self):
""" Asserts that Http404 is raised when the course id is not valid. """
request_factory = RequestFactory()
request = request_factory.get('/dummy-url')
request.user = self.user
with self.assertRaises(Http404):
tabs_handler(request, "/some.invalid.key/course-v1:TTT+CS01+2015_T0")
class PrimitiveTabEdit(ModuleStoreTestCase):
"""Tests for the primitive tab edit data manipulations"""

View File

@@ -9,6 +9,9 @@ from django.contrib.auth.models import User
from student.models import CourseEnrollment
from student.roles import CourseStaffRole, CourseInstructorRole
from student import auth
from django.http import Http404
from contentstore.views.user import course_team_handler
from django.test.client import RequestFactory
class UsersTestCase(CourseTestCase):
@@ -315,3 +318,11 @@ class UsersTestCase(CourseTestCase):
CourseEnrollment.is_enrolled(self.ext_user, self.course.id),
'User ext_user should have been enrolled in the course'
)
def test_invalid_course_id(self):
""" Asserts that Http404 is raised when the course id is not valid. """
request_factory = RequestFactory()
request = request_factory.get('/dummy-url')
request.user = self.user
with self.assertRaises(Http404):
course_team_handler(request, "/some.invalid.key/course-v1:TTT+CS01+2015_T0")

View File

@@ -8,7 +8,7 @@ from django.views.decorators.csrf import ensure_csrf_cookie
from edxmako.shortcuts import render_to_response
from xmodule.modulestore.django import modulestore
from opaque_keys.edx.keys import CourseKey
from util.course_key_utils import course_key_from_string_or_404
from opaque_keys.edx.locator import LibraryLocator
from util.json_request import JsonResponse, expect_json
from student.roles import CourseInstructorRole, CourseStaffRole, LibraryUserRole
@@ -49,7 +49,7 @@ def course_team_handler(request, course_key_string=None, email=None):
DELETE:
json: remove a particular course team member from the course team (email is required).
"""
course_key = CourseKey.from_string(course_key_string) if course_key_string else None
course_key = course_key_from_string_or_404(course_key_string) if course_key_string else None
# No permissions check here - each helper method does its own check.
if 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json'):

View File

@@ -168,6 +168,12 @@ if ENV_TOKENS.get('SESSION_COOKIE_NAME', None):
EDXMKTG_LOGGED_IN_COOKIE_NAME = ENV_TOKENS.get('EDXMKTG_LOGGED_IN_COOKIE_NAME', EDXMKTG_LOGGED_IN_COOKIE_NAME)
EDXMKTG_USER_INFO_COOKIE_NAME = ENV_TOKENS.get('EDXMKTG_USER_INFO_COOKIE_NAME', EDXMKTG_USER_INFO_COOKIE_NAME)
# Determines whether the CSRF token can be transported on
# unencrypted channels. It is set to False here for backward compatibility,
# but it is highly recommended that this is True for environments accessed
# by end users.
CSRF_COOKIE_SECURE = ENV_TOKENS.get('CSRF_COOKIE_SECURE', False)
#Email overrides
DEFAULT_FROM_EMAIL = ENV_TOKENS.get('DEFAULT_FROM_EMAIL', DEFAULT_FROM_EMAIL)
DEFAULT_FEEDBACK_EMAIL = ENV_TOKENS.get('DEFAULT_FEEDBACK_EMAIL', DEFAULT_FEEDBACK_EMAIL)

View File

@@ -292,7 +292,9 @@ from lms.envs.common import (
# Forwards-compatibility with Django 1.7
CSRF_COOKIE_AGE = 60 * 60 * 24 * 7 * 52
# It is highly recommended that you override this in any environment accessed by
# end users
CSRF_COOKIE_SECURE = False
#################### CAPA External Code Evaluation #############################
XQUEUE_INTERFACE = {
@@ -903,6 +905,9 @@ INSTALLED_APPS = (
# Management commands used for configuration automation
'edx_management_commands.management_commands',
# Tagging
'cms.lib.xblock.tagging',
)

View File

@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
"""
Structured Tagging based on XBlockAsides
"""
from .tagging import StructuredTagsAside

View File

@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='TagAvailableValues',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('value', models.CharField(max_length=255)),
],
options={
'ordering': ('id',),
},
),
migrations.CreateModel(
name='TagCategories',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=255, unique=True)),
('title', models.CharField(max_length=255)),
],
options={
'ordering': ('title',),
},
),
migrations.AddField(
model_name='tagavailablevalues',
name='category',
field=models.ForeignKey(to='tagging.TagCategories'),
),
]

View File

@@ -0,0 +1,40 @@
"""
Django Model for tags
"""
from django.db import models
class TagCategories(models.Model):
"""
This model represents tag categories.
"""
name = models.CharField(max_length=255, unique=True)
title = models.CharField(max_length=255)
class Meta(object):
app_label = "tagging"
ordering = ('title',)
def __unicode__(self):
return "[TagCategories] {}: {}".format(self.name, self.title)
def get_values(self):
"""
Return the list of available values for the particular category
"""
return [t.value for t in TagAvailableValues.objects.filter(category=self)]
class TagAvailableValues(models.Model):
"""
This model represents available values for tags.
"""
category = models.ForeignKey(TagCategories, db_index=True)
value = models.CharField(max_length=255)
class Meta(object):
app_label = "tagging"
ordering = ('id',)
def __unicode__(self):
return "[TagAvailableValues] {}: {}".format(self.category, self.value)

View File

@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
"""
Structured Tagging based on XBlockAsides
"""
@@ -7,64 +8,15 @@ from xblock.fragment import Fragment
from xblock.fields import Scope, Dict
from xmodule.x_module import STUDENT_VIEW
from xmodule.capa_module import CapaModule
from abc import ABCMeta, abstractproperty
from edxmako.shortcuts import render_to_string
from django.conf import settings
from webob import Response
from collections import OrderedDict
from .models import TagCategories
_ = lambda text: text
class AbstractTag(object):
"""
Abstract class for tags
"""
__metaclass__ = ABCMeta
@abstractproperty
def key(self):
"""
Subclasses must implement key
"""
raise NotImplementedError('Subclasses must implement key')
@abstractproperty
def name(self):
"""
Subclasses must implement name
"""
raise NotImplementedError('Subclasses must implement name')
@abstractproperty
def allowed_values(self):
"""
Subclasses must implement allowed_values
"""
raise NotImplementedError('Subclasses must implement allowed_values')
class DifficultyTag(AbstractTag):
"""
Particular implementation tags for difficulty
"""
@property
def key(self):
""" Identifier for the difficulty selector """
return 'difficulty_tag'
@property
def name(self):
""" Label for the difficulty selector """
return _('Difficulty')
@property
def allowed_values(self):
""" Allowed values for the difficulty selector """
return OrderedDict([('easy', 'Easy'), ('medium', 'Medium'), ('hard', 'Hard')])
class StructuredTagsAside(XBlockAside):
"""
Aside that allows tagging blocks
@@ -72,7 +24,12 @@ class StructuredTagsAside(XBlockAside):
saved_tags = Dict(help=_("Dictionary with the available tags"),
scope=Scope.content,
default={},)
available_tags = [DifficultyTag()]
def get_available_tags(self):
"""
Return available tags
"""
return TagCategories.objects.all()
def _get_studio_resource_url(self, relative_url):
"""
@@ -88,14 +45,21 @@ class StructuredTagsAside(XBlockAside):
"""
if isinstance(block, CapaModule):
tags = []
for tag in self.available_tags:
for tag in self.get_available_tags():
values = tag.get_values()
current_value = self.saved_tags.get(tag.name, None)
if current_value is not None and current_value not in values:
values.insert(0, current_value)
tags.append({
'key': tag.key,
'title': tag.name,
'values': tag.allowed_values,
'current_value': self.saved_tags.get(tag.key, None),
'key': tag.name,
'title': tag.title,
'values': values,
'current_value': current_value
})
fragment = Fragment(render_to_string('structured_tags_block.html', {'tags': tags}))
fragment = Fragment(render_to_string('structured_tags_block.html', {'tags': tags,
'block_location': block.location}))
fragment.add_javascript_url(self._get_studio_resource_url('/js/xblock_asides/structured_tags.js'))
fragment.initialize_js('StructuredTagsInit')
return fragment
@@ -113,14 +77,14 @@ class StructuredTagsAside(XBlockAside):
tag = request.params['tag'].split(':')
for av_tag in self.available_tags:
if av_tag.key == tag[0]:
if tag[1] in av_tag.allowed_values:
self.saved_tags[tag[0]] = tag[1]
found = True
elif tag[1] == '':
for av_tag in self.get_available_tags():
if av_tag.name == tag[0]:
if tag[1] == '':
self.saved_tags[tag[0]] = None
found = True
elif tag[1] in av_tag.get_values():
self.saved_tags[tag[0]] = tag[1]
found = True
if not found:
return Response("Invalid 'tag' parameter", status=400)

View File

@@ -7,7 +7,11 @@ from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from xblock_config.models import StudioConfig
from xblock.fields import ScopeIds
from xblock.runtime import DictKeyValueStore, KvsFieldData
from xblock.test.tools import TestRuntime
from cms.lib.xblock.tagging import StructuredTagsAside
from cms.lib.xblock.tagging.models import TagCategories, TagAvailableValues
from contentstore.views.preview import get_preview_fragment
from contentstore.utils import reverse_usage_url
from contentstore.tests.utils import AjaxEnabledTestClient
@@ -30,8 +34,9 @@ class StructuredTagsAsideTestCase(ModuleStoreTestCase):
"""
self.user_password = super(StructuredTagsAsideTestCase, self).setUp()
self.aside_name = 'tagging_aside'
self.aside_tag = 'difficulty_tag'
self.aside_tag_value = 'hard'
self.aside_tag_dif = 'difficulty'
self.aside_tag_dif_value = 'Hard'
self.aside_tag_lo = 'learning_outcome'
course = CourseFactory.create(default_store=ModuleStoreEnum.Type.split)
self.course = ItemFactory.create(
@@ -75,16 +80,47 @@ class StructuredTagsAsideTestCase(ModuleStoreTestCase):
user_id=self.user.id
)
_init_data = [
{
'name': 'difficulty',
'title': 'Difficulty',
'values': ['Easy', 'Medium', 'Hard'],
},
{
'name': 'learning_outcome',
'title': 'Learning outcome',
'values': ['Learned nothing', 'Learned a few things', 'Learned everything']
}
]
for tag in _init_data:
category = TagCategories.objects.create(name=tag['name'], title=tag['title'])
for val in tag['values']:
TagAvailableValues.objects.create(category=category, value=val)
config = StudioConfig.current()
config.enabled = True
config.save()
def tearDown(self):
TagAvailableValues.objects.all().delete()
TagCategories.objects.all().delete()
super(StructuredTagsAsideTestCase, self).tearDown()
def test_aside_contains_tags(self):
"""
Checks that available_tags list is not empty
"""
self.assertGreater(len(StructuredTagsAside.available_tags), 0,
"StructuredTagsAside should contains at least one available tag")
sids = ScopeIds(user_id="bob",
block_type="bobs-type",
def_id="definition-id",
usage_id="usage-id")
key_store = DictKeyValueStore()
field_data = KvsFieldData(key_store)
runtime = TestRuntime(services={'field-data': field_data}) # pylint: disable=abstract-class-instantiated
xblock_aside = StructuredTagsAside(scope_ids=sids, runtime=runtime)
available_tags = xblock_aside.get_available_tags()
self.assertEquals(len(available_tags), 2, "StructuredTagsAside should contains two tag categories")
def test_preview_html(self):
"""
@@ -115,10 +151,26 @@ class StructuredTagsAsideTestCase(ModuleStoreTestCase):
self.assertIn('xblock_asides-v1', div_node.get('class'))
select_nodes = div_node.xpath('div/select')
self.assertEquals(len(select_nodes), 1)
self.assertEquals(len(select_nodes), 2)
select_node = select_nodes[0]
self.assertEquals(select_node.get('name'), self.aside_tag)
select_node1 = select_nodes[0]
self.assertEquals(select_node1.get('name'), self.aside_tag_dif)
option_nodes1 = select_node1.xpath('option')
self.assertEquals(len(option_nodes1), 4)
option_values1 = [opt_elem.text for opt_elem in option_nodes1]
self.assertEquals(option_values1, ['Not selected', 'Easy', 'Medium', 'Hard'])
select_node2 = select_nodes[1]
self.assertEquals(select_node2.get('name'), self.aside_tag_lo)
option_nodes2 = select_node2.xpath('option')
self.assertEquals(len(option_nodes2), 4)
option_values2 = [opt_elem.text for opt_elem in option_nodes2 if opt_elem.text]
self.assertEquals(option_values2, ['Not selected', 'Learned nothing',
'Learned a few things', 'Learned everything'])
# Now ensure the acid_aside is not in the result
self.assertNotRegexpMatches(problem_html, r"data-block-type=[\"\']acid_aside[\"\']")
@@ -146,11 +198,11 @@ class StructuredTagsAsideTestCase(ModuleStoreTestCase):
response = client.post(path=handler_url, data={'tag': 'undefined_tag:undefined'})
self.assertEqual(response.status_code, 400)
val = '%s:undefined' % self.aside_tag
val = '%s:undefined' % self.aside_tag_dif
response = client.post(path=handler_url, data={'tag': val})
self.assertEqual(response.status_code, 400)
val = '%s:%s' % (self.aside_tag, self.aside_tag_value)
val = '%s:%s' % (self.aside_tag_dif, self.aside_tag_dif_value)
response = client.post(path=handler_url, data={'tag': val})
self.assertEqual(response.status_code, 200)
@@ -163,4 +215,4 @@ class StructuredTagsAsideTestCase(ModuleStoreTestCase):
break
self.assertIsNotNone(tag_aside, "Necessary StructuredTagsAside object isn't found")
self.assertEqual(tag_aside.saved_tags[self.aside_tag], self.aside_tag_value)
self.assertEqual(tag_aside.saved_tags[self.aside_tag_dif], self.aside_tag_dif_value)

View File

@@ -1,4 +1,5 @@
requirejs.config({
baseUrl: '/base/',
paths: {
"gettext": "xmodule_js/common_static/js/test/i18n",
"mustache": "xmodule_js/common_static/js/vendor/mustache",
@@ -42,10 +43,9 @@ requirejs.config({
"accessibility": "xmodule_js/common_static/js/src/accessibility_tools",
"sinon": "xmodule_js/common_static/js/vendor/sinon-1.17.0",
"squire": "xmodule_js/common_static/js/vendor/Squire",
"jasmine-jquery": "xmodule_js/common_static/js/vendor/jasmine-jquery",
"jasmine-imagediff": "xmodule_js/common_static/js/vendor/jasmine-imagediff",
"jasmine-stealth": "xmodule_js/common_static/js/vendor/jasmine-stealth",
"jasmine.async": "xmodule_js/common_static/js/vendor/jasmine.async",
"jasmine-stealth": "xmodule_js/common_static/js/libs/jasmine-stealth",
"jasmine-waituntil": "xmodule_js/common_static/js/libs/jasmine-waituntil",
"draggabilly": "xmodule_js/common_static/js/vendor/draggabilly",
"domReady": "xmodule_js/common_static/js/vendor/domReady",
"URI": "xmodule_js/common_static/js/vendor/URI.min",
@@ -158,17 +158,17 @@ requirejs.config({
"mathjax": {
exports: "MathJax",
init: ->
MathJax.Hub.Config
tex2jax:
inlineMath: [
["\\(","\\)"],
['[mathjaxinline]','[/mathjaxinline]']
]
displayMath: [
["\\[","\\]"],
['[mathjax]','[/mathjax]']
]
MathJax.Hub.Configured()
MathJax.Hub.Config
tex2jax:
inlineMath: [
["\\(", "\\)"],
['[mathjaxinline]', '[/mathjaxinline]']
]
displayMath: [
["\\[", "\\]"],
['[mathjax]', '[/mathjax]']
]
MathJax.Hub.Configured()
},
"URI": {
exports: "URI"
@@ -179,18 +179,12 @@ requirejs.config({
"sinon": {
exports: "sinon"
},
"jasmine-jquery": {
deps: ["jasmine"]
},
"jasmine-imagediff": {
deps: ["jasmine"]
},
"jasmine-imagediff": {},
"jasmine-stealth": {
deps: ["jasmine"]
deps: ["underscore", "underscore.string"]
},
"jasmine.async": {
deps: ["jasmine"],
exports: "AsyncSpec"
"jasmine-waituntil": {
deps: ["jquery"]
},
"xblock/core": {
exports: "XBlock",
@@ -201,7 +195,7 @@ requirejs.config({
deps: ["xblock/core"]
},
"mock-ajax": {
deps: ["jasmine", "jquery"]
deps: ["jquery"]
}
"coffee/src/main": {
@@ -221,35 +215,33 @@ requirejs.config({
jasmine.getFixtures().fixturesPath += 'coffee/fixtures'
define([
testFiles = [
"coffee/spec/main_spec",
"coffee/spec/models/course_spec", "coffee/spec/models/metadata_spec",
"coffee/spec/models/course_spec",
"coffee/spec/models/metadata_spec",
"coffee/spec/models/section_spec",
"coffee/spec/models/settings_course_grader_spec",
"coffee/spec/models/settings_grading_spec", "coffee/spec/models/textbook_spec",
"coffee/spec/models/settings_grading_spec",
"coffee/spec/models/textbook_spec",
"coffee/spec/models/upload_spec",
"coffee/spec/views/course_info_spec",
"coffee/spec/views/metadata_edit_spec",
"coffee/spec/views/module_edit_spec",
"coffee/spec/views/textbook_spec",
"coffee/spec/views/upload_spec",
"js/spec/video/transcripts/utils_spec", "js/spec/video/transcripts/editor_spec",
"js/spec/video/transcripts/videolist_spec", "js/spec/video/transcripts/message_manager_spec",
"js/spec/video/transcripts/file_uploader_spec",
"js/spec/video/transcripts/utils_spec",
"js/spec/video/transcripts/editor_spec",
# "js/spec/video/transcripts/videolist_spec",
# "js/spec/video/transcripts/message_manager_spec",
# "js/spec/video/transcripts/file_uploader_spec",
"js/spec/models/component_template_spec",
"js/spec/models/explicit_url_spec",
"js/spec/models/xblock_info_spec",
"js/spec/models/xblock_validation_spec",
"js/spec/models/license_spec",
"js/spec/utils/drag_and_drop_spec",
"js/spec/utils/handle_iframe_binding_spec",
"js/spec/utils/module_spec",
"js/spec/views/active_video_upload_list_spec",
"js/spec/views/previous_video_upload_spec",
"js/spec/views/previous_video_upload_list_spec",
@@ -266,7 +258,6 @@ define([
"js/spec/views/license_spec",
"js/spec/views/paging_spec",
"js/spec/views/login_studio_spec",
"js/spec/views/pages/container_spec",
"js/spec/views/pages/container_subviews_spec",
"js/spec/views/pages/group_configurations_spec",
@@ -274,25 +265,24 @@ define([
"js/spec/views/pages/course_rerun_spec",
"js/spec/views/pages/index_spec",
"js/spec/views/pages/library_users_spec",
"js/spec/views/modals/base_modal_spec",
"js/spec/views/modals/edit_xblock_spec",
"js/spec/views/modals/validation_error_modal_spec",
"js/spec/views/settings/main_spec",
"js/spec/factories/xblock_validation_spec",
"js/spec/xblock/cms.runtime.v1_spec",
# Certificates application test suite mappings
"js/certificates/spec/models/certificate_spec",
"js/certificates/spec/views/certificate_details_spec",
"js/certificates/spec/views/certificate_editor_spec",
"js/certificates/spec/views/certificates_list_spec",
"js/certificates/spec/views/certificate_preview_spec",
"js/certificates/spec/views/certificate_preview_spec"
]
# these tests are run separately in the cms-squire suite, due to process
# isolation issues with Squire.js
# "coffee/spec/views/assets_spec"
])
i = 0
while i < testFiles.length
testFiles[i] = '/base/' + testFiles[i] + '.js'
i++
require testFiles, ->
# start test run, once Require.js is done
window.__karma__.start()

View File

@@ -1,4 +1,5 @@
require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_helpers", "jasmine-stealth", "jquery.cookie"],
require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_helpers",
"jasmine-stealth", "jasmine-waituntil", "jquery.cookie"],
($, Backbone, main, AjaxHelpers) ->
describe "CMS", ->
it "should initialize URL", ->
@@ -7,8 +8,12 @@ require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_h
describe "main helper", ->
beforeEach ->
@previousAjaxSettings = $.extend(true, {}, $.ajaxSettings)
spyOn($, "cookie")
$.cookie.when("csrftoken").thenReturn("stubCSRFToken")
spyOn($, "cookie").and.callFake(
(param) ->
if param == "csrftoken"
return "stubCSRFToken"
)
main()
afterEach ->
@@ -21,12 +26,15 @@ require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_h
expect($.ajaxSettings.headers["X-CSRFToken"]).toEqual("stubCSRFToken")
describe "AJAX Errors", ->
server = null
beforeEach ->
appendSetFixtures(sandbox({id: "page-notification"}))
afterEach ->
server && server.restore()
it "successful AJAX request does not pop an error notification", ->
server = AjaxHelpers.server(this, [200, {}, ''])
server = AjaxHelpers.server([200, {}, ''])
expect($("#page-notification")).toBeEmpty()
$.ajax("/test")
@@ -35,15 +43,15 @@ require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_h
expect($("#page-notification")).toBeEmpty()
it "AJAX request with error should pop an error notification", ->
server = AjaxHelpers.server(this, [500, {}, ''])
server = AjaxHelpers.server([500, {}, ''])
$.ajax("/test")
server.respond()
expect($("#page-notification")).not.toBeEmpty()
expect($("#page-notification")).toContain('div.wrapper-notification-error')
expect($("#page-notification")).toContainElement('div.wrapper-notification-error')
it "can override AJAX request with error so it does not pop an error notification", ->
server = AjaxHelpers.server(this, [500, {}, ''])
server = AjaxHelpers.server([500, {}, ''])
$.ajax
url: "/test"

View File

@@ -1,4 +1,6 @@
requirejs.config({
baseUrl: '/base/',
paths: {
"gettext": "xmodule_js/common_static/js/test/i18n",
"mustache": "xmodule_js/common_static/js/vendor/mustache",
@@ -22,8 +24,8 @@ 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/common/js/vendor/underscore",
"underscore.string": "xmodule_js/common_static/common/js/vendor/underscore.string",
"underscore": "common/js/vendor/underscore",
"underscore.string": "common/js/vendor/underscore.string",
"backbone": "xmodule_js/common_static/js/vendor/backbone-min",
"backbone.associations": "xmodule_js/common_static/js/vendor/backbone-associations-min",
"backbone.paginator": "xmodule_js/common_static/js/vendor/backbone.paginator.min",
@@ -36,11 +38,11 @@ requirejs.config({
"utility": "xmodule_js/common_static/js/src/utility",
"sinon": "xmodule_js/common_static/js/vendor/sinon-1.17.0",
"squire": "xmodule_js/common_static/js/vendor/Squire",
"jasmine-stealth": "xmodule_js/common_static/js/vendor/jasmine-stealth",
"jasmine.async": "xmodule_js/common_static/js/vendor/jasmine.async",
"modernizr": "xmodule_js/common_static/edx-pattern-library/js/modernizr-custom",
"afontgarde": "xmodule_js/common_static/edx-pattern-library/js/afontgarde",
"edxicons": "xmodule_js/common_static/edx-pattern-library/js/edx-icons",
"jasmine-stealth": "xmodule_js/common_static/js/libs/jasmine-stealth",
"jasmine-waituntil": "xmodule_js/common_static/js/libs/jasmine-waituntil",
"draggabilly": "xmodule_js/common_static/js/vendor/draggabilly",
"domReady": "xmodule_js/common_static/js/vendor/domReady",
"URI": "xmodule_js/common_static/js/vendor/URI.min",
@@ -159,11 +161,10 @@ requirejs.config({
exports: "sinon"
},
"jasmine-stealth": {
deps: ["jasmine"]
deps: ["underscore", "underscore.string"]
},
"jasmine.async": {
deps: ["jasmine"],
exports: "AsyncSpec"
"jasmine-waituntil": {
deps: ["jquery"]
},
"xblock/core": {
exports: "XBlock",
@@ -191,9 +192,16 @@ requirejs.config({
jasmine.getFixtures().fixturesPath += 'coffee/fixtures'
define([
"coffee/spec/views/assets_spec",
"js/spec/video/translations_editor_spec",
"js/spec/video/file_uploader_editor_spec",
"js/spec/models/group_configuration_spec"
])
testFiles = [
'coffee/spec/views/assets_spec',
'js/spec/video/translations_editor_spec',
'js/spec/video/file_uploader_editor_spec',
'js/spec/models/group_configuration_spec'
]
i = 0
while i < testFiles.length
testFiles[i] = '/base/' + testFiles[i] + '.js'
i++
require testFiles, ->
# start test run, once Require.js is done
window.__karma__.start()

View File

@@ -34,7 +34,7 @@ define ["js/models/section", "common/js/spec_helpers/ajax_helpers", "js/utils/mo
})
it "show/hide a notification when it saves to the server", ->
server = AjaxHelpers.server(this, [200, {}, ''])
server = AjaxHelpers.server([200, {}, ''])
@model.save()
expect(Section.prototype.showNotification).toHaveBeenCalled()
@@ -43,7 +43,7 @@ define ["js/models/section", "common/js/spec_helpers/ajax_helpers", "js/utils/mo
it "don't hide notification when saving fails", ->
# this is handled by the global AJAX error handler
server = AjaxHelpers.server(this, [500, {}, ''])
server = AjaxHelpers.server([500, {}, ''])
@model.save()
server.respond()

View File

@@ -1,12 +1,6 @@
define ["backbone", "js/models/textbook", "js/collections/textbook", "js/models/chapter", "js/collections/chapter", "coffee/src/main"],
(Backbone, Textbook, TextbookSet, Chapter, ChapterSet, main) ->
beforeEach ->
@addMatchers
toBeInstanceOf: (expected) ->
return @actual instanceof expected
describe "Textbook model", ->
beforeEach ->
main()

View File

@@ -1,25 +1,25 @@
define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
($, jasmine, AjaxHelpers, Squire) ->
define ["jquery", "common/js/spec_helpers/ajax_helpers", "squire"],
($, AjaxHelpers, Squire) ->
assetLibraryTpl = readFixtures('asset-library.underscore')
assetTpl = readFixtures('asset.underscore')
describe "Asset view", ->
beforeEach ->
beforeEach (done) ->
setFixtures($("<script>", {id: "asset-tpl", type: "text/template"}).text(assetTpl))
appendSetFixtures(sandbox({id: "page-prompt"}))
@promptSpies = jasmine.createSpyObj('Prompt.Warning', ["constructor", "show", "hide"])
@promptSpies.constructor.andReturn(@promptSpies)
@promptSpies.show.andReturn(@promptSpies)
@promptSpies.constructor.and.returnValue(@promptSpies)
@promptSpies.show.and.returnValue(@promptSpies)
@confirmationSpies = jasmine.createSpyObj('Notification.Confirmation', ["constructor", "show"])
@confirmationSpies.constructor.andReturn(@confirmationSpies)
@confirmationSpies.show.andReturn(@confirmationSpies)
@confirmationSpies.constructor.and.returnValue(@confirmationSpies)
@confirmationSpies.show.and.returnValue(@confirmationSpies)
@savingSpies = jasmine.createSpyObj('Notification.Mini', ["constructor", "show", "hide"])
@savingSpies.constructor.andReturn(@savingSpies)
@savingSpies.show.andReturn(@savingSpies)
@savingSpies.constructor.and.returnValue(@savingSpies)
@savingSpies.show.and.returnValue(@savingSpies)
@injector = new Squire()
@injector.mock("common/js/components/views/feedback_prompt", {
@@ -29,8 +29,8 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
"Confirmation": @confirmationSpies.constructor,
"Mini": @savingSpies.constructor
})
runs =>
@injector.require ["js/models/asset", "js/collections/asset", "js/views/asset"],
@injector.require ["js/models/asset", "js/collections/asset", "js/views/asset"],
(AssetModel, AssetCollection, AssetView) =>
@model = new AssetModel
display_name: "test asset"
@@ -39,8 +39,8 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
date_added: 'date'
thumbnail: null
id: 'id'
spyOn(@model, "destroy").andCallThrough()
spyOn(@model, "save").andCallThrough()
spyOn(@model, "destroy").and.callThrough()
spyOn(@model, "save").and.callThrough()
@collection = new AssetCollection([@model])
@collection.url = "assets-url"
@@ -48,8 +48,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
view = new AssetView({model: @model})
requests = if test then AjaxHelpers["requests"](test) else null
return {view: view, requests: requests}
waitsFor (=> @createAssetView), "AssetsView Creation function was not initialized", 1000
done()
afterEach ->
@injector.clean()
@@ -65,7 +64,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
{view: @view, requests: requests} = @createAssetView()
@view.render().$(".remove-asset-button").click()
expect(@promptSpies.constructor).toHaveBeenCalled()
ctorOptions = @promptSpies.constructor.mostRecentCall.args[0]
ctorOptions = @promptSpies.constructor.calls.mostRecent().args[0]
expect(ctorOptions.title).toMatch('Delete File Confirmation')
# hasn't actually been removed
expect(@model.destroy).not.toHaveBeenCalled()
@@ -76,7 +75,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
{view: @view, requests: requests} = @createAssetView(this)
@view.render().$(".remove-asset-button").click()
ctorOptions = @promptSpies.constructor.mostRecentCall.args[0]
ctorOptions = @promptSpies.constructor.calls.mostRecent().args[0]
# run the primary function to indicate confirmation
ctorOptions.actions.primary.click(@promptSpies)
# AJAX request has been sent, but not yet returned
@@ -88,7 +87,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
requests[0].respond(200)
expect(@confirmationSpies.constructor).toHaveBeenCalled()
expect(@confirmationSpies.show).toHaveBeenCalled()
savingOptions = @confirmationSpies.constructor.mostRecentCall.args[0]
savingOptions = @confirmationSpies.constructor.calls.mostRecent().args[0]
expect(savingOptions.title).toMatch("Your file has been deleted.")
expect(@collection.contains(@model)).toBeFalsy()
@@ -96,7 +95,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
{view: @view, requests: requests} = @createAssetView(this)
@view.render().$(".remove-asset-button").click()
ctorOptions = @promptSpies.constructor.mostRecentCall.args[0]
ctorOptions = @promptSpies.constructor.calls.mostRecent().args[0]
# run the primary function to indicate confirmation
ctorOptions.actions.primary.click(@promptSpies)
# AJAX request has been sent, but not yet returned
@@ -115,7 +114,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
expect(requests.length).toEqual(1)
expect(@savingSpies.constructor).toHaveBeenCalled()
expect(@savingSpies.show).toHaveBeenCalled()
savingOptions = @savingSpies.constructor.mostRecentCall.args[0]
savingOptions = @savingSpies.constructor.calls.mostRecent().args[0]
expect(savingOptions.title).toMatch("Saving")
expect(@model.get("locked")).toBeFalsy()
# return a success response
@@ -134,7 +133,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
expect(@model.get("locked")).toBeFalsy()
describe "Assets view", ->
beforeEach ->
beforeEach (done) ->
setFixtures($("<script>", {id: "asset-library-tpl", type: "text/template"}).text(assetLibraryTpl))
appendSetFixtures($("<script>", {id: "asset-tpl", type: "text/template"}).text(assetTpl))
window.analytics = jasmine.createSpyObj('analytics', ['track'])
@@ -142,8 +141,8 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
appendSetFixtures(sandbox({id: "asset_table_body"}))
@promptSpies = jasmine.createSpyObj('Prompt.Warning', ["constructor", "show", "hide"])
@promptSpies.constructor.andReturn(@promptSpies)
@promptSpies.show.andReturn(@promptSpies)
@promptSpies.constructor.and.returnValue(@promptSpies)
@promptSpies.show.and.returnValue(@promptSpies)
@injector = new Squire()
@injector.mock("common/js/components/views/feedback_prompt", {
@@ -175,8 +174,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
totalCount: 2
}
runs =>
@injector.require ["js/models/asset", "js/collections/asset", "js/views/assets"],
@injector.require ["js/models/asset", "js/collections/asset", "js/views/assets"],
(AssetModel, AssetCollection, AssetsView) =>
@AssetModel = AssetModel
@collection = new AssetCollection();
@@ -188,9 +186,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
el: $('#asset_table_body')
view.render()
return {view: view, requests: requests}
waitsFor (=> @createAssetsView), "AssetsView Creation function was not initialized", 2000
done()
$.ajax()
@@ -294,7 +290,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
setup.call(this, requests)
# Delete the 2nd asset with success from server.
@view.$(".remove-asset-button")[1].click()
@promptSpies.constructor.mostRecentCall.args[0].actions.primary.click(@promptSpies)
@promptSpies.constructor.calls.mostRecent().args[0].actions.primary.click(@promptSpies)
AjaxHelpers.respondWithNoContent(requests)
expect(@view.$el).toContainText("test asset 1")
expect(@view.$el).not.toContainText("test asset 2")
@@ -304,7 +300,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
setup.call(this, requests)
# Delete the 2nd asset, but mimic a failure from the server.
@view.$(".remove-asset-button")[1].click()
@promptSpies.constructor.mostRecentCall.args[0].actions.primary.click(@promptSpies)
@promptSpies.constructor.calls.mostRecent().args[0].actions.primary.click(@promptSpies)
AjaxHelpers.respondWithError(requests)
expect(@view.$el).toContainText("test asset 1")
expect(@view.$el).toContainText("test asset 2")
@@ -319,7 +315,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"],
it "does not add an asset if asset already exists", ->
{view: @view, requests: requests} = @createAssetsView(this)
setup.call(this, requests)
spyOn(@collection, "add").andCallThrough()
spyOn(@collection, "add").and.callThrough()
model = @collection.models[1]
@view.addAsset(model)
expect(@collection.add).not.toHaveBeenCalled()

View File

@@ -47,16 +47,16 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model
# Edit button is not in the template under test (it is in parent HTML).
# Therefore call onNew directly.
@courseInfoEdit.onNew(@event)
spyOn(@courseInfoEdit.$codeMirror, 'getValue').andReturn(text)
spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue(text)
@courseInfoEdit.$el.find('.save-button').click()
@cancelNewCourseInfo = (useCancelButton) ->
@courseInfoEdit.onNew(@event)
spyOn(@courseInfoEdit.$modalCover, 'hide').andCallThrough()
spyOn(@courseInfoEdit.$modalCover, 'hide').and.callThrough()
spyOn(@courseInfoEdit.$codeMirror, 'getValue').andReturn('unsaved changes')
spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue('unsaved changes')
model = @collection.at(0)
spyOn(model, "save").andCallThrough()
spyOn(model, "save").and.callThrough()
cancelEditingUpdate(@courseInfoEdit, @courseInfoEdit.$modalCover, useCancelButton)
@@ -67,11 +67,11 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model
@doNotCloseNewCourseInfo = () ->
@courseInfoEdit.onNew(@event)
spyOn(@courseInfoEdit.$modalCover, 'hide').andCallThrough()
spyOn(@courseInfoEdit.$modalCover, 'hide').and.callThrough()
spyOn(@courseInfoEdit.$codeMirror, 'getValue').andReturn('unsaved changes')
spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue('unsaved changes')
model = @collection.at(0)
spyOn(model, "save").andCallThrough()
spyOn(model, "save").and.callThrough()
cancelEditingUpdate(@courseInfoEdit, @courseInfoEdit.$modalCover, false)
@@ -81,11 +81,11 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model
@cancelExistingCourseInfo = (useCancelButton) ->
@createNewUpdate('existing update')
@courseInfoEdit.$el.find('.edit-button').click()
spyOn(@courseInfoEdit.$modalCover, 'hide').andCallThrough()
spyOn(@courseInfoEdit.$modalCover, 'hide').and.callThrough()
spyOn(@courseInfoEdit.$codeMirror, 'getValue').andReturn('modification')
spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue('modification')
model = @collection.at(0)
spyOn(model, "save").andCallThrough()
spyOn(model, "save").and.callThrough()
model.id = "saved_to_server"
cancelEditingUpdate(@courseInfoEdit, @courseInfoEdit.$modalCover, useCancelButton)
@@ -94,6 +94,20 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model
previewContents = @courseInfoEdit.$el.find('.update-contents').html()
expect(previewContents).toEqual('existing update')
@testInvalidDateValue = (value) ->
@courseInfoEdit.onNew(@event)
expect(@courseInfoEdit.$el.find('.save-button').hasClass("is-disabled")).toEqual(false)
@courseInfoEdit.$el.find('input.date').val(value).trigger("change")
courseInfoEdit = @courseInfoEdit
jasmine.waitUntil(->
courseInfoEdit.$el.find('.save-button').hasClass('is-disabled') == true
).then ->
courseInfoEdit.$el.find('input.date').val('01/01/16').trigger 'change'
jasmine.waitUntil(->
courseInfoEdit.$el.find('.save-button').hasClass('is-disabled') == false
).always done
return
cancelEditingUpdate = (update, modalCover, useCancelButton) ->
if useCancelButton
update.$el.find('.cancel-button').click()
@@ -109,8 +123,8 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model
@courseInfoEdit.onNew(@event)
expect(@collection.length).toEqual(1)
model = @collection.at(0)
spyOn(model, "save").andCallThrough()
spyOn(@courseInfoEdit.$codeMirror, 'getValue').andReturn('/static/image.jpg')
spyOn(model, "save").and.callThrough()
spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue('/static/image.jpg')
# Click the "Save button."
@courseInfoEdit.$el.find('.save-button').click()
@@ -153,14 +167,6 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model
it "does not remove existing course info on click outside modal", ->
@cancelExistingCourseInfo(false)
@testInvalidDateValue: (value) ->
@courseInfoEdit.onNew(@event)
expect(@courseInfoEdit.$el.find('.save-button').hasClass("is-disabled")).toEqual(false)
@courseInfoEdit.$el.find('input.date').val(value).trigger("change")
expect(@courseInfoEdit.$el.find('.save-button').hasClass("is-disabled")).toEqual(true)
@courseInfoEdit.$el.find('input.date').val("01/01/16").trigger("change")
expect(@courseInfoEdit.$el.find('.save-button').hasClass("is-disabled")).toEqual(false)
it "does not allow updates to be saved with an invalid date", ->
@testInvalidDateValue("Marchtober 40, 2048")
@@ -196,7 +202,7 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model
expect(requestSent.push_notification_selected).toEqual(true)
# Check that analytics send push_notification info
analytics_payload = window.analytics.track.calls[0].args[1]
analytics_payload = window.analytics.track.calls.first().args[1]
expect(analytics_payload).toEqual(jasmine.objectContaining({'push_notification_selected': true}))
it "sends correct value for push_notification_selected when it is unselected", ->
@@ -208,7 +214,7 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model
expect(requestSent.push_notification_selected).toEqual(false)
# Check that analytics send push_notification info
analytics_payload = window.analytics.track.calls[0].args[1]
analytics_payload = window.analytics.track.calls.first().args[1]
expect(analytics_payload).toEqual(jasmine.objectContaining({'push_notification_selected': false}))
describe "Course Handouts", ->
@@ -237,8 +243,8 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model
# Enter something in the handouts section, verifying that the model is saved
# when "Save" is clicked.
@handoutsEdit.$el.find('.edit-button').click()
spyOn(@handoutsEdit.$codeMirror, 'getValue').andReturn('/static/image.jpg')
spyOn(@model, "save").andCallThrough()
spyOn(@handoutsEdit.$codeMirror, 'getValue').and.returnValue('/static/image.jpg')
spyOn(@model, "save").and.callThrough()
@handoutsEdit.$el.find('.save-button').click()
expect(@model.save).toHaveBeenCalled()
@@ -251,7 +257,7 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model
it "does rewrite links after edit", ->
# Edit handouts and save.
@handoutsEdit.$el.find('.edit-button').click()
spyOn(@handoutsEdit.$codeMirror, 'getValue').andReturn('/static/image.jpg')
spyOn(@handoutsEdit.$codeMirror, 'getValue').and.returnValue('/static/image.jpg')
@handoutsEdit.$el.find('.save-button').click()
# Verify preview text.

View File

@@ -29,7 +29,7 @@ define ["jquery", "common/js/components/utils/view_utils", "js/spec_helpers/edit
</ul>
"""
edit_helpers.installEditTemplates(true);
spyOn($, 'ajax').andReturn(@moduleData)
spyOn($, 'ajax').and.returnValue(@moduleData)
@moduleEdit = new ModuleEdit(
el: $(".component")
@@ -62,7 +62,7 @@ define ["jquery", "common/js/components/utils/view_utils", "js/spec_helpers/edit
spyOn(@moduleEdit, 'loadDisplay')
spyOn(@moduleEdit, 'delegateEvents')
spyOn($.fn, 'append')
spyOn(ViewUtils, 'loadJavaScript').andReturn($.Deferred().resolve().promise());
spyOn(ViewUtils, 'loadJavaScript').and.returnValue($.Deferred().resolve().promise());
window.MockXBlock = (runtime, element) ->
return { }
@@ -70,7 +70,7 @@ define ["jquery", "common/js/components/utils/view_utils", "js/spec_helpers/edit
window.loadedXBlockResources = undefined
@moduleEdit.render()
$.ajax.mostRecentCall.args[0].success(
$.ajax.calls.mostRecent().args[0].success(
html: '<div>Response html</div>'
resources: [
['hash1', {kind: 'text', mimetype: 'text/css', data: 'inline-css'}],
@@ -120,7 +120,7 @@ define ["jquery", "common/js/components/utils/view_utils", "js/spec_helpers/edit
mockXBlockEditorHtml = readFixtures('mock/mock-xblock-editor.underscore')
$.ajax.mostRecentCall.args[0].success(
$.ajax.calls.mostRecent().args[0].success(
html: mockXBlockEditorHtml
resources: [
['hash1', {kind: 'text', mimetype: 'text/css', data: 'inline-css'}],
@@ -161,14 +161,14 @@ define ["jquery", "common/js/components/utils/view_utils", "js/spec_helpers/edit
expect($.fn.append).not.toHaveBeenCalledWith('not-head-html')
it "doesn't reload resources", ->
count = $('head').append.callCount
$.ajax.mostRecentCall.args[0].success(
count = $('head').append.calls.count()
$.ajax.calls.mostRecent().args[0].success(
html: '<div>Response html 2</div>'
resources: [
['hash1', {kind: 'text', mimetype: 'text/css', data: 'inline-css'}],
]
)
expect($('head').append.callCount).toBe(count)
expect($('head').append.calls.count()).toBe(count)
describe "loadDisplay", ->
beforeEach ->
@@ -177,4 +177,4 @@ define ["jquery", "common/js/components/utils/view_utils", "js/spec_helpers/edit
it "loads the .xmodule-display inside the module editor", ->
expect(XBlock.initializeBlock).toHaveBeenCalled()
expect(XBlock.initializeBlock.mostRecentCall.args[0]).toBe($('.xblock-student_view'))
expect(XBlock.initializeBlock.calls.mostRecent().args[0].get(0)).toBe($('.xblock-student_view').get(0))

View File

@@ -5,16 +5,6 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js
"js/spec_helpers/modal_helpers", "jasmine-stealth"],
(Textbook, Chapter, ChapterSet, Course, TextbookSet, ShowTextbook, EditTextbook, ListTextbooks, EditChapter, Prompt, Notification, ViewUtils, AjaxHelpers, modal_helpers) ->
beforeEach ->
# remove this when we upgrade jasmine-jquery
@addMatchers
toContainText: (text) ->
trimmedText = $.trim(@actual.text())
if text and $.isFunction(text.test)
return text.test(trimmedText)
else
return trimmedText.indexOf(text) != -1;
describe "ShowTextbook", ->
tpl = readFixtures('show-textbook.underscore')
@@ -23,12 +13,12 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js
appendSetFixtures(sandbox({id: "page-notification"}))
appendSetFixtures(sandbox({id: "page-prompt"}))
@model = new Textbook({name: "Life Sciences", id: "0life-sciences"})
spyOn(@model, "destroy").andCallThrough()
spyOn(@model, "destroy").and.callThrough()
@collection = new TextbookSet([@model])
@view = new ShowTextbook({model: @model})
@promptSpies = spyOnConstructor(Prompt, "Warning", ["show", "hide"])
@promptSpies.show.andReturn(@promptSpies)
@promptSpies = jasmine.stealth.spyOnConstructor(Prompt, "Warning", ["show", "hide"])
@promptSpies.show.and.returnValue(@promptSpies)
window.course = new Course({
id: "5",
name: "Course Name",
@@ -53,7 +43,7 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js
it "should pop a delete confirmation when the delete button is clicked", ->
@view.render().$(".delete").click()
expect(@promptSpies.constructor).toHaveBeenCalled()
ctorOptions = @promptSpies.constructor.mostRecentCall.args[0]
ctorOptions = @promptSpies.constructor.calls.mostRecent().args[0]
expect(ctorOptions.title).toMatch(/Life Sciences/)
# hasn't actually been removed
expect(@model.destroy).not.toHaveBeenCalled()
@@ -73,9 +63,9 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js
describe "AJAX", ->
beforeEach ->
@savingSpies = spyOnConstructor(Notification, "Mini",
@savingSpies = jasmine.stealth.spyOnConstructor(Notification, "Mini",
["show", "hide"])
@savingSpies.show.andReturn(@savingSpies)
@savingSpies.show.and.returnValue(@savingSpies)
CMS.URL.TEXTBOOKS = "/textbooks"
afterEach ->
@@ -85,7 +75,7 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js
requests = AjaxHelpers["requests"](this)
@view.render().$(".delete").click()
ctorOptions = @promptSpies.constructor.mostRecentCall.args[0]
ctorOptions = @promptSpies.constructor.calls.mostRecent().args[0]
# run the primary function to indicate confirmation
ctorOptions.actions.primary.click(@promptSpies)
# AJAX request has been sent, but not yet returned
@@ -94,7 +84,7 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js
expect(@savingSpies.constructor).toHaveBeenCalled()
expect(@savingSpies.show).toHaveBeenCalled()
expect(@savingSpies.hide).not.toHaveBeenCalled()
savingOptions = @savingSpies.constructor.mostRecentCall.args[0]
savingOptions = @savingSpies.constructor.calls.mostRecent().args[0]
expect(savingOptions.title).toMatch(/Deleting/)
# return a success response
requests[0].respond(200)
@@ -114,7 +104,7 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js
@collection = new TextbookSet()
@collection.add(@model)
@view = new EditTextbook({model: @model})
spyOn(@view, 'render').andCallThrough()
spyOn(@view, 'render').and.callThrough()
it "should render properly", ->
@view.render()
@@ -209,10 +199,16 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js
expect(ViewUtils.setScrollOffset).toHaveBeenCalledWith($sectionEl, 0)
it "should focus first input element of newly added textbook", ->
spyOn(jQuery.fn, 'focus').andCallThrough()
@addMatchers
toHaveBeenCalledOnJQueryObject: (actual, expected) ->
pass: actual.calls && actual.calls.mostRecent() && actual.calls.mostRecent().object[0] == expected[0]
spyOn(jQuery.fn, 'focus').and.callThrough()
jasmine.addMatchers
toHaveBeenCalledOnJQueryObject: () ->
return {
compare: (actual, expected) ->
return {
pass: actual.calls && actual.calls.mostRecent() &&
actual.calls.mostRecent().object[0] == expected[0]
}
}
@view.$(".new-button").click()
$inputEl = @view.$el.find('section:last input:first')
expect($inputEl.length).toEqual(1)
@@ -229,13 +225,13 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js
# beforeEach ->
# setFixtures($("<script>", {id: "no-textbooks-tpl", type: "text/template"}).text(noTextbooksTpl))
# @showSpies = spyOnConstructor("ShowTextbook", ["render"])
# @showSpies.render.andReturn(@showSpies) # equivalent of `return this`
# @showSpies.render.and.returnValue(@showSpies) # equivalent of `return this`
# showEl = $("<li>")
# @showSpies.$el = showEl
# @showSpies.el = showEl.get(0)
# @editSpies = spyOnConstructor("EditTextbook", ["render"])
# editEl = $("<li>")
# @editSpies.render.andReturn(@editSpies)
# @editSpies.render.and.returnValue(@editSpies)
# @editSpies.$el = editEl
# @editSpies.el= editEl.get(0)
#
@@ -304,7 +300,7 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js
@collection = new ChapterSet()
@collection.add(@model)
@view = new EditChapter({model: @model})
spyOn(@view, "remove").andCallThrough()
spyOn(@view, "remove").and.callThrough()
CMS.URL.UPLOAD_ASSET = "/upload"
window.course = new Course({name: "abcde"})
@@ -324,10 +320,10 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js
# it "can open an upload dialog", ->
# uploadSpies = spyOnConstructor("UploadDialog", ["show", "el"])
# uploadSpies.show.andReturn(uploadSpies)
# uploadSpies.show.and.returnValue(uploadSpies)
#
# @view.render().$(".action-upload").click()
# ctorOptions = uploadSpies.constructor.mostRecentCall.args[0]
# ctorOptions = uploadSpies.constructor.calls.mostRecent().args[0]
# expect(ctorOptions.model.get('title')).toMatch(/abcde/)
# expect(typeof ctorOptions.onSuccess).toBe('function')
# expect(uploadSpies.show).toHaveBeenCalled()

View File

@@ -7,75 +7,80 @@ define ["js/models/uploads", "js/views/uploads", "js/models/chapter", "common/js
modal_helpers.installModalTemplates()
appendSetFixtures($("<script>", {id: "upload-dialog-tpl", type: "text/template"}).text(tpl))
CMS.URL.UPLOAD_ASSET = "/upload"
@model = new FileUpload(
mimeTypes: ['application/pdf']
)
@dialogResponse = dialogResponse = []
@view = new UploadDialog(
model: @model,
url: CMS.URL.UPLOAD_ASSET,
onSuccess: (response) =>
dialogResponse.push(response.response)
)
spyOn(@view, 'remove').andCallThrough()
# create mock file input, so that we aren't subject to browser restrictions
@mockFiles = []
mockFileInput = jasmine.createSpy('mockFileInput')
mockFileInput.files = @mockFiles
jqMockFileInput = jasmine.createSpyObj('jqMockFileInput', ['get', 'replaceWith'])
jqMockFileInput.get.andReturn(mockFileInput)
realMethod = @view.$
spyOn(@view, "$").andCallFake (selector) ->
if selector == "input[type=file]"
jqMockFileInput
else
realMethod.apply(this, arguments)
afterEach ->
delete CMS.URL.UPLOAD_ASSET
if (@view && modal_helpers.isShowingModal(@view))
@view.hide()
modal_helpers.cancelModalIfShowing()
createTestView = (test) ->
view = new UploadDialog(
model: test.model,
url: CMS.URL.UPLOAD_ASSET,
onSuccess: (response) =>
test.dialogResponse.push(response.response)
)
spyOn(view, 'remove').and.callThrough()
# create mock file input, so that we aren't subject to browser restrictions
mockFileInput = jasmine.createSpy('mockFileInput')
mockFileInput.files = test.mockFiles
jqMockFileInput = jasmine.createSpyObj('jqMockFileInput', ['get', 'replaceWith'])
jqMockFileInput.get.and.returnValue(mockFileInput)
originalView$ = view.$
spyOn(view, "$").and.callFake (selector) ->
if selector == "input[type=file]"
jqMockFileInput
else
originalView$.apply(this, arguments)
@lastView = view
describe "Basic", ->
it "should render without a file selected", ->
@view.render()
expect(@view.$el).toContain("input[type=file]")
expect(@view.$(".action-upload")).toHaveClass("disabled")
view = createTestView(this)
view.render()
expect(view.$el).toContainElement("input[type=file]")
expect(view.$(".action-upload")).toHaveClass("disabled")
it "should render with a PDF selected", ->
view = createTestView(this)
file = {name: "fake.pdf", "type": "application/pdf"}
@mockFiles.push(file)
@model.set("selectedFile", file)
@view.render()
expect(@view.$el).toContain("input[type=file]")
expect(@view.$el).not.toContain("#upload_error")
expect(@view.$(".action-upload")).not.toHaveClass("disabled")
view.render()
expect(view.$el).toContainElement("input[type=file]")
expect(view.$el).not.toContainElement("#upload_error")
expect(view.$(".action-upload")).not.toHaveClass("disabled")
it "should render an error with an invalid file type selected", ->
view = createTestView(this)
file = {name: "fake.png", "type": "image/png"}
@mockFiles.push(file)
@model.set("selectedFile", file)
@view.render()
expect(@view.$el).toContain("input[type=file]")
expect(@view.$el).toContain("#upload_error")
expect(@view.$(".action-upload")).toHaveClass("disabled")
view.render()
expect(view.$el).toContainElement("input[type=file]")
expect(view.$el).toContainElement("#upload_error")
expect(view.$(".action-upload")).toHaveClass("disabled")
it "should render an error with an invalid file type after a correct file type selected", ->
view = createTestView(this)
correctFile = {name: "fake.pdf", "type": "application/pdf"}
inCorrectFile = {name: "fake.png", "type": "image/png"}
event = {}
@view.render()
view.render()
event.target = {"files": [correctFile]}
@view.selectFile(event)
expect(@view.$el).toContain("input[type=file]")
expect(@view.$el).not.toContain("#upload_error")
expect(@view.$(".action-upload")).not.toHaveClass("disabled")
view.selectFile(event)
expect(view.$el).toContainElement("input[type=file]")
expect(view.$el).not.toContainElement("#upload_error")
expect(view.$(".action-upload")).not.toHaveClass("disabled")
realMethod = @model.set
spyOn(@model, "set").andCallFake (data) ->
spyOn(@model, "set").and.callFake (data) ->
if data.selectedFile != undefined
this.attributes.selectedFile = data.selectedFile
this.changed = {}
@@ -83,51 +88,46 @@ define ["js/models/uploads", "js/views/uploads", "js/models/chapter", "common/js
realMethod.apply(this, arguments)
event.target = {"files": [inCorrectFile]}
@view.selectFile(event)
expect(@view.$el).toContain("input[type=file]")
expect(@view.$el).toContain("#upload_error")
expect(@view.$(".action-upload")).toHaveClass("disabled")
view.selectFile(event)
expect(view.$el).toContainElement("input[type=file]")
expect(view.$el).toContainElement("#upload_error")
expect(view.$(".action-upload")).toHaveClass("disabled")
describe "Uploads", ->
beforeEach ->
@clock = sinon.useFakeTimers()
afterEach ->
modal_helpers.cancelModalIfShowing()
@clock.restore()
it "can upload correctly", ->
requests = AjaxHelpers["requests"](this)
@view.render()
@view.upload()
requests = AjaxHelpers.requests(this);
view = createTestView(this)
view.render()
view.upload()
expect(@model.get("uploading")).toBeTruthy()
expect(requests.length).toEqual(1)
request = requests[0]
expect(request.url).toEqual("/upload")
expect(request.method).toEqual("POST")
request.respond(200, {"Content-Type": "application/json"},
'{"response": "dummy_response"}')
AjaxHelpers.expectRequest(requests, "POST", "/upload")
AjaxHelpers.respondWithJson(requests, { response: "dummy_response"})
expect(@model.get("uploading")).toBeFalsy()
expect(@model.get("finished")).toBeTruthy()
expect(@dialogResponse.pop()).toEqual("dummy_response")
it "can handle upload errors", ->
requests = AjaxHelpers["requests"](this)
@view.render()
@view.upload()
requests[0].respond(500)
requests = AjaxHelpers.requests(this);
view = createTestView(this)
view.render()
view.upload()
AjaxHelpers.respondWithError(requests)
expect(@model.get("title")).toMatch(/error/)
expect(@view.remove).not.toHaveBeenCalled()
expect(view.remove).not.toHaveBeenCalled()
it "removes itself after two seconds on successful upload", ->
requests = AjaxHelpers["requests"](this)
@view.render()
@view.upload()
requests[0].respond(200, {"Content-Type": "application/json"},
'{"response": "dummy_response"}')
expect(modal_helpers.isShowingModal(@view)).toBeTruthy();
requests = AjaxHelpers.requests(this);
view = createTestView(this)
view.render()
view.upload()
AjaxHelpers.respondWithJson(requests, { response: "dummy_response"})
expect(modal_helpers.isShowingModal(view)).toBeTruthy();
@clock.tick(2001)
expect(modal_helpers.isShowingModal(@view)).toBeFalsy();
expect(modal_helpers.isShowingModal(view)).toBeFalsy();

View File

@@ -3,29 +3,21 @@
define(['jquery'], function($) { // jshint ignore:line
'use strict';
return function (that) {
that.addMatchers({
toContainText: function (text) {
// Assert the value being tested has text which matches the provided text
var trimmedText = $.trim($(this.actual).text());
if (text && $.isFunction(text.test)) {
return text.test(trimmedText);
} else {
return trimmedText.indexOf(text) !== -1;
}
},
toBeCorrectValuesInModel: function (values) {
return function () {
jasmine.addMatchers({
toBeCorrectValuesInModel: function () {
// Assert the value being tested has key values which match the provided values
return _.every(values, function (value, key) {
return this.actual.get(key) === value;
}.bind(this));
},
return {
compare: function (actual, values) {
var passed = _.every(values, function (value, key) {
return actual.get(key) === value;
}.bind(this));
toBeInstanceOf: function(expected) {
// Assert the type of the value being tested matches the provided type
return this.actual instanceof expected;
return {
pass: passed
};
}
};
}
});
};

View File

@@ -47,27 +47,6 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
ViewHelpers.verifyPromptHidden(promptSpy);
};
beforeEach(function() {
window.course = new Course({
id: '5',
name: 'Course Name',
url_name: 'course_name',
org: 'course_org',
num: 'course_num',
revision: 'course_rev'
});
window.certWebPreview = new CertificatePreview({
course_modes: ['honor', 'test'],
certificate_web_view_url: '/users/1/courses/orgX/009/2016'
});
window.CMS.User = {isGlobalStaff: true};
});
afterEach(function() {
delete window.course;
delete window.CMS.User;
});
describe('Certificate Details Spec:', function() {
var setValuesToInputs = function (view, values) {
_.each(values, function (value, selector) {
@@ -81,6 +60,20 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
beforeEach(function() {
TemplateHelpers.installTemplates(['certificate-details', 'signatory-details', 'signatory-editor', 'signatory-actions'], true);
window.course = new Course({
id: '5',
name: 'Course Name',
url_name: 'course_name',
org: 'course_org',
num: 'course_num',
revision: 'course_rev'
});
window.certWebPreview = new CertificatePreview({
course_modes: ['honor', 'test'],
certificate_web_view_url: '/users/1/courses/orgX/009/2016'
});
window.CMS.User = {isGlobalStaff: true};
this.newModelOptions = {add: true};
this.model = new CertificateModel({
name: 'Test Name',
@@ -97,7 +90,13 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
model: this.model
});
appendSetFixtures(this.view.render().el);
CustomMatchers(this); // jshint ignore:line
CustomMatchers(); // jshint ignore:line
});
afterEach(function() {
delete window.course;
delete window.certWebPreview;
delete window.CMS.User;
});
describe('The Certificate Details view', function() {

View File

@@ -18,7 +18,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
Notification, AjaxHelpers, TemplateHelpers, ViewHelpers, ValidationHelpers, CustomMatchers) {
'use strict';
var MAX_SIGNATORIES = 100;
var MAX_SIGNATORIES_LIMIT = 10;
var SELECTORS = {
detailsView: '.certificate-details',
editView: '.certificate-edit',
@@ -76,23 +76,6 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
AjaxHelpers.respondWithJson(requests, {asset: {url: file_path}});
};
beforeEach(function() {
window.course = new Course({
id: '5',
name: 'Course Name',
url_name: 'course_name',
org: 'course_org',
num: 'course_num',
revision: 'course_rev'
});
window.CMS.User = {isGlobalStaff: true};
});
afterEach(function() {
delete window.course;
delete window.CMS.User;
});
describe('Certificate editor view', function() {
var setValuesToInputs = function (view, values) {
_.each(values, function (value, selector) {
@@ -109,6 +92,16 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
beforeEach(function() {
TemplateHelpers.installTemplates(['certificate-editor', 'signatory-editor'], true);
window.course = new Course({
id: '5',
name: 'Course Name',
url_name: 'course_name',
org: 'course_org',
num: 'course_num',
revision: 'course_rev'
});
window.CMS.User = {isGlobalStaff: true};
this.newModelOptions = {add: true};
this.model = new CertificateModel({
name: 'Test Name',
@@ -122,10 +115,16 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
});
this.model.set('id', 0);
this.view = new CertificateEditorView({
model: this.model
model: this.model,
max_signatories_limit: MAX_SIGNATORIES_LIMIT
});
appendSetFixtures(this.view.render().el);
CustomMatchers(this); // jshint ignore:line
CustomMatchers(); // jshint ignore:line
});
afterEach(function() {
delete window.course;
delete window.CMS.User;
});
describe('Basic', function () {
@@ -198,8 +197,8 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
expect(this.collection.length).toBe(1);
});
it('user can only add signatories up to max 100', function() {
for(var i = 1; i < MAX_SIGNATORIES ; i++) {
it('user can only add signatories up to limit', function() {
for(var i = 1; i < MAX_SIGNATORIES_LIMIT ; i++) {
this.view.$(SELECTORS.addSignatoryButton).click();
}
expect(this.view.$(SELECTORS.addSignatoryButton)).toHaveClass('disableClick');
@@ -215,7 +214,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
it('user can add signatories when signatory reached the upper limit But after deleting a signatory',
function() {
for(var i = 1; i < MAX_SIGNATORIES ; i++) {
for(var i = 1; i < MAX_SIGNATORIES_LIMIT ; i++) {
this.view.$(SELECTORS.addSignatoryButton).click();
}
expect(this.view.$(SELECTORS.addSignatoryButton)).toHaveClass('disableClick');
@@ -274,7 +273,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
var signatory = this.model.get('signatories').at(0);
var signatory_url = '/certificates/signatory';
signatory.url = signatory_url;
spyOn(signatory, "isNew").andReturn(false);
spyOn(signatory, "isNew").and.returnValue(false);
var text = 'Delete "'+ signatory.get('name') +'" from the list of signatories?';
clickDeleteItem(this, text, SELECTORS.signatoryDeleteButton + ':first', signatory_url);
expect(this.model.get('signatories').length).toEqual(total_signatories - 1);
@@ -283,7 +282,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
it('can cancel deletion of signatories', function() {
this.view.$(SELECTORS.addSignatoryButton).click();
var signatory = this.model.get('signatories').at(0);
spyOn(signatory, "isNew").andReturn(false);
spyOn(signatory, "isNew").and.returnValue(false);
// add one more signatory
this.view.$(SELECTORS.addSignatoryButton).click();
var total_signatories = this.model.get('signatories').length;

View File

@@ -18,23 +18,6 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel
preview_certificate: '.preview-certificate-link'
};
beforeEach(function() {
window.course = new Course({
id: '5',
name: 'Course Name',
url_name: 'course_name',
org: 'course_org',
num: 'course_num',
revision: 'course_rev'
});
window.CMS.User = {isGlobalStaff: true};
});
afterEach(function() {
delete window.course;
delete window.CMS.User;
});
describe('Certificate Web Preview Spec:', function() {
var selectDropDownByText = function ( element, value ) {
@@ -45,8 +28,18 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel
};
beforeEach(function() {
TemplateHelpers.installTemplate('certificate-web-preview', true);
appendSetFixtures('<div class="preview-certificate nav-actions"></div>');
window.course = new Course({
id: '5',
name: 'Course Name',
url_name: 'course_name',
org: 'course_org',
num: 'course_num',
revision: 'course_rev'
});
window.CMS.User = {isGlobalStaff: true};
this.view = new CertificatePreview({
el: $('.preview-certificate'),
course_modes: ['test1', 'test2', 'test3'],
@@ -57,6 +50,11 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel
appendSetFixtures(this.view.render().el);
});
afterEach(function() {
delete window.course;
delete window.CMS.User;
});
describe('Certificate preview', function() {
it('course mode event should call when user choose a new mode', function () {
spyOn(this.view, 'courseModeChanged');
@@ -122,7 +120,7 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel
it('certificate web preview should be removed when method "remove" called', function () {
this.view.remove();
expect(this.view.el.innerHTML).toContain("");
expect(this.view.el.innerHTML).toBe('');
});
it('method "show" should call the render function', function () {

View File

@@ -27,33 +27,28 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
newCertificateButton: '.new-button'
};
beforeEach(function() {
window.course = new Course({
id: '5',
name: 'Course Name',
url_name: 'course_name',
org: 'course_org',
num: 'course_num',
revision: 'course_rev'
});
window.certWebPreview = new CertificatePreview({
course_modes: ['honor', 'test'],
certificate_web_view_url: '/users/1/courses/orgX/009/2016'
});
});
afterEach(function() {
delete window.course;
});
describe('Certificates list view', function() {
var emptyMessage = 'You have not created any certificates yet.';
beforeEach(function() {
TemplateHelpers.installTemplates(
['certificate-editor', 'certificate-edit', 'list']
['certificate-editor', 'list']
);
window.course = new Course({
id: '5',
name: 'Course Name',
url_name: 'course_name',
org: 'course_org',
num: 'course_num',
revision: 'course_rev'
});
window.certWebPreview = new CertificatePreview({
course_modes: ['honor', 'test'],
certificate_web_view_url: '/users/1/courses/orgX/009/2016'
});
window.CMS.User = {isGlobalStaff: true};
this.model = new CertificateModel({
course_title: 'Test Course Title Override'
}, {add: true});
@@ -61,11 +56,18 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
this.collection = new CertificatesCollection([], {
certificateUrl: '/certificates/'+ window.course.id
});
this.model.set('id', 0);
this.view = new CertificatesListView({
collection: this.collection
});
appendSetFixtures(this.view.render().el);
CustomMatchers(this); // jshint ignore:line
CustomMatchers(); // jshint ignore:line
});
afterEach(function() {
delete window.course;
delete window.certWebPreview;
delete window.CMS.User;
});
describe('empty template', function () {

View File

@@ -9,9 +9,11 @@ define([ // jshint ignore:line
'js/certificates/models/signatory',
'js/certificates/views/signatory_details',
'common/js/components/utils/view_utils',
'jquery.smoothScroll'
'jquery.smoothScroll',
'text!templates/certificate-details.underscore'
],
function($, _, str, gettext, BaseView, SignatoryModel, SignatoryDetailsView, ViewUtils) {
function($, _, str, gettext, BaseView, SignatoryModel, SignatoryDetailsView, ViewUtils, smoothScroll,
certificateDetailsTemplate) {
'use strict';
var CertificateDetailsView = BaseView.extend({
tagName: 'div',
@@ -31,7 +33,6 @@ function($, _, str, gettext, BaseView, SignatoryModel, SignatoryDetailsView, Vie
initialize: function() {
// Set up the initial state of the attributes set for this model instance
this.showDetails = true;
this.template = this.loadTemplate('certificate-details');
this.listenTo(this.model, 'change', this.render);
},
@@ -61,7 +62,7 @@ function($, _, str, gettext, BaseView, SignatoryModel, SignatoryDetailsView, Vie
index: this.model.collection.indexOf(this.model),
showDetails: this.showDetails || showDetails || false
});
this.$el.html(this.template(attrs));
this.$el.html(_.template(certificateDetailsTemplate)(attrs));
if(this.showDetails || showDetails) {
var self = this;
this.model.get("signatories").each(function (modelSignatory) {

View File

@@ -7,10 +7,11 @@ define([ // jshint ignore:line
'gettext',
'js/views/list_item_editor',
'js/certificates/models/signatory',
'js/certificates/views/signatory_editor'
'js/certificates/views/signatory_editor',
'text!templates/certificate-editor.underscore'
],
function($, _, Backbone, gettext,
ListItemEditorView, SignatoryModel, SignatoryEditorView) {
ListItemEditorView, SignatoryModel, SignatoryEditorView, certificateEditorTemplate) {
'use strict';
// If signatories limit is required to specific value then we can change it.
@@ -41,14 +42,15 @@ function($, _, Backbone, gettext,
].join(' ');
},
initialize: function() {
initialize: function(options) {
// Set up the initial state of the attributes set for this model instance
_.bindAll(this, "onSignatoryRemoved", "clearErrorMessage");
this.max_signatories_limit = options.max_signatories_limit || MAX_SIGNATORIES_LIMIT;
this.template = _.template(certificateEditorTemplate);
this.eventAgg = _.extend({}, Backbone.Events);
this.eventAgg.bind("onSignatoryRemoved", this.onSignatoryRemoved);
this.eventAgg.bind("onSignatoryUpdated", this.clearErrorMessage);
ListItemEditorView.prototype.initialize.call(this);
this.template = this.loadTemplate('certificate-editor');
},
onSignatoryRemoved: function() {
@@ -87,7 +89,7 @@ function($, _, Backbone, gettext,
disableAddSignatoryButton: function() {
// Disable the 'Add Signatory' link if the constraint has been met.
if(this.$(".signatory-edit-list > div.signatory-edit").length >= MAX_SIGNATORIES_LIMIT) {
if(this.$(".signatory-edit-list > div.signatory-edit").length >= this.max_signatories_limit) {
this.$(".action-add-signatory").addClass("disableClick");
}
},

View File

@@ -7,9 +7,10 @@ define([ // jshint ignore:line
'gettext',
'js/views/baseview',
'common/js/components/utils/view_utils',
'common/js/components/views/feedback_notification'
'common/js/components/views/feedback_notification',
"text!templates/certificate-web-preview.underscore"
],
function(_, gettext, BaseView, ViewUtils, NotificationView) {
function(_, gettext, BaseView, ViewUtils, NotificationView, certificateWebPreviewTemplate) {
'use strict';
var CertificateWebPreview = BaseView.extend({
el: $(".preview-certificate"),
@@ -23,11 +24,10 @@ function(_, gettext, BaseView, ViewUtils, NotificationView) {
this.certificate_web_view_url = options.certificate_web_view_url;
this.certificate_activation_handler_url = options.certificate_activation_handler_url;
this.is_active = options.is_active;
this.template = this.loadTemplate('certificate-web-preview');
},
render: function () {
this.$el.html(this.template({
this.$el.html(_.template(certificateWebPreviewTemplate)({
course_modes: this.course_modes,
certificate_web_view_url: this.certificate_web_view_url,
is_active: this.is_active

View File

@@ -9,9 +9,12 @@ define([ // jshint ignore:line
'js/utils/templates',
'common/js/components/utils/view_utils',
'js/views/baseview',
'js/certificates/views/signatory_editor'
'js/certificates/views/signatory_editor',
'text!templates/signatory-details.underscore',
'text!templates/signatory-actions.underscore'
],
function ($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, SignatoryEditorView) {
function ($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, SignatoryEditorView,
signatoryDetailsTemplate, signatoryActionsTemplate) {
'use strict';
var SignatoryDetailsView = BaseView.extend({
tagName: 'div',
@@ -39,8 +42,6 @@ function ($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, Sign
isEditingAllCollections: false,
eventAgg: this.eventAgg
});
this.template = this.loadTemplate('signatory-details');
this.signatory_action_template = this.loadTemplate('signatory-actions');
},
loadTemplate: function(name) {
@@ -52,7 +53,7 @@ function ($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, Sign
// Retrieve the edit view for this model
if (event && event.preventDefault) { event.preventDefault(); }
this.$el.html(this.edit_view.render());
$(this.signatory_action_template()).appendTo(this.el);
$(_.template(signatoryActionsTemplate)()).appendTo(this.el);
this.edit_view.delegateEvents();
this.delegateEvents();
},
@@ -93,7 +94,7 @@ function ($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, Sign
var attributes = $.extend({}, this.model.attributes, {
signatory_number: this.model.collection.indexOf(this.model) + 1
});
return $(this.el).html(this.template(attributes));
return $(this.el).html(_.template(signatoryDetailsTemplate)(attributes));
}
});
return SignatoryDetailsView;

View File

@@ -10,10 +10,12 @@ define([ // jshint ignore:line
'common/js/components/views/feedback_prompt',
'common/js/components/views/feedback_notification',
'js/models/uploads',
'js/views/uploads'
'js/views/uploads',
'text!templates/signatory-editor.underscore'
],
function ($, _, Backbone, gettext,
TemplateUtils, ViewUtils, PromptView, NotificationView, FileUploadModel, FileUploadDialog) {
TemplateUtils, ViewUtils, PromptView, NotificationView, FileUploadModel, FileUploadDialog,
signatoryEditorTemplate) {
'use strict';
var SignatoryEditorView = Backbone.View.extend({
tagName: 'div',
@@ -41,7 +43,6 @@ function ($, _, Backbone, gettext,
this.model.bind('change', this.render);
this.eventAgg = options.eventAgg;
this.isEditingAllCollections = options.isEditingAllCollections;
this.template = this.loadTemplate('signatory-editor');
},
getModelIndex: function(givenModel) {
@@ -77,7 +78,7 @@ function ($, _, Backbone, gettext,
is_editing_all_collections: this.isEditingAllCollections,
total_saved_signatories: this.getTotalSignatoriesOnServer()
});
return $(this.el).html(this.template(attributes));
return $(this.el).html(_.template(signatoryEditorTemplate)(attributes));
},
setSignatoryName: function(event) {

View File

@@ -219,7 +219,6 @@
"<%= user %> has been successfully added to the exception list. Click Generate Exception Certificate below to send the certificate.": "\u0623\u064f\u064f\u0636\u064a\u0641 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645 <%= user %> \u0628\u0646\u062c\u0627\u062d \u0625\u0644\u0649 \u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0627\u0633\u062a\u062b\u0646\u0627\u0621. \u0627\u0646\u0642\u0631 \u0639\u0644\u0649 \u2019\u0625\u0646\u0634\u0627\u0621 \u0634\u0647\u0627\u062f\u0629 \u0627\u0633\u062a\u062b\u0646\u0627\u0621\u2018 \u0623\u062f\u0646\u0627\u0647 \u0644\u0625\u0631\u0633\u0627\u0644 \u0627\u0644\u0634\u0647\u0627\u062f\u0629.",
"<button data-provider=\"%s\" data-course-key=\"%s\" data-username=\"%s\" class=\"complete-course\" onClick=completeOrder(this)>%s</button>": "<button data-provider=\"%s\" data-course-key=\"%s\" data-username=\"%s\" class=\"complete-course\" onClick=completeOrder(this)>%s</button>",
"<img src='%s' alt='%s'></image>": "<img src='%s' alt='%s'></image>",
"<li>Transcript will be displayed when ": "<li> \u0633\u064a\u064f\u0639\u0631\u0636 \u0646\u0635 \u0627\u0644\u0639\u0646\u0627\u0648\u064a\u0646 \u0627\u0644\u0641\u0631\u0639\u064a\u0651\u0629 \u0639\u0646\u062f\u0645\u0627",
"A driver's license, passport, or government-issued ID with your name and photo.": "\u0631\u062e\u0635\u0629 \u0627\u0644\u0642\u064a\u0627\u062f\u0629\u060c \u0623\u0648 \u062c\u0648\u0627\u0632 \u0627\u0644\u0633\u0641\u0631\u060c \u0623\u0648 \u0628\u0637\u0627\u0642\u0629 \u0634\u062e\u0635\u064a\u0629 \u0635\u0627\u062f\u0631\u0629 \u0639\u0646 \u0627\u0644\u062d\u0643\u0648\u0645\u0629\u060c \u0628\u062d\u064a\u062b \u062a\u062d\u0645\u0644 \u0623\u064a \u0648\u0627\u062d\u062f\u0629 \u0645\u0646 \u0647\u0630\u0647 \u0627\u0644\u0648\u062b\u0627\u0626\u0642 \u0627\u0633\u0645\u0643 \u0648\u0635\u0648\u0631\u062a\u0643 ",
"A driver's license, passport, or other government-issued ID with your name and photo": "\u0631\u062e\u0635\u0629 \u0627\u0644\u0642\u064a\u0627\u062f\u0629\u060c \u0623\u0648 \u062c\u0648\u0627\u0632 \u0627\u0644\u0633\u0641\u0631\u060c \u0623\u0648 \u0628\u0637\u0627\u0642\u0629 \u0634\u062e\u0635\u064a\u0629 \u0635\u0627\u062f\u0631\u0629 \u0639\u0646 \u0627\u0644\u062d\u0643\u0648\u0645\u0629\u060c \u0628\u062d\u064a\u062b \u062a\u062d\u0645\u0644 \u0623\u064a \u0648\u0627\u062d\u062f\u0629 \u0645\u0646 \u0647\u0630\u0647 \u0627\u0644\u0648\u062b\u0627\u0626\u0642 \u0627\u0633\u0645\u0643 \u0648\u0635\u0648\u0631\u062a\u0643 ",
"A list of courses you have just enrolled in as a verified student": "\u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0645\u0633\u0627\u0642\u0627\u062a \u0627\u0644\u062a\u064a \u0633\u062c\u0651\u0644\u062a \u0641\u064a\u0647\u0627 \u0644\u062a\u0648\u0651\u0643 \u0643\u0637\u0627\u0644\u0628 \u0645\u0648\u062b\u0651\u064e\u0642 ",
@@ -238,7 +237,6 @@
"Actions": "\u0627\u0644\u0625\u062c\u0631\u0627\u0621\u0627\u062a",
"Activate": "\u062a\u0641\u0639\u064a\u0644",
"Activate Your Account": "\u0642\u0645 \u0628\u062a\u0641\u0639\u064a\u0644 \u062d\u0633\u0627\u0628\u0643 ",
"Activating an item in this group will spool the video to the corresponding time point. To skip transcript, go to previous item.": "\u0633\u064a\u0624\u062f\u0651\u064a \u062a\u0641\u0639\u064a\u0644 \u0623\u062d\u062f \u0627\u0644\u0639\u0646\u0627\u0635\u0631 \u0641\u064a \u0647\u0630\u0647 \u0627\u0644\u0645\u062c\u0645\u0648\u0639\u0629 \u0625\u0644\u0649 \u062a\u062d\u0631\u064a\u0643 \u0627\u0644\u0641\u064a\u062f\u064a\u0648 \u0646\u062d\u0648 \u0627\u0644\u0646\u0642\u0637\u0629 \u0627\u0644\u0632\u0645\u0646\u064a\u0629 \u0627\u0644\u0645\u0648\u0627\u0641\u0642\u0629. \u0648\u0644\u062a\u062e\u0637\u0651\u064a \u0627\u0644\u0646\u0635\u060c \u064a\u064f\u0631\u062c\u0649 \u0627\u0644\u0630\u0647\u0627\u0628 \u0625\u0644\u0649 \u0627\u0644\u0639\u0646\u0635\u0631 \u0627\u0644\u0633\u0627\u0628\u0642.",
"Active Threads": "\u0627\u0644\u0645\u0648\u0627\u0636\u064a\u0639 \u0627\u0644\u0646\u0634\u0637\u0629",
"Active Uploads": "\u0627\u0644\u062a\u062d\u0645\u064a\u0644\u0627\u062a \u0627\u0644\u0646\u0634\u0637\u0629",
"Add": "\u0625\u0636\u0627\u0641\u0629",
@@ -406,7 +404,6 @@
"Change My Email Address": "\u062a\u063a\u064a\u064a\u0631 \u0639\u0646\u0648\u0627\u0646 \u0628\u0631\u064a\u062f\u064a \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a",
"Change image": "\u062a\u063a\u064a\u064a\u0631 \u0627\u0644\u0635\u0648\u0631\u0629",
"Change the settings for %(display_name)s": "\u062a\u063a\u064a\u064a\u0631 \u0627\u0644\u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0627\u0644\u062e\u0627\u0635\u0629 \u0628\u0640 %(display_name)s ",
"Chapter %s": "\u0627\u0644\u0641\u0635\u0644 %s",
"Chapter Asset": "\u0645\u0627\u062f\u0629 \u0645\u0644\u062d\u0642\u0629 \u0628\u0641\u0635\u0644",
"Chapter Name": "\u0627\u0633\u0645 \u0627\u0644\u0641\u0635\u0644",
"Chapter information": "\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0639\u0646 \u0627\u0644\u0641\u0635\u0644",
@@ -775,7 +772,6 @@
"General": "\u0639\u0627\u0645",
"Generate": "\u0625\u0646\u0634\u0627\u0621",
"Generate Exception Certificates": "\u0625\u0646\u0634\u0627\u0621 \u0634\u0647\u0627\u062f\u0627\u062a \u0627\u0633\u062a\u062b\u0646\u0627\u0626\u064a\u0629",
"Generate a Certificate for all ": "\u0625\u0646\u0634\u0627\u0621 \u0634\u0647\u0627\u062f\u0629 \u0644\u0644\u062c\u0645\u064a\u0639",
"Generate a Certificate for all users on the Exception list": "\u0625\u0646\u0634\u0627\u0621 \u0634\u0647\u0627\u062f\u0629 \u0644\u062c\u0645\u064a\u0639 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645\u064a\u0646 \u0627\u0644\u0645\u062f\u0631\u062c\u0629 \u0627\u0633\u0645\u0627\u0624\u0647\u0645 \u0639\u0644\u0649 \u0644\u0627\u0626\u062d\u0629 \u0627\u0644\u0627\u0633\u062a\u062b\u0646\u0627\u0621\u0627\u062a",
"Generate the user's certificate": "\u0625\u0646\u0634\u0627\u0621 \u0634\u0647\u0627\u062f\u0629 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645",
"Get Credit": "\u0627\u062d\u0635\u0644 \u0639\u0644\u0649 \u0645\u0627\u062f\u0651\u0629 \u062f\u0631\u0627\u0633\u064a\u0629",
@@ -898,7 +894,6 @@
"Keywords": "\u0643\u0644\u0645\u0627\u062a \u0645\u0641\u062a\u0627\u062d\u064a\u0629",
"LEARN MORE": "\u0627\u0639\u0631\u0641 \u0627\u0644\u0645\u0632\u064a\u062f",
"Language": "\u0627\u0644\u0644\u063a\u0629",
"Language: Press the UP arrow key to enter the language menu, then use UP and DOWN arrow keys to navigate language options. Press ENTER to change to the selected language.": "\u0627\u0644\u0644\u063a\u0629: \u0627\u0644\u0636\u063a\u0637 \u0639\u0644\u0649 \u0632\u0631 \u0627\u0644\u0633\u0647\u0645 \"\u0623\u0639\u0644\u0649\" \u0644\u0644\u062f\u062e\u0648\u0644 \u0625\u0644\u0649 \u0642\u0627\u0626\u0645\u0629 \u0636\u0628\u0637 \u0627\u0644\u0644\u063a\u0629 \u0648\u0645\u0646 \u062b\u0645 \u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0632\u0631\u064a\u0651 \u0627\u0644\u0623\u0633\u0647\u0645 \"\u0623\u0639\u0644\u0649\" \u0648\"\u0623\u0633\u0641\u0644\" \u0644\u0644\u0627\u0646\u062a\u0642\u0627\u0644 \u0628\u064a\u0646 \u062e\u064a\u0627\u0631\u0627\u062a \u0627\u0644\u0644\u063a\u0627\u062a \u0627\u0644\u0645\u062e\u062a\u0644\u0641\u0629 \u0648\u0645\u0646 \u062b\u0645 \u0627\u0644\u0636\u063a\u0637 \u0639\u0644\u0649 \u0632\u0631 \"Enter\" \u0644\u0627\u0639\u062a\u0645\u0627\u062f \u0627\u0644\u0644\u063a\u0629 \u0627\u0644\u0645\u062e\u062a\u0627\u0631\u0629.",
"Large": "\u0643\u0628\u064a\u0631 ",
"Last Activity %(date)s": "\u0627\u0644\u0646\u0634\u0627\u0637 \u0627\u0644\u0623\u062e\u064a\u0631 \u0628\u062a\u0627\u0631\u064a\u062e %(date)s",
"Last Edited:": "\u0622\u062e\u0631 \u0645\u0631\u0627\u062c\u0639\u0629 \u0641\u064a:",
@@ -994,7 +989,6 @@
"Name of the signatory": "\u0627\u0633\u0645 \u0627\u0644\u0645\u0648\u0642\u0651\u0650\u0639",
"Name or short description of the configuration": "\u0627\u0633\u0645 \u0627\u0644\u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0623\u0648 \u0648\u0635\u0641 \u0645\u0648\u062c\u064e\u0632 \u0639\u0646\u0647\u0627",
"Never published": "\u0644\u0645 \u062a\u064f\u0646\u0634\u064e\u0631 \u0642\u0637\u0651",
"New": "\u062c\u062f\u064a\u062f",
"New %(component_type)s": "\u0625\u0636\u0627\u0641\u0629 %(component_type)s",
"New %(item_type)s": "%(item_type)s \u062c\u062f\u064a\u062f",
"New Address": "\u0639\u0646\u0648\u0627\u0646 \u062c\u062f\u064a\u062f",
@@ -1045,13 +1039,10 @@
"Numbered list": "\u0644\u0627\u0626\u062d\u0629 \u0645\u0631\u0642\u0651\u0645\u0629",
"OK": "\u0645\u0648\u0627\u0641\u0642",
"Ok": "\u0645\u0648\u0627\u0641\u0642",
"Once in position, use the camera button %(icon)s to capture your ID": "\u062d\u0627\u0644\u0645\u0627 \u062a\u0636\u0628\u0637 \u0648\u0636\u0639\u064a\u0629 \u0628\u0637\u0627\u0642\u062a\u0643 \u0627\u0644\u0634\u062e\u0635\u064a\u0629\u060c \u0627\u0633\u062a\u062e\u062f\u0645 \u0632\u0631 \u0627\u0644\u0643\u0627\u0645\u064a\u0631\u0627 %(icon)s \u0644\u0627\u0644\u062a\u0642\u0627\u0637 \u0635\u0648\u0631\u0629 \u0644\u0647\u0627. ",
"Once in position, use the camera button %(icon)s to capture your photo": "\u062d\u0627\u0644\u0645\u0627 \u062a\u062a\u0651\u062e\u0630 \u0648\u0636\u0639\u064a\u0629 \u0627\u0644\u062c\u0644\u0648\u0633 \u0627\u0644\u0645\u0646\u0627\u0633\u0628\u0629\u060c \u064a\u064f\u0631\u062c\u0649 \u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0632\u0631 \u0627\u0644\u0643\u0627\u0645\u064a\u0631\u0627 %(icon)s \u0644\u062a\u0644\u062a\u0642\u0637 \u0635\u0648\u0631\u0643. ",
"Only <%= fileTypes %> files can be uploaded. Please select a file ending in <%= fileExtensions %> to upload.": "\u0644\u0627 \u064a\u0645\u0643\u0646 \u062a\u062d\u0645\u064a\u0644 \u0633\u0648\u0649 \u0627\u0644\u0645\u0644\u0641\u0651\u0627\u062a <%= fileTypes %>. \u0644\u0630\u0627 \u064a\u064f\u0631\u062c\u0649 \u0627\u062e\u062a\u064a\u0627\u0631 \u0645\u0644\u0641 \u064a\u0646\u062a\u0647\u064a \u0628\u0640 <%= fileExtensions %> \u0644\u062a\u062d\u0645\u064a\u0644\u0647. ",
"Only properly formatted .csv files will be accepted.": "\u0644\u0646 \u062a\u064f\u0642\u0628\u0644 \u0633\u0648\u0649 \u0645\u0644\u0641\u0651\u0627\u062a .csv \u0627\u0644\u0645\u0646\u0633\u0651\u0642\u0629 \u062a\u0646\u0633\u064a\u0642\u064b\u0627 \u0635\u062d\u064a\u062d\u064b\u0627. ",
"Open": "\u0641\u062a\u062d",
"Open Calculator": "\u0641\u062a\u062d \u0627\u0644\u0622\u0644\u0629 \u0627\u0644\u062d\u0627\u0633\u0628\u0629 ",
"Open language menu": "\u0641\u062a\u062d \u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0644\u063a\u0627\u062a \u0627\u0644\u0645\u062a\u0648\u0641\u0631\u0629",
"Open/download this file": "\u0641\u062a\u062d/\u062a\u0646\u0632\u064a\u0644 \u0647\u0630\u0627 \u0627\u0644\u0645\u0644\u0641\u0651",
"OpenAssessment Save Error": "\u0646\u0623\u0633\u0641 \u0644\u062d\u062f\u0648\u062b \u062e\u0637\u0623 \u0641\u064a \u062d\u0641\u0638 \u0627\u0644\u062a\u0642\u064a\u064a\u0645 \u0627\u0644\u0645\u0641\u062a\u0648\u062d.",
"Optional Characteristics": "\u0627\u0644\u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u0627\u062e\u062a\u064a\u0627\u0631\u064a\u0629",
@@ -1063,7 +1054,6 @@
"Organization of the signatory": "\u0645\u0624\u0633\u0651\u0633\u0629 \u0627\u0644\u0645\u0648\u0642\u0651\u0650\u0639",
"Other": "\u063a\u064a\u0631 \u0630\u0644\u0643",
"Page break": "\u0641\u0627\u0635\u0644 \u0627\u0644\u0635\u0641\u062d\u0629",
"Page number": "\u0631\u0642\u0645 \u0627\u0644\u0635\u0641\u062d\u0629",
"Paragraph": "\u0641\u0642\u0631\u0629",
"Password": "\u0643\u0644\u0645\u0629 \u0627\u0644\u0633\u0631",
"Password Reset Email Sent": "\u0644\u0642\u062f \u0623\u0631\u0633\u0644\u0646\u0627 \u0628\u0631\u064a\u062f\u0627\u064b \u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a\u0627\u064b \u0644\u0643 \u0644\u062a\u063a\u064a\u064a\u0631 \u0643\u0644\u0645\u0629 \u0627\u0644\u0633\u0631.",
@@ -1146,7 +1136,6 @@
"Proctored": "\u0645\u064f\u0631\u0627\u0642\u0628",
"Proctored Exam": "\u0627\u0645\u062a\u062d\u0627\u0646 \u0645\u0631\u0627\u0642\u064e\u0628",
"Proctored exams are timed and they record video of each learner taking the exam. The videos are then reviewed to ensure that learners follow all examination rules.": "\u0627\u0644\u0627\u0645\u062a\u062d\u0627\u0646\u0627\u062a \u0627\u0644\u0645\u0631\u0627\u0642\u0628\u0629 \u0645\u062d\u062f\u0651\u062f\u0629 \u0627\u0644\u062a\u0648\u0642\u064a\u062a\u060c \u0648\u0633\u064a\u064f\u0633\u062c\u0651\u0644 \u0645\u0642\u0637\u0639 \u0641\u064a\u062f\u064a\u0648 \u0644\u0643\u0644 \u0645\u062a\u0639\u0644\u0651\u0645 \u064a\u064f\u062c\u0631\u064a \u0627\u0645\u062a\u062d\u0627\u0646\u064b\u0627 \u0644\u062a\u064f\u0631\u0627\u062c\u0639 \u0645\u0642\u0627\u0637\u0639 \u0627\u0644\u0641\u064a\u062f\u064a\u0648 \u0647\u0630\u0647 \u0628\u0639\u062f \u0630\u0644\u0643 \u0628\u0647\u062f\u0641 \u0636\u0645\u0627\u0646 \u0627\u0644\u062a\u0632\u0627\u0645 \u0627\u0644\u0645\u062a\u0639\u0644\u0651\u0645\u064a\u0646 \u0628\u062c\u0645\u064a\u0639 \u0627\u0644\u0642\u0648\u0627\u0639\u062f \u0627\u0644\u0627\u0645\u062a\u062d\u0627\u0646\u064a\u0629.",
"Professional Certificate for %(courseName)s": "\u0634\u0647\u0627\u062f\u0629 \u0645\u0647\u0646\u064a\u0651\u0629 \u0644\u0644\u0645\u0633\u0627\u0642 %(courseName)s",
"Professional Education": "\u0627\u0644\u062a\u0639\u0644\u064a\u0645 \u0627\u0644\u0645\u0647\u0646\u064a",
"Professional Education Verified Certificate": "\u0634\u0647\u0627\u062f\u0629 \u0645\u0648\u062b\u0651\u0642\u0629 \u0644\u0644\u062a\u0639\u0644\u064a\u0645 \u0627\u0644\u0645\u0647\u0646\u064a",
"Profile Image": "\u0635\u0648\u0631\u0629 \u0627\u0644\u0645\u0644\u0641 \u0627\u0644\u0634\u062e\u0635\u064a",
@@ -1413,9 +1402,7 @@
"Textbook name is required": "\u0627\u0633\u0645 \u0627\u0644\u0643\u062a\u0627\u0628 \u0645\u0637\u0644\u0648\u0628",
"Thank you for submitting your financial assistance application for {course_name}! You can expect a response in 2-4 business days.": "\u0646\u0634\u0643\u0631\u0643 \u0644\u062a\u0642\u062f\u064a\u0645\u0643 \u0637\u0644\u0628 \u062f\u0639\u0645 \u0645\u0627\u0644\u064a \u0644\u0644\u0645\u0633\u0627\u0642 {course_name}! \u064a\u0645\u0643\u0646\u0643 \u0623\u0646 \u062a\u062a\u0648\u0642\u0639 \u0627\u0633\u062a\u0644\u0627\u0645 \u0627\u0644\u0631\u062f\u0651 \u062e\u0644\u0627\u0644 2-4 \u0623\u064a\u0627\u0645 \u0639\u0645\u0644.",
"Thank you for submitting your photos. We will review them shortly. You can now sign up for any %(platformName)s course that offers verified certificates. Verification is good for one year. After one year, you must submit photos for verification again.": "\u0634\u0643\u0631\u064b\u0627 \u0644\u0643 \u0639\u0644\u0649 \u062a\u0642\u062f\u064a\u0645 \u0635\u0648\u0631\u0643. \u0633\u0646\u0631\u0627\u062c\u0639\u0647\u0627 \u0642\u0631\u064a\u0628\u064b\u0627. \u0648\u064a\u0645\u0643\u0646\u0643 \u0627\u0644\u0622\u0646 \u062a\u0633\u062c\u064a\u0644 \u0639\u0636\u0648\u064a\u062a\u0643 \u0641\u064a \u0623\u064a\u064b \u0645\u0646 \u0645\u0633\u0627\u0642\u0627\u062a %(platformName)s \u0627\u0644\u062a\u064a \u062a\u0645\u0646\u062d \u0634\u0647\u0627\u062f\u0627\u062a \u0645\u0648\u062b\u0651\u0651\u064e\u0642\u0629. \u0648\u0628\u064a\u0646\u0645\u0627 \u064a\u0633\u0631\u064a \u0645\u0641\u0639\u0648\u0644 \u0639\u0645\u0644\u064a\u0629 \u0627\u0644\u062a\u062d\u0642\u0651\u0642 \u0644\u0645\u062f\u0651\u0629 \u0639\u0627\u0645\u060c \u064a\u062c\u0628 \u0623\u0646 \u062a\u0642\u062f\u0651\u0645 \u0627\u0644\u0635\u0648\u0631 \u0644\u0644\u062a\u062d\u0642\u0651\u0642 \u0645\u0646\u0647\u0627 \u0645\u062c\u062f\u0651\u062f\u064b\u0627 \u0628\u0639\u062f \u0627\u0646\u0642\u0636\u0627\u0621 \u0627\u0644\u0639\u0627\u0645. ",
"Thank you! We have received your payment for %(courseName)s.": "\u0634\u0643\u0631\u064b\u0627 \u062c\u0632\u064a\u0644\u064b\u0627! \u0644\u0642\u062f \u062a\u0644\u0642\u0651\u064a\u0646\u0627 \u0627\u0644\u0645\u0628\u0644\u063a \u0627\u0644\u0630\u064a \u0633\u0627\u0647\u0645\u062a \u0628\u0647 \u0641\u064a %(courseName)s",
"Thank you! We have received your payment for %(course_name)s.": "\u0634\u0643\u0631\u064b\u0627 \u062c\u0632\u064a\u0644\u064b\u0627! \u0644\u0642\u062f \u0627\u0633\u062a\u0644\u0645\u0646\u0627 \u0627\u0644\u0645\u0628\u0644\u063a \u0627\u0644\u0630\u064a \u0633\u062f\u062f\u062a\u0647 \u0644\u0642\u0627\u0621 \u0627\u0644\u0645\u0634\u0627\u0631\u0643\u0629 \u0641\u064a %(course_name)s",
"Thanks for returning to verify your ID in: %(courseName)s": "\u0634\u0643\u0631\u064b\u0627 \u0644\u0643 \u0639\u0644\u0649 \u0627\u0644\u0639\u0648\u062f\u0629 \u0644\u062a\u0623\u0643\u064a\u062f \u0647\u0648\u064a\u0651\u062a\u0643 \u0641\u064a: %(courseName)s",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u064a\u0628\u062f\u0648 \u0623\u0646\u0651 \u0627\u0644\u0631\u0627\u0628\u0637 \u0627\u0644\u0630\u064a \u0623\u062f\u062e\u0644\u062a\u0647 \u0639\u0628\u0627\u0631\u0629 \u0639\u0646 \u0639\u0646\u0648\u0627\u0646 \u0628\u0631\u064a\u062f \u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a\u060c \u0647\u0644 \u062a\u0631\u064a\u062f \u0625\u0636\u0627\u0641\u0629 \u0627\u0644\u0628\u0627\u062f\u0626\u0629 \u2019\u0625\u0631\u0633\u0627\u0644 \u0625\u0644\u0649:\u2018 \u0627\u0644\u0644\u0627\u0632\u0645\u0629\u061f",
"The URL you entered seems to be an external link. Do you want to add the required http:// prefix?": "\u064a\u0628\u062f\u0648 \u0623\u0646 \u0627\u0644\u0631\u0627\u0628\u0637 \u0627\u0644\u0630\u064a \u0623\u062f\u062e\u0644\u062a\u0647 \u0639\u0628\u0627\u0631\u0629 \u0639\u0646 \u0631\u0627\u0628\u0637 \u062e\u0627\u0631\u062c\u064a\u060c \u0647\u0644 \u062a\u0631\u064a\u062f \u0625\u0636\u0627\u0641\u0629 \u0627\u0644\u0628\u0627\u062f\u0626\u0629 http:// \u0627\u0644\u0644\u0627\u0632\u0645\u0629\u061f",
"The certificate for this learner has been re-validated and the system is re-running the grade for this learner.": "\u062c\u0631\u062a \u0625\u0639\u0627\u062f\u0629 \u062a\u0648\u062b\u064a\u0642 \u0634\u0647\u0627\u062f\u0629 \u0647\u0630\u0627 \u0627\u0644\u0645\u062a\u0639\u0644\u0651\u0645 \u0648\u064a\u0639\u0645\u0644 \u0627\u0644\u0646\u0638\u0627\u0645 \u0639\u0644\u0649 \u0625\u0639\u0627\u062f\u0629 \u0639\u0631\u0636 \u0639\u0644\u0627\u0645\u062a\u0647 \u0627\u0644\u0645\u0645\u0646\u0648\u062d\u0629.",
@@ -1520,7 +1507,6 @@
"This content group is not in use. Add a content group to any unit from the {linkStart}Course Outline{linkEnd}.": "\u0625\u0646\u0651 \u0645\u062c\u0645\u0648\u0639\u0629 \u0627\u0644\u0645\u062d\u062a\u0648\u0649 \u0647\u0630\u0647 \u0644\u064a\u0633\u062a \u0642\u064a\u062f \u0627\u0644\u0627\u0633\u062a\u062e\u062f\u0627\u0645. \u064a\u064f\u0631\u062c\u0649 \u0625\u0636\u0627\u0641\u0629 \u0645\u062c\u0645\u0648\u0639\u0629 \u0645\u062d\u062a\u0648\u0649 \u0625\u0644\u0649 \u0623\u064a \u0648\u062d\u062f\u0629 \u0645\u0646 \u062e\u0644\u0627\u0644 {linkStart}\u0646\u0628\u0630\u0629 \u0639\u0646 \u0627\u0644\u0645\u0633\u0627\u0642{linkEnd}.",
"This content group is used in one or more units.": "\u0645\u062c\u0645\u0648\u0639\u0629 \u0627\u0644\u0645\u062d\u062a\u0648\u0649 \u0647\u0630\u0647 \u0645\u0633\u062a\u062e\u062f\u0645\u0629 \u0641\u064a \u0648\u062d\u062f\u0629 \u0648\u0627\u062d\u062f\u0629 \u0623\u0648 \u0623\u0643\u062b\u0631.",
"This content group is used in:": "\u062a\u064f\u0633\u062a\u062e\u062f\u064e\u0645 \u0645\u062c\u0645\u0648\u0639\u0629 \u0627\u0644\u0645\u062d\u062a\u0648\u0649 \u0647\u0630\u0647 \u0641\u064a:",
"This edX learner is currently sharing a limited profile.": "\u064a\u064f\u0634\u0627\u0631\u0643 \u062d\u0627\u0644\u064a\u064b\u0651\u0627 \u0647\u0630\u0627 \u0627\u0644\u0637\u0627\u0644\u0628 \u0644\u062f\u0649 edX \u0645\u0644\u0641\u0651\u064b\u0627 \u0634\u062e\u0635\u064a\u0651\u064b\u0627 \u0645\u062d\u062f\u0648\u062f\u064b\u0627.",
"This image is for decorative purposes only and does not require a description.": "\u0627\u0633\u062a\u064f\u062e\u062f\u0645\u062a \u0647\u0630\u0647 \u0627\u0644\u0635\u0648\u0631\u0629 \u0644\u0623\u0647\u062f\u0627\u0641 \u062a\u0632\u064a\u0646\u064a\u0629 \u0641\u0642\u0637 \u0648\u0644\u0627 \u062a\u062a\u0637\u0644\u0651\u0628 \u062a\u0648\u0635\u064a\u0641\u064b\u0627.",
"This is the Description of the Group Configuration": "\u0625\u0646\u0647 \u0648\u0635\u0641 \u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0627\u0644\u0645\u062c\u0645\u0648\u0639\u0629",
"This is the Name of the Group Configuration": "\u0625\u0646\u0647 \u0627\u0633\u0645 \u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0627\u0644\u0645\u062c\u0645\u0648\u0639\u0629",
@@ -1558,7 +1544,6 @@
"To receive credit on a problem, you must click \"Check\" or \"Final Check\" on it before you select \"End My Exam\".": "\u064a\u062c\u0628 \u0627\u0644\u0646\u0642\u0631 \u0639\u0644\u0649 \u2019\u0645\u0631\u0627\u062c\u0639\u0629\u2018 \u0623\u0648 \u2019\u0645\u0631\u0627\u062c\u0639\u0629 \u0646\u0647\u0627\u0626\u064a\u0629\u2018 \u0639\u0644\u0649 \u0627\u0644\u0645\u0627\u062f\u0629 \u0627\u0644\u062f\u0631\u0627\u0633\u064a\u0629 \u0642\u0628\u0644 \u0627\u062e\u062a\u064a\u0627\u0631 \u2019\u0623\u0646\u0647\u064a \u0627\u0645\u062a\u062d\u0627\u0646\u064a\u2018 \u0644\u062a\u0644\u0642\u064a \u0645\u0627\u062f\u0629 \u062f\u0631\u0627\u0633\u064a\u0629 \u0644\u0628\u0631\u0646\u0627\u0645\u062c \u0645\u0639\u064a\u0651\u0646.",
"To review student cohort assignments or see the results of uploading a CSV file, download course profile information or cohort results on {link_start} the Data Download page. {link_end}": "\u0644\u0645\u0631\u0627\u062c\u0639\u0629 \u0627\u0644\u0648\u0627\u062c\u0628\u0627\u062a \u0627\u0644\u0645\u0633\u0646\u062f\u0629 \u0625\u0644\u0649 \u0627\u0644\u0637\u0644\u0651\u0627\u0628 \u0641\u064a \u0643\u0644 \u0645\u062c\u0645\u0648\u0639\u0629 \u0623\u0648 \u0631\u0624\u064a\u0629 \u0646\u062a\u0627\u0626\u062c \u062a\u062d\u0645\u064a\u0644 \u0645\u0644\u0641 \u2019CSV\u2018\u060c \u064a\u064f\u0631\u062c\u0649 \u062a\u0646\u0632\u064a\u0644 \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0645\u0644\u0641\u0651 \u0627\u0644\u0645\u0633\u0627\u0642 \u0623\u0648 \u0646\u062a\u0627\u0626\u062c \u0627\u0644\u0645\u062c\u0645\u0648\u0639\u0627\u062a \u0639\u0646 \u0637\u0631\u064a\u0642 {link_start} \u0635\u0641\u062d\u0629 \u062a\u0646\u0632\u064a\u0644 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a. {link_end}",
"To take a successful photo, make sure that:": "\u0644\u0627\u0644\u062a\u0642\u0627\u0637 \u0635\u0648\u0631\u0629 \u0646\u0627\u062c\u062d\u0629\u060c \u064a\u064f\u0631\u062c\u0649 \u0627\u0644\u062a\u0623\u0643\u0651\u062f \u0645\u0645\u0651\u0627 \u064a\u0644\u064a:",
"To use the current photo, select the camera button %(icon)s. To take another photo, select the retake button %(icon)s.": "\u0644\u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0627\u0644\u0635\u0648\u0631\u0629 \u0627\u0644\u062d\u0627\u0644\u064a\u0629\u060c \u064a\u064f\u0631\u062c\u0649 \u0627\u062e\u062a\u064a\u0627\u0631 \u0632\u0631\u0651 \u0627\u0644\u0643\u0627\u0645\u064a\u0631\u0627 %(icon)s. \u0648\u0644\u0627\u0644\u062a\u0642\u0627\u0637 \u0635\u0648\u0631\u0629 \u0623\u062e\u0631\u0649\u060c \u064a\u064f\u0631\u062c\u0649 \u0627\u062e\u062a\u064a\u0627\u0631 \u0632\u0631\u0651 \u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062a\u0635\u0648\u064a\u0631 %(icon)s.",
"To verify your identity, you need a webcam and a government-issued photo ID.": "\u0644\u062a\u0623\u0643\u064a\u062f \u0635\u062d\u0651\u0629 \u0647\u0648\u064a\u0651\u062a\u0643\u060c \u0623\u0646\u062a \u0628\u062d\u0627\u062c\u0629 \u0644\u0643\u0627\u0645\u064a\u0631\u0627 \u0648\u0628\u0637\u0627\u0642\u0629 \u0647\u0648\u064a\u0651\u0629 \u062d\u0643\u0648\u0645\u064a\u0629 \u062a\u062d\u0645\u0644 \u0635\u0648\u0631\u0629 \u0634\u062e\u0635\u064a\u0651\u0629.",
"Toggle Notifications Setting": "\u062a\u0628\u062f\u064a\u0644 \u0625\u0639\u062f\u0627\u062f \u0627\u0644\u0625\u0634\u0639\u0627\u0631\u0627\u062a ",
"Tools": "\u0627\u0644\u0623\u062f\u0648\u0627\u062a",
@@ -1570,7 +1555,6 @@
"Total Number": "\u0627\u0644\u0639\u062f\u062f \u0627\u0644\u0625\u062c\u0645\u0627\u0644\u064a",
"Try the transaction again in a few minutes.": "\u0627\u0644\u0631\u062c\u0627\u0621 \u0645\u0639\u0627\u0648\u062f\u0629 \u0637\u0644\u0628 \u0627\u0644\u0639\u0645\u0644\u064a\u0629 \u0645\u062c\u062f\u0651\u062f\u064b\u0627 \u0628\u0639\u062f \u0628\u0636\u0639 \u062f\u0642\u0627\u0626\u0642.",
"Try using a different browser, such as Google Chrome.": "\u064a\u064f\u0631\u062c\u0649 \u0645\u062d\u0627\u0648\u0644\u0629 \u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0645\u062a\u0635\u0641\u0651\u062d \u0622\u062e\u0631\u060c \u0645\u062b\u0644 \u063a\u0648\u063a\u0644 \u0643\u0631\u0648\u0645.",
"Turn off transcript": "\u0625\u062e\u0641\u0627\u0621 \u0646\u0635 \u0627\u0644\u0643\u0644\u0627\u0645 \u0627\u0644\u0645\u062f\u0648\u0651\u0646",
"Turn off transcripts": "\u0625\u062e\u0641\u0627\u0621 \u0627\u0644\u0646\u0635",
"Turn on closed captioning": "\u062a\u0634\u063a\u064a\u0644 \u0627\u0644\u0639\u0646\u0627\u0648\u064a\u0646 \u0627\u0644\u0641\u0631\u0639\u064a\u0629 \u0627\u0644\u0645\u063a\u0644\u0642\u0629",
"Turn on transcripts": "\u0639\u0631\u0636 \u0646\u0635 \u0627\u0644\u0643\u0644\u0627\u0645 \u0627\u0644\u0645\u062f\u0648\u0651\u0646",
@@ -1608,7 +1592,6 @@
"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",
"Upload": "\u062a\u062d\u0645\u064a\u0644",
"Upload File": "\u062a\u062d\u0645\u064a\u0644 \u0627\u0644\u0645\u0644\u0641",
"Upload File and Assign Students": "\u062a\u062d\u0645\u064a\u0644 \u0627\u0644\u0645\u0644\u0641 \u0648\u0625\u0633\u0646\u0627\u062f \u0627\u0644\u0648\u0627\u062c\u0628\u0627\u062a \u0625\u0644\u0649 \u0627\u0644\u0637\u0644\u0651\u0627\u0628",
@@ -1667,7 +1650,6 @@
"Verification Deadline": "\u0627\u0644\u0645\u0648\u0639\u062f \u0627\u0644\u0646\u0647\u0627\u0626\u064a \u0644\u0644\u062a\u062d\u0642\u0651\u0642",
"Verification checkpoint to be completed": "\u064a\u062a\u0648\u062c\u0651\u0628 \u0625\u062a\u0645\u0627\u0645 \u0646\u0642\u0637\u0629 \u0627\u0644\u0627\u062e\u062a\u0628\u0627\u0631 \u0627\u0644\u062e\u0627\u0635\u0651\u0629 \u0628\u0639\u0645\u0644\u064a\u0629 \u0627\u0644\u062a\u062d\u0642\u0651\u0642",
"Verified Certificate": "\u0627\u0644\u0634\u0647\u0627\u062f\u0629 \u0627\u0644\u0645\u0648\u062b\u0651\u0642\u0629",
"Verified Certificate for %(courseName)s": "\u0634\u0647\u0627\u062f\u0629 \u0645\u0648\u062b\u0642\u0629 \u0644\u0644\u0645\u0633\u0627\u0642 %(courseName)s",
"Verified Certificate upgrade": "\u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0634\u0647\u0627\u062f\u0629 \u0627\u0644\u0645\u0648\u062b\u0642\u0629",
"Verified Status": "\u062d\u0627\u0644\u0629 \u062c\u0631\u0649 \u0627\u0644\u062a\u062d\u0642\u0651\u0642 \u0645\u0646\u0647\u0627",
"Verified mode price": "\u0633\u0639\u0631 \u0648\u0636\u0639 \u2019\u0634\u0647\u0627\u062f\u0629 \u0645\u0648\u062b\u0651\u0642\u0629\u2018",
@@ -1748,7 +1730,6 @@
"What does %(platformName)s do with this photo?": "\u0645\u0627 \u0627\u0644\u0630\u064a \u062a\u0641\u0639\u0644\u0647 %(platformName)s \u0628\u0647\u0630\u0647 \u0627\u0644\u0635\u0648\u0631\u0629\u061f",
"What does this mean?": "\u0645\u0627\u0630\u0627 \u064a\u0639\u0646\u064a \u0647\u0630\u0627\u061f",
"When you click \"Reset Password\", a message will be sent to your email address. Click the link in the message to reset your password.": "\u0639\u0646\u062f\u0645\u0627 \u062a\u0646\u0642\u0631 \u0639\u0644\u0649 \"\u0625\u0639\u0627\u062f\u0629 \u0636\u0628\u0637 \u0643\u0644\u0645\u0629 \u0627\u0644\u0633\u0631\"\u060c \u0633\u062a\u0635\u0644 \u0631\u0633\u0627\u0644\u0629 \u0644\u0628\u0631\u064a\u062f\u0643 \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a. \u064a\u064f\u0631\u062c\u0649 \u0639\u0646\u062f\u0647\u0627 \u0627\u0644\u0646\u0642\u0631 \u0639\u0644\u0649 \u0627\u0644\u0631\u0627\u0628\u0637 \u0627\u0644\u0645\u0648\u062c\u0648\u062f \u0641\u064a \u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u0644\u062a\u063a\u064a\u0651\u0631\u0647\u0627.",
"When your face is in position, use the camera button %(icon)s below to take your photo.": "\u062d\u0627\u0644\u0645\u0627 \u062a\u0636\u0628\u0637 \u0648\u0636\u0639\u064a\u0629 \u062c\u0644\u0648\u0633\u0643 \u0648\u0648\u062c\u0647\u0643\u060c \u064a\u064f\u0631\u062c\u0649 \u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0632\u0631\u0651 \u0627\u0644\u0643\u0627\u0645\u064a\u0631\u0627 %(icon)s \u0623\u062f\u0646\u0627\u0647 \u0644\u0627\u0644\u062a\u0642\u0627\u0637 \u0635\u0648\u0631\u062a\u0643. ",
"Which timed transcript would you like to use?": "\u0645\u0627 \u0647\u0648 \u0627\u0644\u0646\u0635 \u0645\u062d\u062f\u0651\u064e\u062f \u0627\u0644\u062a\u0648\u0642\u064a\u062a \u0627\u0644\u0630\u064a \u062a\u0631\u063a\u0628 \u0628\u0627\u0633\u062a\u062e\u062f\u0627\u0645\u0647\u061f",
"Whole words": "\u0643\u0644\u0645\u0627\u062a \u0643\u0627\u0645\u0644\u0629 ",
"Why does %(platformName)s need my photo?": "\u0644\u0645\u0627\u0630\u0627 \u062a\u062d\u062a\u0627\u062c %(platformName)s \u0625\u0644\u0649 \u0635\u0648\u0631\u062a\u064a\u061f",
@@ -1766,11 +1747,8 @@
"You are about to send an email titled '<%= subject %>' to everyone who is staff or instructor on this course. Is this OK?": "\u0623\u0646\u062a \u0639\u0644\u0649 \u0648\u0634\u0643 \u0625\u0631\u0633\u0627\u0644 \u0631\u0633\u0627\u0644\u0629 \u0628\u0631\u064a\u062f \u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a \u0628\u0639\u0646\u0648\u0627\u0646 \u2019<%= subject %>\u2018 \u0625\u0644\u0649 \u0643\u0644\u0651 \u0645\u0646 \u0647\u0648 \u0623\u0633\u062a\u0627\u0630 \u0641\u064a \u0647\u0630\u0627 \u0627\u0644\u0645\u0633\u0627\u0642 \u0623\u0648 \u0641\u0631\u062f \u0641\u064a \u0641\u0631\u064a\u0642 \u0639\u0645\u0644\u0647. \u0647\u0644 \u0623\u0646\u062a \u0648\u0627\u062b\u0642 \u0645\u0646 \u0647\u0630\u0627\u061f",
"You are about to send an email titled '<%= subject %>' to yourself. Is this OK?": "\u0623\u0646\u062a \u0639\u0644\u0649 \u0648\u0634\u0643 \u0625\u0631\u0633\u0627\u0644 \u0631\u0633\u0627\u0644\u0629 \u0628\u0631\u064a\u062f \u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a \u0628\u0639\u0646\u0648\u0627\u0646 \u2019<%= subject %>\u2018 \u0625\u0644\u0649 \u0646\u0641\u0633\u0643. \u0647\u0644 \u0623\u0646\u062a \u0648\u0627\u062b\u0642 \u0645\u0646 \u0647\u0630\u0627\u061f",
"You are currently sharing a limited profile.": "\u0625\u0646\u0651\u0643 \u062d\u0627\u0644\u064a\u064b\u0651\u0627 \u062a\u0634\u0627\u0631\u0643 \u0645\u0644\u0641\u0651\u064b\u0627 \u0634\u062e\u0635\u064a\u0651\u064b\u0627 \u0645\u062d\u062f\u0648\u062f\u064b\u0627.",
"You are enrolling in %(courseName)s": "\u0623\u0646\u062a \u062a\u0633\u062c\u0651\u0644 \u0641\u064a %(courseName)s",
"You are enrolling in: %(courseName)s": "\u0625\u0646\u0651\u0643 \u062a\u0633\u062c\u0651\u0644 \u0641\u064a: %(courseName)s",
"You are not currently a member of any team.": "\u062d\u0627\u0644\u064a\u064b\u0627\u060c \u0623\u0646\u062a \u0644\u0633\u062a \u0639\u0636\u0648\u064b\u0627 \u0641\u064a \u0623\u064a \u0641\u0631\u064a\u0642.",
"You are now enrolled as a verified student for:": "\u0623\u0646\u062a \u0627\u0644\u0622\u0646 \u0645\u0633\u062c\u0651\u0650\u0644 \u0643\u0637\u0627\u0644\u0628 \u0645\u0648\u062b\u0651\u064e\u0642 \u0644\u062f\u0649: ",
"You are upgrading your enrollment for: %(courseName)s": "\u0625\u0646\u0651\u0643 \u062a\u062c\u062f\u0651\u062f \u062a\u0633\u062c\u064a\u0644\u0643 \u0641\u064a: %(courseName)s",
"You can now enter your payment information and complete your enrollment.": "\u064a\u0645\u0643\u0646\u0643 \u0627\u0644\u0622\u0646 \u0625\u062f\u062e\u0627\u0644 \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0627\u0644\u062f\u0641\u0639 \u0648\u0627\u0633\u062a\u0643\u0645\u0627\u0644 \u062a\u0633\u062c\u064a\u0644\u0643. ",
"You can pay now even if you don't have the following items available, but you will need to have these by %(date)s to qualify to earn a Verified Certificate.": "\u064a\u0645\u0643\u0646\u0643 \u0623\u0646 \u062a\u062f\u0641\u0639 \u0627\u0644\u0622\u0646 \u062d\u062a\u0649 \u0644\u0645 \u0644\u0645 \u062a\u062a\u0648\u0641\u0651\u0631 \u0644\u062f\u064a\u0643 \u0627\u0644\u0639\u0646\u0627\u0635\u0631 \u0627\u0644\u062a\u0627\u0644\u064a\u0629\u060c \u0644\u0643\u0646 \u064a\u062c\u0628 \u0639\u0644\u064a\u0643 \u062a\u0648\u0641\u064a\u0631\u0647\u0627 \u0628\u062d\u0644\u0648\u0644 %(date)s \u0645\u0646 \u0623\u062c\u0644 \u0627\u0644\u062a\u0623\u0647\u0651\u0644 \u0644\u0646\u064a\u0644 \"\u0634\u0647\u0627\u062f\u0629 \u0645\u0648\u062b\u0651\u0642\u0629\". ",
"You can pay now even if you don't have the following items available, but you will need to have these to qualify to earn a Verified Certificate.": "\u064a\u0645\u0643\u0646\u0643 \u0623\u0646 \u062a\u062f\u0641\u0639 \u0627\u0644\u0622\u0646 \u062d\u062a\u0649 \u0644\u0645 \u0644\u0645 \u062a\u062a\u0648\u0641\u0651\u0631 \u0644\u062f\u064a\u0643 \u0627\u0644\u0639\u0646\u0627\u0635\u0631 \u0627\u0644\u062a\u0627\u0644\u064a\u0629\u060c \u0644\u0643\u0646 \u064a\u062c\u0628 \u0639\u0644\u064a\u0643 \u062a\u0648\u0641\u064a\u0631\u0647\u0627 \u0645\u0646 \u0623\u062c\u0644 \u0627\u0644\u062a\u0623\u0647\u0651\u0644 \u0644\u0646\u064a\u0644 \"\u0634\u0647\u0627\u062f\u0629 \u0645\u0648\u062b\u0651\u0642\u0629\". ",
@@ -1842,7 +1820,6 @@
"Your team could not be updated.": "\u0639\u0630\u0631\u064b\u0627\u060c \u0644\u0645 \u0646\u062a\u0645\u0643\u0651\u0646 \u0645\u0646 \u062a\u062d\u062f\u064a\u062b \u0641\u0631\u064a\u0642\u0643.",
"Your upload of '{file}' failed.": "\u0639\u0630\u0631\u064b\u0627\u060c \u0641\u0634\u0644 \u062a\u062d\u0645\u064a\u0644\u0643 \u0644\u0645\u0644\u0641 '{file}'. ",
"Your upload of '{file}' succeeded.": "\u0646\u062c\u062d \u062a\u062d\u0645\u064a\u0644\u0643 \u0644\u0645\u0644\u0641 '{file}'. ",
"Your verification status is good until %(verificationGoodUntil)s.": "\u064a\u0633\u0631\u064a \u0645\u0641\u0639\u0648\u0644 \u0639\u0645\u0644\u064a\u0629 \u0627\u0644\u062a\u062d\u0642\u0651\u0642 \u0645\u0646 \u0647\u0648\u064a\u0651\u062a\u0643 \u062d\u062a\u0649 \u062a\u0627\u0631\u064a\u062e %(verificationGoodUntil)s.",
"Your video uploads are not complete.": "\u0639\u0645\u0644\u064a\u0627\u062a \u062a\u062d\u0645\u064a\u0644 \u0645\u0644\u0641 \u0627\u0644\u0641\u064a\u062f\u064a\u0648 \u0627\u0644\u062e\u0627\u0635 \u0628\u0643 \u063a\u064a\u0631 \u0645\u0643\u062a\u0645\u0644\u0629.",
"Zoom In": "\u062a\u0643\u0628\u064a\u0631",
"Zoom Out": "\u062a\u0635\u063a\u064a\u0631",
@@ -1860,7 +1837,6 @@
"about a month": "\u062d\u0648\u0627\u0644\u064a \u0634\u0647\u0631",
"about a year": "\u062d\u0648\u0627\u0644\u064a \u0633\u0646\u0629",
"about an hour": "\u062d\u0648\u0627\u0644\u064a \u0633\u0627\u0639\u0629",
"additions to the Exception list": "\u0625\u0636\u0627\u0641\u0627\u062a \u0625\u0644\u0649 \u0644\u0627\u0626\u062d\u0629 \u0627\u0644\u0627\u0633\u062a\u062b\u0646\u0627\u0621\u0627\u062a",
"and others": "\u0648\u0622\u062e\u0631\u064a\u0646",
"anonymous": "\u0645\u062c\u0647\u0648\u0644",
"answer": "\u0627\u0644\u0625\u062c\u0627\u0628\u0629",
@@ -1910,7 +1886,6 @@
"or": "\u0623\u0648",
"or create a new one here": "\u0623\u0648 \u0623\u0646\u0634\u0626 \u062d\u0633\u0627\u0628\u0627\u064b \u062c\u062f\u064a\u062f\u0627\u064b \u0628\u0627\u0633\u062a\u062e\u062f\u0627\u0645",
"or sign in with": "\u0623\u0648 \u0633\u062c\u0651\u0644 \u0627\u0644\u062f\u062e\u0648\u0644 \u0628\u0627\u0633\u062a\u062e\u062f\u0627\u0645",
"path/to/introductionToCookieBaking-CH%d.pdf": "path/to/introductionToCookieBaking-CH%d.pdf",
"post anonymously": "\u0627\u0646\u0634\u064f\u0631 \u0645\u0646 \u062f\u0648\u0646 \u0627\u0644\u0643\u0634\u0641 \u0639\u0646 \u0627\u0644\u0647\u0648\u064a\u0629 ",
"post anonymously to classmates": "\u0627\u0646\u0634\u0631 \u0623\u0645\u0627\u0645 \u0627\u0644\u0632\u0645\u0644\u0627\u0621 \u0645\u0646 \u062f\u0648\u0646 \u0627\u0644\u0643\u0634\u0641 \u0639\u0646 \u0627\u0644\u0647\u0648\u064a\u0629 ",
"posted %(time_ago)s by %(author)s": "\u0646\u064f\u0634\u0650\u0631 %(time_ago)s \u0645\u0646 \u0642\u0650\u0628\u0644 %(author)s",

View File

@@ -135,7 +135,6 @@
"<%= user %> has been successfully added to the exception list. Click Generate Exception Certificate below to send the certificate.": "<%= user %> ha sido a\u00f1adido a la lista de excepciones. Haga clic en Generar cerfificado de excepci\u00f3n para enviar este certificado.",
"<button data-provider=\"%s\" data-course-key=\"%s\" data-username=\"%s\" class=\"complete-course\" onClick=completeOrder(this)>%s</button>": "<button data-provider=\"%s\" data-course-key=\"%s\" data-username=\"%s\" class=\"complete-course\" onClick=completeOrder(this)>%s</button>",
"<img src='%s' alt='%s'></image>": "<img src='%s' alt='%s'></image>",
"<li>Transcript will be displayed when ": "<li>La transcripci\u00f3n se mostrar\u00e1 cuando",
"A driver's license, passport, or government-issued ID with your name and photo.": "Una licencia de conducir, pasaporte, c\u00e9dula o otra identificaci\u00f3n oficial con su nombre y foto",
"A driver's license, passport, or other government-issued ID with your name and photo": "Una licencia de conducir, pasaporte, c\u00e9dula o otra identificaci\u00f3n oficial con su nombre y foto",
"A list of courses you have just enrolled in as a verified student": "Lista de cursos que te has inscrito como estudiante verificado",
@@ -154,7 +153,6 @@
"Actions": "Acciones",
"Activate": "Activar",
"Activate Your Account": "Activar su cuenta",
"Activating an item in this group will spool the video to the corresponding time point. To skip transcript, go to previous item.": "Activar un \u00edtem en este grupo llevar\u00e1 el v\u00eddeo al momento correspondiente. Para saltar la transcripci\u00f3n, vaya al item anterior.",
"Active Threads": "Hilos Activos",
"Active Uploads": "Cargas activas",
"Add": "A\u00f1adir",
@@ -322,7 +320,6 @@
"Change My Email Address": "Cambiar mi direcci\u00f3n de correo electr\u00f3nico",
"Change image": "Cambiar imagen",
"Change the settings for %(display_name)s": "Cambiar la configuraci\u00f3n para %(display_name)s",
"Chapter %s": "Cap\u00edtulo %s",
"Chapter Asset": "Recursos del cap\u00edtulo",
"Chapter Name": "Nombre del cap\u00edtulo",
"Chapter information": "Informaci\u00f3n del cap\u00edtulo",
@@ -675,7 +672,6 @@
"General": "General",
"Generate": "Generar",
"Generate Exception Certificates": "Generar excepciones de certificados",
"Generate a Certificate for all ": "Generar certificado para todos",
"Generate a Certificate for all users on the Exception list": "Generar un certificado para cada usuario en la lista de excepciones",
"Generate the user's certificate": "Generar el certificado del usuario",
"Get Credit": "Obtenga cr\u00e9ditos",
@@ -798,7 +794,6 @@
"Keywords": "Palabras clave",
"LEARN MORE": "APRENDER MAS",
"Language": "Idioma",
"Language: Press the UP arrow key to enter the language menu, then use UP and DOWN arrow keys to navigate language options. Press ENTER to change to the selected language.": "Idioma: Presione la flecha ARRIBA para entrar al men\u00fa de idioma, luego use las flechas ARRIBA y ABAJO para navegar las opciones. Presione ENTRAR para cambiar al idioma seleccionado.",
"Large": "Largo",
"Last Activity %(date)s": "\u00daltima Actividad %(date)s",
"Last Edited:": "\u00daltima modificaci\u00f3n:",
@@ -890,7 +885,6 @@
"Name of the signatory": "Nombre del signatario",
"Name or short description of the configuration": "Nombre o descripci\u00f3n corta de la configuraci\u00f3n",
"Never published": "Nunca publicad",
"New": "Nuevo",
"New %(component_type)s": "Nuevo %(component_type)s",
"New %(item_type)s": "Nueva %(item_type)s",
"New Address": "Nueva direcci\u00f3n ",
@@ -940,13 +934,10 @@
"Numbered list": "Lista numerada",
"OK": "Aceptar",
"Ok": "Bien",
"Once in position, use the camera button %(icon)s to capture your ID": "Una vez en posici\u00f3n, usa el bot\u00f3n de la c\u00e1mara %(icon)s para capturar tu ID",
"Once in position, use the camera button %(icon)s to capture your photo": "Una vez en posici\u00f3n, use el bot\u00f3n de la c\u00e1mara %(icon)s para capturar su foto",
"Only <%= fileTypes %> files can be uploaded. Please select a file ending in <%= fileExtensions %> to upload.": "S\u00f3lo pueden cargarse archivos de tipo <%= fileTypes %>. Por favor seleccione un archivo que termine en <%= fileExtensions %> para ser cargado.",
"Only properly formatted .csv files will be accepted.": "Solo archivos .csv correctamente formateados pueden ser utilizados.",
"Open": "Abrir",
"Open Calculator": "Abrir Calculadora",
"Open language menu": "Abrir men\u00fa de lenguaje",
"Open/download this file": "Abrir / descargar este archivo",
"OpenAssessment Save Error": "Error al guardar en el servidor OpenAssessment",
"Optional Characteristics": "Caracter\u00edsiticas Opcionales",
@@ -958,7 +949,6 @@
"Organization of the signatory": "Organizaci\u00f3n del signatario",
"Other": "Otro",
"Page break": "Salto de p\u00e1gina",
"Page number": "N\u00famero de p\u00e1gina",
"Paragraph": "P\u00e1rrafo",
"Password": "Contrase\u00f1a",
"Password Reset Email Sent": "El correo para restablecer contrase\u00f1a ha sido enviado.",
@@ -1041,7 +1031,6 @@
"Proctored": "Supervisado",
"Proctored Exam": "Examen supervisado",
"Proctored exams are timed and they record video of each learner taking the exam. The videos are then reviewed to ensure that learners follow all examination rules.": "Los ex\u00e1menes supervisados son cronometrados y un software graba a cada estudiante que toma el examen. Los videos luego son revisados para garantizar que el estudiante cumpli\u00f3 con todas las reglas del examen.",
"Professional Certificate for %(courseName)s": "Certificado Verificado para %(courseName)s",
"Professional Education": "Educaci\u00f3n profesional",
"Professional Education Verified Certificate": "Certificado verificado",
"Profile Image": "Foto de perfil",
@@ -1300,9 +1289,7 @@
"Textbook name is required": "Se requiere el nombre del texto",
"Thank you for submitting your financial assistance application for {course_name}! You can expect a response in 2-4 business days.": "Gracias por enviar tu aplicaci\u00f3n de financiamiento para {course_name}!. Espera una respuesta de 2-4 dias h\u00e1biles.",
"Thank you for submitting your photos. We will review them shortly. You can now sign up for any %(platformName)s course that offers verified certificates. Verification is good for one year. After one year, you must submit photos for verification again.": "Gracias por enviar sus fotos. Las revisaremos pronto. Ahora puede registrarse para cualquier curso de %(platformName)s que ofrezca Certficados Verificados. La verificaci\u00f3n es v\u00e1lida por un a\u00f1o. Despu\u00e9s de este periodo, deber\u00e1 volver a enviar fotograf\u00edas para una nueva verificaci\u00f3n.",
"Thank you! We have received your payment for %(courseName)s.": "Gracias! Hemos recibido su pago para %(courseName)s.",
"Thank you! We have received your payment for %(course_name)s.": "Gracias! Hemos recibido su pago para el curso %(course_name)s.",
"Thanks for returning to verify your ID in: %(courseName)s": "Gracias por volver a verificar su identificaci\u00f3n en: %(courseName)s",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "La URL que introdujo parece ser una direcci\u00f3n de correo electr\u00f3nico. \u00bfDesea agregarle el prefijo requerido mailto:?",
"The URL you entered seems to be an external link. Do you want to add the required http:// prefix?": "La URL que introdujo parece ser un v\u00ednculo externo. \u00bfDesea agregarle el prefijo requerido http://?",
"The certificate for this learner has been re-validated and the system is re-running the grade for this learner.": "El certificado para este estudiante ha sido revalidado y el sistema est\u00e1 computando nuevamente la calificaci\u00f3n.",
@@ -1397,7 +1384,6 @@
"This content group is not in use. Add a content group to any unit from the {linkStart}Course Outline{linkEnd}.": "Este grupo de contenidos no est\u00e1 en uso. A\u00f1ada un grupo de contenidos a cualquier unidad de la {linkStart}Estructura del curso{linkEnd}.",
"This content group is used in one or more units.": "Este contenido de grupo es usado en uno o mas unidades.",
"This content group is used in:": "Este contenido de grupo es usado en:",
"This edX learner is currently sharing a limited profile.": "Este usuario est\u00e1 compartiendo un perfil limitado.",
"This image is for decorative purposes only and does not require a description.": "Esta imagen es decorativa solamente y no requiere descripci\u00f3n.",
"This is the Description of the Group Configuration": "Esta es la descripci\u00f3n de configuraci\u00f3n del grupo",
"This is the Name of the Group Configuration": "Este es el nombre de la Configuraci\u00f3n del Grupo",
@@ -1434,7 +1420,6 @@
"To receive a certificate, you must also verify your identity.": "Para recibir un certificado, tambi\u00e9n debe verificar su identidad.",
"To receive credit on a problem, you must click \"Check\" or \"Final Check\" on it before you select \"End My Exam\".": "Para recibir cr\u00e9ditos para un problema, debe hacer clic en el bot\u00f3n de \"Revisar\" o \"Env\u00edo Final\" de dicho problema antes de seleccionar \"Terminar el examen\".",
"To take a successful photo, make sure that:": "Para tomar la foto correctamente, aseg\u00farese de: ",
"To use the current photo, select the camera button %(icon)s. To take another photo, select the retake button %(icon)s.": "Para usar la foto actual, seleccione el bot\u00f3n con la camara %(icon)s. Para tomar una nueva foto, seleccione el bot\u00f3n de nueva toma %(icon)s.",
"To verify your identity, you need a webcam and a government-issued photo ID.": "Para verificar su identidad, necesitar\u00e1 una c\u00e1mara web, y un documento de identificaci\u00f3n oficial con foto.",
"Toggle Notifications Setting": "Cambiar las opciones de notificaci\u00f3n",
"Tools": "Herramientas",
@@ -1446,7 +1431,6 @@
"Total Number": "N\u00famero total",
"Try the transaction again in a few minutes.": "Intente la transacci\u00f3n nuevamente en algunos minutos.",
"Try using a different browser, such as Google Chrome.": "Intente usar otro navegador. Por ejemplo Google Chrome.",
"Turn off transcript": "Desactivar transcripci\u00f3n",
"Turn off transcripts": "Desactivar transcripci\u00f3n",
"Turn on closed captioning": "Activar subt\u00edtulos",
"Turn on transcripts": "Activar transcripci\u00f3n",
@@ -1484,7 +1468,6 @@
"Updating Tags": "Actualizando Etiquetas",
"Updating with latest library content": "Actualizando con el m\u00e1s reciente contenido de la librer\u00eda",
"Upgrade Deadline": "Actualizar la fecha l\u00edmite",
"Upgrade to a Verified Certificate for %(courseName)s": "Cambiar a Certificado Verificado para %(courseName)s",
"Upload": "Subir",
"Upload File": "Subir archivo",
"Upload File and Assign Students": "Cargar archivo y asignar estudiantes",
@@ -1535,7 +1518,6 @@
"Verification Deadline": "Fecha l\u00edmite de verificaci\u00f3n",
"Verification checkpoint to be completed": "El punto de verificaci\u00f3n debe ser completado",
"Verified Certificate": "Certificado verificado",
"Verified Certificate for %(courseName)s": "Certificado Verificado para %(courseName)s",
"Verified Certificate upgrade": "Ascender a un Certificado verificado",
"Verified Status": "Verificaci\u00f3n",
"Verified mode price": "Precio del modo verificado",
@@ -1612,7 +1594,6 @@
"What does %(platformName)s do with this photo?": "\u00bfQu\u00e9 hace %(platformName)s con esta imagen?",
"What does this mean?": "\u00bfQu\u00e9 significa esto?",
"When you click \"Reset Password\", a message will be sent to your email address. Click the link in the message to reset your password.": "Cuando realice clic en \"Restablecer Contrase\u00f1a\", se enviar\u00e1 un mensaje a su direcci\u00f3n de correo. Haga clic en el v\u00ednculo que encontrar\u00e1 en el mensaje para restablecer su contrase\u00f1a.",
"When your face is in position, use the camera button %(icon)s below to take your photo.": "Luego de colocar su rostro en posici\u00f3n, haga clic en el siguiente icono %(icon)s para tomar la foto.",
"Which timed transcript would you like to use?": "\u00bfCu\u00e1l de las transcripciones desea utilizar?",
"Whole words": "Palabras completas",
"Why does %(platformName)s need my photo?": "Por qu\u00e9 %(platformName)s necesita mi foto ?",
@@ -1630,11 +1611,8 @@
"You are about to send an email titled '<%= subject %>' to everyone who is staff or instructor on this course. Is this OK?": "Est\u00e1 a punto de enviarse un correo electr\u00f3nico con asunto '<%= subject %>' a todos los instructores y funcionarios del curso. \u00bfEst\u00e1 seguro de proceder?",
"You are about to send an email titled '<%= subject %>' to yourself. Is this OK?": "Est\u00e1 a punto de enviarse un correo electr\u00f3nico con asunto '<%= subject %>' a usted mismo. \u00bfEst\u00e1 seguro de proceder?",
"You are currently sharing a limited profile.": "Actualmente est\u00e1 compartiendo un perfil limitado.",
"You are enrolling in %(courseName)s": "Usted est\u00e1 inscribiendose a %(courseName)s",
"You are enrolling in: %(courseName)s": "Estas inscrito en: %(courseName)s",
"You are not currently a member of any team.": "Usted no es actualmente miembro de ning\u00fan equipo.",
"You are now enrolled as a verified student for:": "Ahora estas inscrito como estudiante verificado para:",
"You are upgrading your enrollment for: %(courseName)s": "Estas actualizando tu inscripci\u00f3n para: %(courseName)s",
"You can now enter your payment information and complete your enrollment.": "Ahora puede agregar su informaci\u00f3n de pago, y completar su inscripci\u00f3n",
"You can pay now even if you don't have the following items available, but you will need to have these by %(date)s to qualify to earn a Verified Certificate.": "Puede pagar ahora, incluso si no tiene los siguientes items disponibles, pero deber\u00e1 tenerlos antes del %(date)s para calificar para un Certificado Verificado.",
"You can pay now even if you don't have the following items available, but you will need to have these to qualify to earn a Verified Certificate.": "Puede pagar ahora, incluso si no tiene los siguientes items disponibles, pero deber\u00e1 tenerlos para calificar para un Certificado Verificado.",
@@ -1706,7 +1684,6 @@
"Your team could not be updated.": "Su equipo no pudo ser actualizado.",
"Your upload of '{file}' failed.": "No se ha podido cargar el archivo '{file}'.",
"Your upload of '{file}' succeeded.": "Se ha cargado el archivo '{file}' exitosamente.",
"Your verification status is good until %(verificationGoodUntil)s.": "Su estado de verificaci\u00f3n es v\u00e1lido hasta %(verificationGoodUntil)s.",
"Your video uploads are not complete.": "Los archivos de v\u00eddeo no han terminado de cargar.",
"Zoom In": "Acercar",
"Zoom Out": "Alejar",
@@ -1720,7 +1697,6 @@
"about a month": "cerca de un mes",
"about a year": "cerca de un a\u00f1o",
"about an hour": "cerca de una hora",
"additions to the Exception list": "adiciones a la lista de excepciones",
"and others": "y otros",
"anonymous": "an\u00f3nimo",
"answer": "pregunta",
@@ -1770,7 +1746,6 @@
"or": "o",
"or create a new one here": "o crear una nueva aqu\u00ed",
"or sign in with": "o inicie sesi\u00f3n con",
"path/to/introductionToCookieBaking-CH%d.pdf": "ruta/al/capitulo%d.pdf",
"post anonymously": "escribir an\u00f3nimamente",
"post anonymously to classmates": "publicar an\u00f3nimamente a mis compa\u00f1eros de curso",
"posted %(time_ago)s by %(author)s": "publicado %(time_ago)s por %(author)s",

View File

@@ -163,6 +163,7 @@
"Active Uploads": "\u023a\u0254\u0287\u1d09\u028c\u01dd \u0244dl\u00f8\u0250ds",
"Add": "\u023add",
"Add Additional Signatory": "\u023add \u023add\u1d09\u0287\u1d09\u00f8n\u0250l S\u1d09\u0183n\u0250\u0287\u00f8\u0279\u028e",
"Add Allowance": "\u023add \u023all\u00f8\u028d\u0250n\u0254\u01dd",
"Add Cohort": "\u023add \u023b\u00f8\u0265\u00f8\u0279\u0287",
"Add Component:": "\u023add \u023b\u00f8\u026fd\u00f8n\u01ddn\u0287:",
"Add Country": "\u023add \u023b\u00f8nn\u0287\u0279\u028e",
@@ -171,6 +172,7 @@
"Add Students": "\u023add S\u0287nd\u01ddn\u0287s",
"Add URLs for additional versions": "\u023add \u0244\u024c\u0141s \u025f\u00f8\u0279 \u0250dd\u1d09\u0287\u1d09\u00f8n\u0250l \u028c\u01dd\u0279s\u1d09\u00f8ns",
"Add a Chapter": "\u023add \u0250 \u023b\u0265\u0250d\u0287\u01dd\u0279",
"Add a New Allowance": "\u023add \u0250 N\u01dd\u028d \u023all\u00f8\u028d\u0250n\u0254\u01dd",
"Add a New Cohort": "\u023add \u0250 N\u01dd\u028d \u023b\u00f8\u0265\u00f8\u0279\u0287",
"Add a Response": "\u023add \u0250 \u024c\u01ddsd\u00f8ns\u01dd",
"Add a clear and descriptive title to encourage participation.": "\u023add \u0250 \u0254l\u01dd\u0250\u0279 \u0250nd d\u01dds\u0254\u0279\u1d09d\u0287\u1d09\u028c\u01dd \u0287\u1d09\u0287l\u01dd \u0287\u00f8 \u01ddn\u0254\u00f8n\u0279\u0250\u0183\u01dd d\u0250\u0279\u0287\u1d09\u0254\u1d09d\u0250\u0287\u1d09\u00f8n.",
@@ -189,6 +191,7 @@
"Adding": "\u023add\u1d09n\u0183",
"Adding the selected course to your cart": "\u023add\u1d09n\u0183 \u0287\u0265\u01dd s\u01ddl\u01dd\u0254\u0287\u01ddd \u0254\u00f8n\u0279s\u01dd \u0287\u00f8 \u028e\u00f8n\u0279 \u0254\u0250\u0279\u0287",
"Additional Information (optional)": "\u023add\u1d09\u0287\u1d09\u00f8n\u0250l \u0197n\u025f\u00f8\u0279\u026f\u0250\u0287\u1d09\u00f8n (\u00f8d\u0287\u1d09\u00f8n\u0250l)",
"Additional Time (minutes)": "\u023add\u1d09\u0287\u1d09\u00f8n\u0250l \u0166\u1d09\u026f\u01dd (\u026f\u1d09nn\u0287\u01dds)",
"Admin": "\u023ad\u026f\u1d09n",
"Advanced": "\u023ad\u028c\u0250n\u0254\u01ddd",
"Align center": "\u023al\u1d09\u0183n \u0254\u01ddn\u0287\u01dd\u0279",
@@ -214,6 +217,9 @@
"Allow others to copy, distribute, display and perform your work - and derivative works based upon it - but for noncommercial purposes only.": "\u023all\u00f8\u028d \u00f8\u0287\u0265\u01dd\u0279s \u0287\u00f8 \u0254\u00f8d\u028e, d\u1d09s\u0287\u0279\u1d09bn\u0287\u01dd, d\u1d09sdl\u0250\u028e \u0250nd d\u01dd\u0279\u025f\u00f8\u0279\u026f \u028e\u00f8n\u0279 \u028d\u00f8\u0279\u029e - \u0250nd d\u01dd\u0279\u1d09\u028c\u0250\u0287\u1d09\u028c\u01dd \u028d\u00f8\u0279\u029es b\u0250s\u01ddd nd\u00f8n \u1d09\u0287 - bn\u0287 \u025f\u00f8\u0279 n\u00f8n\u0254\u00f8\u026f\u026f\u01dd\u0279\u0254\u1d09\u0250l dn\u0279d\u00f8s\u01dds \u00f8nl\u028e.",
"Allow others to distribute derivative works only under a license identical to the license that governs your work. This option is incompatible with \"No Derivatives\".": "\u023all\u00f8\u028d \u00f8\u0287\u0265\u01dd\u0279s \u0287\u00f8 d\u1d09s\u0287\u0279\u1d09bn\u0287\u01dd d\u01dd\u0279\u1d09\u028c\u0250\u0287\u1d09\u028c\u01dd \u028d\u00f8\u0279\u029es \u00f8nl\u028e nnd\u01dd\u0279 \u0250 l\u1d09\u0254\u01ddns\u01dd \u1d09d\u01ddn\u0287\u1d09\u0254\u0250l \u0287\u00f8 \u0287\u0265\u01dd l\u1d09\u0254\u01ddns\u01dd \u0287\u0265\u0250\u0287 \u0183\u00f8\u028c\u01dd\u0279ns \u028e\u00f8n\u0279 \u028d\u00f8\u0279\u029e. \u0166\u0265\u1d09s \u00f8d\u0287\u1d09\u00f8n \u1d09s \u1d09n\u0254\u00f8\u026fd\u0250\u0287\u1d09bl\u01dd \u028d\u1d09\u0287\u0265 \"N\u00f8 \u0110\u01dd\u0279\u1d09\u028c\u0250\u0287\u1d09\u028c\u01dds\".",
"Allow students to generate certificates for this course?": "\u023all\u00f8\u028d s\u0287nd\u01ddn\u0287s \u0287\u00f8 \u0183\u01ddn\u01dd\u0279\u0250\u0287\u01dd \u0254\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dds \u025f\u00f8\u0279 \u0287\u0265\u1d09s \u0254\u00f8n\u0279s\u01dd?",
"Allowance Type": "\u023all\u00f8\u028d\u0250n\u0254\u01dd \u0166\u028ed\u01dd",
"Allowance Value": "\u023all\u00f8\u028d\u0250n\u0254\u01dd V\u0250ln\u01dd",
"Allowances": "\u023all\u00f8\u028d\u0250n\u0254\u01dds",
"Already a course team member": "\u023al\u0279\u01dd\u0250d\u028e \u0250 \u0254\u00f8n\u0279s\u01dd \u0287\u01dd\u0250\u026f \u026f\u01dd\u026fb\u01dd\u0279",
"Already a library team member": "\u023al\u0279\u01dd\u0250d\u028e \u0250 l\u1d09b\u0279\u0250\u0279\u028e \u0287\u01dd\u0250\u026f \u026f\u01dd\u026fb\u01dd\u0279",
"Already a member": "\u023al\u0279\u01dd\u0250d\u028e \u0250 \u026f\u01dd\u026fb\u01dd\u0279",
@@ -398,6 +404,7 @@
"Commentary": "\u023b\u00f8\u026f\u026f\u01ddn\u0287\u0250\u0279\u028e",
"Common Problem Types": "\u023b\u00f8\u026f\u026f\u00f8n \u2c63\u0279\u00f8bl\u01dd\u026f \u0166\u028ed\u01dds",
"Community TA": "\u023b\u00f8\u026f\u026fnn\u1d09\u0287\u028e \u0166\u023a",
"Completed At": "\u023b\u00f8\u026fdl\u01dd\u0287\u01ddd \u023a\u0287",
"Component": "\u023b\u00f8\u026fd\u00f8n\u01ddn\u0287",
"Configure": "\u023b\u00f8n\u025f\u1d09\u0183n\u0279\u01dd",
"Confirm": "\u023b\u00f8n\u025f\u1d09\u0279\u026f",
@@ -640,6 +647,8 @@
"Error: User '<%= username %>' has not yet activated their account. Users must create and activate their accounts before they can be assigned a role.": "\u0246\u0279\u0279\u00f8\u0279: \u0244s\u01dd\u0279 '<%= username %>' \u0265\u0250s n\u00f8\u0287 \u028e\u01dd\u0287 \u0250\u0254\u0287\u1d09\u028c\u0250\u0287\u01ddd \u0287\u0265\u01dd\u1d09\u0279 \u0250\u0254\u0254\u00f8nn\u0287. \u0244s\u01dd\u0279s \u026fns\u0287 \u0254\u0279\u01dd\u0250\u0287\u01dd \u0250nd \u0250\u0254\u0287\u1d09\u028c\u0250\u0287\u01dd \u0287\u0265\u01dd\u1d09\u0279 \u0250\u0254\u0254\u00f8nn\u0287s b\u01dd\u025f\u00f8\u0279\u01dd \u0287\u0265\u01dd\u028e \u0254\u0250n b\u01dd \u0250ss\u1d09\u0183n\u01ddd \u0250 \u0279\u00f8l\u01dd.",
"Error: You cannot remove yourself from the Instructor group!": "\u0246\u0279\u0279\u00f8\u0279: \u024e\u00f8n \u0254\u0250nn\u00f8\u0287 \u0279\u01dd\u026f\u00f8\u028c\u01dd \u028e\u00f8n\u0279s\u01ddl\u025f \u025f\u0279\u00f8\u026f \u0287\u0265\u01dd \u0197ns\u0287\u0279n\u0254\u0287\u00f8\u0279 \u0183\u0279\u00f8nd!",
"Errors": "\u0246\u0279\u0279\u00f8\u0279s",
"Exam Name": "\u0246x\u0250\u026f N\u0250\u026f\u01dd",
"Exam Type": "\u0246x\u0250\u026f \u0166\u028ed\u01dd",
"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",
@@ -649,6 +658,7 @@
"Explanation": "\u0246xdl\u0250n\u0250\u0287\u1d09\u00f8n",
"Explicitly Hiding from Students": "\u0246xdl\u1d09\u0254\u1d09\u0287l\u028e \u0126\u1d09d\u1d09n\u0183 \u025f\u0279\u00f8\u026f S\u0287nd\u01ddn\u0287s",
"Explore New XSeries": "\u0246xdl\u00f8\u0279\u01dd N\u01dd\u028d XS\u01dd\u0279\u1d09\u01dds",
"Explore XSeries Programs": "\u0246xdl\u00f8\u0279\u01dd XS\u01dd\u0279\u1d09\u01dds \u2c63\u0279\u00f8\u0183\u0279\u0250\u026fs",
"Explore your course!": "\u0246xdl\u00f8\u0279\u01dd \u028e\u00f8n\u0279 \u0254\u00f8n\u0279s\u01dd!",
"Failed to delete student state.": "F\u0250\u1d09l\u01ddd \u0287\u00f8 d\u01ddl\u01dd\u0287\u01dd s\u0287nd\u01ddn\u0287 s\u0287\u0250\u0287\u01dd.",
"Failed to rescore problem.": "F\u0250\u1d09l\u01ddd \u0287\u00f8 \u0279\u01dds\u0254\u00f8\u0279\u01dd d\u0279\u00f8bl\u01dd\u026f.",
@@ -691,6 +701,7 @@
"Generate Exception Certificates": "\u01e4\u01ddn\u01dd\u0279\u0250\u0287\u01dd \u0246x\u0254\u01ddd\u0287\u1d09\u00f8n \u023b\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dds",
"Generate a Certificate for all users on the Exception list": "\u01e4\u01ddn\u01dd\u0279\u0250\u0287\u01dd \u0250 \u023b\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dd \u025f\u00f8\u0279 \u0250ll ns\u01dd\u0279s \u00f8n \u0287\u0265\u01dd \u0246x\u0254\u01ddd\u0287\u1d09\u00f8n l\u1d09s\u0287",
"Generate certificates for all users on the Exception list for whom certificates have not yet been run": "\u01e4\u01ddn\u01dd\u0279\u0250\u0287\u01dd \u0254\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dds \u025f\u00f8\u0279 \u0250ll ns\u01dd\u0279s \u00f8n \u0287\u0265\u01dd \u0246x\u0254\u01ddd\u0287\u1d09\u00f8n l\u1d09s\u0287 \u025f\u00f8\u0279 \u028d\u0265\u00f8\u026f \u0254\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dds \u0265\u0250\u028c\u01dd n\u00f8\u0287 \u028e\u01dd\u0287 b\u01dd\u01ddn \u0279nn",
"Generate certificates for all users on the Exception list who do not yet have a certificate": "\u01e4\u01ddn\u01dd\u0279\u0250\u0287\u01dd \u0254\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dds \u025f\u00f8\u0279 \u0250ll ns\u01dd\u0279s \u00f8n \u0287\u0265\u01dd \u0246x\u0254\u01ddd\u0287\u1d09\u00f8n l\u1d09s\u0287 \u028d\u0265\u00f8 d\u00f8 n\u00f8\u0287 \u028e\u01dd\u0287 \u0265\u0250\u028c\u01dd \u0250 \u0254\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dd",
"Generate the user's certificate": "\u01e4\u01ddn\u01dd\u0279\u0250\u0287\u01dd \u0287\u0265\u01dd ns\u01dd\u0279's \u0254\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dd",
"Get Credit": "\u01e4\u01dd\u0287 \u023b\u0279\u01ddd\u1d09\u0287",
"Go to Dashboard": "\u01e4\u00f8 \u0287\u00f8 \u0110\u0250s\u0265b\u00f8\u0250\u0279d",
@@ -1227,6 +1238,7 @@
"Sorted by": "S\u00f8\u0279\u0287\u01ddd b\u028e",
"Source": "S\u00f8n\u0279\u0254\u01dd",
"Source code": "S\u00f8n\u0279\u0254\u01dd \u0254\u00f8d\u01dd",
"Special Exam": "Sd\u01dd\u0254\u1d09\u0250l \u0246x\u0250\u026f",
"Special character": "Sd\u01dd\u0254\u1d09\u0250l \u0254\u0265\u0250\u0279\u0250\u0254\u0287\u01dd\u0279",
"Specify an alternative to the official course title to display on certificates. Leave blank to use the official course title.": "Sd\u01dd\u0254\u1d09\u025f\u028e \u0250n \u0250l\u0287\u01dd\u0279n\u0250\u0287\u1d09\u028c\u01dd \u0287\u00f8 \u0287\u0265\u01dd \u00f8\u025f\u025f\u1d09\u0254\u1d09\u0250l \u0254\u00f8n\u0279s\u01dd \u0287\u1d09\u0287l\u01dd \u0287\u00f8 d\u1d09sdl\u0250\u028e \u00f8n \u0254\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dds. \u0141\u01dd\u0250\u028c\u01dd bl\u0250n\u029e \u0287\u00f8 ns\u01dd \u0287\u0265\u01dd \u00f8\u025f\u025f\u1d09\u0254\u1d09\u0250l \u0254\u00f8n\u0279s\u01dd \u0287\u1d09\u0287l\u01dd.",
"Specify any additional rules or rule exceptions that the proctoring review team should enforce when reviewing the videos. For example, you could specify that calculators are allowed.": "Sd\u01dd\u0254\u1d09\u025f\u028e \u0250n\u028e \u0250dd\u1d09\u0287\u1d09\u00f8n\u0250l \u0279nl\u01dds \u00f8\u0279 \u0279nl\u01dd \u01ddx\u0254\u01ddd\u0287\u1d09\u00f8ns \u0287\u0265\u0250\u0287 \u0287\u0265\u01dd d\u0279\u00f8\u0254\u0287\u00f8\u0279\u1d09n\u0183 \u0279\u01dd\u028c\u1d09\u01dd\u028d \u0287\u01dd\u0250\u026f s\u0265\u00f8nld \u01ddn\u025f\u00f8\u0279\u0254\u01dd \u028d\u0265\u01ddn \u0279\u01dd\u028c\u1d09\u01dd\u028d\u1d09n\u0183 \u0287\u0265\u01dd \u028c\u1d09d\u01dd\u00f8s. F\u00f8\u0279 \u01ddx\u0250\u026fdl\u01dd, \u028e\u00f8n \u0254\u00f8nld sd\u01dd\u0254\u1d09\u025f\u028e \u0287\u0265\u0250\u0287 \u0254\u0250l\u0254nl\u0250\u0287\u00f8\u0279s \u0250\u0279\u01dd \u0250ll\u00f8\u028d\u01ddd.",
@@ -1247,6 +1259,7 @@
"Start regenerating certificates for students in this course?": "S\u0287\u0250\u0279\u0287 \u0279\u01dd\u0183\u01ddn\u01dd\u0279\u0250\u0287\u1d09n\u0183 \u0254\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dds \u025f\u00f8\u0279 s\u0287nd\u01ddn\u0287s \u1d09n \u0287\u0265\u1d09s \u0254\u00f8n\u0279s\u01dd?",
"Start search": "S\u0287\u0250\u0279\u0287 s\u01dd\u0250\u0279\u0254\u0265",
"Start working toward your next learning goal.": "S\u0287\u0250\u0279\u0287 \u028d\u00f8\u0279\u029e\u1d09n\u0183 \u0287\u00f8\u028d\u0250\u0279d \u028e\u00f8n\u0279 n\u01ddx\u0287 l\u01dd\u0250\u0279n\u1d09n\u0183 \u0183\u00f8\u0250l.",
"Started At": "S\u0287\u0250\u0279\u0287\u01ddd \u023a\u0287",
"Started entrance exam rescore task for student '{student_id}'. Click the 'Show Background Task History for Student' button to see the status of the task.": "S\u0287\u0250\u0279\u0287\u01ddd \u01ddn\u0287\u0279\u0250n\u0254\u01dd \u01ddx\u0250\u026f \u0279\u01dds\u0254\u00f8\u0279\u01dd \u0287\u0250s\u029e \u025f\u00f8\u0279 s\u0287nd\u01ddn\u0287 '{student_id}'. \u023bl\u1d09\u0254\u029e \u0287\u0265\u01dd 'S\u0265\u00f8\u028d \u0243\u0250\u0254\u029e\u0183\u0279\u00f8nnd \u0166\u0250s\u029e \u0126\u1d09s\u0287\u00f8\u0279\u028e \u025f\u00f8\u0279 S\u0287nd\u01ddn\u0287' bn\u0287\u0287\u00f8n \u0287\u00f8 s\u01dd\u01dd \u0287\u0265\u01dd s\u0287\u0250\u0287ns \u00f8\u025f \u0287\u0265\u01dd \u0287\u0250s\u029e.",
"Started rescore problem task for problem '<%= problem_id %>' and student '<%= student_id %>'. Click the 'Show Background Task History for Student' button to see the status of the task.": "S\u0287\u0250\u0279\u0287\u01ddd \u0279\u01dds\u0254\u00f8\u0279\u01dd d\u0279\u00f8bl\u01dd\u026f \u0287\u0250s\u029e \u025f\u00f8\u0279 d\u0279\u00f8bl\u01dd\u026f '<%= problem_id %>' \u0250nd s\u0287nd\u01ddn\u0287 '<%= student_id %>'. \u023bl\u1d09\u0254\u029e \u0287\u0265\u01dd 'S\u0265\u00f8\u028d \u0243\u0250\u0254\u029e\u0183\u0279\u00f8nnd \u0166\u0250s\u029e \u0126\u1d09s\u0287\u00f8\u0279\u028e \u025f\u00f8\u0279 S\u0287nd\u01ddn\u0287' bn\u0287\u0287\u00f8n \u0287\u00f8 s\u01dd\u01dd \u0287\u0265\u01dd s\u0287\u0250\u0287ns \u00f8\u025f \u0287\u0265\u01dd \u0287\u0250s\u029e.",
"Starts": "S\u0287\u0250\u0279\u0287s",
@@ -1437,6 +1450,7 @@
"This team is full.": "\u0166\u0265\u1d09s \u0287\u01dd\u0250\u026f \u1d09s \u025fnll.",
"This thread is closed.": "\u0166\u0265\u1d09s \u0287\u0265\u0279\u01dd\u0250d \u1d09s \u0254l\u00f8s\u01ddd.",
"Time Allotted (HH:MM):": "\u0166\u1d09\u026f\u01dd \u023all\u00f8\u0287\u0287\u01ddd (\u0126\u0126:MM):",
"Time Limit": "\u0166\u1d09\u026f\u01dd \u0141\u1d09\u026f\u1d09\u0287",
"Time Sent": "\u0166\u1d09\u026f\u01dd S\u01ddn\u0287",
"Time Sent:": "\u0166\u1d09\u026f\u01dd S\u01ddn\u0287:",
"Timed": "\u0166\u1d09\u026f\u01ddd",
@@ -1554,6 +1568,7 @@
"User": "\u0244s\u01dd\u0279",
"User Email": "\u0244s\u01dd\u0279 \u0246\u026f\u0250\u1d09l",
"Username": "\u0244s\u01dd\u0279n\u0250\u026f\u01dd",
"Username or Email": "\u0244s\u01dd\u0279n\u0250\u026f\u01dd \u00f8\u0279 \u0246\u026f\u0250\u1d09l",
"Username or email address": "\u0244s\u01dd\u0279n\u0250\u026f\u01dd \u00f8\u0279 \u01dd\u026f\u0250\u1d09l \u0250dd\u0279\u01ddss",
"Users": "\u0244s\u01dd\u0279s",
"Users must create and activate their account before they can be promoted to beta tester.": "\u0244s\u01dd\u0279s \u026fns\u0287 \u0254\u0279\u01dd\u0250\u0287\u01dd \u0250nd \u0250\u0254\u0287\u1d09\u028c\u0250\u0287\u01dd \u0287\u0265\u01dd\u1d09\u0279 \u0250\u0254\u0254\u00f8nn\u0287 b\u01dd\u025f\u00f8\u0279\u01dd \u0287\u0265\u01dd\u028e \u0254\u0250n b\u01dd d\u0279\u00f8\u026f\u00f8\u0287\u01ddd \u0287\u00f8 b\u01dd\u0287\u0250 \u0287\u01dds\u0287\u01dd\u0279.",
@@ -1561,6 +1576,7 @@
"Valid": "V\u0250l\u1d09d",
"Validation Error": "V\u0250l\u1d09d\u0250\u0287\u1d09\u00f8n \u0246\u0279\u0279\u00f8\u0279",
"Validation Error While Saving": "V\u0250l\u1d09d\u0250\u0287\u1d09\u00f8n \u0246\u0279\u0279\u00f8\u0279 W\u0265\u1d09l\u01dd S\u0250\u028c\u1d09n\u0183",
"Value": "V\u0250ln\u01dd",
"Verification Checkpoint": "V\u01dd\u0279\u1d09\u025f\u1d09\u0254\u0250\u0287\u1d09\u00f8n \u023b\u0265\u01dd\u0254\u029ed\u00f8\u1d09n\u0287",
"Verification Deadline": "V\u01dd\u0279\u1d09\u025f\u1d09\u0254\u0250\u0287\u1d09\u00f8n \u0110\u01dd\u0250dl\u1d09n\u01dd",
"Verification checkpoint to be completed": "V\u01dd\u0279\u1d09\u025f\u1d09\u0254\u0250\u0287\u1d09\u00f8n \u0254\u0265\u01dd\u0254\u029ed\u00f8\u1d09n\u0287 \u0287\u00f8 b\u01dd \u0254\u00f8\u026fdl\u01dd\u0287\u01ddd",
@@ -1652,6 +1668,7 @@
"Will Be Visible To:": "W\u1d09ll \u0243\u01dd V\u1d09s\u1d09bl\u01dd \u0166\u00f8:",
"Words: {0}": "W\u00f8\u0279ds: {0}",
"Would you like to sign in using your %(providerName)s credentials?": "W\u00f8nld \u028e\u00f8n l\u1d09\u029e\u01dd \u0287\u00f8 s\u1d09\u0183n \u1d09n ns\u1d09n\u0183 \u028e\u00f8n\u0279 %(providerName)s \u0254\u0279\u01ddd\u01ddn\u0287\u1d09\u0250ls?",
"XSeries Program Certificates": "XS\u01dd\u0279\u1d09\u01dds \u2c63\u0279\u00f8\u0183\u0279\u0250\u026f \u023b\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dds",
"Year of Birth": "\u024e\u01dd\u0250\u0279 \u00f8\u025f \u0243\u1d09\u0279\u0287\u0265",
"Yes, allow edits to the active Certificate": "\u024e\u01dds, \u0250ll\u00f8\u028d \u01ddd\u1d09\u0287s \u0287\u00f8 \u0287\u0265\u01dd \u0250\u0254\u0287\u1d09\u028c\u01dd \u023b\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dd",
"Yes, delete this %(xblock_type)s": "\u024e\u01dds, d\u01ddl\u01dd\u0287\u01dd \u0287\u0265\u1d09s %(xblock_type)s",
@@ -1664,6 +1681,7 @@
"You are currently sharing a limited profile.": "\u024e\u00f8n \u0250\u0279\u01dd \u0254n\u0279\u0279\u01ddn\u0287l\u028e s\u0265\u0250\u0279\u1d09n\u0183 \u0250 l\u1d09\u026f\u1d09\u0287\u01ddd d\u0279\u00f8\u025f\u1d09l\u01dd.",
"You are enrolling in: {courseName}": "\u024e\u00f8n \u0250\u0279\u01dd \u01ddn\u0279\u00f8ll\u1d09n\u0183 \u1d09n: {courseName}",
"You are not currently a member of any team.": "\u024e\u00f8n \u0250\u0279\u01dd n\u00f8\u0287 \u0254n\u0279\u0279\u01ddn\u0287l\u028e \u0250 \u026f\u01dd\u026fb\u01dd\u0279 \u00f8\u025f \u0250n\u028e \u0287\u01dd\u0250\u026f.",
"You are not enrolled in any XSeries Programs yet.": "\u024e\u00f8n \u0250\u0279\u01dd n\u00f8\u0287 \u01ddn\u0279\u00f8ll\u01ddd \u1d09n \u0250n\u028e XS\u01dd\u0279\u1d09\u01dds \u2c63\u0279\u00f8\u0183\u0279\u0250\u026fs \u028e\u01dd\u0287.",
"You are now enrolled as a verified student for:": "\u024e\u00f8n \u0250\u0279\u01dd n\u00f8\u028d \u01ddn\u0279\u00f8ll\u01ddd \u0250s \u0250 \u028c\u01dd\u0279\u1d09\u025f\u1d09\u01ddd s\u0287nd\u01ddn\u0287 \u025f\u00f8\u0279:",
"You are upgrading your enrollment for: {courseName}": "\u024e\u00f8n \u0250\u0279\u01dd nd\u0183\u0279\u0250d\u1d09n\u0183 \u028e\u00f8n\u0279 \u01ddn\u0279\u00f8ll\u026f\u01ddn\u0287 \u025f\u00f8\u0279: {courseName}",
"You can now enter your payment information and complete your enrollment.": "\u024e\u00f8n \u0254\u0250n n\u00f8\u028d \u01ddn\u0287\u01dd\u0279 \u028e\u00f8n\u0279 d\u0250\u028e\u026f\u01ddn\u0287 \u1d09n\u025f\u00f8\u0279\u026f\u0250\u0287\u1d09\u00f8n \u0250nd \u0254\u00f8\u026fdl\u01dd\u0287\u01dd \u028e\u00f8n\u0279 \u01ddn\u0279\u00f8ll\u026f\u01ddn\u0287.",
@@ -1759,6 +1777,8 @@
"asset_path is required": "\u0250ss\u01dd\u0287_d\u0250\u0287\u0265 \u1d09s \u0279\u01ddbn\u1d09\u0279\u01ddd",
"bytes": "b\u028e\u0287\u01dds",
"certificate": "\u0254\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dd",
"certificate.credential_url": "\u0254\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dd.\u0254\u0279\u01ddd\u01ddn\u0287\u1d09\u0250l_n\u0279l",
"certificate.display_name": "\u0254\u01dd\u0279\u0287\u1d09\u025f\u1d09\u0254\u0250\u0287\u01dd.d\u1d09sdl\u0250\u028e_n\u0250\u026f\u01dd",
"close": "\u0254l\u00f8s\u01dd",
"content group": "\u0254\u00f8n\u0287\u01ddn\u0287 \u0183\u0279\u00f8nd",
"correct": "\u0254\u00f8\u0279\u0279\u01dd\u0254\u0287",
@@ -1794,6 +1814,7 @@
"marked as answer %(time_ago)s": "\u026f\u0250\u0279\u029e\u01ddd \u0250s \u0250ns\u028d\u01dd\u0279 %(time_ago)s",
"marked as answer %(time_ago)s by %(user)s": "\u026f\u0250\u0279\u029e\u01ddd \u0250s \u0250ns\u028d\u01dd\u0279 %(time_ago)s b\u028e %(user)s",
"message": "\u026f\u01ddss\u0250\u0183\u01dd",
"minutes": "\u026f\u1d09nn\u0287\u01dds",
"name": "n\u0250\u026f\u01dd",
"off": "\u00f8\u025f\u025f",
"on": "\u00f8n",

View File

@@ -125,7 +125,6 @@
"Account Settings page.": "Param\u00e8tres du compte",
"Actions": "Actions",
"Activate Your Account": "Activez votre compte",
"Activating an item in this group will spool the video to the corresponding time point. To skip transcript, go to previous item.": "L'activation d'un \u00e9l\u00e9ment de ce groupe jouera la vid\u00e9o \u00e0 partir de ce point. Pour passer la transcription, allez \u00e0 l'\u00e9l\u00e9ment pr\u00e9c\u00e9dent.",
"Active Uploads": "T\u00e9l\u00e9chargement Actifs",
"Add Cohort": "Ajouter une cohorte",
"Add Component:": "Ajouter un composant :",
@@ -649,14 +648,12 @@
"Only <%= fileTypes %> files can be uploaded. Please select a file ending in <%= fileExtensions %> to upload.": "Seuls les fichiers de type <%= fileTypes %> peuvent \u00eatre envoy\u00e9s. Merci de s\u00e9lectionner un fichier se terminant par <%= fileExtensions %> pour l'envoyer.",
"Only properly formatted .csv files will be accepted.": "Seuls les fichiers au format .csv seront accept\u00e9s.",
"Open Calculator": "Afficher la calculatrice",
"Open language menu": "Ouvrir le menu des langues",
"Open/download this file": "Ouvrir/T\u00e9l\u00e9charger ce fichier",
"OpenAssessment Save Error": "Erreur de la sauvegarde d'OpenAssessment",
"Order No.": "Commande N\u00b0",
"Organization": "Organisation",
"Other": "Autre",
"Page break": "Saut de page",
"Page number": "Num\u00e9ro de page",
"Paragraph": "Paragraphe",
"Password": "Mot de passe",
"Password Reset Email Sent": "L'email de r\u00e9initialisation du mot de passe a \u00e9t\u00e9 envoy\u00e9",
@@ -890,7 +887,6 @@
"Text": "Texte",
"Text color": "Couleur du texte",
"Text to display": "Texte \u00e0 afficher",
"Thank you! We have received your payment for %(courseName)s.": "Merci ! Nous avons re\u00e7u votre paiement pour %(courseName)s.",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "L'URL que vous avez entr\u00e9e semble \u00eatre une adresse e-mail. Voulez-vous ajouter le prefix requis mailto: ?",
"The URL you entered seems to be an external link. Do you want to add the required http:// prefix?": "L'URL que vous avez entr\u00e9e semble \u00eatre un lien externe. Voulez-vous ajouter le pr\u00e9fixe http:// requis ?",
"The cohort cannot be added": "La cohorte ne peut pas \u00eatre ajout\u00e9e",
@@ -958,7 +954,6 @@
],
"This browser cannot play .mp4, .ogg, or .webm files.": "Ce navigateur ne peut pas lire les fichiers .mp4, .ogg, ou .webm",
"This component has validation issues.": "Ce composant a des probl\u00e8mes de validation.",
"This edX learner is currently sharing a limited profile.": "Cette utilisateur partage actuellement un profil restreint.",
"This learner will be removed from the team, allowing another learner to take the available spot.": "Cet apprenant sera supprim\u00e9 de l'\u00e9quipe, permettant \u00e0 un nouvel apprenant de prendre la place vacante.",
"This link will open in a modal window": "Ce lien s'ouvrira dans une nouvelle fen\u00eatre contextuelle",
"This link will open in a new browser window/tab": "Ce lien s'ouvrira dans une nouvelle fen\u00eatre ou onglet de votre navigateur",
@@ -1096,7 +1091,6 @@
"You are about to send an email titled '<%= subject %>' to everyone who is staff or instructor on this course. Is this OK?": "Vous \u00eates sur le point d'envoyer un e-mail intitul\u00e9 '<%= subject %>' \u00e0 tous les membres du staff et enseignants. Voulez-vous continuer ?",
"You are about to send an email titled '<%= subject %>' to yourself. Is this OK?": "Vous \u00eates sur le point d'envoyer un e-mail intitul\u00e9 '<%= subject %>' \u00e0 vous-m\u00eame. Voulez-vous continuer ?",
"You are currently sharing a limited profile.": "Vous partagez actuellement votre profil restreint.",
"You are enrolling in: %(courseName)s": "Vous vous inscrivez \u00e0 : %(courseName)s",
"You are not currently a member of any team.": "Actuellement, vous n'\u00eates membre d'aucune \u00e9quipe.",
"You are now enrolled as a verified student for:": "Vous vous \u00eates maintenant engag\u00e9 en tant qu'\u00e9tudiant v\u00e9rifi\u00e9 pour :",
"You can now enter your payment information and complete your enrollment.": "Vous pouvez maintenant entrer vos informations de paiement et terminer votre inscription.",
@@ -1151,7 +1145,6 @@
"Your request could not be completed. Reload the page and try again.": "Votre demande n'a pas pu \u00eatre r\u00e9alis\u00e9e. Rafra\u00eechissez la page et r\u00e9essayez.",
"Your upload of '{file}' failed.": "Le chargement de '{file}' a \u00e9chou\u00e9.",
"Your upload of '{file}' succeeded.": "Chargement de '{file}' r\u00e9ussi.",
"Your verification status is good until %(verificationGoodUntil)s.": "Votre v\u00e9rification est valable jusqu'au %(verificationGoodUntil)s.",
"Zoom In": "Zoomer",
"Zoom Out": "D\u00e9zoomer ",
"[no tags]": "[aucun tag]",

View File

@@ -79,7 +79,6 @@
"About me": "\uc790\uae30\uc18c\uac1c",
"Account Settings": "\uacc4\uc815 \uc124\uc815",
"Account Settings page.": "\uacc4\uc815 \uc124\uc815 \ud398\uc774\uc9c0",
"Activating an item in this group will spool the video to the corresponding time point. To skip transcript, go to previous item.": "\uc774 \uadf8\ub8f9\uc758 \ud56d\ubaa9 \ud65c\uc131\ud654\uac00 \uc77c\uce58\ud558\ub294 \uc2dc\uac04 \uc9c0\uc810\uc5d0 \ub3d9\uc601\uc0c1\uc744 \uc2a4\ud480\ud560 \uac83\uc785\ub2c8\ub2e4. \uc790\ub9c9\uc744 \ub118\uae30\ub824\uba74, \uc774\uc804 \ud56d\ubaa9\uc73c\ub85c \uac00\uc138\uc694. ",
"Add Cohort": "\ud559\uc2b5\uc9d1\ub2e8 \ucd94\uac00\ud558\uae30",
"Add Country": "\uad6d\uac00 \ucd94\uac00",
"Add Students": "\ud559\uc2b5\uc790 \ucd94\uac00",

View File

@@ -129,7 +129,6 @@
"- Sortable": "- Classific\u00e1veis",
"<button data-provider=\"%s\" data-course-key=\"%s\" data-username=\"%s\" class=\"complete-course\" onClick=completeOrder(this)>%s</button>": "<button data-provider=\"%s\" data-course-key=\"%s\" data-username=\"%s\" class=\"complete-course\" onClick=completeOrder(this)>%s</button>",
"<img src='%s' alt='%s'></image>": "<img src='%s' alt='%s'></image>",
"<li>Transcript will be displayed when ": "<li> Transcri\u00e7\u00e3o ser\u00e1 exibida quando",
"A driver's license, passport, or government-issued ID with your name and photo.": "Uma carteira de motorista, um passaporte ou um documento de identidade oficial com o seu nome e foto.",
"A driver's license, passport, or other government-issued ID with your name and photo": "Uma carteira de motorista, um passaporte ou outro documento de identidade oficial com o seu nome e foto",
"A list of courses you have just enrolled in as a verified student": "Lista de cursos para quais voc\u00ea se inscreveu como um aluno verificado",
@@ -147,7 +146,6 @@
"Actions": "A\u00e7\u00f5es",
"Activate": "Ativar",
"Activate Your Account": "Ativar a sua conta",
"Activating an item in this group will spool the video to the corresponding time point. To skip transcript, go to previous item.": "Ativar um item nesse grupo vai mover o v\u00eddeo para o ponto no tempo correspondente. Para pular a transcri\u00e7\u00e3o, v\u00e1 at\u00e9 o item anterior.",
"Active Threads": "T\u00f3picos ativos",
"Active Uploads": "Uploads ativos",
"Add": "Adicionar",
@@ -310,7 +308,6 @@
"Change My Email Address": "Alterar meu endere\u00e7o de E-mail",
"Change image": "Trocar imagem",
"Change the settings for %(display_name)s": "Alterar configura\u00e7\u00f5es para %(display_name)s",
"Chapter %s": "Cap\u00edtulo %s",
"Chapter Asset": "Ativo do Cap\u00edtulo",
"Chapter Name": "Nome do Cap\u00edtulo",
"Chapter information": "Informa\u00e7\u00e3o do cap\u00edtulo",
@@ -654,7 +651,6 @@
"General": "Geral",
"Generate": "Emitir",
"Generate Exception Certificates": "Gerar certificados de exce\u00e7\u00e3o",
"Generate a Certificate for all ": "Gerar um Certificado para todos",
"Generate a Certificate for all users on the Exception list": "Gerar um certificado para todos os usu\u00e1rios na lista de exce\u00e7\u00f5es",
"Generate the user's certificate": "Emitir certificado do usu\u00e1rio",
"Get Credit": "Obter Cr\u00e9dito",
@@ -774,7 +770,6 @@
"Keywords": "Palavras-chave",
"LEARN MORE": "APRENDER MAIS",
"Language": "Idioma",
"Language: Press the UP arrow key to enter the language menu, then use UP and DOWN arrow keys to navigate language options. Press ENTER to change to the selected language.": "Idioma: Pressione a tecla UP para entrar no menu de idioma, ent\u00e3o pressione as teclas UP e DOWN para navegar nas op\u00e7\u00f5es de idioma. Pressione ENTER para mudar para o idioma selecionado.",
"Large": "Grande",
"Last Activity %(date)s": "\u00daltima atividade %(date)s",
"Last Edited:": "\u00daltima Edi\u00e7\u00e3o:",
@@ -862,7 +857,6 @@
"Name of the signatory": "Nome da assinatura",
"Name or short description of the configuration": "Nome ou descri\u00e7\u00e3o curta da configura\u00e7\u00e3o",
"Never published": "Nunca publicado",
"New": "Novo",
"New %(component_type)s": "Novos %(component_type)s",
"New %(item_type)s": "Novo %(item_type)s",
"New Address": "Novo Endere\u00e7o",
@@ -911,13 +905,10 @@
"Numbered list": "Lista numerada",
"OK": "OK",
"Ok": "Ok",
"Once in position, use the camera button %(icon)s to capture your ID": "Uma vez em posi\u00e7\u00e3o, utilize o bot\u00e3o da c\u00e2mera %(icon)s para tirar a foto da sua identidade.",
"Once in position, use the camera button %(icon)s to capture your photo": "Quando estiver na posi\u00e7\u00e3o, use o bot\u00e3o da c\u00e2mera %(icon)s para capturar a sua foto",
"Only <%= fileTypes %> files can be uploaded. Please select a file ending in <%= fileExtensions %> to upload.": "Apenas arquivos <%= fileTypes %> podem ser enviados. Por favor selecione uma extens\u00e3o de arquivo finalizando em <%= fileExtensions %> para enviar.",
"Only properly formatted .csv files will be accepted.": "Apenas arquivos .csv formatados corretamente ser\u00e3o aceitos.",
"Open": "Abrir",
"Open Calculator": "Abrir calculadora",
"Open language menu": "Abrir menu de idiomas",
"Open/download this file": "Abrir/baixar este arquivo",
"OpenAssessment Save Error": "Erro ao salvar o OpenAssessment",
"Optional Characteristics": "Caracter\u00edsticas Opcionais",
@@ -929,7 +920,6 @@
"Organization of the signatory": "Organiza\u00e7\u00e3o do signat\u00e1rio",
"Other": "Outro",
"Page break": "Quebra de p\u00e1gina",
"Page number": "N\u00famero da p\u00e1gina",
"Paragraph": "Par\u00e1grafo",
"Password": "Senha",
"Password Reset Email Sent": "O e-mail para redefinir a senha foi enviado",
@@ -1007,7 +997,6 @@
"Proctored": "Supervisionado",
"Proctored Exam": "Exame supervisionado",
"Proctored exams are timed and they record video of each learner taking the exam. The videos are then reviewed to ensure that learners follow all examination rules.": "Exames supervisionados s\u00e3o cronometrados e eles gravam um v\u00eddeo de cada aluno fazendo a prova. Os v\u00eddeos s\u00e3o ent\u00e3o revisados para garantir que os alunos sigam as regras do exame.",
"Professional Certificate for %(courseName)s": "Certificado profissional para %(courseName)s",
"Professional Education": "Educa\u00e7\u00e3o Profissional",
"Professional Education Verified Certificate": "Certificado verificado de profissional de educa\u00e7\u00e3o",
"Profile Image": "Imagem do perfil",
@@ -1260,9 +1249,7 @@
"Textbook name is required": "O nome do livro texto \u00e9 obrigat\u00f3rio",
"Thank you for submitting your financial assistance application for {course_name}! You can expect a response in 2-4 business days.": "Agradecemos por nos enviar o seu pedido de assist\u00eancia financeira para {course_name}! Voc\u00ea pode esperar uma resposta entre 2-4 dias \u00fateis.",
"Thank you for submitting your photos. We will review them shortly. You can now sign up for any %(platformName)s course that offers verified certificates. Verification is good for one year. After one year, you must submit photos for verification again.": "Obrigado por enviar suas fotos. N\u00f3s vamos analis\u00e1-las rapidamente. Voc\u00ea pode inscrever-se para qualquer curso da plataforma %(platformName)s que ofere\u00e7a certificados verificados. A verifica\u00e7\u00e3o \u00e9 v\u00e1lida por um ano. Depois disso, voc\u00ea precisa enviar fotos para verificar novamente.",
"Thank you! We have received your payment for %(courseName)s.": "Obrigado! N\u00f3s recebemos o seu pagamento para o curso %(courseName)s.",
"Thank you! We have received your payment for %(course_name)s.": "Obrigado! Recebemos o seu pagamento para %(course_name)s.",
"Thanks for returning to verify your ID in: %(courseName)s": "Obrigado por retornar para verificar sua identidade em: %(courseName)s",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "A URL que voc\u00ea inseriu parece ser um endere\u00e7o de e-mail. Deseja adicionar o prefixo obrigat\u00f3rio mailto:? ",
"The URL you entered seems to be an external link. Do you want to add the required http:// prefix?": "A URL que voc\u00ea inseriu parece ser um link externo. Deseja adicionar o prefixo obrigat\u00f3rio http://?",
"The cohort cannot be added": "O grupo n\u00e3o pode ser adicionado",
@@ -1351,7 +1338,6 @@
"This configuration is currently used in content experiments. If you make changes to the groups, you may need to edit those experiments.": "Essa configura\u00e7\u00e3o est\u00e1 sendo usada em experimentos de conte\u00fado. Se fizer altera\u00e7\u00f5es aos grupos, voc\u00ea vai precisar editar os experimentos.",
"This content group is used in one or more units.": "Este grupo de conte\u00fado \u00e9 utilizado em uma ou mais unidades.",
"This content group is used in:": "Esse grupo de conte\u00fado \u00e9 utilizado em:",
"This edX learner is currently sharing a limited profile.": "Este estudante da edX est\u00e1 atualmente compartilhando um perfil limitado.",
"This is the Description of the Group Configuration": "Esta \u00e9 a Descri\u00e7\u00e3o da Configura\u00e7\u00e3o do Grupo",
"This is the Name of the Group Configuration": "Este \u00e9 o Nome da Configura\u00e7\u00e3o do Grupo",
"This is the name of the group": "Esse \u00e9 o nome do grupo",
@@ -1385,7 +1371,6 @@
"To receive a certificate, you must also verify your identity before %(date)s.": "Para receber um certificado, voc\u00ea tamb\u00e9m deve verificar sua identidade antes de %(date)s.",
"To receive a certificate, you must also verify your identity.": "Para receber um certificado, voc\u00ea tamb\u00e9m deve verificar a sua identidade.",
"To take a successful photo, make sure that:": "Para tirar uma foto corretamente, certifique-se que:",
"To use the current photo, select the camera button %(icon)s. To take another photo, select the retake button %(icon)s.": "Para usar a foto atual, selecione o %(icon)s do bot\u00e3o da c\u00e2mera. Para tirar outra foto, selecione o %(icon)s do bot\u00e3o tirar novamente.",
"To verify your identity, you need a webcam and a government-issued photo ID.": "Para verificar sua identidade, voc\u00ea precisa de uma webcam e um documento com foto emitido pelo governo.",
"Toggle Notifications Setting": "Alterar Configura\u00e7\u00f5es de Notifica\u00e7\u00e3o",
"Tools": "Ferramentas",
@@ -1397,7 +1382,6 @@
"Total Number": "N\u00famero Total",
"Try the transaction again in a few minutes.": "Tente fazer esta transa\u00e7\u00e3o novamente em alguns minutos.",
"Try using a different browser, such as Google Chrome.": "Tente usar um navegador diferente, como o Google Chrome.",
"Turn off transcript": "Desativar transcri\u00e7\u00f5es",
"Turn off transcripts": "Desligar legendas",
"Turn on closed captioning": "Ativar as legendas ocultas",
"Turn on transcripts": "Ativar legendas",
@@ -1433,7 +1417,6 @@
"Update team.": "Atualizar equipe.",
"Updating with latest library content": "Atualizando com o conte\u00fado mais recente da biblioteca",
"Upgrade Deadline": "Prazo final para atualiza\u00e7\u00e3o",
"Upgrade to a Verified Certificate for %(courseName)s": "Atualizar para um Certificado Verificado de %(courseName)s",
"Upload": "Enviar",
"Upload File": "Carregar arquivo",
"Upload File and Assign Students": "Fa\u00e7a o upload do arquivo e a atribui\u00e7\u00e3o de Alunos.",
@@ -1482,7 +1465,6 @@
"Verification Deadline": "Prazo de verifica\u00e7\u00e3o",
"Verification checkpoint to be completed": "Ponto de verifica\u00e7\u00e3o a completar",
"Verified Certificate": "Certificado Verificado",
"Verified Certificate for %(courseName)s": "Certificado verificado para %(courseName)s",
"Verified Certificate upgrade": "Atualiza\u00e7\u00e3o do certificado verificado",
"Verified Status": "Status verificado",
"Verified mode price": "Pre\u00e7o de modo verificado",
@@ -1558,7 +1540,6 @@
"What does %(platformName)s do with this photo?": "O que %(platformName)s faz com esta foto?",
"What does this mean?": "O que isso significa?",
"When you click \"Reset Password\", a message will be sent to your email address. Click the link in the message to reset your password.": "Quando voc\u00ea clicar em \"Redefinir senha\", uma mensagem ser\u00e1 enviada para o seu endere\u00e7o de e-mail. Clique no link na mensagem para redefinir sua senha.",
"When your face is in position, use the camera button %(icon)s below to take your photo.": "Quando seu rosto estiver posicionado, use o %(icon)s do bot\u00e3o da c\u00e2mera abaixo para tirar sua foto.",
"Which timed transcript would you like to use?": "Qual transcri\u00e7\u00e3o sincronizada voc\u00ea gostaria de utilizar?",
"Whole words": "Palavras completas",
"Why does %(platformName)s need my photo?": "Por que %(platformName)s precisa da minha foto?",
@@ -1576,11 +1557,8 @@
"You are about to send an email titled '<%= subject %>' to everyone who is staff or instructor on this course. Is this OK?": "Voc\u00ea est\u00e1 prestes a enviar um email com o t\u00edtulo '<%= subject %>' para todos da equipe ou os instrutores deste curso. Tem certeza?",
"You are about to send an email titled '<%= subject %>' to yourself. Is this OK?": "Voc\u00ea est\u00e1 prestes a enviar um email com o t\u00edtulo '<%= subject %>' para si mesmo. Tem certeza?",
"You are currently sharing a limited profile.": "Voc\u00ea est\u00e1 compartilhando um perfil limitado no momento.",
"You are enrolling in %(courseName)s": "Voc\u00ea est\u00e1 se matriculando em %(courseName)s",
"You are enrolling in: %(courseName)s": "Voc\u00ea est\u00e1 se inscrevendo em: %(courseName)s",
"You are not currently a member of any team.": "No momento, voc\u00ea n\u00e3o \u00e9 membro de nenhuma equipe. ",
"You are now enrolled as a verified student for:": "Voc\u00ea est\u00e1 inscrito como aluno verificado para:",
"You are upgrading your enrollment for: %(courseName)s": "Voc\u00ea est\u00e1 atualizando sua matr\u00edcula para: %(courseName)s",
"You can now enter your payment information and complete your enrollment.": "Voc\u00ea pode preencher agora as informa\u00e7\u00f5es sobre o pagamento e completar a sua matr\u00edcula",
"You can pay now even if you don't have the following items available, but you will need to have these by %(date)s to qualify to earn a Verified Certificate.": "Voc\u00ea pode pagar agora, mesmo que n\u00e3o tenha nenhum dos seguintes itens dispon\u00edveis, mas voc\u00ea ter\u00e1 que t\u00ea-los at\u00e9 %(date)s para se qualificar para um Certificado Verificado.",
"You can pay now even if you don't have the following items available, but you will need to have these to qualify to earn a Verified Certificate.": "Voc\u00ea pode pagar agora, mesmo n\u00e3o tendo nenhum dos seguintes itens dispon\u00edveis, mas voc\u00ea ter\u00e1 que t\u00ea-los para se qualificar para um Certificado Verificado.",
@@ -1652,7 +1630,6 @@
"Your team could not be updated.": "Sua equipe n\u00e3o p\u00f4de ser atualizada.",
"Your upload of '{file}' failed.": "O carregamento do arquivo '{file}' falhou.",
"Your upload of '{file}' succeeded.": "O carregamento do arquivo '{file}' foi conclu\u00eddo com sucesso.",
"Your verification status is good until %(verificationGoodUntil)s.": "Seu status de verifica\u00e7\u00e3o \u00e9 v\u00e1lido at\u00e9 %(verificationGoodUntil)s.",
"Your video uploads are not complete.": "Os seus uploads de v\u00eddeo n\u00e3o est\u00e3o completos.",
"Zoom In": "Aumentar a tela",
"Zoom Out": "Diminuir a tela",
@@ -1666,7 +1643,6 @@
"about a month": "aproximadamente um m\u00eas",
"about a year": "aproximadamente um ano",
"about an hour": "aproximadamente uma hora",
"additions to the Exception list": "adi\u00e7\u00f5es \u00e0 lista de exce\u00e7\u00e3o",
"and others": "e outros",
"anonymous": "an\u00f4nimo",
"answer": "resposta",
@@ -1713,7 +1689,6 @@
"or": "ou",
"or create a new one here": "ou criar uma nova aqui",
"or sign in with": "ou entrar com",
"path/to/introductionToCookieBaking-CH%d.pdf": "path/to/introductionToCookieBaking-CH%d.pdf",
"post anonymously": "publicar anonimamente",
"post anonymously to classmates": "publicar anonimamente para os colegas da turma",
"posted %(time_ago)s by %(author)s": "postado %(time_ago)s por %(author)s",

View File

@@ -177,7 +177,6 @@
"<%= user %> has been successfully added to the exception list. Click Generate Exception Certificate below to send the certificate.": "<%= user %> \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d. \u0414\u043b\u044f \u0432\u044b\u0434\u0430\u0447\u0438 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u00ab\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u044b \u0434\u043b\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432\u00bb.",
"<button data-provider=\"%s\" data-course-key=\"%s\" data-username=\"%s\" class=\"complete-course\" onClick=completeOrder(this)>%s</button>": "<button data-provider=\"%s\" data-course-key=\"%s\" data-username=\"%s\" class=\"complete-course\" onClick=completeOrder(this)>%s</button>",
"<img src='%s' alt='%s'></image>": "<img src='%s' alt='%s'></image>",
"<li>Transcript will be displayed when ": "<li>\u041e\u0446\u0435\u043d\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u044b, \u043a\u043e\u0433\u0434\u0430",
"A driver's license, passport, or government-issued ID with your name and photo.": "\u0412\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0435 \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u0435\u043d\u0438\u0435, \u043f\u0430\u0441\u043f\u043e\u0440\u0442 \u0438\u043b\u0438 \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u0435\u043d\u0438\u0435 \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u0438 \u0433\u043e\u0441\u0443\u0434\u0430\u0440\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0446\u0430 \u0441 \u0432\u0430\u0448\u0438\u043c\u0438 \u0438\u043c\u0435\u043d\u0435\u043c \u0438 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0435\u0439.",
"A driver's license, passport, or other government-issued ID with your name and photo": "\u0412\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0435 \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u0435\u043d\u0438\u0435, \u043f\u0430\u0441\u043f\u043e\u0440\u0442 \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u0433\u043e\u0441\u0443\u0434\u0430\u0440\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0446\u0430 \u0441 \u0432\u0430\u0448\u0438\u043c\u0438 \u0438\u043c\u0435\u043d\u0435\u043c \u0438 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0435\u0439",
"A list of courses you have just enrolled in as a verified student": "\u0421\u043f\u0438\u0441\u043e\u043a \u043a\u0443\u0440\u0441\u043e\u0432, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u044b \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0437\u0430\u0447\u0438\u0441\u043b\u0435\u043d\u044b",
@@ -196,7 +195,6 @@
"Actions": "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044f",
"Activate": "\u0410\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c",
"Activate Your Account": "\u0410\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0439\u0442\u0435 \u0421\u0432\u043e\u044e \u0423\u0447\u0451\u0442\u043d\u0443\u044e \u0417\u0430\u043f\u0438\u0441\u044c",
"Activating an item in this group will spool the video to the corresponding time point. To skip transcript, go to previous item.": "\u041f\u0440\u0438 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 \u043f\u0443\u043d\u043a\u0442\u0430 \u0432 \u044d\u0442\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0451\u0442 \u043f\u0435\u0440\u0435\u043c\u043e\u0442\u043a\u0430 \u0432\u0438\u0434\u0435\u043e \u043a \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0442\u043e\u0447\u043a\u0435. \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0442\u0438\u0442\u0440\u044b, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043a \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c\u0443 \u043f\u0443\u043d\u043a\u0442\u0443.",
"Active Threads": "\u0410\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0442\u0435\u043c\u044b",
"Active Uploads": "\u0410\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438",
"Add": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c",
@@ -363,7 +361,6 @@
"Change My Email Address": "\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0430\u0434\u0440\u0435\u0441 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b",
"Change image": "\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435",
"Change the settings for %(display_name)s": "%(display_name)s: \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 ",
"Chapter %s": "\u0413\u043b\u0430\u0432\u0430 %s",
"Chapter Asset": "\u0410\u043a\u0442\u0438\u0432 \u0433\u043b\u0430\u0432\u044b",
"Chapter Name": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0433\u043b\u0430\u0432\u044b",
"Chapter information": "\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0433\u043b\u0430\u0432\u0435",
@@ -720,7 +717,6 @@
"General": "\u041e\u0431\u0449\u0435\u0435",
"Generate": "\u0421\u043e\u0437\u0434\u0430\u0442\u044c",
"Generate Exception Certificates": "\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u044b \u0434\u043b\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432",
"Generate a Certificate for all ": "\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u044b \u0434\u043b\u044f \u0432\u0441\u0435\u0445",
"Generate a Certificate for all users on the Exception list": "\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u044b \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439",
"Generate the user's certificate": "\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442",
"Get Credit": "\u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0437\u0430\u0447\u0451\u0442",
@@ -843,7 +839,6 @@
"Keywords": "\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430",
"LEARN MORE": "\u041f\u041e\u0414\u0420\u041e\u0411\u041d\u0415\u0415",
"Language": "\u042f\u0437\u044b\u043a",
"Language: Press the UP arrow key to enter the language menu, then use UP and DOWN arrow keys to navigate language options. Press ENTER to change to the selected language.": "\u042f\u0437\u044b\u043a: \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u0441\u043e \u0441\u0442\u0440\u0435\u043b\u043a\u043e\u0439 \u0432\u0432\u0435\u0440\u0445 \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u044f\u0437\u044b\u043a\u0430, \u0437\u0430\u0442\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u0442\u0440\u0435\u043b\u043a\u0438 \u0432\u0432\u0435\u0440\u0445 \u0438 \u0432\u043d\u0438\u0437 \u0434\u043b\u044f \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u043f\u043e \u043c\u0435\u043d\u044e. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 ENTER \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u044f\u0437\u044b\u043a\u0430.",
"Large": "\u0411\u043e\u043b\u044c\u0448\u043e\u0439",
"Last Activity %(date)s": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c %(date)s",
"Last Edited:": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f",
@@ -937,7 +932,6 @@
"Name of the signatory": "\u0418\u043c\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u0435\u043b\u044f, \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0435\u0433\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442",
"Name or short description of the configuration": "\u0418\u043c\u044f \u0438 \u043a\u0440\u0430\u0442\u043a\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0433\u0440\u0443\u043f\u043f",
"Never published": "\u0420\u0430\u043d\u0435\u0435 \u043d\u0435 \u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043b\u043e\u0441\u044c",
"New": "\u041d\u043e\u0432\u044b\u0439",
"New %(component_type)s": "\u041d\u043e\u0432\u044b\u0439 %(component_type)s",
"New %(item_type)s": "\u041d\u043e\u0432\u0430\u044f %(item_type)s",
"New Address": "\u041d\u043e\u0432\u044b\u0439 \u0430\u0434\u0440\u0435\u0441",
@@ -987,13 +981,10 @@
"Numbered list": "\u041d\u0443\u043c\u0435\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a",
"OK": "\u041e\u041a",
"Ok": "\u041e\u043a",
"Once in position, use the camera button %(icon)s to capture your ID": "\u041a\u043e\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442\u0435 \u0433\u043e\u0442\u043e\u0432\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u043a\u0430\u043c\u0435\u0440\u044b %(icon)s, \u0447\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043d\u0438\u043c\u043e\u043a \u0441\u0432\u043e\u0435\u0433\u043e \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u0435\u043d\u0438\u044f \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u0438",
"Once in position, use the camera button %(icon)s to capture your photo": "\u041a\u043e\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442\u0435 \u0433\u043e\u0442\u043e\u0432\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u043a\u0430\u043c\u0435\u0440\u044b %(icon)s, \u0447\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043d\u0438\u043c\u043e\u043a",
"Only <%= fileTypes %> files can be uploaded. Please select a file ending in <%= fileExtensions %> to upload.": "\u0422\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b\u044b \u0442\u0438\u043f\u043e\u0432 <%= fileTypes %> \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u044b. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0444\u0430\u0439\u043b \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c <%= fileExtensions %>.",
"Only properly formatted .csv files will be accepted.": "\u0422\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043e\u0442\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b .csv \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0438\u043d\u044f\u0442\u044b.",
"Open": "\u041e\u0442\u043a\u0440\u044b\u0442\u044c",
"Open Calculator": "\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u0430\u043b\u044c\u043a\u0443\u043b\u044f\u0442\u043e\u0440",
"Open language menu": "\u0412\u044b\u0431\u043e\u0440 \u044f\u0437\u044b\u043a\u0430",
"Open/download this file": "\u041e\u0442\u043a\u0440\u044b\u0442\u044c/\u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0444\u0430\u0439\u043b",
"OpenAssessment Save Error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f OpenAssessment",
"Optional Characteristics": "\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b",
@@ -1005,7 +996,6 @@
"Organization of the signatory": "\u041c\u0435\u0441\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u0435\u043b\u044f, \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0435\u0433\u043e \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442",
"Other": "\u0414\u0440\u0443\u0433\u043e\u0435",
"Page break": "\u041a\u043e\u043d\u0435\u0446 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b",
"Page number": "\u041d\u043e\u043c\u0435\u0440 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b",
"Paragraph": "\u0410\u0431\u0437\u0430\u0446",
"Password": "\u041f\u0430\u0440\u043e\u043b\u044c",
"Password Reset Email Sent": "\u0418\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u043f\u043e \u0441\u0431\u0440\u043e\u0441\u0443 \u043f\u0430\u0440\u043e\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b",
@@ -1088,7 +1078,6 @@
"Proctored": "\u041d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u043e\u0435",
"Proctored Exam": "\u041d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u043e\u0435 \u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435",
"Proctored exams are timed and they record video of each learner taking the exam. The videos are then reviewed to ensure that learners follow all examination rules.": "\u041d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u044b\u0435 \u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u044b \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043a \u0442\u043e\u043c\u0443 \u0436\u0435 \u0437\u0430 \u043a\u0430\u0436\u0434\u044b\u043c \u0438\u0437 \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u043e\u0432 \u0432\u0435\u0434\u0451\u0442\u0441\u044f \u0432\u0438\u0434\u0435\u043e\u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435. \u0417\u0430\u0442\u0435\u043c \u0432\u0438\u0434\u0435\u043e\u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0438 \u043f\u0440\u0430\u0432\u0438\u043b.",
"Professional Certificate for %(courseName)s": "\u0421\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044f \u043a\u0432\u0430\u043b\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 %(courseName)s",
"Professional Education": "\u041f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435",
"Professional Education Verified Certificate": "\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 \u043e \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u0438 \u043a\u0432\u0430\u043b\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438",
"Profile Image": "\u0424\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u044f",
@@ -1350,9 +1339,7 @@
"Textbook name is required": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0430",
"Thank you for submitting your financial assistance application for {course_name}! You can expect a response in 2-4 business days.": "\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u0438\u043c \u0432\u0430\u0441 \u0437\u0430 \u043f\u043e\u0434\u0430\u0447\u0443 \u0437\u0430\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430 \u0433\u0440\u0430\u043d\u0442 \u043f\u043e \u043a\u0443\u0440\u0441\u0443 {course_name}! \u0412\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u043e\u0442\u0432\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 2-4 \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u0434\u043d\u044f.",
"Thank you for submitting your photos. We will review them shortly. You can now sign up for any %(platformName)s course that offers verified certificates. Verification is good for one year. After one year, you must submit photos for verification again.": "\u0421\u043f\u0430\u0441\u0438\u0431\u043e, \u0447\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0444\u043e\u0442\u043e! \u041c\u044b \u0441\u043a\u043e\u0440\u043e \u0438\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c. \u0421\u0435\u0439\u0447\u0430\u0441 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 \u043a\u0443\u0440\u0441\u043e\u0432 %(platformName)s, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e\u0449\u0438\u0445 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d\u043d\u044b\u0435 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u044b. \u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u043e\u0434\u0438\u043d \u0433\u043e\u0434. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0444\u043e\u0442\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e.",
"Thank you! We have received your payment for %(courseName)s.": "\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u0438\u043c \u0432\u0430\u0441! \u0412\u0430\u0448 \u043f\u043b\u0430\u0442\u0451\u0436 \u0437\u0430 \u043a\u0443\u0440\u0441 %(courseName)s \u043f\u043e\u043b\u0443\u0447\u0435\u043d.",
"Thank you! We have received your payment for %(course_name)s.": "\u0421\u043f\u0430\u0441\u0438\u0431\u043e! \u0412\u0430\u0448 \u043f\u043b\u0430\u0442\u0451\u0436 \u043f\u043e \u043a\u0443\u0440\u0441\u0443 \u00ab%(course_name)s\u00bb \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d.",
"Thanks for returning to verify your ID in: %(courseName)s": "\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u0438\u043c \u0437\u0430 \u0442\u043e, \u0447\u0442\u043e \u0432\u044b \u0432\u0435\u0440\u043d\u0443\u043b\u0438\u0441\u044c \u0438 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u043b\u0438 \u0441\u0432\u043e\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u043a\u0443\u0440\u0441\u0435: %(courseName)s",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u0410\u0434\u0440\u0435\u0441 URL, \u0432\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0439 \u0432\u0430\u043c\u0438, \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u044b\u0439 \u0430\u0434\u0440\u0435\u0441. \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0435\u0444\u0438\u043a\u0441 \u00abmailto:\u00bb?",
"The URL you entered seems to be an external link. Do you want to add the required http:// prefix?": "\u0410\u0434\u0440\u0435\u0441 URL, \u0432\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0439 \u0432\u0430\u043c\u0438, \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 \u0432\u043d\u0435\u0448\u043d\u044e\u044e \u0441\u0441\u044b\u043b\u043a\u0443. \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0435\u0444\u0438\u043a\u0441 \u00abhttp://\u00bb?",
"The certificate for this learner has been re-validated and the system is re-running the grade for this learner.": "\u0421\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0435\u0433\u043e\u0441\u044f \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d, \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u043f\u0435\u0440\u0435\u0441\u0447\u0451\u0442 \u043e\u0446\u0435\u043d\u043a\u0438.",
@@ -1447,7 +1434,6 @@
"This configuration is currently used in content experiments. If you make changes to the groups, you may need to edit those experiments.": "\u042d\u0442\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430.\u0415\u0441\u043b\u0438 \u0432\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0435 \u0433\u0440\u0443\u043f\u043f\u044b, \u0432\u0430\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u044b",
"This content group is used in one or more units.": "\u042d\u0442\u0430 \u0433\u0440\u0443\u043f\u043f\u0430 \u043f\u043e \u0438\u0437\u0443\u0447\u0430\u0435\u043c\u044b\u043c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430\u043c \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0431\u043b\u043e\u043a\u0430\u0445",
"This content group is used in:": "\u042d\u0442\u0430 \u0433\u0440\u0443\u043f\u043f\u0430 \u043f\u043e \u0438\u0437\u0443\u0447\u0430\u0435\u043c\u044b\u043c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0431\u043b\u043e\u043a\u0430\u0445:",
"This edX learner is currently sharing a limited profile.": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u043b \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0432\u043e\u0435\u043c\u0443 \u043f\u0440\u043e\u0444\u0438\u043b\u044e.",
"This image is for decorative purposes only and does not require a description.": "\u042d\u0442\u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u0446\u0435\u043b\u0435\u0439 \u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f.",
"This is the Description of the Group Configuration": "\u042d\u0442\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0433\u0440\u0443\u043f\u043f",
"This is the Name of the Group Configuration": "\u042d\u0442\u043e \u0438\u043c\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0433\u0440\u0443\u043f\u043f",
@@ -1483,7 +1469,6 @@
"To receive a certificate, you must also verify your identity.": "\u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c \u0441\u0432\u043e\u044e \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u044c.",
"To receive credit on a problem, you must click \"Check\" or \"Final Check\" on it before you select \"End My Exam\".": "\u0427\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0437\u0430 \u0437\u0430\u0434\u0430\u043d\u0438\u0435 \u0437\u0430\u0447\u0451\u0442\u043d\u044b\u0435 \u0435\u0434\u0438\u043d\u0438\u0446\u044b, \u043f\u0435\u0440\u0435\u0434 \u043d\u0430\u0436\u0430\u0442\u0438\u0435\u043c \u043a\u043d\u043e\u043f\u043a\u0438 \u00ab\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0441\u0434\u0430\u0447\u0443 \u044d\u043a\u0437\u0430\u043c\u0435\u043d\u0430\u00bb \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u0436\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c\u00bb \u0438\u043b\u0438 \u00ab\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c/\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u043f\u043e\u043f\u044b\u0442\u043a\u0430\u00bb \u0432 \u044d\u0442\u043e\u043c \u0437\u0430\u0434\u0430\u043d\u0438\u0438.",
"To take a successful photo, make sure that:": "\u0427\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0443\u0434\u0430\u0447\u043d\u044b\u0439 \u0441\u043d\u0438\u043c\u043e\u043a, \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u044c\u0442\u0435\u0441\u044c, \u0447\u0442\u043e:",
"To use the current photo, select the camera button %(icon)s. To take another photo, select the retake button %(icon)s.": "\u0427\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u044e, \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u0441 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c \u043a\u0430\u043c\u0435\u0440\u044b %(icon)s. \u0427\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0443\u044e \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u044e, \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u043f\u0435\u0440\u0435\u0441\u044a\u0451\u043c\u043a\u0438 %(icon)s.",
"To verify your identity, you need a webcam and a government-issued photo ID.": "\u0414\u043b\u044f \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f, \u0432\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0432\u0435\u0431-\u043a\u0430\u043c\u0435\u0440\u0430 \u0438 \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u0435\u043d\u0438\u0435 \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u0438 \u0441 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0435\u0439: \u043f\u0430\u0441\u043f\u043e\u0440\u0442 \u0438\u043b\u0438 \u0438\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442.",
"Toggle Notifications Setting": "\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439",
"Tools": "\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b",
@@ -1495,7 +1480,6 @@
"Total Number": "\u041e\u0431\u0449\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e",
"Try the transaction again in a few minutes.": "\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437 \u0441\u043e\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043f\u043b\u0430\u0442\u0451\u0436 \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435.",
"Try using a different browser, such as Google Chrome.": "\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u0440\u0443\u0433\u0438\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Google Chrome.",
"Turn off transcript": "\u041e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0442\u0440\u0430\u043d\u0441\u043a\u0440\u0438\u043f\u0442",
"Turn off transcripts": "\u041e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0442\u0440\u0430\u043d\u0441\u043a\u0440\u0438\u043f\u0442\u044b",
"Turn on closed captioning": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b",
"Turn on transcripts": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0442\u0440\u0430\u043d\u0441\u043a\u0440\u0438\u043f\u0442\u044b",
@@ -1532,7 +1516,6 @@
"Update team.": "\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b",
"Updating with latest library content": "\u041f\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0438\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438",
"Upgrade Deadline": "\u041f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u0440\u043e\u043a \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f",
"Upgrade to a Verified Certificate for %(courseName)s": "\u041f\u043e\u0432\u044b\u0441\u044c\u0442\u0435 \u0434\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430 %(courseName)s",
"Upload": "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c",
"Upload File": "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0444\u0430\u0439\u043b",
"Upload File and Assign Students": "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0444\u0430\u0439\u043b \u0438 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0445\u0441\u044f",
@@ -1583,7 +1566,6 @@
"Verification Deadline": "\u0421\u0440\u043e\u043a \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f",
"Verification checkpoint to be completed": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u043e\u0439\u0442\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u0438",
"Verified Certificate": "\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442",
"Verified Certificate for %(courseName)s": "\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 %(courseName)s",
"Verified Certificate upgrade": "\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430",
"Verified Status": "\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d\u043d\u044b\u0439 \u0441\u0442\u0430\u0442\u0443\u0441",
"Verified mode price": "\u0421\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430",
@@ -1662,7 +1644,6 @@
"What does %(platformName)s do with this photo?": "\u0414\u043b\u044f \u0447\u0435\u0433\u043e %(platformName)s \u043d\u0443\u0436\u0435\u043d \u044d\u0442\u043e\u0442 \u0441\u043d\u0438\u043c\u043e\u043a?",
"What does this mean?": "\u0427\u0442\u043e \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442?",
"When you click \"Reset Password\", a message will be sent to your email address. Click the link in the message to reset your password.": "\u041f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u00ab\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u044c\u00bb \u043d\u0430 \u0430\u0434\u0440\u0435\u0441 \u0432\u0430\u0448\u0435\u0439 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0441\u043b\u0430\u043d\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435. \u0427\u0442\u043e\u0431\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u044c, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0432 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0438.",
"When your face is in position, use the camera button %(icon)s below to take your photo.": "\u041a\u043e\u0433\u0434\u0430 \u0432\u0430\u0448\u0435 \u043b\u0438\u0446\u043e \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u043e\u043f\u0430\u0434\u0451\u0442 \u0432 \u043a\u0430\u0434\u0440, \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u043d\u0443\u044e \u043d\u0438\u0436\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u0441 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c \u043a\u0430\u043c\u0435\u0440\u044b %(icon)s, \u0447\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043d\u0438\u043c\u043e\u043a.",
"Which timed transcript would you like to use?": "\u041a\u0430\u043a\u0438\u0435 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c?",
"Whole words": "\u0421\u043b\u043e\u0432\u0430 \u0446\u0435\u043b\u0438\u043a\u043e\u043c",
"Why does %(platformName)s need my photo?": "\u0417\u0430\u0447\u0435\u043c %(platformName)s \u043d\u0443\u0436\u043d\u0430 \u043c\u043e\u044f \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u044f?",
@@ -1680,11 +1661,8 @@
"You are about to send an email titled '<%= subject %>' to everyone who is staff or instructor on this course. Is this OK?": "\u0412\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c '<%= subject %>' \u0432\u0441\u0435\u043c \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c \u0438 \u043f\u0440\u0435\u043f\u043e\u0434\u0430\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u043a\u0443\u0440\u0441\u0430. \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c?",
"You are about to send an email titled '<%= subject %>' to yourself. Is this OK?": "\u0412\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c '<%= subject %>' \u043d\u0430 \u0441\u0432\u043e\u0439 \u0430\u0434\u0440\u0435\u0441. \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c?",
"You are currently sharing a limited profile.": "\u0421\u0435\u0439\u0447\u0430\u0441 \u0441\u043e\u043a\u0443\u0440\u0441\u043d\u0438\u043a\u0430\u043c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0432\u0430\u0448\u0435\u043c\u0443 \u043f\u0440\u043e\u0444\u0438\u043b\u044e.",
"You are enrolling in %(courseName)s": "\u0412\u044b \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0435\u0441\u044c \u043d\u0430 \u043a\u0443\u0440\u0441: %(courseName)s",
"You are enrolling in: %(courseName)s": "\u0412\u044b \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0435\u0441\u044c \u043d\u0430 \u043a\u0443\u0440\u0441: %(courseName)s",
"You are not currently a member of any team.": "\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u044b \u043d\u0435 \u0432\u0445\u043e\u0434\u0438\u0442\u0435 \u0432 \u0441\u043e\u0441\u0442\u0430\u0432 \u043d\u0438 \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b.",
"You are now enrolled as a verified student for:": "\u0412\u044b \u0437\u0430\u0447\u0438\u0441\u043b\u0435\u043d\u044b \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043a\u0443\u0440\u0441\u044b:",
"You are upgrading your enrollment for: %(courseName)s": "\u0412\u044b \u043c\u0435\u043d\u044f\u0435\u0442\u0435 \u0444\u043e\u0440\u043c\u0443 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0430 \u043a\u0443\u0440\u0441: %(courseName)s",
"You can now enter your payment information and complete your enrollment.": "\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u0432\u0435\u0441\u0442\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043f\u043b\u0430\u0442\u0435\u0436\u0435 \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e.",
"You can pay now even if you don't have the following items available, but you will need to have these by %(date)s to qualify to earn a Verified Certificate.": "\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0441\u0435\u0439\u0447\u0430\u0441, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0438 \u0432\u0441\u0435 \u0448\u0430\u0433\u0438. \u041d\u043e \u0432\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u0438\u0445 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043d\u0435 \u043f\u043e\u0437\u0434\u043d\u0435\u0435 %(date)s , \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442.",
"You can pay now even if you don't have the following items available, but you will need to have these to qualify to earn a Verified Certificate.": "\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0441\u0435\u0439\u0447\u0430\u0441, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0438 \u0432\u0441\u0435 \u0448\u0430\u0433\u0438. \u041d\u043e \u0432\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u0438\u0445 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442.",
@@ -1756,7 +1734,6 @@
"Your team could not be updated.": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0432\u0430\u0448\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b.",
"Your upload of '{file}' failed.": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 '{file}'",
"Your upload of '{file}' succeeded.": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 '{file}' \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430",
"Your verification status is good until %(verificationGoodUntil)s.": "\u0412\u0430\u0448 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d\u043d\u044b\u0439 \u0441\u0442\u0430\u0442\u0443\u0441 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u043e %(verificationGoodUntil)s.",
"Your video uploads are not complete.": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0432\u0438\u0434\u0435\u043e \u043d\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430.",
"Zoom In": "\u041f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u044c",
"Zoom Out": "\u041e\u0442\u0434\u0430\u043b\u0438\u0442\u044c",
@@ -1772,7 +1749,6 @@
"about a month": "\u043e\u043a\u043e\u043b\u043e \u043c\u0435\u0441\u044f\u0446\u0430",
"about a year": "\u043e\u043a\u043e\u043b\u043e \u0433\u043e\u0434\u0430",
"about an hour": "\u043e\u043a\u043e\u043b\u043e \u0447\u0430\u0441\u0430",
"additions to the Exception list": "\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439",
"and others": "\u0438 \u0434\u0440\u0443\u0433\u0438\u0435",
"anonymous": "\u0430\u043d\u043e\u043d\u0438\u043c",
"answer": "\u043e\u0442\u0432\u0435\u0442",
@@ -1822,7 +1798,6 @@
"or": "\u0438\u043b\u0438",
"or create a new one here": "\u0438\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0432 \u044d\u0442\u043e\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u0435",
"or sign in with": "\u0438\u043b\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e",
"path/to/introductionToCookieBaking-CH%d.pdf": "\u043f\u0443\u0442\u044c/\u043a/\u0432\u0432\u043e\u0434\u043d\u0430\u044f\u041f\u043e\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u044eCookie-\u0413\u041b%d.pdf",
"post anonymously": "\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u043e",
"post anonymously to classmates": "\u041e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u043e\u0432",
"posted %(time_ago)s by %(author)s": "\u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043e %(time_ago)s \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c %(author)s",

View File

@@ -521,8 +521,6 @@
"Numbered list": "\u7f16\u53f7\u5217\u8868",
"OK": "\u662f\u7684",
"Ok": "\u786e\u5b9a",
"Once in position, use the camera button %(icon)s to capture your ID": "\u4e00\u65e6\u4f60\u5c06\u8eab\u4efd\u8bc1\u4ef6\u6446\u653e\u59a5\u5f53\uff0c\u8bf7\u7528\u76f8\u673a\u6309\u94ae%(icon)s\u6765\u62cd\u7167",
"Once in position, use the camera button %(icon)s to capture your photo": "\u4e00\u4f46\u4f60\u5df2\u7ecf\u5c31\u4f4d\uff0c\u8bf7\u7528\u76f8\u673a\u6309\u94ae%(icon)s\u6765\u62cd\u7167",
"Only <%= fileTypes %> files can be uploaded. Please select a file ending in <%= fileExtensions %> to upload.": "\u53ea\u6709 <%= fileTypes %> \u683c\u5f0f\u7684\u6587\u4ef6\u53ef\u4ee5\u4e0a\u4f20\u3002\u8bf7\u9009\u62e9\u4e00\u4e2a\u4ee5 <%= fileExtensions %> \u7ed3\u5c3e\u7684\u6587\u4ef6\u4e0a\u4f20\u3002",
"Only properly formatted .csv files will be accepted.": "\u53ea\u6709\u6807\u51c6\u7684CSV\u683c\u5f0f\u6587\u4ef6\u4f1a\u88ab\u63a5\u53d7\u3002",
"Open Calculator": "\u6253\u5f00\u8ba1\u7b97\u5668",
@@ -717,8 +715,6 @@
"Text color": "\u6587\u672c\u989c\u8272",
"Text to display": "\u8981\u663e\u793a\u7684\u6587\u5b57",
"Thank you for submitting your photos. We will review them shortly. You can now sign up for any %(platformName)s course that offers verified certificates. Verification is good for one year. After one year, you must submit photos for verification again.": "\u611f\u8c22\u4f60\u63d0\u4ea4\u7167\u7247\uff0c\u6211\u4eec\u5c06\u4e8e\u7a0d\u540e\u8fdb\u884c\u5ba1\u6838\u3002\u4f60\u73b0\u5728\u5c31\u53ef\u4ee5\u6ce8\u518c%(platformName)s\u4e0a\u4efb\u610f\u63d0\u4f9b\u8ba4\u8bc1\u8bc1\u4e66\u7684\u8bfe\u7a0b\u3002\u8ba4\u8bc1\u53ea\u5728\u4e00\u5e74\u5185\u6709\u6548\uff0c\u4e00\u5e74\u540e\uff0c\u4f60\u5fc5\u987b\u8981\u63d0\u4ea4\u7167\u7247\u91cd\u65b0\u8ba4\u8bc1\u3002",
"Thank you! We have received your payment for %(courseName)s.": "\u8c22\u8c22\uff01\u6211\u4eec\u5df2\u7ecf\u6536\u5230\u4f60\u5bf9%(courseName)s\u7684\u4ed8\u6b3e\u3002",
"Thanks for returning to verify your ID in: %(courseName)s": "\u611f\u8c22\u4f60\u56de\u6765\u4e3a%(courseName)s\u9a8c\u8bc1\u4f60\u7684\u8eab\u4efd\u8bc1\u4ef6",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u8f93\u5165\u7684URL\u4f3c\u4e4e\u662f\u4e00\u4e2a\u7535\u5b50\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0a\u201cmailto:\u201d\u524d\u7f00\u5417\uff1f",
"The URL you entered seems to be an external link. Do you want to add the required http:// prefix?": "\u8f93\u5165\u7684 URL \u4f3c\u4e4e\u662f\u4e00\u4e2a\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0a\u201chttp://\u201d\u524d\u7f00\u5417\uff1f",
"The cohort cannot be added": "\u8be5\u7fa4\u7ec4\u4e0d\u80fd\u6dfb\u52a0",
@@ -877,9 +873,7 @@
"You are about to send an email titled '<%= subject %>' to ALL (everyone who is enrolled in this course as student, staff, or instructor). Is this OK?": "\u60a8\u5373\u5c06\u5411\u9009\u4fee\u8be5\u8bfe\u7a0b\u7684\u6240\u6709\u4eba(\u9009\u8bfe\u7684\u5b66\u751f\u3001\u6559\u5458\u548c\u4e3b\u8bb2\u6559\u5e08)\u53d1\u9001\u4e00\u5c01\u6807\u9898\u4e3a\u201c<%= subject %>\u201d\u7684\u90ae\u4ef6\uff0c\u786e\u8ba4\u5417\uff1f",
"You are about to send an email titled '<%= subject %>' to everyone who is staff or instructor on this course. Is this OK?": "\u60a8\u51c6\u5907\u5411\u8be5\u8bfe\u7a0b\u7684\u6240\u6709\u6559\u5458\u548c\u4e3b\u8bb2\u6559\u5e08\u53d1\u9001\u4e00\u5c01\u6807\u9898\u4e3a\u201c<%= subject %>\u201d\u7684\u90ae\u4ef6\uff0c\u786e\u8ba4\u5417\uff1f",
"You are about to send an email titled '<%= subject %>' to yourself. Is this OK?": "\u4f60\u51c6\u5907\u5411\u81ea\u5df1\u53d1\u9001\u4e00\u5c01\u6807\u9898\u4e3a\u201c<%= subject %>\u201d\u7684\u90ae\u4ef6\uff0c\u786e\u8ba4\u5417\uff1f",
"You are enrolling in: %(courseName)s": "\u4f60\u5373\u5c06\u9009\u4fee\uff1a%(courseName)s",
"You are now enrolled as a verified student for:": "\u4f60\u73b0\u5728\u6b63\u4ee5\u5df2\u8ba4\u8bc1\u5b66\u751f\u7684\u8eab\u4efd\u9009\u4fee\uff1a",
"You are upgrading your enrollment for: %(courseName)s": "\u4f60\u6b63\u5728\u4e3a%(courseName)s\u5347\u7ea7\u4f60\u7684\u9009\u8bfe\u7c7b\u578b",
"You can now enter your payment information and complete your enrollment.": "\u4f60\u53ef\u4ee5\u73b0\u5728\u5c31\u8f93\u5165\u652f\u4ed8\u4fe1\u606f\u5e76\u5b8c\u6210\u9009\u8bfe\u3002",
"You can pay now even if you don't have the following items available, but you will need to have these by %(date)s to qualify to earn a Verified Certificate.": "\u5373\u4f7f\u4f60\u6ca1\u6709\u6ee1\u8db3\u4e0b\u9762\u8fd9\u4e9b\u8981\u6c42\uff0c\u4f60\u4e5f\u53ef\u4ee5\u73b0\u5728\u5c31\u4ed8\u6b3e\uff1b\u4f46\u662f\u4f60\u53ea\u6709\u5728%(date)s\u4e4b\u524d\u6ee1\u8db3\u8fd9\u4e9b\u8981\u6c42\u624d\u6709\u8d44\u683c\u83b7\u5f97\u4e00\u4efd\u5df2\u8ba4\u8bc1\u7684\u8bc1\u4e66\u3002",
"You can pay now even if you don't have the following items available, but you will need to have these to qualify to earn a Verified Certificate.": "\u5373\u4f7f\u4f60\u6ca1\u6709\u6ee1\u8db3\u4e0b\u9762\u8fd9\u4e9b\u8981\u6c42\uff0c\u4f60\u4e5f\u53ef\u4ee5\u73b0\u5728\u5c31\u4ed8\u6b3e\uff1b\u4f46\u662f\u4f60\u53ea\u6709\u6ee1\u8db3\u4e86\u8fd9\u4e9b\u8981\u6c42\u624d\u6709\u8d44\u683c\u83b7\u5f97\u4e00\u4efd\u5df2\u8ba4\u8bc1\u7684\u8bc1\u4e66\u3002",
@@ -923,7 +917,6 @@
"Your post will be discarded.": "\u60a8\u7684\u5e16\u5b50\u5c06\u88ab\u64a4\u9500\u3002",
"Your upload of '{file}' failed.": "\u4f60\u7684\u6587\u4ef6\u201c{file}\u201d\u4e0a\u4f20\u5931\u8d25\u3002",
"Your upload of '{file}' succeeded.": "\u4f60\u7684\u6587\u4ef6\u201c{file}\u201d\u4e0a\u4f20\u6210\u529f\u3002",
"Your verification status is good until %(verificationGoodUntil)s.": "\u5728%(verificationGoodUntil)s\u4e4b\u524d\u60a8\u7684\u9a8c\u8bc1\u72b6\u6001\u90fd\u6709\u6548\u3002",
"a day": "\u4e00\u5929",
"about %d hour": [
"\u5927\u7ea6 %d \u5c0f\u65f6"

View File

@@ -1,41 +1,29 @@
define([
'backbone', 'coffee/src/main', 'js/models/group_configuration',
'js/models/group', 'js/collections/group', 'squire'
], function(
Backbone, main, GroupConfigurationModel, GroupModel, GroupCollection, Squire
) {
], function (Backbone, main, GroupConfigurationModel, GroupModel, GroupCollection, Squire) {
'use strict';
beforeEach(function() {
this.addMatchers({
toBeInstanceOf: function(expected) {
return this.actual instanceof expected;
},
toBeEmpty: function() {
return this.actual.length === 0;
}
});
});
describe('GroupConfigurationModel', function() {
beforeEach(function() {
describe('GroupConfigurationModel', function () {
beforeEach(function () {
main();
this.model = new GroupConfigurationModel();
});
describe('Basic', function() {
it('should have an empty name by default', function() {
describe('Basic', function () {
it('should have an empty name by default', function () {
expect(this.model.get('name')).toEqual('');
});
it('should have an empty description by default', function() {
it('should have an empty description by default', function () {
expect(this.model.get('description')).toEqual('');
});
it('should not show groups by default', function() {
it('should not show groups by default', function () {
expect(this.model.get('showGroups')).toBeFalsy();
});
it('should have a collection with 2 groups by default', function() {
it('should have a collection with 2 groups by default', function () {
var groups = this.model.get('groups');
expect(groups).toBeInstanceOf(GroupCollection);
@@ -43,11 +31,11 @@ define([
expect(groups.at(1).get('name')).toBe('Group B');
});
it('should have an empty usage by default', function() {
expect(this.model.get('usage')).toBeEmpty();
it('should have an empty usage by default', function () {
expect(this.model.get('usage').length).toBe(0);
});
it('should be able to reset itself', function() {
it('should be able to reset itself', function () {
var originalName = 'Original Name',
model = new GroupConfigurationModel({name: originalName});
model.set({name: 'New Name'});
@@ -56,18 +44,18 @@ define([
expect(model.get('name')).toEqual(originalName);
});
it('should be dirty after it\'s been changed', function() {
it('should be dirty after it\'s been changed', function () {
this.model.set('name', 'foobar');
expect(this.model.isDirty()).toBeTruthy();
});
describe('should not be dirty', function () {
it('by default', function() {
it('by default', function () {
expect(this.model.isDirty()).toBeFalsy();
});
it('after calling setOriginalAttributes', function() {
it('after calling setOriginalAttributes', function () {
this.model.set('name', 'foobar');
this.model.setOriginalAttributes();
@@ -76,13 +64,13 @@ define([
});
});
describe('Input/Output', function() {
var deepAttributes = function(obj) {
describe('Input/Output', function () {
var deepAttributes = function (obj) {
if (obj instanceof Backbone.Model) {
return deepAttributes(obj.attributes);
} else if (obj instanceof Backbone.Collection) {
return obj.map(deepAttributes);
} else if (_.isObject(obj)) {
} else if ($.isPlainObject(obj)) {
var attributes = {};
for (var prop in obj) {
@@ -96,7 +84,7 @@ define([
}
};
it('should match server model to client model', function() {
it('should match server model to client model', function () {
var serverModelSpec = {
'id': 10,
'name': 'My Group Configuration',
@@ -139,32 +127,32 @@ define([
'usage': []
},
model = new GroupConfigurationModel(
serverModelSpec, { parse: true }
serverModelSpec, {parse: true}
);
expect(deepAttributes(model)).toEqual(clientModelSpec);
expect(model.toJSON()).toEqual(serverModelSpec);
expect(JSON.parse(JSON.stringify(model))).toEqual(serverModelSpec);
});
});
describe('Validation', function() {
it('requires a name', function() {
var model = new GroupConfigurationModel({ name: '' });
describe('Validation', function () {
it('requires a name', function () {
var model = new GroupConfigurationModel({name: ''});
expect(model.isValid()).toBeFalsy();
});
it('can pass validation', function() {
it('can pass validation', function () {
// Note that two groups - Group A and Group B - are
// created by default.
var model = new GroupConfigurationModel({ name: 'foo' });
var model = new GroupConfigurationModel({name: 'foo'});
expect(model.isValid()).toBeTruthy();
});
it('requires at least one group', function() {
var group1 = new GroupModel({ name: 'Group A' }),
model = new GroupConfigurationModel({ name: 'foo', groups: [] });
it('requires at least one group', function () {
var group1 = new GroupModel({name: 'Group A'}),
model = new GroupConfigurationModel({name: 'foo', groups: []});
expect(model.isValid()).toBeFalsy();
@@ -172,21 +160,21 @@ define([
expect(model.isValid()).toBeTruthy();
});
it('requires a valid group', function() {
var model = new GroupConfigurationModel({ name: 'foo', groups: [{ name: '' }] });
it('requires a valid group', function () {
var model = new GroupConfigurationModel({name: 'foo', groups: [{name: ''}]});
expect(model.isValid()).toBeFalsy();
});
it('requires all groups to be valid', function() {
var model = new GroupConfigurationModel({ name: 'foo', groups: [{ name: 'Group A' }, { name: '' }] });
it('requires all groups to be valid', function () {
var model = new GroupConfigurationModel({name: 'foo', groups: [{name: 'Group A'}, {name: ''}]});
expect(model.isValid()).toBeFalsy();
});
it('requires all groups to have unique names', function() {
it('requires all groups to have unique names', function () {
var model = new GroupConfigurationModel({
name: 'foo', groups: [{ name: 'Group A' }, { name: 'Group A' }]
name: 'foo', groups: [{name: 'Group A'}, {name: 'Group A'}]
});
expect(model.isValid()).toBeFalsy();
@@ -194,91 +182,92 @@ define([
});
});
describe('GroupModel', function() {
beforeEach(function() {
describe('GroupModel', function () {
beforeEach(function () {
this.collection = new GroupCollection([{}]);
this.model = this.collection.at(0);
});
describe('Basic', function() {
it('should have an empty name by default', function() {
describe('Basic', function () {
it('should have an empty name by default', function () {
expect(this.model.get('name')).toEqual('');
});
it('should be empty by default', function() {
it('should be empty by default', function () {
expect(this.model.isEmpty()).toBeTruthy();
});
});
describe('Validation', function() {
it('requires a name', function() {
var model = new GroupModel({ name: '' });
describe('Validation', function () {
it('requires a name', function () {
var model = new GroupModel({name: ''});
expect(model.isValid()).toBeFalsy();
});
it('can pass validation', function() {
var model = new GroupConfigurationModel({ name: 'foo' });
it('can pass validation', function () {
var model = new GroupConfigurationModel({name: 'foo'});
expect(model.isValid()).toBeTruthy();
});
});
});
describe('GroupCollection', function() {
beforeEach(function() {
describe('GroupCollection', function () {
beforeEach(function () {
this.collection = new GroupCollection();
});
it('is empty by default', function() {
it('is empty by default', function () {
expect(this.collection.isEmpty()).toBeTruthy();
});
it('is empty if all groups are empty', function() {
this.collection.add([{ name: '' }, { name: '' }, { name: '' }]);
it('is empty if all groups are empty', function () {
this.collection.add([{name: ''}, {name: ''}, {name: ''}]);
expect(this.collection.isEmpty()).toBeTruthy();
});
it('is not empty if a group is not empty', function() {
it('is not empty if a group is not empty', function () {
this.collection.add([
{ name: '' }, { name: 'full' }, { name: '' }
{name: ''}, {name: 'full'}, {name: ''}
]);
expect(this.collection.isEmpty()).toBeFalsy();
});
describe('getGroupId', function () {
var collection, injector, mockGettext, initializeGroupModel;
var collection, injector, mockGettext, initializeGroupModel, cleanUp;
mockGettext = function (returnedValue) {
var injector = new Squire();
injector.mock('gettext', function () {
return function () { return returnedValue; };
return function () {
return returnedValue;
};
});
return injector;
};
initializeGroupModel = function (dict, that) {
runs(function() {
injector = mockGettext(dict);
injector.require(['js/collections/group'],
function(GroupCollection) {
initializeGroupModel = function (dict) {
var deferred = $.Deferred();
injector = mockGettext(dict);
injector.require(['js/collections/group'],
function (GroupCollection) {
collection = new GroupCollection();
deferred.resolve(collection);
});
});
waitsFor(function() {
return collection;
}, 'GroupModel was not instantiated', 500);
return deferred.promise();
};
that.after(function () {
collection = null;
injector.clean();
injector.remove();
});
cleanUp = function () {
collection = null;
injector.clean();
injector.remove();
};
it('returns correct ids', function () {
@@ -294,34 +283,46 @@ define([
expect(collection.getGroupId(475279)).toBe('AAAAZ');
});
it('just 1 character in the dictionary', function () {
initializeGroupModel('1', this);
runs(function() {
expect(collection.getGroupId(0)).toBe('1');
expect(collection.getGroupId(1)).toBe('11');
expect(collection.getGroupId(5)).toBe('111111');
});
it('just 1 character in the dictionary', function (done) {
initializeGroupModel('1')
.then(function (collection) {
expect(collection.getGroupId(0)).toBe('1');
expect(collection.getGroupId(1)).toBe('11');
expect(collection.getGroupId(5)).toBe('111111');
})
.always(function () {
cleanUp();
done();
});
});
it('allow to use unicode characters in the dict', function () {
initializeGroupModel('ö诶úeœ', this);
runs(function() {
expect(collection.getGroupId(0)).toBe('ö');
expect(collection.getGroupId(1)).toBe('诶');
expect(collection.getGroupId(5)).toBe('öö');
expect(collection.getGroupId(29)).toBe('œœ');
expect(collection.getGroupId(30)).toBe('ööö');
expect(collection.getGroupId(43)).toBe('öúe');
});
it('allow to use unicode characters in the dict', function (done) {
initializeGroupModel('ö诶úeœ')
.then(function (collection) {
expect(collection.getGroupId(0)).toBe('ö');
expect(collection.getGroupId(1)).toBe('诶');
expect(collection.getGroupId(5)).toBe('öö');
expect(collection.getGroupId(29)).toBe('œœ');
expect(collection.getGroupId(30)).toBe('ööö');
expect(collection.getGroupId(43)).toBe('öúe');
})
.always(function () {
cleanUp();
done();
});
});
it('return initial value if dictionary is empty', function () {
initializeGroupModel('', this);
runs(function() {
expect(collection.getGroupId(0)).toBe('0');
expect(collection.getGroupId(5)).toBe('5');
expect(collection.getGroupId(30)).toBe('30');
});
it('return initial value if dictionary is empty', function (done) {
initializeGroupModel('')
.then(function (collection) {
expect(collection.getGroupId(0)).toBe('0');
expect(collection.getGroupId(5)).toBe('5');
expect(collection.getGroupId(30)).toBe('30');
})
.always(function () {
cleanUp();
done();
});
});
});
});

View File

@@ -40,7 +40,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
left: $ele.offset().left
});
destination = ContentDragger.findDestination($ele, 1);
expect(destination.ele).toBe($('#unit-2'));
expect(destination.ele).toEqual($('#unit-2'));
expect(destination.attachMethod).toBe('before');
});
it("can drag and drop across section boundaries, with special handling for single sibling", function () {
@@ -52,17 +52,17 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
left: $ele.offset().left
});
destination = ContentDragger.findDestination($ele, 1);
expect(destination.ele).toBe($unit4);
expect(destination.ele).toEqual($unit4);
expect(destination.attachMethod).toBe('after');
destination = ContentDragger.findDestination($ele, -1);
expect(destination.ele).toBe($unit4);
expect(destination.ele).toEqual($unit4);
expect(destination.attachMethod).toBe('before');
$ele.offset({
top: $unit4.offset().top + $unit4.height() + 1,
left: $ele.offset().left
});
destination = ContentDragger.findDestination($ele, 0);
expect(destination.ele).toBe($unit4);
expect(destination.ele).toEqual($unit4);
expect(destination.attachMethod).toBe('after');
$unit0 = $('#unit-0');
$ele.offset({
@@ -70,7 +70,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
left: $ele.offset().left
});
destination = ContentDragger.findDestination($ele, 0);
expect(destination.ele).toBe($unit0);
expect(destination.ele).toEqual($unit0);
expect(destination.attachMethod).toBe('before');
});
it("can drop before the first element, even if element being dragged is\nslightly before the first element", function () {
@@ -81,7 +81,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
left: $ele.offset().left
});
destination = ContentDragger.findDestination($ele, -1);
expect(destination.ele).toBe($('#subsection-0'));
expect(destination.ele).toEqual($('#subsection-0'));
expect(destination.attachMethod).toBe('before');
});
it("can drag and drop across section boundaries, with special handling for last element", function () {
@@ -92,14 +92,14 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
left: $ele.offset().left
});
destination = ContentDragger.findDestination($ele, -1);
expect(destination.ele).toBe($('#unit-3'));
expect(destination.ele).toEqual($('#unit-3'));
expect(destination.attachMethod).toBe('after');
$ele.offset({
top: $('#unit-3').offset().top + 4,
left: $ele.offset().left
});
destination = ContentDragger.findDestination($ele, -1);
expect(destination.ele).toBe($('#unit-3'));
expect(destination.ele).toEqual($('#unit-3'));
expect(destination.attachMethod).toBe('before');
});
it("can drop past the last element, even if element being dragged is\nslightly before/taller then the last element", function () {
@@ -110,7 +110,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
left: $ele.offset().left
});
destination = ContentDragger.findDestination($ele, 1);
expect(destination.ele).toBe($('#subsection-4'));
expect(destination.ele).toEqual($('#subsection-4'));
expect(destination.attachMethod).toBe('after');
});
it("can drag into an empty list", function () {
@@ -121,7 +121,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
left: $ele.offset().left
});
destination = ContentDragger.findDestination($ele, 1);
expect(destination.ele).toBe($('#subsection-list-3'));
expect(destination.ele).toEqual($('#subsection-list-3'));
expect(destination.attachMethod).toBe('prepend');
});
it("reports a null destination on a failed drag", function () {
@@ -146,8 +146,8 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
left: $ele.offset().left
});
destination = ContentDragger.findDestination($ele, 1);
expect(destination.ele).toBe($('#subsection-list-2'));
expect(destination.parentList).toBe($('#subsection-2'));
expect(destination.ele).toEqual($('#subsection-list-2'));
expect(destination.parentList).toEqual($('#subsection-2'));
expect(destination.attachMethod).toBe('prepend');
});
});
@@ -176,7 +176,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
});
describe("onDragMove", function () {
beforeEach(function () {
this.redirectSpy = spyOn(window, 'scrollBy').andCallThrough();
this.redirectSpy = spyOn(window, 'scrollBy').and.callThrough();
});
it("adds the correct CSS class to the drop destination", function () {
var $ele, dragX, dragY;
@@ -239,7 +239,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
this.reorderSpy = spyOn(ContentDragger, 'handleReorder');
});
afterEach(function () {
this.reorderSpy.reset();
this.reorderSpy.calls.reset();
});
it("calls handleReorder on a successful drag", function () {
ContentDragger.dragState.dropDestination = $('#unit-2');
@@ -279,7 +279,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
expect($('#subsection-1')).not.toHaveClass('expand-on-drop');
});
it("expands a collapsed element when something is dropped in it", function () {
expandElementSpy = spyOn(ContentDragger, 'expandElement').andCallThrough();
var expandElementSpy = spyOn(ContentDragger, 'expandElement').and.callThrough();
expect(expandElementSpy).not.toHaveBeenCalled();
expect($('#subsection-2').data('ensureChildrenRendered')).not.toHaveBeenCalled();
@@ -301,8 +301,8 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
});
describe("AJAX", function () {
beforeEach(function () {
this.savingSpies = spyOnConstructor(Notification, "Mini", ["show", "hide"]);
this.savingSpies.show.andReturn(this.savingSpies);
this.savingSpies = jasmine.stealth.spyOnConstructor(Notification, "Mini", ["show", "hide"]);
this.savingSpies.show.and.returnValue(this.savingSpies);
this.clock = sinon.useFakeTimers();
});
afterEach(function () {
@@ -327,7 +327,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
expect(this.savingSpies.constructor).toHaveBeenCalled();
expect(this.savingSpies.show).toHaveBeenCalled();
expect(this.savingSpies.hide).not.toHaveBeenCalled();
savingOptions = this.savingSpies.constructor.mostRecentCall.args[0];
savingOptions = this.savingSpies.constructor.calls.mostRecent().args[0];
expect(savingOptions.title).toMatch(/Saving/);
expect($('#unit-1')).toHaveClass('was-dropped');
expect(request.requestBody).toEqual('{"children":["fourth-unit-id","first-unit-id"]}');

View File

@@ -39,7 +39,9 @@ function ($, _, IframeBinding) {
//after calling iframeBinding function: src url of iframes should have "wmode=transparent" in its querystring
//and embed objects should have "wmode='transparent'" as an attribute
expect(iframe_html).toContain('<iframe src="http://www.youtube.com/embed/NHd27UvY-lw?wmode=transparent"');
expect(iframe_html).toContain('<embed wmode="transparent" type="application/x-shockwave-flash" src="http://www.youtube.com/embed/NHd27UvY-lw"');
expect(iframe_html).toContainHtml(
'<embed wmode="transparent" type="application/x-shockwave-flash"' +
' src="http://www.youtube.com/embed/NHd27UvY-lw"');
});
it("does not modify src url of DOM iframe if it is empty", function () {

View File

@@ -30,61 +30,104 @@ function ($, _, Squire) {
var createPromptSpy = function (name) {
var spy = jasmine.createSpyObj(name, ['constructor', 'show', 'hide']);
spy.constructor.andReturn(spy);
spy.show.andReturn(spy);
spy.extend = jasmine.createSpy().andReturn(spy.constructor);
spy.constructor.and.returnValue(spy);
spy.show.and.returnValue(spy);
spy.extend = jasmine.createSpy().and.returnValue(spy.constructor);
return spy;
};
beforeEach(function () {
beforeEach(function (done) {
self = this;
this.addMatchers({
assertValueInView: function(expected) {
var value = this.actual.getValueFromEditor();
return this.env.equals_(value, expected);
jasmine.addMatchers({
assertValueInView: function() {
return {
compare: function (actual, expected) {
var value = actual.getValueFromEditor(),
passed = _.isEqual(value, expected);
return {
pass: passed,
message: 'Expected ' + actual + (passed ? '' : ' not') + ' to equal ' + expected
};
}
};
},
assertCanUpdateView: function (expected) {
var view = this.actual,
value;
assertCanUpdateView: function () {
return {
compare: function (actual, expected) {
var view = actual,
value,
passed;
view.setValueInEditor(expected);
value = view.getValueFromEditor();
view.setValueInEditor(expected);
value = view.getValueFromEditor();
return this.env.equals_(value, expected);
passed = _.isEqual(value, expected);
return {
pass: passed,
message: 'Expected ' + actual + (passed ? '' : ' not') + ' to equal ' + expected
};
}
};
},
assertClear: function (modelValue) {
var env = this.env,
view = this.actual,
model = view.model;
assertClear: function () {
return {
compare: function (actual, modelValue) {
var view = actual,
model = view.model,
passed;
return model.getValue() === null &&
env.equals_(model.getDisplayValue(), modelValue) &&
env.equals_(view.getValueFromEditor(), modelValue);
passed = model.getValue() === null &&
_.isEqual(model.getDisplayValue(), modelValue) &&
_.isEqual(view.getValueFromEditor(), modelValue);
return {
pass: passed
};
}
};
},
assertUpdateModel: function (originalValue, newValue) {
var env = this.env,
view = this.actual,
model = view.model,
expectOriginal;
assertUpdateModel: function () {
return {
compare: function (actual, originalValue, newValue) {
var view = actual,
model = view.model,
expectOriginal,
passed;
view.setValueInEditor(newValue);
expectOriginal = env.equals_(model.getValue(), originalValue);
view.updateModel();
view.setValueInEditor(newValue);
expectOriginal = _.isEqual(model.getValue(), originalValue);
view.updateModel();
return expectOriginal &&
env.equals_(model.getValue(), newValue);
passed = expectOriginal &&
_.isEqual(model.getValue(), newValue);
return {
pass: passed
};
}
};
},
verifyButtons: function (upload, download, index) {
var view = this.actual,
uploadBtn = view.$('.upload-setting'),
downloadBtn = view.$('.download-setting');
verifyButtons: function () {
return {
compare: function (actual, upload, download) {
var view = actual,
uploadBtn = view.$('.upload-setting'),
downloadBtn = view.$('.download-setting'),
passed;
upload = upload ? uploadBtn.length : !uploadBtn.length;
download = download ? downloadBtn.length : !downloadBtn.length;
upload = upload ? uploadBtn.length : !uploadBtn.length;
download = download ? downloadBtn.length : !downloadBtn.length;
passed = upload && download;
return upload && download;
return {
pass: passed
};
}
};
}
});
@@ -107,22 +150,18 @@ function ($, _, Squire) {
injector.mock('js/views/video/transcripts/metadata_videolist');
injector.mock('js/views/video/translations_editor');
runs(function() {
injector.require([
injector.require([
'js/models/metadata', 'js/views/metadata'
],
function(MetadataModel, MetadataView) {
function (MetadataModel, MetadataView) {
var model = new MetadataModel($.extend(true, {}, modelStub));
self.view = new MetadataView.FileUploader({
model: model,
locator: locator
});
});
});
waitsFor(function() {
return self.view;
}, 'FileUploader was not created', 2000);
done();
});
});
afterEach(function () {
@@ -150,7 +189,7 @@ function ($, _, Squire) {
expect(this.uploadSpies.constructor).toHaveBeenCalled();
expect(this.uploadSpies.show).toHaveBeenCalled();
options = this.uploadSpies.constructor.mostRecentCall.args[0];
options = this.uploadSpies.constructor.calls.mostRecent().args[0];
options.onSuccess({
'asset': {
'url': 'http://example.org/test_3'

View File

@@ -3,8 +3,7 @@ define(
"jquery", "backbone", "underscore",
"js/views/video/transcripts/utils", "js/views/video/transcripts/editor",
"js/views/metadata", "js/models/metadata", "js/collections/metadata",
"underscore.string", "xmodule", "js/views/video/transcripts/metadata_videolist",
"jasmine-jquery"
"underscore.string", "xmodule", "js/views/video/transcripts/metadata_videolist"
],
function ($, Backbone, _, Utils, Editor, MetadataView, MetadataModel, MetadataCollection, _str) {
describe('Transcripts.Editor', function () {
@@ -43,6 +42,13 @@ function ($, Backbone, _, Utils, Editor, MetadataView, MetadataModel, MetadataCo
},
transcripts, container;
var waitsForDisplayName = function (collection) {
return jasmine.waitUntil(function () {
var displayNameValue = collection[0].getValue();
return displayNameValue !== '' && displayNameValue !== 'video_id';
});
};
beforeEach(function () {
var tpl = sandbox({
'class': 'wrapper-comp-settings basic_metadata_edit',
@@ -60,7 +66,6 @@ function ($, Backbone, _, Utils, Editor, MetadataView, MetadataModel, MetadataCo
});
describe('Test initialization', function () {
beforeEach(function () {
spyOn(MetadataView, 'Editor');
@@ -158,27 +163,23 @@ function ($, Backbone, _, Utils, Editor, MetadataView, MetadataModel, MetadataCo
});
describe('Test Advanced to Basic synchronization', function () {
it('Correct data', function () {
it('Correct data', function (done) {
transcripts.syncBasicTab(metadataCollection, metadataView);
var collection = transcripts.collection.models;
waitsFor(function() {
var displayNameValue = collection[0].getValue();
return (displayNameValue !== "" && displayNameValue != "video_id");
}, "Defaults never loaded", 1000);
waitsForDisplayName(collection)
.then(function () {
var displayNameValue = collection[0].getValue(),
videoUrlValue = collection[1].getValue();
runs(function() {
var displayNameValue = collection[0].getValue(),
videoUrlValue = collection[1].getValue();
expect(displayNameValue).toEqual('default');
expect(videoUrlValue).toEqual([
'http://youtu.be/OEoXaMPEzfM',
'default.mp4',
'default.webm'
]);
});
expect(displayNameValue).toEqual('default');
expect(videoUrlValue).toEqual([
'http://youtu.be/OEoXaMPEzfM',
'default.mp4',
'default.webm'
]);
})
.always(done);
});
it('If metadataCollection is not defined', function () {
@@ -219,31 +220,26 @@ function ($, Backbone, _, Utils, Editor, MetadataView, MetadataModel, MetadataCo
});
describe('Test Basic to Advanced synchronization', function () {
it('Correct data', function () {
it('Correct data', function (done) {
transcripts.syncAdvancedTab(metadataCollection);
var collection = metadataCollection.models;
waitsForDisplayName(collection)
.then(function () {
var displayNameValue = collection[0].getValue();
var subValue = collection[1].getValue();
var html5SourcesValue = collection[2].getValue();
var youtubeValue = collection[3].getValue();
waitsFor(function() {
var displayNameValue = collection[0].getValue();
return (displayNameValue !== "" && displayNameValue != "video_id");
}, "Defaults never loaded", 1000);
runs(function() {
var displayNameValue = collection[0].getValue();
var subValue = collection[1].getValue();
var html5SourcesValue = collection[2].getValue();
var youtubeValue = collection[3].getValue();
expect(displayNameValue).toEqual('display value');
expect(subValue).toEqual('default');
expect(html5SourcesValue).toEqual([
'video.mp4',
'video.webm'
]);
expect(youtubeValue).toEqual('12345678901');
});
expect(displayNameValue).toEqual('display value');
expect(subValue).toEqual('default');
expect(html5SourcesValue).toEqual([
'video.mp4',
'video.webm'
]);
expect(youtubeValue).toEqual('12345678901');
})
.always(done);
});
it('metadataCollection is not defined', function () {
@@ -307,8 +303,7 @@ function ($, Backbone, _, Utils, Editor, MetadataView, MetadataModel, MetadataCo
transcripts.syncAdvancedTab(metadataCollection);
transcripts.syncAdvancedTab(metadataCollection);
transcripts.syncAdvancedTab(metadataCollection);
expect(subModel.setValue.calls.length).toEqual(1);
expect(subModel.setValue.calls.count()).toEqual(1);
});
});

View File

@@ -2,7 +2,7 @@ define(
[
"jquery", "underscore",
"js/views/video/transcripts/utils", "js/views/video/transcripts/file_uploader",
"xmodule", "jquery.form", "jasmine-jquery"
"xmodule", "jquery.form"
],
function ($, _, Utils, FileUploader) {
// TODO: fix TNL-559 Intermittent failures of Transcript FileUploader JS tests
@@ -43,7 +43,7 @@ function ($, _, Utils, FileUploader) {
.append('<div class="transcripts-file-uploader" />')
.append('<a class="setting-upload" href="#">Upload</a>');
spyOn(FileUploader.prototype, 'render').andCallThrough();
spyOn(FileUploader.prototype, 'render').and.callThrough();
view = new FileUploader({
el: $container,
@@ -61,7 +61,7 @@ function ($, _, Utils, FileUploader) {
describe('Render', function () {
beforeEach(function () {
spyOn(_, 'template').andCallThrough();
spyOn(_, 'template').and.callThrough();
});
it('Template doesn\'t exist', function () {
@@ -138,7 +138,7 @@ function ($, _, Utils, FileUploader) {
});
it('Valid File Type - error should be hided', function () {
spyOn(view, 'checkExtValidity').andReturn(true);
spyOn(view, 'checkExtValidity').and.returnValue(true);
view.$input.change();
@@ -148,7 +148,7 @@ function ($, _, Utils, FileUploader) {
});
it('Invalid File Type - error should be shown', function () {
spyOn(view, 'checkExtValidity').andReturn(false);
spyOn(view, 'checkExtValidity').and.returnValue(false);
view.$input.change();
@@ -189,7 +189,7 @@ function ($, _, Utils, FileUploader) {
it('xhrProgressHandler', function () {
var percent = 26;
spyOn($.fn, 'width').andCallThrough();
spyOn($.fn, 'width').and.callThrough();
view.xhrProgressHandler(null, null, null, percent);
expect(view.$progress.width).toHaveBeenCalledWith(percent + '%');
@@ -209,7 +209,7 @@ function ($, _, Utils, FileUploader) {
view.xhrCompleteHandler(xhr);
expect(view.$progress).toHaveClass('is-invisible');
expect(view.options.messenger.render.mostRecentCall.args[0])
expect(view.options.messenger.render.calls.mostRecent().args[0])
.toEqual('uploaded');
expect(Utils.Storage.set)
.toHaveBeenCalledWith('sub', 'test');

View File

@@ -2,7 +2,7 @@ define(
[
"jquery", "underscore",
"js/views/video/transcripts/utils", "js/views/video/transcripts/message_manager",
"js/views/video/transcripts/file_uploader", "sinon", "jasmine-jquery",
"js/views/video/transcripts/file_uploader", "sinon",
"xmodule"
],
function ($, _, Utils, MessageManager, FileUploader, sinon) {
@@ -67,10 +67,10 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) {
});
// Disabled 2/6/14 after intermittent failure in master
xdescribe('Render', function () {
describe('Render', function () {
beforeEach(function () {
spyOn(_,'template').andCallThrough();
spyOn(_,'template').and.callThrough();
spyOn(fileUploader, 'render');
});
@@ -101,7 +101,7 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) {
beforeEach(function () {
view.render('found');
spyOn(view, 'hideError');
spyOn($.fn, 'html').andCallThrough();
spyOn($.fn, 'html').and.callThrough();
$error = view.$el.find('.transcripts-error-message');
$buttons = view.$el.find('.wrapper-transcripts-buttons');
});
@@ -147,10 +147,10 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) {
$.each(handlers, function(key, value) {
it(key, function () {
var eventObj = jasmine.createSpyObj('event', ['preventDefault']);
spyOn($.fn, 'data').andReturn('video_id');
spyOn($.fn, 'data').and.returnValue('video_id');
spyOn(view, 'processCommand');
view[key](eventObj);
expect(view.processCommand.mostRecentCall.args).toEqual(value);
expect(view.processCommand.calls.mostRecent().args).toEqual(value);
});
});
@@ -162,7 +162,7 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) {
beforeEach(function () {
view.render('found');
spyOn(Utils, 'command').andCallThrough();
spyOn(Utils, 'command').and.callThrough();
spyOn(view, 'render');
spyOn(view, 'showError');
@@ -174,35 +174,19 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) {
sinonXhr.restore();
});
var assertCommand = function (config, expectFunc) {
var flag = false,
defaults = {
var assertCommand = function (config) {
var defaults = {
action: 'replace',
errorMessage: 'errorMessage',
extraParamas: void(0)
};
args = $.extend({}, defaults, config);
var args = $.extend({}, defaults, config);
runs(function() {
view
.processCommand(
args.action,
args.errorMessage,
args.extraParamas
)
.always(function () { flag = true; });
});
waitsFor(function() {
return flag;
}, "Ajax Timeout", 750);
runs(expectFunc);
return view
.processCommand(args.action, args.errorMessage, args.extraParamas);
};
it('Invoke without extraParamas', function () {
it('Invoke without extraParamas', function (done) {
sinonXhr.respondWith([
200,
{ "Content-Type": "application/json"},
@@ -212,9 +196,8 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) {
})
]);
assertCommand(
{ },
function() {
assertCommand({})
.then(function () {
expect(Utils.command).toHaveBeenCalledWith(
action,
view.component_locator,
@@ -222,15 +205,14 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) {
void(0)
);
expect(view.showError).not.toHaveBeenCalled();
expect(view.render.mostRecentCall.args[0])
expect(view.render.calls.mostRecent().args[0])
.toEqual('found');
expect(Utils.Storage.set).toHaveBeenCalled();
}
);
})
.always(done);
});
it('Invoke with extraParamas', function () {
it('Invoke with extraParamas', function (done) {
sinonXhr.respondWith([
200,
{ "Content-Type": "application/json"},
@@ -242,9 +224,8 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) {
view.processCommand(action, errorMessage, extraParamas);
assertCommand(
{ extraParamas : extraParamas },
function () {
assertCommand({extraParamas : extraParamas})
.then(function () {
expect(Utils.command).toHaveBeenCalledWith(
action,
view.component_locator,
@@ -254,20 +235,16 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) {
}
);
expect(view.showError).not.toHaveBeenCalled();
expect(view.render.mostRecentCall.args[0])
.toEqual('found');
expect(view.render.calls.mostRecent().args[0]).toEqual('found');
expect(Utils.Storage.set).toHaveBeenCalled();
}
);
})
.always(done);
});
it('Fail', function () {
it('Fail', function (done) {
sinonXhr.respondWith([400, {}, '']);
assertCommand(
{ },
function () {
assertCommand({})
.then(function () {
expect(Utils.command).toHaveBeenCalledWith(
action,
view.component_locator,
@@ -277,8 +254,8 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) {
expect(view.showError).toHaveBeenCalled();
expect(view.render).not.toHaveBeenCalled();
expect(Utils.Storage.set).not.toHaveBeenCalled();
}
);
})
.always(done);
});
});

View File

@@ -2,7 +2,7 @@ define(
[
'jquery', 'underscore',
'js/views/video/transcripts/utils',
'underscore.string', 'xmodule', 'jasmine-jquery'
'underscore.string', 'xmodule'
],
function ($, _, Utils, _str) {
'use strict';

View File

@@ -5,7 +5,7 @@ define(
'js/views/video/transcripts/metadata_videolist', 'js/models/metadata',
'js/views/abstract_editor',
'common/js/spec_helpers/ajax_helpers',
'xmodule', 'jasmine-jquery'
'xmodule'
],
function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
'use strict';
@@ -53,6 +53,19 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
}),
MessageManager, messenger;
var createMockAjaxServer = function () {
var mockServer = AjaxHelpers.server(
[
200,
{ 'Content-Type': 'application/json'},
response
]
);
mockServer.autoRespond = true;
return mockServer;
};
beforeEach(function () {
var tpl = sandbox({
'class': 'component',
@@ -70,9 +83,12 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
).text(videoListEntryTemplate)
);
spyOn(Utils, 'command').andCallThrough();
spyOn(abstractEditor, 'initialize').andCallThrough();
spyOn(abstractEditor, 'render').andCallThrough();
// create mock server
this.mockServer = createMockAjaxServer();
spyOn(Utils, 'command').and.callThrough();
spyOn(abstractEditor, 'initialize').and.callThrough();
spyOn(abstractEditor, 'render').and.callThrough();
spyOn(console, 'error');
messenger = jasmine.createSpyObj('MessageManager',[
@@ -80,7 +96,7 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
]);
$.each(messenger, function(index, method) {
method.andReturn(messenger);
method.and.returnValue(messenger);
});
MessageManager = function () {
@@ -89,40 +105,54 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
return messenger;
};
this.addMatchers({
assertValueInView: function(expected) {
var actualValue = this.actual.getValueFromEditor();
return this.env.equals_(actualValue, expected);
jasmine.addMatchers({
assertValueInView: function() {
return {
compare: function (actual, expected) {
var actualValue = actual.getValueFromEditor(),
passed = _.isEqual(actualValue, expected);
return {
pass: passed
};
}
};
},
assertCanUpdateView: function (expected) {
var actual = this.actual,
actualValue;
assertCanUpdateView: function () {
return {
compare: function (actual, expected) {
var actualValue,
passed;
actual.setValueInEditor(expected);
actualValue = actual.getValueFromEditor();
actual.setValueInEditor(expected);
actualValue = actual.getValueFromEditor();
passed = _.isEqual(actualValue, expected);
return this.env.equals_(actualValue, expected);
return {
pass: passed
};
}
};
},
assertIsCorrectVideoList: function (expected) {
var actualValue = this.actual.getVideoObjectsList();
assertIsCorrectVideoList: function () {
return {
compare: function (actual, expected) {
var actualValue = actual.getVideoObjectsList(),
passed = _.isEqual(actualValue, expected);
return this.env.equals_(actualValue, expected);
return {
pass: passed
};
}
};
}
});
});
var createMockAjaxServer = function (test) {
var mockServer = AjaxHelpers.server(
test,
[
200,
{ 'Content-Type': 'application/json'},
response
]
);
mockServer.autoRespond = true;
return mockServer;
};
afterEach(function () {
// restore mock server
this.mockServer.restore();
});
var createVideoListView = function () {
var model = new MetadataModel(modelStub);
@@ -133,37 +163,25 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
});
};
var waitsForResponse = function (mockServer, expectFunc, prep) {
var flag = false;
if (prep) {
runs(prep);
}
waitsFor(function() {
var waitsForResponse = function (mockServer) {
return jasmine.waitUntil(function () {
var requests = mockServer.requests,
len = requests.length;
if (len && requests[0].readyState === 4) {
flag = true;
}
return flag;
}, 'Ajax Timeout', 750);
runs(expectFunc);
return len && requests[0].readyState === 4;
});
};
it('Initialize', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
waitsForResponse(mockServer, function () {
expect(abstractEditor.initialize).toHaveBeenCalled();
expect(messenger.initialize).toHaveBeenCalled();
expect(view.component_locator).toBe(component_locator);
expect(view.$el).toHandle('input');
});
it('Initialize', function (done) {
var view = createVideoListView();
waitsForResponse(this.mockServer)
.then(function () {
expect(abstractEditor.initialize).toHaveBeenCalled();
expect(messenger.initialize).toHaveBeenCalled();
expect(view.component_locator).toBe(component_locator);
expect(view.$el).toHandle('input');
}).always(done);
});
describe('Render', function () {
@@ -178,23 +196,23 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
expect(messenger.render).toHaveBeenCalled();
},
resetSpies = function(mockServer) {
abstractEditor.render.reset();
Utils.command.reset();
messenger.render.reset();
abstractEditor.render.calls.reset();
Utils.command.calls.reset();
messenger.render.calls.reset();
mockServer.requests.length = 0;
};
it('is rendered in correct way', function () {
var mockServer = createMockAjaxServer(this);
it('is rendered in correct way', function (done) {
createVideoListView();
waitsForResponse(mockServer, function () {
assertToHaveBeenRendered(videoList);
});
waitsForResponse(this.mockServer)
.then(function () {
assertToHaveBeenRendered(videoList);
})
.always(done);
});
it('is rendered with opened extra videos bar', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
it('is rendered with opened extra videos bar', function (done) {
var view = createVideoListView();
var videoListLength = [
{
mode: 'youtube',
@@ -215,41 +233,35 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
}
];
spyOn(view, 'getVideoObjectsList').andReturn(videoListLength);
spyOn(view, 'getVideoObjectsList').and.returnValue(videoListLength);
spyOn(view, 'openExtraVideosBar');
waitsForResponse(
mockServer,
function () {
assertToHaveBeenRendered(videoListLength);
view.getVideoObjectsList.andReturn(videoListLength);
expect(view.openExtraVideosBar).toHaveBeenCalled();
},
function () {
resetSpies(mockServer);
view.render();
}
);
resetSpies(this.mockServer);
view.render();
waitsForResponse(
mockServer,
function () {
assertToHaveBeenRendered(videoListHtml5mode);
waitsForResponse(this.mockServer)
.then(function () {
assertToHaveBeenRendered(videoListLength);
view.getVideoObjectsList.and.returnValue(videoListLength);
expect(view.openExtraVideosBar).toHaveBeenCalled();
},
function () {
resetSpies(mockServer);
view.openExtraVideosBar.reset();
view.getVideoObjectsList.andReturn(videoListHtml5mode);
})
.then(_.bind(function () {
resetSpies(this.mockServer);
view.openExtraVideosBar.calls.reset();
view.getVideoObjectsList.and.returnValue(videoListHtml5mode);
view.render();
}
);
return waitsForResponse(this.mockServer)
.then(function () {
assertToHaveBeenRendered(videoListHtml5mode);
expect(view.openExtraVideosBar).toHaveBeenCalled();
}).then(done);
}, this));
});
it('is rendered without opened extra videos bar', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView(),
it('is rendered without opened extra videos bar', function (done) {
var view = createVideoListView(),
videoList = [
{
mode: 'youtube',
@@ -258,44 +270,40 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
}
];
spyOn(view, 'getVideoObjectsList').andReturn(videoList);
spyOn(view, 'getVideoObjectsList').and.returnValue(videoList);
spyOn(view, 'closeExtraVideosBar');
waitsForResponse(
mockServer,
function () {
assertToHaveBeenRendered(videoList);
expect(view.closeExtraVideosBar).toHaveBeenCalled();
},
function () {
resetSpies(mockServer);
view.render();
}
);
});
resetSpies(this.mockServer);
view.render();
waitsForResponse(this.mockServer)
.then(function () {
assertToHaveBeenRendered(videoList);
expect(view.closeExtraVideosBar).toHaveBeenCalled();
})
.always(done);
});
});
describe('isUniqOtherVideos', function () {
it('Unique data - return true', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView(),
it('Unique data - return true', function (done) {
var view = createVideoListView(),
data = videoList.concat([{
mode: 'html5',
type: 'other',
video: 'pxxZrg'
}]);
waitsForResponse(mockServer, function () {
var result = view.isUniqOtherVideos(data);
expect(result).toBe(true);
});
waitsForResponse(this.mockServer)
.then(function () {
var result = view.isUniqOtherVideos(data);
expect(result).toBe(true);
})
.always(done);
});
it('Not Unique data - return false', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView(),
it('Not Unique data - return false', function (done) {
var view = createVideoListView(),
data = [
{
mode: 'html5',
@@ -323,30 +331,31 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
video: '12345678901'
}
];
waitsForResponse(mockServer, function () {
var result = view.isUniqOtherVideos(data);
expect(result).toBe(false);
});
waitsForResponse(this.mockServer)
.then(function () {
var result = view.isUniqOtherVideos(data);
expect(result).toBe(false);
})
.always(done);
});
});
describe('isUniqVideoTypes', function () {
it('Unique data - return true', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView(),
it('Unique data - return true', function (done) {
var view = createVideoListView(),
data = videoList;
waitsForResponse(mockServer, function () {
var result = view.isUniqVideoTypes(data);
expect(result).toBe(true);
});
waitsForResponse(this.mockServer)
.then(function () {
var result = view.isUniqVideoTypes(data);
expect(result).toBe(true);
})
.always(done);
});
it('Not Unique data - return false', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView(),
it('Not Unique data - return false', function (done) {
var view = createVideoListView(),
data = [
{
mode: 'html5',
@@ -369,18 +378,19 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
video: '12345678901'
}
];
waitsForResponse(mockServer, function () {
var result = view.isUniqVideoTypes(data);
expect(result).toBe(false);
});
waitsForResponse(this.mockServer)
.then(function () {
var result = view.isUniqVideoTypes(data);
expect(result).toBe(false);
})
.always(done);
});
});
describe('checkIsUniqVideoTypes', function () {
it('Error is shown', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView(),
it('Error is shown', function (done) {
var view = createVideoListView(),
data = [
{
mode: 'html5',
@@ -404,125 +414,137 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
}
];
waitsForResponse(mockServer, function () {
var result = view.checkIsUniqVideoTypes(data);
waitsForResponse(this.mockServer)
.then(function () {
var result = view.checkIsUniqVideoTypes(data);
expect(messenger.showError).toHaveBeenCalled();
expect(result).toBe(false);
});
expect(messenger.showError).toHaveBeenCalled();
expect(result).toBe(false);
})
.always(done);
});
it('All works okay if arguments are not passed', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
spyOn(view, 'getVideoObjectsList').andReturn(videoList);
waitsForResponse(mockServer, function () {
var result = view.checkIsUniqVideoTypes();
it('All works okay if arguments are not passed', function (done) {
var view = createVideoListView();
spyOn(view, 'getVideoObjectsList').and.returnValue(videoList);
expect(view.getVideoObjectsList).toHaveBeenCalled();
expect(messenger.showError).not.toHaveBeenCalled();
expect(result).toBe(true);
});
waitsForResponse(this.mockServer)
.then(function () {
var result = view.checkIsUniqVideoTypes();
expect(view.getVideoObjectsList).toHaveBeenCalled();
expect(messenger.showError).not.toHaveBeenCalled();
expect(result).toBe(true);
})
.always(done);
});
});
describe('checkValidity', function () {
it('Error message is shown', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
spyOn(view, 'checkIsUniqVideoTypes').andReturn(true);
waitsForResponse(mockServer, function () {
var data = { mode: 'incorrect' },
it('Error message is shown', function (done) {
var view = createVideoListView();
spyOn(view, 'checkIsUniqVideoTypes').and.returnValue(true);
waitsForResponse(this.mockServer)
.then(function () {
var data = {mode: 'incorrect'},
result = view.checkValidity(data, true);
expect(messenger.showError).toHaveBeenCalled();
expect(view.checkIsUniqVideoTypes).toHaveBeenCalled();
expect(result).toBe(false);
});
expect(messenger.showError).toHaveBeenCalled();
expect(view.checkIsUniqVideoTypes).toHaveBeenCalled();
expect(result).toBe(false);
})
.always(done);
});
it('Error message is shown when flag is not passed', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
spyOn(view, 'checkIsUniqVideoTypes').andReturn(true);
waitsForResponse(mockServer, function () {
var data = { mode: 'incorrect' },
it('Error message is shown when flag is not passed', function (done) {
var view = createVideoListView();
spyOn(view, 'checkIsUniqVideoTypes').and.returnValue(true);
waitsForResponse(this.mockServer)
.then(function () {
var data = {mode: 'incorrect'},
result = view.checkValidity(data);
expect(messenger.showError).not.toHaveBeenCalled();
expect(view.checkIsUniqVideoTypes).toHaveBeenCalled();
expect(result).toBe(true);
});
expect(messenger.showError).not.toHaveBeenCalled();
expect(view.checkIsUniqVideoTypes).toHaveBeenCalled();
expect(result).toBe(true);
}).always(done);
});
it('All works okay if correct data is passed', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
spyOn(view, 'checkIsUniqVideoTypes').andReturn(true);
waitsForResponse(mockServer, function () {
var data = videoList,
it('All works okay if correct data is passed', function (done) {
var view = createVideoListView();
spyOn(view, 'checkIsUniqVideoTypes').and.returnValue(true);
waitsForResponse(this.mockServer)
.then(function () {
var data = videoList,
result = view.checkValidity(data);
expect(messenger.showError).not.toHaveBeenCalled();
expect(view.checkIsUniqVideoTypes).toHaveBeenCalled();
expect(result).toBe(true);
});
expect(messenger.showError).not.toHaveBeenCalled();
expect(view.checkIsUniqVideoTypes).toHaveBeenCalled();
expect(result).toBe(true);
})
.always(done);
});
});
it('openExtraVideosBar', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
waitsForResponse(mockServer, function () {
view.$extraVideosBar.removeClass('is-visible');
view.openExtraVideosBar();
expect(view.$extraVideosBar).toHaveClass('is-visible');
});
it('openExtraVideosBar', function (done) {
var view = createVideoListView();
waitsForResponse(this.mockServer)
.then(function () {
view.$extraVideosBar.removeClass('is-visible');
view.openExtraVideosBar();
expect(view.$extraVideosBar).toHaveClass('is-visible');
})
.always(done);
});
it('closeExtraVideosBar', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
waitsForResponse(mockServer, function () {
view.$extraVideosBar.addClass('is-visible');
view.closeExtraVideosBar();
it('closeExtraVideosBar', function (done) {
var view = createVideoListView();
waitsForResponse(this.mockServer)
.then(function () {
view.$extraVideosBar.addClass('is-visible');
view.closeExtraVideosBar();
expect(view.$extraVideosBar).not.toHaveClass('is-visible');
});
expect(view.$extraVideosBar).not.toHaveClass('is-visible');
})
.always(done);
});
it('toggleExtraVideosBar', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
waitsForResponse(mockServer, function () {
view.$extraVideosBar.addClass('is-visible');
view.toggleExtraVideosBar();
expect(view.$extraVideosBar).not.toHaveClass('is-visible');
view.toggleExtraVideosBar();
expect(view.$extraVideosBar).toHaveClass('is-visible');
});
it('toggleExtraVideosBar', function (done) {
var view = createVideoListView();
waitsForResponse(this.mockServer)
.then(function () {
view.$extraVideosBar.addClass('is-visible');
view.toggleExtraVideosBar();
expect(view.$extraVideosBar).not.toHaveClass('is-visible');
view.toggleExtraVideosBar();
expect(view.$extraVideosBar).toHaveClass('is-visible');
})
.always(done);
});
it('getValueFromEditor', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
waitsForResponse(mockServer, function () {
expect(view).assertValueInView(modelStub.value);
});
it('getValueFromEditor', function (done) {
var view = createVideoListView();
waitsForResponse(this.mockServer)
.then(function () {
expect(view).assertValueInView(modelStub.value);
})
.always(done);
});
it('setValueInEditor', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
waitsForResponse(mockServer, function () {
expect(view).assertCanUpdateView(['abc.mp4']);
});
it('setValueInEditor', function (done) {
var view = createVideoListView();
waitsForResponse(this.mockServer)
.then(function () {
expect(view).assertCanUpdateView(['abc.mp4']);
})
.always(done);
});
it('getVideoObjectsList', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
it('getVideoObjectsList', function (done) {
var view = createVideoListView();
var value = [
{
mode: 'youtube',
@@ -541,36 +563,39 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
}
];
waitsForResponse(mockServer, function () {
view.setValueInEditor([
'http://youtu.be/12345678901',
'video.mp4',
'http://goo.gl/pxxZrg',
'video'
]);
expect(view).assertIsCorrectVideoList(value);
});
waitsForResponse(this.mockServer)
.then(function () {
view.setValueInEditor([
'http://youtu.be/12345678901',
'video.mp4',
'http://goo.gl/pxxZrg',
'video'
]);
expect(view).assertIsCorrectVideoList(value);
})
.always(done);
});
describe('getPlaceholders', function () {
it('All works okay if empty values are passed', function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView(),
it('All works okay if empty values are passed', function (done) {
var view = createVideoListView(),
defaultPlaceholders = view.placeholders;
waitsForResponse(mockServer, function () {
var result = view.getPlaceholders([]),
expectedResult = _.values(defaultPlaceholders).reverse();
expect(result).toEqual(expectedResult);
});
waitsForResponse(this.mockServer)
.then(function () {
var result = view.getPlaceholders([]),
expectedResult = _.values(defaultPlaceholders).reverse();
expect(result).toEqual(expectedResult);
})
.always(done);
});
it('On filling less than 3 fields, remaining fields should have ' +
'placeholders for video types that were not filled yet',
function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView(),
function (done) {
var view = createVideoListView(),
defaultPlaceholders = view.placeholders;
var dataDict = {
youtube: {
@@ -598,14 +623,17 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
]
}
};
defaultPlaceholders = view.placeholders;
waitsForResponse(mockServer, function () {
$.each(dataDict, function(index, val) {
var result = view.getPlaceholders(val.value);
expect(result).toEqual(val.expectedResult);
});
});
defaultPlaceholders = view.placeholders;
waitsForResponse(this.mockServer)
.then(function () {
$.each(dataDict, function (index, val) {
var result = view.getPlaceholders(val.value);
expect(result).toEqual(val.expectedResult);
});
})
.always(done);
}
);
});
@@ -614,9 +642,9 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
var eventObject;
var resetSpies = function (view) {
messenger.hideError.reset();
view.updateModel.reset();
view.closeExtraVideosBar.reset();
messenger.hideError.calls.reset();
view.updateModel.calls.reset();
view.closeExtraVideosBar.calls.reset();
};
var setUp = function (view) {
@@ -628,100 +656,104 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) {
spyOn($.fn, 'hasClass');
spyOn($.fn, 'addClass');
spyOn($.fn, 'removeClass');
spyOn($.fn, 'prop').andCallThrough();
spyOn($.fn, 'prop').and.callThrough();
spyOn(_, 'isEqual');
resetSpies(view);
};
it('Field has invalid value - nothing should happen',
function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
function (done) {
var view = createVideoListView();
setUp(view);
$.fn.hasClass.andReturn(false);
view.checkValidity.andReturn(false);
$.fn.hasClass.and.returnValue(false);
view.checkValidity.and.returnValue(false);
waitsForResponse(mockServer, function () {
view.inputHandler(eventObject);
expect(messenger.hideError).not.toHaveBeenCalled();
expect(view.updateModel).not.toHaveBeenCalled();
expect(view.closeExtraVideosBar).not.toHaveBeenCalled();
expect($.fn.prop).toHaveBeenCalledWith(
'disabled', true
);
expect($.fn.addClass).toHaveBeenCalledWith(
'is-disabled'
);
});
waitsForResponse(this.mockServer)
.then(function () {
view.inputHandler(eventObject);
expect(messenger.hideError).not.toHaveBeenCalled();
expect(view.updateModel).not.toHaveBeenCalled();
expect(view.closeExtraVideosBar).not.toHaveBeenCalled();
expect($.fn.prop).toHaveBeenCalledWith(
'disabled', true
);
expect($.fn.addClass).toHaveBeenCalledWith(
'is-disabled'
);
})
.always(done);
}
);
it('Main field has invalid value - extra Videos Bar is closed',
function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
function (done) {
var view = createVideoListView();
setUp(view);
$.fn.hasClass.andReturn(true);
view.checkValidity.andReturn(false);
$.fn.hasClass.and.returnValue(true);
view.checkValidity.and.returnValue(false);
waitsForResponse(mockServer, function () {
view.inputHandler(eventObject);
expect(messenger.hideError).not.toHaveBeenCalled();
expect(view.updateModel).not.toHaveBeenCalled();
expect(view.closeExtraVideosBar).toHaveBeenCalled();
expect($.fn.prop).toHaveBeenCalledWith(
'disabled', true
);
expect($.fn.addClass).toHaveBeenCalledWith(
'is-disabled'
);
});
waitsForResponse(this.mockServer)
.then(function () {
view.inputHandler(eventObject);
expect(messenger.hideError).not.toHaveBeenCalled();
expect(view.updateModel).not.toHaveBeenCalled();
expect(view.closeExtraVideosBar).toHaveBeenCalled();
expect($.fn.prop).toHaveBeenCalledWith(
'disabled', true
);
expect($.fn.addClass).toHaveBeenCalledWith(
'is-disabled'
);
})
.always(done);
}
);
it('Model is updated if value is valid',
function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
function (done) {
var view = createVideoListView();
setUp(view);
view.checkValidity.andReturn(true);
_.isEqual.andReturn(false);
view.checkValidity.and.returnValue(true);
_.isEqual.and.returnValue(false);
waitsForResponse(mockServer, function () {
view.inputHandler(eventObject);
expect(messenger.hideError).not.toHaveBeenCalled();
expect(view.updateModel).toHaveBeenCalled();
expect(view.closeExtraVideosBar).not.toHaveBeenCalled();
expect($.fn.prop).toHaveBeenCalledWith(
'disabled', false
);
expect($.fn.removeClass).toHaveBeenCalledWith(
'is-disabled'
);
});
waitsForResponse(this.mockServer)
.then(function () {
view.inputHandler(eventObject);
expect(messenger.hideError).not.toHaveBeenCalled();
expect(view.updateModel).toHaveBeenCalled();
expect(view.closeExtraVideosBar).not.toHaveBeenCalled();
expect($.fn.prop).toHaveBeenCalledWith(
'disabled', false
);
expect($.fn.removeClass).toHaveBeenCalledWith(
'is-disabled'
);
})
.always(done);
}
);
it('Corner case: Error is hided',
function () {
var mockServer = createMockAjaxServer(this),
view = createVideoListView();
function (done) {
var view = createVideoListView();
setUp(view);
view.checkValidity.andReturn(true);
_.isEqual.andReturn(true);
waitsForResponse(mockServer, function () {
view.inputHandler(eventObject);
expect(messenger.hideError).toHaveBeenCalled();
expect(view.updateModel).not.toHaveBeenCalled();
expect(view.closeExtraVideosBar).not.toHaveBeenCalled();
expect($.fn.prop).toHaveBeenCalledWith(
'disabled', false
);
expect($.fn.removeClass).toHaveBeenCalledWith(
'is-disabled'
);
});
view.checkValidity.and.returnValue(true);
_.isEqual.and.returnValue(true);
waitsForResponse(this.mockServer)
.then(function () {
view.inputHandler(eventObject);
expect(messenger.hideError).toHaveBeenCalled();
expect(view.updateModel).not.toHaveBeenCalled();
expect(view.closeExtraVideosBar).not.toHaveBeenCalled();
expect($.fn.prop).toHaveBeenCalledWith(
'disabled', false
);
expect($.fn.removeClass).toHaveBeenCalledWith(
'is-disabled'
);
})
.always(done);
}
);

View File

@@ -45,82 +45,133 @@ function ($, _, Squire) {
var createPromptSpy = function (name) {
var spy = jasmine.createSpyObj(name, ['constructor', 'show', 'hide']);
spy.constructor.andReturn(spy);
spy.show.andReturn(spy);
spy.extend = jasmine.createSpy().andReturn(spy.constructor);
spy.constructor.and.returnValue(spy);
spy.show.and.returnValue(spy);
spy.extend = jasmine.createSpy().and.returnValue(spy.constructor);
return spy;
};
beforeEach(function () {
beforeEach(function (done) {
self = this;
this.addMatchers({
assertValueInView: function(expected) {
var value = this.actual.getValueFromEditor();
return this.env.equals_(value, expected);
jasmine.addMatchers({
assertValueInView: function() {
return {
compare: function (actual, expected) {
var value = actual.getValueFromEditor();
var passed = _.isEqual(value, expected);
return {
pass: passed,
message: 'Expected ' + actual + (passed ? '' : ' not') + ' to equal ' + expected
};
}
};
},
assertCanUpdateView: function (expected) {
var view = this.actual,
value;
assertCanUpdateView: function () {
return {
compare: function (actual, expected) {
var view = actual,
value,
passed;
view.setValueInEditor(expected);
value = view.getValueFromEditor();
view.setValueInEditor(expected);
value = view.getValueFromEditor();
passed = _.isEqual(value, expected);
return this.env.equals_(value, expected);
return {
pass: passed,
message: 'Expected ' + actual + (passed ? '' : ' not') + ' to equal ' + expected
};
}
};
},
assertClear: function (modelValue) {
var env = this.env,
view = this.actual,
model = view.model;
assertClear: function () {
return {
compare: function (actual, modelValue) {
var view = actual,
model = view.model,
passed;
return model.getValue() === null &&
env.equals_(model.getDisplayValue(), modelValue) &&
env.equals_(view.getValueFromEditor(), modelValue);
passed = model.getValue() === null &&
_.isEqual(model.getDisplayValue(), modelValue) &&
_.isEqual(view.getValueFromEditor(), modelValue);
return {
pass: passed
};
}
};
},
assertUpdateModel: function (originalValue, newValue) {
var env = this.env,
view = this.actual,
model = view.model,
expectOriginal;
assertUpdateModel: function () {
return {
compare: function (actual, originalValue, newValue) {
var view = actual,
model = view.model,
expectOriginal,
passed;
view.setValueInEditor(newValue);
expectOriginal = env.equals_(model.getValue(), originalValue);
view.updateModel();
view.setValueInEditor(newValue);
expectOriginal = _.isEqual(model.getValue(), originalValue);
view.updateModel();
return expectOriginal &&
env.equals_(model.getValue(), newValue);
passed = expectOriginal &&
_.isEqual(model.getValue(), newValue);
return {
pass: passed
};
}
};
},
verifyKeysUnique: function (initial, expected, testData) {
var env = this.env,
view = this.actual,
item, value;
verifyKeysUnique: function () {
return {
compare: function (actual, initial, expected, testData) {
var view = this.actual,
item,
value,
passed;
view.setValueInEditor(initial);
view.updateModel();
view.$el.find('.create-setting').click();
item = view.$el.find('.list-settings-item').last();
item.find('select').val(testData.key);
item.find('input:hidden').val(testData.value);
value = view.getValueFromEditor();
view.setValueInEditor(initial);
view.updateModel();
view.$el.find('.create-setting').click();
item = view.$el.find('.list-settings-item').last();
item.find('select').val(testData.key);
item.find('input:hidden').val(testData.value);
value = view.getValueFromEditor();
return env.equals_(value, expected);
passed = _.isEqual(value, expected);
return {
pass: passed
};
}
};
},
verifyButtons: function (upload, download, remove, index) {
var view = this.actual,
items = view.$el.find('.list-settings-item'),
item = index ? items.eq(index) : items.last(),
uploadBtn = item.find('.upload-setting'),
downloadBtn = item.find('.download-setting'),
removeBtn = item.find('.remove-setting');
verifyButtons: function () {
return {
compare: function (actual, upload, download, remove, index) {
var view = this.actual,
items = view.$el.find('.list-settings-item'),
item = index ? items.eq(index) : items.last(),
uploadBtn = item.find('.upload-setting'),
downloadBtn = item.find('.download-setting'),
removeBtn = item.find('.remove-setting'),
passed;
upload = upload ? uploadBtn.length : !uploadBtn.length;
download = download ? downloadBtn.length : !downloadBtn.length;
remove = remove ? removeBtn.length : !removeBtn.length;
upload = upload ? uploadBtn.length : !uploadBtn.length;
download = download ? downloadBtn.length : !downloadBtn.length;
remove = remove ? removeBtn.length : !removeBtn.length;
return upload && download && remove;
passed = upload && download && remove;
return {
pass: passed
};
}
};
}
});
@@ -141,19 +192,15 @@ function ($, _, Squire) {
return self.uploadSpies;
});
runs(function() {
injector.require([
injector.require([
'js/models/metadata', 'js/views/video/translations_editor'
],
function(MetadataModel, Translations) {
function (MetadataModel, Translations) {
var model = new MetadataModel($.extend(true, {}, modelStub));
self.view = new Translations({model: model});
});
});
waitsFor(function() {
return self.view;
}, 'VideoTranslations was not created', 1000);
done();
});
});
afterEach(function () {
@@ -198,7 +245,7 @@ function ($, _, Squire) {
expect(this.uploadSpies.constructor).toHaveBeenCalled();
expect(this.uploadSpies.show).toHaveBeenCalled();
options = this.uploadSpies.constructor.mostRecentCall.args[0];
options = this.uploadSpies.constructor.calls.mostRecent().args[0];
options.onSuccess({'filename': 'zh.srt'});
expect(this.view).verifyButtons(true, true, true);

View File

@@ -1,5 +1,11 @@
define(
["jquery", "js/models/active_video_upload", "js/views/active_video_upload_list", "common/js/spec_helpers/template_helpers", "mock-ajax", "jasmine-jquery"],
[
"jquery",
"js/models/active_video_upload",
"js/views/active_video_upload_list",
"common/js/spec_helpers/template_helpers",
"mock-ajax"
],
function($, ActiveVideoUpload, ActiveVideoUploadListView, TemplateHelpers) {
"use strict";
var concurrentUploadLimit = 2;
@@ -16,8 +22,7 @@ define(
uploadButton: this.uploadButton
});
this.view.render();
jasmine.Ajax.useMock();
clearAjaxRequests();
jasmine.Ajax.install();
this.globalAjaxError = jasmine.createSpy();
$(document).ajaxError(this.globalAjaxError);
});
@@ -25,15 +30,16 @@ define(
// Remove window unload handler triggered by the upload requests
afterEach(function() {
$(window).off("beforeunload");
jasmine.Ajax.uninstall();
});
it("should trigger file selection when either the upload button or the drop zone is clicked", function() {
var clickSpy = jasmine.createSpy();
clickSpy.andCallFake(function(event) { event.preventDefault(); });
clickSpy.and.callFake(function(event) { event.preventDefault(); });
this.view.$(".js-file-input").on("click", clickSpy);
this.view.$(".file-drop-area").click();
expect(clickSpy).toHaveBeenCalled();
clickSpy.reset();
clickSpy.calls.reset();
this.uploadButton.click();
expect(clickSpy).toHaveBeenCalled();
});
@@ -47,17 +53,16 @@ define(
};
var getSentRequests = function() {
return _.filter(
ajaxRequests,
function(request) { return request.readyState > 0; }
);
return jasmine.Ajax.requests.filter(function (request) {
return request.readyState > 0;
});
};
_.each(
[
{desc: "a single file", numFiles: 1},
{desc: "multiple files", numFiles: concurrentUploadLimit},
{desc: "more files than upload limit", numFiles: concurrentUploadLimit + 1},
{desc: "more files than upload limit", numFiles: concurrentUploadLimit + 1}
],
function(caseInfo) {
var fileNames = _.map(
@@ -71,7 +76,7 @@ define(
// security reasons, so we must mock the access mechanism
// that jQuery-File-Upload uses to retrieve it.
var realProp = $.prop;
spyOn($, "prop").andCallFake(function(el, propName) {
spyOn($, "prop").and.callFake(function(el, propName) {
if (arguments.length == 2 && propName == "files") {
return _.map(
fileNames,
@@ -82,7 +87,7 @@ define(
}
});
this.view.$(".js-file-input").change();
this.request = mostRecentAjaxRequest();
this.request = jasmine.Ajax.requests.mostRecent();
});
it("should trigger the correct request", function() {
@@ -99,14 +104,14 @@ define(
});
it("should trigger the global AJAX error handler on server error", function() {
this.request.response({status: 500});
this.request.respondWith({status: 500});
expect(this.globalAjaxError).toHaveBeenCalled();
});
describe("and successful server response", function() {
beforeEach(function() {
clearAjaxRequests();
this.request.response({
jasmine.Ajax.requests.reset();
this.request.respondWith({
status: 200,
responseText: JSON.stringify({
files: _.map(
@@ -141,7 +146,6 @@ define(
});
it("should display upload status and progress", function() {
var spec = this;
expect(this.$uploadElems.length).toEqual(caseInfo.numFiles);
this.$uploadElems.each(function(i, uploadElem) {
var $uploadElem = $(uploadElem);
@@ -154,7 +158,7 @@ define(
ActiveVideoUpload.STATUS_QUEUED :
ActiveVideoUpload.STATUS_UPLOADING
);
expect($uploadElem.find(".video-detail-progress").attr("value")).toEqual(0);
expect($uploadElem.find(".video-detail-progress").val()).toEqual(0);
expect($uploadElem).not.toHaveClass("success");
expect($uploadElem).not.toHaveClass("error");
expect($uploadElem.hasClass("queued")).toEqual(queued);
@@ -187,12 +191,12 @@ define(
progressValue: 0,
presentClass: "error",
absentClass: "success"
},
}
],
function(subCaseInfo) {
describe("and upload " + subCaseInfo.desc, function() {
beforeEach(function() {
getSentRequests()[0].response({status: subCaseInfo.responseStatus});
getSentRequests()[0].respondWith({status: subCaseInfo.responseStatus});
});
it("should update status and progress", function() {
@@ -202,7 +206,7 @@ define(
subCaseInfo.statusText
);
expect(
$uploadElem.find(".video-detail-progress").attr("value")
$uploadElem.find(".video-detail-progress").val()
).toEqual(subCaseInfo.progressValue);
expect($uploadElem).toHaveClass(subCaseInfo.presentClass);
expect($uploadElem).not.toHaveClass(subCaseInfo.absentClass);

View File

@@ -16,7 +16,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset
appendSetFixtures(uploadModalTpl);
appendSetFixtures(sandbox({ id: "asset_table_body" }));
spyOn($.fn, "fileupload").andReturn("");
spyOn($.fn, "fileupload").and.returnValue("");
var collection = new AssetCollection();
collection.url = "assets-url";
@@ -181,7 +181,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset
it('uploads file properly', function () {
var requests = setup.call(this);
expect(assetsView).toBeDefined();
spyOn(assetsView, "addAsset").andCallFake(function () {
spyOn(assetsView, "addAsset").and.callFake(function () {
assetsView.collection.add(mockAssetUploadResponse.asset);
assetsView.pagingView.renderPageItems();
assetsView.pagingView.setPage(0);

View File

@@ -13,8 +13,8 @@ define(["jquery", "underscore", "js/views/baseview", "js/utils/handle_iframe_bin
spyOn(baseViewPrototype, 'initialize');
spyOn(baseViewPrototype, 'beforeRender');
spyOn(baseViewPrototype, 'render').andCallThrough();
spyOn(baseViewPrototype, 'afterRender').andCallThrough();
spyOn(baseViewPrototype, 'render').and.callThrough();
spyOn(baseViewPrototype, 'afterRender').and.callThrough();
});
afterEach(function () {

View File

@@ -125,7 +125,7 @@ define([
ViewHelpers.verifyNotificationShowing(notificationSpy, /Deleting/);
expect($(listItemView)).toExist();
};
var assertCannotDeleteUsed = function (that, toolTipText, warningText){
var assertCannotDeleteUsed = function (that, toolTipText, warningText) {
setUsageInfo(that.model);
that.view.render();
expect(that.view.$(SELECTORS.note)).toHaveAttr(
@@ -153,36 +153,69 @@ define([
revision: 'course_rev'
});
this.addMatchers({
toContainText: function(text) {
var trimmedText = $.trim(this.actual.text());
jasmine.addMatchers({
toContainText: function() {
return {
compare: function (actual, text) {
var trimmedText = $.trim(actual.text()),
passed;
if (text && $.isFunction(text.test)) {
return text.test(trimmedText);
} else {
return trimmedText.indexOf(text) !== -1;
}
},
toBeCorrectValuesInInputs: function (values) {
var expected = {
name: this.actual.$(SELECTORS.inputName).val(),
description: this.actual
.$(SELECTORS.inputDescription).val()
if (text && $.isFunction(text.test)) {
passed = text.test(trimmedText);
} else {
passed = trimmedText.indexOf(text) !== -1;
}
return {
pass: passed
};
}
};
return _.isEqual(values, expected);
},
toBeCorrectValuesInModel: function (values) {
return _.every(values, function (value, key) {
return this.actual.get(key) === value;
}.bind(this));
},
toHaveDefaultNames: function (values) {
var actualValues = $.map(this.actual, function (item) {
return $(item).val();
});
toBeCorrectValuesInInputs: function () {
return {
compare: function (actual, values) {
var expected = {
name: actual.$(SELECTORS.inputName).val(),
description: actual
.$(SELECTORS.inputDescription).val()
};
return _.isEqual(actualValues, values);
var passed = _.isEqual(values, expected);
return {
pass: passed
};
}
};
},
toBeCorrectValuesInModel: function () {
return {
compare: function (actual, values) {
var passed = _.every(values, function (value, key) {
return actual.get(key) === value;
}.bind(this));
return {
pass: passed
};
}
};
},
toHaveDefaultNames: function () {
return {
compare: function (actual, values) {
var actualValues = $.map(actual, function (item) {
return $(item).val();
});
var passed = _.isEqual(actualValues, values);
return {
pass: passed
};
}
};
}
});
});
@@ -389,7 +422,7 @@ define([
groups = this.model.get('groups');
expect(groups.length).toBe(3);
expect(groups.at(2).get('name')).toBe('Group C');
expect(this.view.$el).not.toExist();
expect(this.view.$el).not.toBeInDOM();
});
it('does not hide saving message if failure', function() {
@@ -421,7 +454,7 @@ define([
});
it('should be removed on cancel if it is a new item', function() {
spyOn(this.model, 'isNew').andReturn(true);
spyOn(this.model, 'isNew').and.returnValue(true);
setValuesToInputs(this.view, {
inputName: 'New Configuration',
inputDescription: 'New Description'
@@ -454,18 +487,23 @@ define([
name: 'New Configuration'
});
// Error message disappear
expect(this.view.$(SELECTORS.errorMessage)).not.toExist();
expect(this.view.$(SELECTORS.errorMessage)).not.toBeInDOM();
AjaxHelpers.expectNoRequests(requests);
});
it('should have appropriate class names on focus/blur', function () {
it('should have appropriate class names on focus/blur', function (done) {
var groupInput = this.view.$(SELECTORS.inputGroupName).first(),
groupFields = this.view.$(SELECTORS.groupFields);
groupInput.focus();
expect(groupFields).toHaveClass('is-focused');
groupInput.blur();
expect(groupFields).not.toHaveClass('is-focused');
jasmine.waitUntil(function() {
return groupFields.hasClass('is-focused');
}).then(function () {
groupInput.blur();
jasmine.waitUntil(function() {
return !groupFields.hasClass('is-focused');
}).then(done);
});
});
describe('removes all newly created groups on cancel', function () {
@@ -957,13 +995,13 @@ define([
expect(this.model).toBeCorrectValuesInModel({
name: 'New Content Group'
});
expect(this.view.$el).not.toExist();
expect(this.view.$el).not.toBeInDOM();
});
it('does not hide saving message if failure', function() {
var requests = AjaxHelpers.requests(this),
notificationSpy = ViewHelpers.createNotificationSpy();
this.view.$(SELECTORS.inputName).val('New Content Group')
this.view.$(SELECTORS.inputName).val('New Content Group');
ViewHelpers.submitAndVerifyFormError(this.view, requests, notificationSpy)
});

View File

@@ -12,7 +12,7 @@ function($, LoginFactory, AjaxHelpers, ViewUtils) {
});
it('disable the submit button once it is clicked', function() {
spyOn(ViewUtils, 'redirect').andCallFake(function(){});
spyOn(ViewUtils, 'redirect').and.callFake(function(){});
var requests = AjaxHelpers.requests(this);
expect(submitButton).not.toHaveClass('is-disabled');
submitButton.click();

View File

@@ -31,14 +31,13 @@ define(["jquery", "underscore", "js/views/modals/base_modal", "js/spec_helpers/m
expect(ModelHelpers.isShowingModal(modal)).toBeTruthy();
});
it('sends focus to the modal window after show is called', function() {
it('sends focus to the modal window after show is called', function(done) {
showMockModal();
waitsFor(function () {
// This is the implementation of "toBeFocused". However, simply calling that method
// with no wait seems to be flaky.
jasmine.waitUntil(function() {
var modalWindow = ModelHelpers.getModalWindow(modal);
return $(modalWindow)[0] === $(modalWindow)[0].ownerDocument.activeElement;
}, 'Modal Window did not get focus', 5000);
return ($(modalWindow)[0] === $(modalWindow)[0].ownerDocument.activeElement);
}).then(done);
});
it('is removed after hide is called', function () {

View File

@@ -51,7 +51,7 @@ define(['jquery', 'underscore', 'js/spec_helpers/validation_helpers', 'js/views/
ValidationHelpers.checkErrorContents(modal, errorObjects);
});
it('run callback when undo changes button is clicked', function () {
it('run callback when undo changes button is clicked', function (done) {
var errorObjects = [
{
model: {display_name: 'test_attribute1'},
@@ -64,7 +64,7 @@ define(['jquery', 'underscore', 'js/spec_helpers/validation_helpers', 'js/views/
];
var callback = function() {
return true;
done();
};
// Show Modal and click undo changes
@@ -72,15 +72,8 @@ define(['jquery', 'underscore', 'js/spec_helpers/validation_helpers', 'js/views/
expect(ValidationHelpers.isShowingModal(modal)).toBeTruthy();
ValidationHelpers.undoChanges(modal);
// Wait for the callback to be fired
waitsFor(function () {
return callback();
}, 'the callback to be called', 5000);
// After checking callback fire, check modal hide
runs(function () {
expect(ValidationHelpers.isShowingModal(modal)).toBe(false);
});
expect(ValidationHelpers.isShowingModal(modal)).toBe(false);
});
});
});

View File

@@ -74,7 +74,10 @@ define(["jquery", "underscore", "common/js/spec_helpers/ajax_helpers", "URI", "j
var pagingContainer;
beforeEach(function () {
pagingContainer = new MockPagingView({page_size: PAGE_SIZE});
pagingContainer = new MockPagingView({
page_size: PAGE_SIZE,
page: jasmine.createSpyObj('page', ['updatePreviewButton', 'renderAddXBlockComponents'])
});
});
describe("Container", function () {
@@ -546,7 +549,7 @@ define(["jquery", "underscore", "common/js/spec_helpers/ajax_helpers", "URI", "j
mockXBlockView.model.id = 'mock-location';
pagingContainer.refresh(mockXBlockView, true);
expect(pagingContainer.render).toHaveBeenCalled();
expect(pagingContainer.render.mostRecentCall.args[0].force_render).toEqual('mock-location');
expect(pagingContainer.render.calls.mostRecent().args[0].force_render).toEqual('mock-location');
});
});
});

View File

@@ -70,7 +70,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja
containerPage.render();
respondWithHtml(html);
AjaxHelpers.expectJsonRequest(requests, 'GET', '/xblock/locator-container');
AjaxHelpers.respondWithJson(requests, options);
AjaxHelpers.respondWithJson(requests, options || {});
};
handleContainerPageRefresh = function(requests) {

View File

@@ -1,9 +1,10 @@
define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/ajax_helpers",
"common/js/spec_helpers/template_helpers", "js/spec_helpers/edit_helpers",
"common/js/components/views/feedback_prompt", "js/views/pages/container",
"js/views/pages/container_subviews", "js/models/xblock_info", "js/views/utils/xblock_utils"],
"js/views/pages/container_subviews", "js/models/xblock_info", "js/views/utils/xblock_utils",
'js/models/course'],
function ($, _, str, AjaxHelpers, TemplateHelpers, EditHelpers, Prompt, ContainerPage, ContainerSubviews,
XBlockInfo, XBlockUtils) {
XBlockInfo, XBlockUtils, Course) {
var VisibilityState = XBlockUtils.VisibilityState;
describe("Container Subviews", function() {
@@ -14,12 +15,26 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja
mockContainerXBlockHtml = readFixtures('mock/mock-empty-container-xblock.underscore');
beforeEach(function () {
window.course = new Course({
id: '5',
name: 'Course Name',
url_name: 'course_name',
org: 'course_org',
num: 'course_num',
revision: 'course_rev'
});
TemplateHelpers.installTemplate('xblock-string-field-editor');
TemplateHelpers.installTemplate('publish-xblock');
TemplateHelpers.installTemplate('publish-history');
TemplateHelpers.installTemplate('unit-outline');
TemplateHelpers.installTemplate('container-message');
appendSetFixtures(mockContainerPage);
requests = AjaxHelpers.requests(this);
});
afterEach(function() {
delete window.course;
});
defaultXBlockInfo = {
@@ -39,7 +54,6 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja
};
createContainerPage = function (test, options) {
requests = AjaxHelpers.requests(test);
model = new XBlockInfo(createXBlockInfo(options), { parse: true });
containerPage = new ContainerPage({
model: model,
@@ -135,7 +149,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja
// Confirm the discard.
expect(promptSpies.constructor).toHaveBeenCalled();
promptSpies.constructor.mostRecentCall.args[0].actions.primary.click(promptSpies);
promptSpies.constructor.calls.mostRecent().args[0].actions.primary.click(promptSpies);
AjaxHelpers.expectJsonRequest(requests, "POST", "/xblock/locator-container",
{"publish": "discard_changes"}
@@ -152,8 +166,8 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja
};
beforeEach(function() {
promptSpies = spyOnConstructor(Prompt, "Warning", ["show", "hide"]);
promptSpies.show.andReturn(this.promptSpies);
promptSpies = jasmine.stealth.spyOnConstructor(Prompt, "Warning", ["show", "hide"]);
promptSpies.show.and.returnValue(this.promptSpies);
});
it('renders correctly with private content', function () {
@@ -268,7 +282,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja
var notificationSpy, renderPageSpy, numRequests;
createContainerPage(this);
notificationSpy = EditHelpers.createNotificationSpy();
renderPageSpy = spyOn(containerPage.xblockPublisher, 'renderPage').andCallThrough();
renderPageSpy = spyOn(containerPage.xblockPublisher, 'renderPage').and.callThrough();
sendDiscardChangesToServer();
numRequests = requests.length;
@@ -287,7 +301,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja
it('does not fetch if discard changes fails', function () {
var renderPageSpy, numRequests;
createContainerPage(this);
renderPageSpy = spyOn(containerPage.xblockPublisher, 'renderPage').andCallThrough();
renderPageSpy = spyOn(containerPage.xblockPublisher, 'renderPage').and.callThrough();
sendDiscardChangesToServer();
@@ -309,7 +323,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja
// Click cancel to confirmation.
expect(promptSpies.constructor).toHaveBeenCalled();
promptSpies.constructor.mostRecentCall.args[0].actions.secondary.click(promptSpies);
promptSpies.constructor.calls.mostRecent().args[0].actions.secondary.click(promptSpies);
AjaxHelpers.expectNoRequests(requests);
expect(containerPage.$(discardChangesButtonCss)).not.toHaveClass('is-disabled');
});

View File

@@ -1,14 +1,15 @@
define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/utils/view_utils", "js/views/pages/course_outline",
"js/models/xblock_outline_info", "js/utils/date_utils", "js/spec_helpers/edit_helpers",
"common/js/spec_helpers/template_helpers"],
function($, AjaxHelpers, ViewUtils, CourseOutlinePage, XBlockOutlineInfo, DateUtils, EditHelpers, TemplateHelpers) {
"common/js/spec_helpers/template_helpers", 'js/models/course',],
function($, AjaxHelpers, ViewUtils, CourseOutlinePage, XBlockOutlineInfo, DateUtils,
EditHelpers, TemplateHelpers, Course) {
describe("CourseOutlinePage", function() {
var createCourseOutlinePage, displayNameInput, model, outlinePage, requests,
getItemsOfType, getItemHeaders, verifyItemsExpanded, expandItemsAndVerifyState,
collapseItemsAndVerifyState, createMockCourseJSON, createMockSectionJSON, createMockSubsectionJSON,
verifyTypePublishable, mockCourseJSON, mockEmptyCourseJSON, mockSingleSectionCourseJSON,
createMockVerticalJSON, createMockIndexJSON, mockCourseEntranceExamJSON
createMockVerticalJSON, createMockIndexJSON, mockCourseEntranceExamJSON,
mockOutlinePage = readFixtures('mock/mock-course-outline-page.underscore'),
mockRerunNotification = readFixtures('mock/mock-course-rerun-notification.underscore');
@@ -214,6 +215,15 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
};
beforeEach(function () {
window.course = new Course({
id: '5',
name: 'Course Name',
url_name: 'course_name',
org: 'course_org',
num: 'course_num',
revision: 'course_rev'
});
EditHelpers.installMockAnalytics();
EditHelpers.installViewTemplates();
TemplateHelpers.installTemplates([
@@ -252,6 +262,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
$("#start_date").datepicker( "destroy" );
$("#due_date").datepicker( "destroy" );
$('.ui-datepicker').remove();
delete window.course;
});
describe('Initial display', function() {
@@ -346,8 +357,8 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
it('can start reindex of a course', function() {
createCourseOutlinePage(this, mockSingleSectionCourseJSON);
var reindexSpy = spyOn(outlinePage, 'startReIndex').andCallThrough();
var successSpy = spyOn(outlinePage, 'onIndexSuccess').andCallThrough();
var reindexSpy = spyOn(outlinePage, 'startReIndex').and.callThrough();
var successSpy = spyOn(outlinePage, 'onIndexSuccess').and.callThrough();
var reindexButton = outlinePage.$('.button.button-reindex');
var test_url = '/course/5/search_reindex';
reindexButton.attr('href', test_url)
@@ -360,11 +371,11 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
it('shows an error message when reindexing fails', function() {
createCourseOutlinePage(this, mockSingleSectionCourseJSON);
var reindexSpy = spyOn(outlinePage, 'startReIndex').andCallThrough();
var errorSpy = spyOn(outlinePage, 'onIndexError').andCallThrough();
var reindexSpy = spyOn(outlinePage, 'startReIndex').and.callThrough();
var errorSpy = spyOn(outlinePage, 'onIndexError').and.callThrough();
var reindexButton = outlinePage.$('.button.button-reindex');
var test_url = '/course/5/search_reindex';
reindexButton.attr('href', test_url)
reindexButton.attr('href', test_url);
reindexButton.trigger('click');
AjaxHelpers.expectJsonRequest(requests, 'GET', test_url);
AjaxHelpers.respondWithError(requests, 500, createMockIndexJSON(false));

View File

@@ -40,9 +40,15 @@ define([
'content-group-editor', 'group-edit', 'list'
]);
this.addMatchers({
jasmine.addMatchers({
toBeExpanded: function () {
return Boolean($('a.group-toggle.hide-groups', $(this.actual)).length);
return {
compare: function (actual) {
return {
pass: Boolean($('a.group-toggle.hide-groups', $(actual)).length)
};
}
};
}
});
});
@@ -67,7 +73,7 @@ define([
});
it('should focus and expand if its id is part of url hash', function() {
spyOn(this.view, 'getLocationHash').andReturn('#0');
spyOn(this.view, 'getLocationHash').and.returnValue('#0');
this.view.render();
// We cannot use .toBeFocused due to flakiness.
expect($.fn.focus).toHaveBeenCalled();
@@ -75,14 +81,14 @@ define([
});
it('should not focus on any experiment configuration if url hash is empty', function() {
spyOn(this.view, 'getLocationHash').andReturn('');
spyOn(this.view, 'getLocationHash').and.returnValue('');
this.view.render();
expect($.fn.focus).not.toHaveBeenCalled();
expect(this.view.$(groupConfigItemClassName)).not.toBeExpanded();
});
it('should not focus on any experiment configuration if url hash contains wrong id', function() {
spyOn(this.view, 'getLocationHash').andReturn('#1');
spyOn(this.view, 'getLocationHash').and.returnValue('#1');
this.view.render();
expect($.fn.focus).not.toHaveBeenCalled();
expect(this.view.$(groupConfigItemClassName)).not.toBeExpanded();

View File

@@ -22,7 +22,7 @@ function ($, AjaxHelpers, ViewHelpers, ManageUsersFactory, ViewUtils) {
describe("read-write access", function() {
var mockHTML = readFixtures('mock/mock-manage-users-lib.underscore');
beforeEach(function () {
beforeEach(function (done) {
ViewHelpers.installMockAnalytics();
setFixtures(mockHTML);
appendSetFixtures($("<script>", { id: "team-member-tpl", type: "text/template"}).text(team_member_fixture));
@@ -37,9 +37,10 @@ function ($, AjaxHelpers, ViewHelpers, ManageUsersFactory, ViewUtils) {
10000,
true
);
waitsFor(function(){
return $(".ui-loading").length === 0;
}, "Waiting for backbone render to happen", 1000);
jasmine.waitUntil(function() {
return ($(".ui-loading").length === 0);
}).then(done);
});
afterEach(function () {

View File

@@ -47,7 +47,7 @@ define(
it("should render created timestamp correctly", function() {
var fakeDate = "fake formatted date";
spyOn(Date.prototype, "toLocaleString").andCallFake(
spyOn(Date.prototype, "toLocaleString").and.callFake(
function(locales, options) {
expect(locales).toEqual([]);
expect(options.timeZone).toEqual("UTC");

View File

@@ -1,6 +1,8 @@
define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers/template_helpers",
"common/js/spec_helpers/view_helpers", "common/js/components/utils/view_utils", "js/views/unit_outline", "js/models/xblock_info"],
function ($, AjaxHelpers, TemplateHelpers, ViewHelpers, ViewUtils, UnitOutlineView, XBlockInfo) {
"common/js/spec_helpers/view_helpers", "common/js/components/utils/view_utils", "js/models/course",
"js/views/unit_outline", "js/models/xblock_info"],
function ($, AjaxHelpers, TemplateHelpers, ViewHelpers, ViewUtils,
Course, UnitOutlineView, XBlockInfo) {
describe("UnitOutlineView", function() {
var createUnitOutlineView, createMockXBlockInfo,
@@ -71,6 +73,14 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers
};
beforeEach(function () {
window.course = new Course({
id: '5',
name: 'Course Name',
url_name: 'course_name',
org: 'course_org',
num: 'course_num',
revision: 'course_rev'
});
ViewHelpers.installMockAnalytics();
ViewHelpers.installViewTemplates();
TemplateHelpers.installTemplate('unit-outline');
@@ -78,6 +88,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers
});
afterEach(function () {
delete window.course;
ViewHelpers.removeMockAnalytics();
});

View File

@@ -91,7 +91,7 @@ define(["jquery", "URI", "common/js/spec_helpers/ajax_helpers", "common/js/compo
var requests = AjaxHelpers.requests(this),
missingJavaScriptUrl = "no_such_file.js",
promise;
spyOn(ViewUtils, 'loadJavaScript').andReturn($.Deferred().reject().promise());
spyOn(ViewUtils, 'loadJavaScript').and.returnValue($.Deferred().reject().promise());
promise = postXBlockRequest(requests, [
["hash5", { mimetype: "application/javascript", kind: "url", data: missingJavaScriptUrl }]
]);
@@ -99,7 +99,7 @@ define(["jquery", "URI", "common/js/spec_helpers/ajax_helpers", "common/js/compo
});
it('Triggers an event to the runtime when a notification-action-button is clicked', function () {
var notifySpy = spyOn(xblockView, "notifyRuntime").andCallThrough();
var notifySpy = spyOn(xblockView, "notifyRuntime").and.callThrough();
postXBlockRequest(AjaxHelpers.requests(this), []);
xblockView.$el.find(".notification-action-button").click();

View File

@@ -3,9 +3,9 @@
* It is expected to be backed by a Group model.
*/
define([
'js/views/baseview'
'js/views/baseview', 'underscore', 'underscore.string', 'gettext', 'text!templates/group-edit.underscore'
],
function(BaseView) {
function(BaseView, _, str, gettext, groupEditTemplate) {
'use strict';
var ExperimentGroupEditView = BaseView.extend({
tagName: 'li',
@@ -22,7 +22,6 @@ function(BaseView) {
},
initialize: function() {
this.template = this.loadTemplate('group-edit');
this.listenTo(this.model, 'change', this.render);
},
@@ -30,7 +29,7 @@ function(BaseView) {
var collection = this.model.collection,
index = collection.indexOf(this.model);
this.$el.html(this.template({
this.$el.html(_.template(groupEditTemplate)({
name: this.model.get('name'),
allocation: this.getAllocation(),
index: index,

View File

@@ -1,4 +1,8 @@
define(["js/views/baseview", "underscore"], function(BaseView, _) {
define([
"js/views/baseview",
"underscore",
"text!templates/license-selector.underscore"
], function(BaseView, _, licenseSelectorTemplate) {
var defaultLicenseInfo = {
"all-rights-reserved": {
"name": gettext("All Rights Reserved"),
@@ -55,7 +59,6 @@ define(["js/views/baseview", "underscore"], function(BaseView, _) {
initialize: function(options) {
this.licenseInfo = options.licenseInfo || defaultLicenseInfo;
this.showPreview = !!options.showPreview; // coerce to boolean
this.template = this.loadTemplate("license-selector");
// Rerender when the model changes
this.listenTo(this.model, 'change', this.render);
@@ -79,7 +82,7 @@ define(["js/views/baseview", "underscore"], function(BaseView, _) {
},
render: function() {
this.$el.html(this.template({
this.$el.html(_.template(licenseSelectorTemplate)({
model: this.model.attributes,
licenseString: this.model.toString() || "",
licenseInfo: this.licenseInfo,

View File

@@ -48,10 +48,9 @@ lib_paths:
- xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill.js
- xmodule_js/common_static/js/vendor/sinon-1.17.0.js
- xmodule_js/common_static/js/vendor/Squire.js
- xmodule_js/common_static/js/vendor/jasmine-jquery.js
- xmodule_js/common_static/js/vendor/jasmine-stealth.js
- xmodule_js/common_static/js/libs/jasmine-stealth.js
- xmodule_js/common_static/js/libs/jasmine-waituntil.js
- xmodule_js/common_static/js/vendor/jasmine-imagediff.js
- xmodule_js/common_static/js/vendor/jasmine.async.js
- xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js
- xmodule_js/common_static/js/vendor/jQuery-File-Upload/js
- xmodule_js/src/xmodule.js

View File

@@ -45,10 +45,7 @@ lib_paths:
- xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill.js
- xmodule_js/common_static/js/vendor/sinon-1.17.0.js
- xmodule_js/common_static/js/vendor/Squire.js
- xmodule_js/common_static/js/vendor/jasmine-jquery.js
- xmodule_js/common_static/js/vendor/jasmine-stealth.js
- xmodule_js/common_static/js/vendor/jasmine-imagediff.js
- xmodule_js/common_static/js/vendor/jasmine.async.js
- xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js
- xmodule_js/common_static/js/vendor/domReady.js
- xmodule_js/common_static/js/vendor/URI.min.js

View File

@@ -0,0 +1,140 @@
// Common JavaScript tests, using RequireJS.
//
// To run all the tests and print results to the console:
//
// karma start cms/static/karma_cms.conf.js
//
//
// To run the tests for debugging: Debugging can be done in any browser
// but Chrome's developer console debugging experience is best.
//
// karma start cms/static/karma_cms.conf.js --browsers=BROWSER --single-run=false
//
//
// To run the tests with coverage and junit reports:
//
// karma start cms/static/karma_cms.conf.js --browsers=BROWSER --coverage
// --junitreportpath=<xunit_report_path> --coveragereportpath=<report_path>
//
// where `BROWSER` could be Chrome or Firefox.
//
/* jshint node: true */
/*jshint -W079 */
'use strict';
var path = require('path');
var _ = require('underscore');
var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js'));
var libraryFiles = [
{pattern: 'xmodule_js/common_static/coffee/src/ajax_prefix.js', included: false},
{pattern: 'xmodule_js/common_static/js/src/utility.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery-ui.min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.cookie.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.simulate.js', included: false},
{pattern: 'xmodule_js/common_static/common/js/vendor/underscore.js', included: false},
{pattern: 'xmodule_js/common_static/common/js/vendor/underscore.string.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/backbone-min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/backbone-associations-min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/backbone.paginator.min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/backbone-relational.min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/timepicker/jquery.timepicker.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.leanModal.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.ajaxQueue.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.form.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/sinon-1.17.0.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/Squire.js', included: false},
{pattern: 'xmodule_js/common_static/js/libs/jasmine-stealth.js', included: false},
{pattern: 'xmodule_js/common_static/js/libs/jasmine-waituntil.js', included: false},
{pattern: 'xmodule_js/common_static/js/libs/jasmine-extensions.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/jasmine-imagediff.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/**/*.js', included: false},
{pattern: 'xmodule_js/src/xmodule.js', included: false},
{pattern: 'xmodule_js/common_static/js/test/i18n.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/draggabilly.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/date.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/domReady.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/URI.min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.smooth-scroll.min.js', included: false},
{pattern: 'xmodule_js/common_static/coffee/src/jquery.immediateDescendents.js', included: false},
{pattern: 'xmodule_js/common_static/js/xblock/**/*.js', included: false},
{pattern: 'xmodule_js/common_static/coffee/src/xblock/**/*.js', included: false},
{
pattern: 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport.js',
included: false
},
{pattern: 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload.js', included: false},
{
pattern: 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-process.js',
included: false
},
{
pattern: 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate.js',
included: false
},
{pattern: 'xmodule_js/common_static/js/vendor/mock-ajax.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/requirejs/text.js', included: false},
{pattern: 'edx-ui-toolkit/js/utils/global-loader.js', included: false},
{pattern: 'edx-pattern-library/js/modernizr-custom.js', included: false},
{pattern: 'edx-pattern-library/js/afontgarde.js', included: false},
{pattern: 'edx-pattern-library/js/edx-icons.js', included: false},
{pattern: 'edx-pattern-library/js/**/*.js', included: false},
{pattern: 'edx-ui-toolkit/js/**/*.js', included: false}
];
// Paths to source JavaScript files
var sourceFiles = [
{pattern: 'coffee/src/**/!(*spec).js', included: false},
{pattern: 'js/**/!(*spec).js', included: false},
{pattern: 'common/js/**/!(*spec).js', included: false}
];
// Paths to spec (test) JavaScript files
var specFiles = [
{pattern: 'coffee/spec/**/*spec.js', included: false},
{pattern: 'js/spec/**/*spec.js', included: false},
{pattern: 'js/certificates/spec/**/*spec.js', included: false}
];
// Paths to fixture files
var fixtureFiles = [
{pattern: 'coffee/fixtures/**/*.underscore', included: false},
{pattern: 'templates/**/*.underscore', included: false},
{pattern: 'common/templates/**/*.underscore', included: false}
];
// override fixture path and other config.
var runAndConfigFiles = [
{pattern: path.join(configModule.appRoot, 'common/static/common/js/jasmine.common.conf.js'), included: true},
'coffee/spec/main.js'
];
// do not include tests or libraries
// (these files will be instrumented by Istanbul)
var preprocessors = configModule.getPreprocessorObject(_.flatten([sourceFiles, specFiles]));
module.exports = function (config) {
var commonConfig = configModule.getConfig(config),
files = _.flatten([libraryFiles, sourceFiles, specFiles, fixtureFiles, runAndConfigFiles]),
localConfig;
// add nocache in files if coverage is not set
if (!config.coverage) {
files.forEach(function (f) {
if (_.isObject(f)) {
f.nocache = true;
}
});
}
localConfig = {
files: files,
preprocessors: preprocessors
};
config.set(_.extend(commonConfig, localConfig));
};

View File

@@ -0,0 +1,127 @@
// Common JavaScript tests, using RequireJS.
//
// To run all the tests and print results to the console:
//
// karma start cms/static/karma_cms_squire.conf.js
//
//
// To run the tests for debugging: Debugging can be done in any browser
// but Chrome's developer console debugging experience is best.
//
// karma start cms/static/karma_cms_squire.conf.js --browsers=BROWSER --single-run=false
//
//
// To run the tests with coverage and junit reports:
//
// karma start cms/static/karma_cms_squire.conf.js --browsers=BROWSER --coverage
// --junitreportpath=<xunit_report_path> --coveragereportpath=<report_path>
//
// where `BROWSER` could be Chrome or Firefox.
//
/* jshint node: true */
/*jshint -W079 */
'use strict';
var path = require('path');
var _ = require('underscore');
var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js'));
var libraryFiles = [
{pattern: 'xmodule_js/common_static/js/vendor/requirejs/require.js', included: false},
{pattern: 'xmodule_js/common_static/coffee/src/ajax_prefix.js', included: false},
{pattern: 'xmodule_js/common_static/js/src/utility.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery-ui.min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.cookie.js', included: false},
{pattern: 'xmodule_js/common_static/common/js/vendor/underscore.js', included: false},
{pattern: 'xmodule_js/common_static/common/js/vendor/underscore.string.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/backbone-min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/backbone-associations-min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/backbone.paginator.min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/timepicker/jquery.timepicker.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.leanModal.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.form.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/sinon-1.17.0.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/Squire.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jasmine-imagediff.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/domReady.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/URI.min.js', included: false},
{pattern: 'xmodule_js/common_static/js/libs/jasmine-extensions.js', included: true},
{pattern: 'xmodule_js/src/xmodule.js', included: false},
{pattern: 'xmodule_js/common_static/coffee/src/jquery.immediateDescendents.js', included: false},
{pattern: 'xmodule_js/common_static/js/test/i18n.js', included: false},
{pattern: 'xmodule_js/common_static/js/xblock/**/*.js', included: false},
{pattern: 'xmodule_js/common_static/coffee/src/xblock/**/*.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/URI.min.js', included: false},
{
pattern: 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport.js',
included: false
},
{pattern: 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload.js', included: false},
{
pattern: 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-process.js',
included: false
},
{
pattern: 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate.js',
included: false
},
{pattern: 'xmodule_js/common_static/js/vendor/requirejs/text.js', included: false}
];
// Paths to source JavaScript files
var sourceFiles = [
{pattern: 'coffee/src/**/*.js', included: false},
{pattern: 'js/collections/**/*.js', included: false},
{pattern: 'js/models/**/*.js', included: false},
{pattern: 'js/utils/**/*.js', included: false},
{pattern: 'js/views/**/*.js', included: false},
{pattern: 'common/js/**/*.js', included: false}
];
// Paths to spec (test) JavaScript files
var specFiles = [
{pattern: 'coffee/spec/**/*.js', included: false},
{pattern: 'js/spec/**/*.js', included: false}
];
// Paths to fixture files
var fixtureFiles = [
{pattern: 'coffee/fixtures/**/*.*', included: false},
{pattern: 'templates/**/*.*', included: false},
{pattern: 'common/templates/**/*.*', included: false}
];
// override fixture path and other config.
var runAndConfigFiles = [
{pattern: path.join(configModule.appRoot, 'common/static/common/js/jasmine.common.conf.js'), included: true},
'coffee/spec/main_squire.js'
];
// do not include tests or libraries
// (these files will be instrumented by Istanbul)
var preprocessors = configModule.getPreprocessorObject(_.flatten([sourceFiles, specFiles]));
module.exports = function (config) {
var commonConfig = configModule.getConfig(config),
files = _.flatten([libraryFiles, sourceFiles, specFiles, fixtureFiles, runAndConfigFiles]),
localConfig;
// add nocache in files if coverage is not set
if (!config.coverage) {
files.forEach(function (f) {
if (_.isObject(f)) {
f.nocache = true;
}
});
}
localConfig = {
files: files,
preprocessors: preprocessors
};
config.set(_.extend(commonConfig, localConfig));
};

View File

@@ -1,3 +1,4 @@
<%page expression_filter="h"/>
<%inherit file="base.html" />
<%def name="online_help_token()"><% return "pages" %></%def>
<%namespace name='static' file='static_content.html'/>
@@ -5,7 +6,7 @@
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
from xmodule.tabs import StaticTab
from django.template.defaultfilters import escapejs
from openedx.core.djangolib.js_utils import js_escaped_string
%>
<%block name="title">${_("Pages")}</%block>
<%block name="bodyclass">is-signedin course view-static-pages</%block>
@@ -20,7 +21,7 @@
<%block name="requirejs">
require(["js/factories/edit_tabs"], function (EditTabsFactory) {
EditTabsFactory("${context_course.location | escapejs}", "${reverse('contentstore.views.tabs_handler', kwargs={'course_key_string': context_course.id})}");
EditTabsFactory("${context_course.location | n, js_escaped_string}", "${reverse('contentstore.views.tabs_handler', kwargs={'course_key_string': context_course.id})}");
});
</%block>
@@ -30,7 +31,7 @@
<h1 class="page-header">
<small class="subtitle">${_("Content")}</small>
## Translators: Pages refer to the tabs that appear in the top navigation of each course.
<span class="sr">&gt; </span>${_("Pages")}
<span class="sr"> > </span>${_("Pages")}
</h1>
<nav class="nav-actions" aria-label="${_('Page Actions')}">
@@ -72,7 +73,7 @@
%>
% if isinstance(tab, StaticTab):
<li class="component ${css_class}" data-locator="${tab.locator | h}" data-tab-id="${tab.tab_id | h}"></li>
<li class="component ${css_class}" data-locator="${tab.locator}" data-tab-id="${tab.tab_id}"></li>
% else:
<li class="course-nav-item ${css_class}" data-tab-id="${tab.tab_id}">

View File

@@ -1,3 +1,4 @@
<%page expression_filter="h"/>
<%inherit file="base.html" />
<%!
from django.utils.translation import ugettext as _
@@ -22,17 +23,17 @@ help_link_end = '</a>'
<article class="error-prompt">
% if error == '404':
<h1>${_("The Page You Requested Page Cannot be Found")}</h1>
<p class="description">${_("We're sorry. We couldn't find the {studio_name} page you're looking for. You may want to return to the {studio_name} Dashboard and try again. If you are still having problems accessing things, please feel free to {link_start}contact {studio_name} support{link_end} for further help.").format(
<p class="description">${Text(_("We're sorry. We couldn't find the {studio_name} page you're looking for. You may want to return to the {studio_name} Dashboard and try again. If you are still having problems accessing things, please feel free to {link_start}contact {studio_name} support{link_end} for further help.")).format(
studio_name=settings.STUDIO_SHORT_NAME,
link_start=help_link_start,
link_end=help_link_end,
link_start=HTML(help_link_start),
link_end=HTML(help_link_end),
)}</p>
% elif error == '500':
<h1>${_("The Server Encountered an Error")}</h1>
<p class="description">${_("We're sorry. There was a problem with the server while trying to process your last request. You may want to return to the {studio_name} Dashboard or try this request again. If you are still having problems accessing things, please feel free to {link_start}contact {studio_name} support{link_end} for further help.").format(
<p class="description">${Text(_("We're sorry. There was a problem with the server while trying to process your last request. You may want to return to the {studio_name} Dashboard or try this request again. If you are still having problems accessing things, please feel free to {link_start}contact {studio_name} support{link_end} for further help.")).format(
studio_name=settings.STUDIO_SHORT_NAME,
link_start=help_link_start,
link_end=help_link_end,
link_start=HTML(help_link_start),
link_end=HTML(help_link_end),
)}</p>
% endif
<a href="/" class="back-button">${_("Back to dashboard")}</a>

View File

@@ -1,6 +1,6 @@
<div class="xblock xblock-studio_view xmodule_edit xmodule_WrapperDescriptor" data-runtime-class="StudioRuntime"
data-init="XBlockToXModuleShim" data-runtime-version="1" data-usage-id="i4x:;_;_edX;_mock"
data-type="VerticalDescriptor" tabindex="0">
data-type="MockDescriptor" tabindex="0">
<div class="wrapper-comp-editor is-active" id="editor-tab" data-base-asset-url="/c4x/AndyA/ABT101/asset/">
<section class="editor-with-tabs">
<div class="edit-header">

View File

@@ -1,4 +1,4 @@
<div class="xblock xblock-studio_view xmodule_edit xmodule_WrapperDescriptor" data-runtime-class="StudioRuntime" data-init="XBlockToXModuleShim" data-runtime-version="1" data-usage-id="i4x:;_;_AndyA;_ABT101;_wrapper;_wrapper_l1_poll" data-type="VerticalDescriptor" tabindex="0">
<div class="xblock xblock-studio_view xmodule_edit xmodule_WrapperDescriptor" data-runtime-class="StudioRuntime" data-init="XBlockToXModuleShim" data-runtime-version="1" data-usage-id="i4x:;_;_AndyA;_ABT101;_wrapper;_wrapper_l1_poll" data-type="MockDescriptor" tabindex="0">
<section class="sequence-edit">
<script id="metadata-editor-tpl" type="text/template">
<ul class="list-input settings-list">

View File

@@ -1,16 +1,16 @@
<div class="xblock-render">
<div class="xblock-render" class="studio-xblock-wrapper">
% for tag in tags:
<label for="problem_tags_${tag['key']}">${tag['title']}</label>:
<select id="problem_tags_${tag['key']}" name="${tag['key']}">
<label for="tags_${tag['key']}_${block_location}">${tag['title']}</label>:
<select id="tags_${tag['key']}_${block_location}" name="${tag['key']}">
<option value="" ${'' if tag['current_value'] else 'selected=""'}>Not selected</option>
% for k,v in tag['values'].iteritems():
% for v in tag['values']:
<%
selected = ''
if k == tag['current_value']:
if v == tag['current_value']:
selected = 'selected'
%>
<option value="${k}" ${selected}>${v}</option>
<option value="${v}" ${selected}>${v}</option>
% endfor
% endfor
</select>
</div>
% endfor
</div>

View File

@@ -219,6 +219,17 @@ class AutoAuthEnabledTestCase(UrlResetMixin, TestCase):
self.assertTrue(response.url.endswith(url_pattern)) # pylint: disable=no-member
def test_redirect_to_specified(self):
# Create user and redirect to specified url
url_pattern = '/u/test#about_me'
response = self._auto_auth({
'username': 'test',
'redirect_to': url_pattern,
'staff': 'true',
}, status_code=302)
self.assertTrue(response.url.endswith(url_pattern)) # pylint: disable=no-member
def _auto_auth(self, params=None, status_code=None, **kwargs):
"""
Make a request to the auto-auth end-point and check

View File

@@ -117,22 +117,6 @@ class CourseEndingTest(TestCase):
}
)
cert_status = {'status': 'regenerating', 'grade': '67', 'mode': 'verified'}
self.assertEqual(
_cert_info(user, course, cert_status, course_mode),
{
'status': 'generating',
'show_disabled_download_button': True,
'show_download_url': False,
'show_survey_button': True,
'survey_url': survey_url,
'grade': '67',
'mode': 'verified',
'linked_in_url': None,
'can_unenroll': False,
}
)
download_url = 'http://s3.edx/cert'
cert_status = {
'status': 'downloadable', 'grade': '67',
@@ -501,8 +485,8 @@ class DashboardTest(ModuleStoreTestCase):
self.client.login(username="jack", password="test")
response = self.client.get(reverse("dashboard"))
# "Find courses" is shown in the side panel
self.assertContains(response, "Find courses")
# "Explore courses" is shown in the side panel
self.assertContains(response, "Explore courses")
# But other links are hidden in the navigation
self.assertNotContains(response, "How it Works")

View File

@@ -312,7 +312,6 @@ def _cert_info(user, course_overview, cert_status, course_mode): # pylint: disa
# simplify the status for the template using this lookup table
template_state = {
CertificateStatuses.generating: 'generating',
CertificateStatuses.regenerating: 'generating',
CertificateStatuses.downloadable: 'ready',
CertificateStatuses.notpassing: 'notpassing',
CertificateStatuses.restricted: 'restricted',
@@ -1908,8 +1907,9 @@ def auto_auth(request):
* `course_id`: Enroll the student in the course with `course_id`
* `roles`: Comma-separated list of roles to grant the student in the course with `course_id`
* `no_login`: Define this to create the user but not login
* `redirect`: Set to "true" will redirect to course if course_id is defined, otherwise it will redirect to dashboard
* `redirect`: Set to "true" will redirect to the `redirect_to` value if set, or
course home page if course_id is defined, otherwise it will redirect to dashboard
* `redirect_to`: will redirect to to this url
If username, email, or password are not provided, use
randomly generated credentials.
"""
@@ -1925,6 +1925,7 @@ def auto_auth(request):
is_staff = request.GET.get('staff', None)
is_superuser = request.GET.get('superuser', None)
course_id = request.GET.get('course_id', None)
redirect_to = request.GET.get('redirect_to', None)
# mode has to be one of 'honor'/'professional'/'verified'/'audit'/'no-id-professional'/'credit'
enrollment_mode = request.GET.get('enrollment_mode', 'honor')
@@ -1933,7 +1934,7 @@ def auto_auth(request):
if course_id:
course_key = CourseLocator.from_string(course_id)
role_names = [v.strip() for v in request.GET.get('roles', '').split(',') if v.strip()]
redirect_when_done = request.GET.get('redirect', '').lower() == 'true'
redirect_when_done = request.GET.get('redirect', '').lower() == 'true' or redirect_to
login_when_done = 'no_login' not in request.GET
form = AccountCreationForm(
@@ -1998,8 +1999,11 @@ def auto_auth(request):
# Provide the user with a valid CSRF token
# then return a 200 response unless redirect is true
if redirect_when_done:
# Redirect to specific page if specified
if redirect_to:
redirect_url = redirect_to
# Redirect to course info page if course_id is known
if course_id:
elif course_id:
try:
# redirect to course info page in LMS
redirect_url = reverse(

View File

@@ -6,14 +6,15 @@ from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey
def from_string_or_404(course_key_string):
def course_key_from_string_or_404(course_key_string, message=None):
"""
Gets CourseKey from the string passed as parameter.
Parses course key from string(containing course key) or raises 404 if the string's format is invalid.
Arguments:
course_key_string(str): It is string containing the course key
course_key_string(str): It contains the course key
message(str): It contains the exception message
Returns:
CourseKey: A key that uniquely identifies a course
@@ -25,6 +26,6 @@ def from_string_or_404(course_key_string):
try:
course_key = CourseKey.from_string(course_key_string)
except InvalidKeyError:
raise Http404
raise Http404(message)
return course_key

View File

@@ -1,32 +1,54 @@
"""
Tests for util.course_key_utils
"""
from nose.tools import assert_equals, assert_raises # pylint: disable=no-name-in-module
from util.course_key_utils import from_string_or_404
import ddt
import unittest
from util.course_key_utils import course_key_from_string_or_404
from opaque_keys.edx.keys import CourseKey
from django.http import Http404
def test_from_string_or_404():
@ddt.ddt
class TestFromStringOr404(unittest.TestCase):
"""
Base Test class for course_key_from_string_or_404 utility tests
"""
@ddt.data(
"course-v1:TTT+CS01+2015_T0", # split style course keys
"TTT/CS01/2015_T0" # mongo style course keys
)
def test_from_string_or_404_for_valid_course_key(self, valid_course_key):
"""
Tests course_key_from_string_or_404 for valid split style course keys and mongo style course keys.
"""
self.assertEquals(
CourseKey.from_string(valid_course_key),
course_key_from_string_or_404(valid_course_key)
)
#testing with split style course keys
assert_raises(
Http404,
from_string_or_404,
"/some.invalid.key/course-v1:TTT+CS01+2015_T0"
)
assert_equals(
CourseKey.from_string("course-v1:TTT+CS01+2015_T0"),
from_string_or_404("course-v1:TTT+CS01+2015_T0")
@ddt.data(
"/some.invalid.key/course-v1:TTT+CS01+2015_T0", # split style course keys
"/some.invalid.key/TTT/CS01/2015_T0" # mongo style course keys
)
def test_from_string_or_404_for_invalid_course_key(self, invalid_course_key):
"""
Tests course_key_from_string_or_404 for valid split style course keys and mongo style course keys.
"""
self.assertRaises(
Http404,
course_key_from_string_or_404,
invalid_course_key,
)
#testing with mongo style course keys
assert_raises(
Http404,
from_string_or_404,
"/some.invalid.key/TTT/CS01/2015_T0"
)
assert_equals(
CourseKey.from_string("TTT/CS01/2015_T0"),
from_string_or_404("TTT/CS01/2015_T0")
@ddt.data(
"/some.invalid.key/course-v1:TTT+CS01+2015_T0", # split style invalid course key
"/some.invalid.key/TTT/CS01/2015_T0" # mongo style invalid course key
)
def test_from_string_or_404_with_message(self, course_string):
"""
Tests course_key_from_string_or_404 with exception message for split style and monog style invalid course keys.
:return:
"""
with self.assertRaises(Http404) as context:
course_key_from_string_or_404(course_string, message="Invalid Keys")
self.assertEquals(str(context.exception), "Invalid Keys")

View File

@@ -399,6 +399,7 @@ class CapaMixin(CapaFields):
'ajax_url': self.runtime.ajax_url,
'progress_status': Progress.to_js_status_str(progress),
'progress_detail': Progress.to_js_detail_str(progress),
'content': self.get_problem_html(encapsulate=False),
})
def check_button_name(self):
@@ -1422,6 +1423,7 @@ class CapaMixin(CapaFields):
return {
'success': True,
'msg': msg,
'html': self.get_problem_html(encapsulate=False),
}
def reset_problem(self, _data):

View File

@@ -73,6 +73,10 @@ class Date(JSONField):
return time.strftime('%Y-%m-%dT%H:%M:%SZ', value)
elif isinstance(value, datetime.datetime):
if value.tzinfo is None or value.utcoffset().total_seconds() == 0:
if value.year < 1900:
# strftime doesn't work for pre-1900 dates, so use
# isoformat instead
return value.isoformat()
# isoformat adds +00:00 rather than Z
return value.strftime('%Y-%m-%dT%H:%M:%SZ')
else:

View File

@@ -4,7 +4,7 @@
<div
id="video_id"
class="video closed"
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": "[]", "speed": "1.5", "startTime": "", "streams": "0.5:7tqY6eQzVhE,1.0:cogebirgzzM,1.5:abcdefghijkl", "sub": "Z5KLxerq05Y", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": [], "speed": "1.5", "startTime": "", "streams": "0.5:7tqY6eQzVhE,1.0:cogebirgzzM,1.5:abcdefghijkl", "sub": "Z5KLxerq05Y", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "/base/fixtures/youtube_iframe_api.js", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
>
<div class="focus_grabber first"></div>

View File

@@ -4,7 +4,7 @@
<div
id="video_id"
class="video closed"
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "speed": "1.5", "startTime": "", "streams": "", "sub": "Z5KLxerq05Y", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["/base/fixtures/test.mp4","/base/fixtures/test.webm","/base/fixtures/test.ogv"], "speed": "1.5", "startTime": "", "streams": "", "sub": "Z5KLxerq05Y", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "/base/fixtures/youtube_iframe_api.js", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
>
<div class="focus_grabber first"></div>

View File

@@ -4,7 +4,7 @@
<div
id="video_id"
class="video closed"
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "speed": "1.5", "startTime": "", "streams": "", "sub": "Z5KLxerq05Y", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/", "source": "", "html5_sources": ["http://youtu.be/3_yD_cEKoCk.mp4"]}'
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["/base/fixtures/test.mp4","/base/fixtures/test.webm","/base/fixtures/test.ogv"], "speed": "1.5", "startTime": "", "streams": "", "sub": "Z5KLxerq05Y", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "/base/fixtures/youtube_iframe_api.js", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/", "source": "", "html5_sources": ["http://youtu.be/3_yD_cEKoCk.mp4"]}'
>
<div class="focus_grabber first"></div>

View File

@@ -4,7 +4,7 @@
<div
id="video_id"
class="video closed"
data-metadata='{"streams":"0.5:7tqY6eQzVhE,1.0:cogebirgzzM,1.5:abcdefghijkl", "showCaptions": false, "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "speed": "1.5", "startTime": "", "end": "", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
data-metadata='{"streams":"0.5:7tqY6eQzVhE,1.0:cogebirgzzM,1.5:abcdefghijkl", "showCaptions": false, "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "speed": "1.5", "startTime": "", "end": "", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "/base/fixtures/youtube_iframe_api.js", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
>
<div class="focus_grabber first"></div>

View File

@@ -4,9 +4,9 @@
<div
id="video_id"
class="video closed"
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "speed": "1.5", "startTime": "", "streams": "", "sub": "Z5KLxerq05Y", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
data-bumper-metadata='{"transcriptLanguage": "en", "showCaptions": "true", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "transcriptTranslationUrl": "/transcript/translation/__lang__/?is_bumper=1", "transcriptAvailableTranslationsUrl": "/transcript/available_translations/?is_bumper=1", "streams": "", "saveStateUrl": "/save_user_state"}'
data-poster='{"url": "xmodule/include/fixtures/poster.jpg", "type": "youtube"}'
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["/base/fixtures/test.mp4","/base/fixtures/test.webm","/base/fixtures/test.ogv"], "speed": "1.5", "startTime": "", "streams": "", "sub": "Z5KLxerq05Y", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "/base/fixtures/youtube_iframe_api.js", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
data-bumper-metadata='{"transcriptLanguage": "en", "showCaptions": "true", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "sources": ["/base/fixtures/test.mp4","/base/fixtures/test.webm","/base/fixtures/test.ogv"], "transcriptTranslationUrl": "/transcript/translation/__lang__/?is_bumper=1", "transcriptAvailableTranslationsUrl": "/transcript/available_translations/?is_bumper=1", "streams": "", "saveStateUrl": "/save_user_state"}'
data-poster='{"url": "/base/fixtures/poster.jpg", "type": "youtube"}'
>
<div class="focus_grabber first"></div>

View File

@@ -4,7 +4,7 @@
<div
id="video_id1"
class="video closed"
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "speed": "1.5", "startTime": "", "streams": "0.5:7tqY6eQzVhE,1.0:cogebirgzzM,1.5:abcdefghijkl", "sub": "", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["/base/fixtures/test.mp4","/base/fixtures/test.webm","/base/fixtures/test.ogv"], "speed": "1.5", "startTime": "", "streams": "0.5:7tqY6eQzVhE,1.0:cogebirgzzM,1.5:abcdefghijkl", "sub": "", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "/base/fixtures/youtube_iframe_api.js", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
>
<div class="focus_grabber first"></div>
@@ -38,7 +38,7 @@
<div
id="video_id2"
class="video"
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "speed": "1.0", "startTime": "", "streams": "0.75:7tqY6eQzVhE,1.0:cogebirgzzM", "sub": "", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["/base/fixtures/test.mp4","/base/fixtures/test.webm","/base/fixtures/test.ogv"], "speed": "1.0", "startTime": "", "streams": "0.75:7tqY6eQzVhE,1.0:cogebirgzzM", "sub": "", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "/base/fixtures/youtube_iframe_api.js", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
>
<div class="tc-wrapper">
<article class="video-wrapper">
@@ -68,7 +68,7 @@
<div
id="video_id3"
class="video"
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["xmodule/include/fixtures/test.mp4","xmodule/include/fixtures/test.webm","xmodule/include/fixtures/test.ogv"], "speed": "1.0", "startTime": "", "streams": "0.75:7tqY6eQzVhE,1.0:cogebirgzzM", "sub": "", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "www.youtube.com/iframe_api", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
data-metadata='{"autohideHtml5": "true", "autoplay": "false", "captionDataDir": "", "endTime": "", "generalSpeed": "1.0", "saveStateUrl": "/save_user_state", "savedVideoPosition": "0", "showCaptions": "true", "sources": ["/base/fixtures/test.mp4","/base/fixtures/test.webm","/base/fixtures/test.ogv"], "speed": "1.0", "startTime": "", "streams": "0.75:7tqY6eQzVhE,1.0:cogebirgzzM", "sub": "", "transcriptAvailableTranslationsUrl": "/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English", "de": "Deutsch", "zh": "普通话"}, "transcriptTranslationUrl": "/transcript/translation/__lang__", "ytApiUrl": "/base/fixtures/youtube_iframe_api.js", "ytImageUrl": "", "ytTestTimeout": "1500", "ytMetadataUrl": "www.googleapis.com/youtube/v3/videos/"}'
>
<div class="tc-wrapper">
<article class="video-wrapper">

View File

@@ -36,8 +36,8 @@ lib_paths:
- common_static/js/test/i18n.js
- common_static/coffee/src/ajax_prefix.js
- common_static/js/src/logger.js
- common_static/js/vendor/jasmine-jquery.js
- common_static/js/vendor/jasmine-imagediff.js
- common_static/js/libs/jasmine-waituntil.js
- common_static/js/vendor/requirejs/require.js
- RequireJS-namespace-undefine.js
- common_static/js/vendor/jquery.min.js

Some files were not shown because too many files have changed in this diff Show More