add new text fields to schedule and details settings page
This commit is contained in:
@@ -245,6 +245,10 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
|
||||
self.assertContains(response, "Introducing Your Course")
|
||||
self.assertContains(response, "Course Image")
|
||||
self.assertContains(response, "Course Short Description")
|
||||
self.assertNotContains(response, "Course Title")
|
||||
self.assertNotContains(response, "Course Subtitle")
|
||||
self.assertNotContains(response, "Course Duration")
|
||||
self.assertNotContains(response, "Course Description")
|
||||
self.assertNotContains(response, "Course Overview")
|
||||
self.assertNotContains(response, "Course Introduction Video")
|
||||
self.assertNotContains(response, "Requirements")
|
||||
@@ -355,7 +359,8 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
|
||||
def test_regular_site_fetch(self):
|
||||
settings_details_url = get_url(self.course.id)
|
||||
|
||||
with mock.patch.dict('django.conf.settings.FEATURES', {'ENABLE_MKTG_SITE': False}):
|
||||
with mock.patch.dict('django.conf.settings.FEATURES', {'ENABLE_MKTG_SITE': False,
|
||||
'ENABLE_EXTENDED_COURSE_DETAILS': True}):
|
||||
response = self.client.get_html(settings_details_url)
|
||||
self.assertContains(response, "Course Summary Page")
|
||||
self.assertContains(response, "Send a note to students via email")
|
||||
@@ -369,6 +374,10 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
|
||||
|
||||
self.assertContains(response, "Introducing Your Course")
|
||||
self.assertContains(response, "Course Image")
|
||||
self.assertContains(response, "Course Title")
|
||||
self.assertContains(response, "Course Subtitle")
|
||||
self.assertContains(response, "Course Duration")
|
||||
self.assertContains(response, "Course Description")
|
||||
self.assertContains(response, "Course Short Description")
|
||||
self.assertContains(response, "Course Overview")
|
||||
self.assertContains(response, "Course Introduction Video")
|
||||
|
||||
@@ -976,11 +976,15 @@ def settings_handler(request, course_key_string):
|
||||
'ENABLE_MKTG_SITE',
|
||||
settings.FEATURES.get('ENABLE_MKTG_SITE', False)
|
||||
)
|
||||
enable_extended_course_details = microsite.get_value_for_org(
|
||||
course_module.location.org,
|
||||
'ENABLE_EXTENDED_COURSE_DETAILS',
|
||||
settings.FEATURES.get('ENABLE_EXTENDED_COURSE_DETAILS', False)
|
||||
)
|
||||
|
||||
about_page_editable = not marketing_site_enabled
|
||||
enrollment_end_editable = GlobalStaff().has_user(request.user) or not marketing_site_enabled
|
||||
short_description_editable = settings.FEATURES.get('EDITABLE_SHORT_DESCRIPTION', True)
|
||||
|
||||
self_paced_enabled = SelfPacedConfiguration.current().enabled
|
||||
|
||||
settings_context = {
|
||||
@@ -1001,6 +1005,7 @@ def settings_handler(request, course_key_string):
|
||||
'is_prerequisite_courses_enabled': is_prerequisite_courses_enabled(),
|
||||
'is_entrance_exams_enabled': is_entrance_exams_enabled(),
|
||||
'self_paced_enabled': self_paced_enabled,
|
||||
'enable_extended_course_details': enable_extended_course_details
|
||||
}
|
||||
if is_prerequisite_courses_enabled():
|
||||
courses, in_process_course_actions = get_courses_accessible_to_user(request)
|
||||
|
||||
@@ -12,6 +12,10 @@ var CourseDetails = Backbone.Model.extend({
|
||||
enrollment_start: null,
|
||||
enrollment_end: null,
|
||||
syllabus: null,
|
||||
title: "",
|
||||
subtitle: "",
|
||||
duration: "",
|
||||
description: "",
|
||||
short_description: "",
|
||||
overview: "",
|
||||
intro_video: null,
|
||||
@@ -32,9 +36,30 @@ var CourseDetails = Backbone.Model.extend({
|
||||
newattrs, ["start_date", "end_date", "enrollment_start", "enrollment_end"]
|
||||
);
|
||||
|
||||
if (newattrs.title.length > 50) {
|
||||
errors.title = gettext("The title field must be limited to 50 characters.");
|
||||
}
|
||||
|
||||
if (newattrs.subtitle.length > 150) {
|
||||
errors.subtitle = gettext("The subtitle field must be limited to 150 characters.");
|
||||
}
|
||||
|
||||
if (newattrs.duration.length > 50) {
|
||||
errors.duration = gettext("The duration field must be limited to 50 characters.");
|
||||
}
|
||||
|
||||
if (newattrs.short_description.length > 150) {
|
||||
errors.short_description = gettext("The short description field must be limited to 150 characters.");
|
||||
}
|
||||
|
||||
if (newattrs.description.length > 1000) {
|
||||
errors.description = gettext("The description field must be limited to 1000 characters.");
|
||||
}
|
||||
|
||||
if (newattrs.start_date === null) {
|
||||
errors.start_date = gettext("The course must have an assigned start date.");
|
||||
}
|
||||
|
||||
if (newattrs.start_date && newattrs.end_date && newattrs.start_date >= newattrs.end_date) {
|
||||
errors.end_date = gettext("The course end date must be later than the course start date.");
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ define([
|
||||
course_id : '',
|
||||
run : '',
|
||||
syllabus : null,
|
||||
title: '',
|
||||
subtitle: '',
|
||||
duration: '',
|
||||
description: '',
|
||||
short_description : '',
|
||||
overview : '',
|
||||
intro_video : null,
|
||||
|
||||
@@ -71,6 +71,16 @@ var DetailsView = ValidatingView.extend({
|
||||
this.$el.find('#' + this.fieldToSelectorMap['overview']).val(this.model.get('overview'));
|
||||
this.codeMirrorize(null, $('#course-overview')[0]);
|
||||
|
||||
if (this.model.get('title') !== '') {
|
||||
this.$el.find('#' + this.fieldToSelectorMap.title).val(this.model.get('title'));
|
||||
} else {
|
||||
var displayName = this.$el.find('#' + this.fieldToSelectorMap.title).attr('data-display-name');
|
||||
this.$el.find('#' + this.fieldToSelectorMap.title).val(displayName);
|
||||
}
|
||||
this.$el.find('#' + this.fieldToSelectorMap.subtitle).val(this.model.get('subtitle'));
|
||||
this.$el.find('#' + this.fieldToSelectorMap.duration).val(this.model.get('duration'));
|
||||
this.$el.find('#' + this.fieldToSelectorMap.description).val(this.model.get('description'));
|
||||
|
||||
this.$el.find('#' + this.fieldToSelectorMap['short_description']).val(this.model.get('short_description'));
|
||||
|
||||
this.$el.find('.current-course-introduction-video iframe').attr('src', this.model.videosourceSample());
|
||||
@@ -126,6 +136,10 @@ var DetailsView = ValidatingView.extend({
|
||||
'enrollment_start' : 'enrollment-start',
|
||||
'enrollment_end' : 'enrollment-end',
|
||||
'overview' : 'course-overview',
|
||||
'title': 'course-title',
|
||||
'subtitle': 'course-subtitle',
|
||||
'duration': 'course-duration',
|
||||
'description': 'course-description',
|
||||
'short_description' : 'course-short-description',
|
||||
'intro_video' : 'course-introduction-video',
|
||||
'effort' : "course-effort",
|
||||
@@ -194,9 +208,6 @@ var DetailsView = ValidatingView.extend({
|
||||
|
||||
updateModel: function(event) {
|
||||
switch (event.currentTarget.id) {
|
||||
case 'course-language':
|
||||
this.setField(event);
|
||||
break;
|
||||
case 'course-image-url':
|
||||
this.setField(event);
|
||||
var url = $(event.currentTarget).val();
|
||||
@@ -208,9 +219,6 @@ var DetailsView = ValidatingView.extend({
|
||||
$('#course-image').attr('src', $(event.currentTarget).val());
|
||||
}, 1000);
|
||||
break;
|
||||
case 'course-effort':
|
||||
this.setField(event);
|
||||
break;
|
||||
case 'entrance-exam-enabled':
|
||||
if($(event.currentTarget).is(":checked")){
|
||||
this.$('.div-grade-requirements').show();
|
||||
@@ -228,9 +236,6 @@ var DetailsView = ValidatingView.extend({
|
||||
this.setField(event);
|
||||
}
|
||||
break;
|
||||
case 'course-short-description':
|
||||
this.setField(event);
|
||||
break;
|
||||
case 'pre-requisite-course':
|
||||
var value = $(event.currentTarget).val();
|
||||
value = value == "" ? [] : [value];
|
||||
@@ -257,6 +262,15 @@ var DetailsView = ValidatingView.extend({
|
||||
case 'course-pace-instructor-paced':
|
||||
this.model.set('self_paced', JSON.parse(event.currentTarget.value));
|
||||
break;
|
||||
case 'course-language':
|
||||
case 'course-effort':
|
||||
case 'course-title':
|
||||
case 'course-subtitle':
|
||||
case 'course-duration':
|
||||
case 'course-description':
|
||||
case 'course-short-description':
|
||||
this.setField(event);
|
||||
break;
|
||||
default: // Everything else is handled by datepickers and CodeMirror.
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<script type="text/javascript">
|
||||
window.CMS = window.CMS || {};
|
||||
CMS.URL = CMS.URL || {};
|
||||
CMS.URL.UPLOAD_ASSET = '${upload_asset_url}';
|
||||
CMS.URL.UPLOAD_ASSET = '${upload_asset_url}'
|
||||
</script>
|
||||
</%block>
|
||||
|
||||
@@ -292,9 +292,33 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url}';
|
||||
<span class="tip">${_("Information for prospective students")}</span>
|
||||
</header>
|
||||
<ol class="list-input">
|
||||
|
||||
% if enable_extended_course_details:
|
||||
<li class="field text" id="field-course-title">
|
||||
<label for="course-title">${_("Course Title")}</label>
|
||||
<input type="text" id="course-title" data-display-name="${context_course.display_name}">
|
||||
<span class="tip tip-stacked">${_("Displayed as hero image overlay on the course details page. Limit to 50 characters.")}</span>
|
||||
</li>
|
||||
<li class="field text" id="field-course-subtitle">
|
||||
<label for="course-subtitle">${_("Course Subtitle")}</label>
|
||||
<input type="text" id="course-subtitle">
|
||||
<span class="tip tip-stacked">${_("Displayed as hero image overlay on the course details page below the Course Title in a smaller font. Limit to 150 characters.")}</span>
|
||||
</li>
|
||||
<li class="field text" id="field-course-duration">
|
||||
<label for="course-duration">${_("Course Duration")}</label>
|
||||
<input type="text" id="course-duration">
|
||||
<span class="tip tip-stacked">${_("Displayed on the course details page below the hero image. Limit to 50 characters.")}</span>
|
||||
</li>
|
||||
<li class="field text" id="field-course-description">
|
||||
<label for="course-description">${_("Course Description")}</label>
|
||||
<textarea class="text" id="course-description"></textarea>
|
||||
<span class="tip tip-stacked">${_("Displayed on the course details page. Limit to 1000 characters.")}</span>
|
||||
</li>
|
||||
% endif
|
||||
|
||||
% if short_description_editable:
|
||||
<li class="field text" id="field-course-short-description">
|
||||
<label for="course-overview">${_("Course Short Description")}</label>
|
||||
<label for="course-short-description">${_("Course Short Description")}</label>
|
||||
<textarea class="text" id="course-short-description"></textarea>
|
||||
<span class="tip tip-stacked">${_("Appears on the course catalog page when students roll over the course name. Limit to ~150 characters")}</span>
|
||||
</li>
|
||||
@@ -315,7 +339,7 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url}';
|
||||
% endif
|
||||
|
||||
<li class="field image" id="field-course-image">
|
||||
<label>${_("Course Image")}</label>
|
||||
<label for="course-image-url">${_("Course Image")}</label>
|
||||
<div class="current current-course-image">
|
||||
% if context_course.course_image:
|
||||
<span class="wrapper-course-image">
|
||||
@@ -346,7 +370,7 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url}';
|
||||
|
||||
% if about_page_editable:
|
||||
<li class="field video" id="field-course-introduction-video">
|
||||
<label for="course-overview">${_("Course Introduction Video")}</label>
|
||||
<label for="course-introduction-video">${_("Course Introduction Video")}</label>
|
||||
<div class="input input-existing">
|
||||
<div class="current current-course-introduction-video">
|
||||
<iframe width="618" height="350" title="${_('Course Introduction Video')}" src="" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
@@ -475,3 +475,36 @@ class ContentLicenseTest(StudioCourseTest):
|
||||
# The course_license text will include a bunch of screen reader text to explain
|
||||
# the selected options
|
||||
self.assertIn("Some Rights Reserved", self.lms_courseware.course_license)
|
||||
|
||||
|
||||
@attr('a11y')
|
||||
class StudioSettingsA11yTest(StudioCourseTest):
|
||||
|
||||
"""
|
||||
Class to test Studio pages accessibility.
|
||||
"""
|
||||
|
||||
def setUp(self): # pylint: disable=arguments-differ
|
||||
super(StudioSettingsA11yTest, self).setUp()
|
||||
self.settings_page = SettingsPage(self.browser, self.course_info['org'], self.course_info['number'],
|
||||
self.course_info['run'])
|
||||
|
||||
def test_studio_settings_page_a11y(self):
|
||||
"""
|
||||
Check accessibility of SettingsPage.
|
||||
"""
|
||||
self.settings_page.visit()
|
||||
self.settings_page.wait_for_page()
|
||||
|
||||
# There are several existing color contrast errors on this page,
|
||||
# we will ignore this error in the test until we fix them.
|
||||
self.settings_page.a11y_audit.config.set_rules({
|
||||
"ignore": [
|
||||
'color-contrast', # TODO: AC-225
|
||||
'link-href', # TODO: AC-226
|
||||
'nav-aria-label', # TODO: AC-227
|
||||
'icon-aria-hidden', # TODO: AC-229
|
||||
],
|
||||
})
|
||||
|
||||
self.settings_page.a11y_audit.check_for_accessibility_errors()
|
||||
|
||||
@@ -18,6 +18,10 @@ from xmodule.modulestore.django import modulestore
|
||||
# handled separately; its value maps to an alternate key name.
|
||||
ABOUT_ATTRIBUTES = [
|
||||
'syllabus',
|
||||
'title',
|
||||
'subtitle',
|
||||
'duration',
|
||||
'description',
|
||||
'short_description',
|
||||
'overview',
|
||||
'effort',
|
||||
@@ -43,6 +47,10 @@ class CourseDetails(object):
|
||||
self.enrollment_start = None
|
||||
self.enrollment_end = None
|
||||
self.syllabus = None # a pdf file asset
|
||||
self.title = ""
|
||||
self.subtitle = ""
|
||||
self.duration = ""
|
||||
self.description = ""
|
||||
self.short_description = ""
|
||||
self.overview = "" # html to render as the overview
|
||||
self.intro_video = None # a video pointer
|
||||
|
||||
Reference in New Issue
Block a user