fix: eslint autofixable issues (#32181)

* fix: eslint operator-linebreak issue

* fix: eslint quotes issue

* fix: react jsx indent and props issues

* fix: eslint trailing spaces issues

* fix: eslint line around directives issue

* fix: eslint semi rule

* fix: eslint newline per chain rule

* fix: eslint space infix ops rule

* fix: eslint space-in-parens issue

* fix: eslint space before function paren issue

* fix: eslint space before blocks issue

* fix: eslint arrow body style issue

* fix: eslint dot-location issue

* fix: eslint quotes issue

* fix: eslint quote props issue

* fix: eslint operator assignment issue

* fix: eslint new line after import issue

* fix: indent issues

* fix: operator assignment issue

* fix: all autofixable eslint issues

* fix: all react related fixable issues

* fix: autofixable eslint issues

* chore: remove all template literals

* fix: remaining autofixable issues

* fix: failing js test
This commit is contained in:
Syed Ali Abbas Zaidi
2023-05-18 11:03:59 +05:00
committed by GitHub
parent f2daf37d4a
commit d7053a6783
140 changed files with 849 additions and 833 deletions

View File

@@ -49,7 +49,6 @@
"import/no-dynamic-require": "off", "import/no-dynamic-require": "off",
"import/no-unresolved": "off", "import/no-unresolved": "off",
"max-len": "off", "max-len": "off",
"newline-per-chained-call": "off",
"no-console": "off", "no-console": "off",
"no-lonely-if": "off", "no-lonely-if": "off",
"no-param-reassign": "off", "no-param-reassign": "off",
@@ -73,7 +72,6 @@
"radix": "off", "radix": "off",
"react/jsx-indent-props": ["error", 4], "react/jsx-indent-props": ["error", 4],
"react/prop-types": "off", "react/prop-types": "off",
"semi": "off",
"vars-on-top": "off" "vars-on-top": "off"
} }
} }

View File

@@ -1,5 +1,3 @@
jasmine.getFixtures().fixturesPath = '/base/templates';
import 'common/js/spec_helpers/jasmine-extensions'; import 'common/js/spec_helpers/jasmine-extensions';
import 'common/js/spec_helpers/jasmine-stealth'; import 'common/js/spec_helpers/jasmine-stealth';
import 'common/js/spec_helpers/jasmine-waituntil'; import 'common/js/spec_helpers/jasmine-waituntil';
@@ -12,11 +10,6 @@ import _ from 'underscore';
import str from 'underscore.string'; import str from 'underscore.string';
import HtmlUtils from 'edx-ui-toolkit/js/utils/html-utils'; import HtmlUtils from 'edx-ui-toolkit/js/utils/html-utils';
import StringUtils from 'edx-ui-toolkit/js/utils/string-utils'; import StringUtils from 'edx-ui-toolkit/js/utils/string-utils';
window._ = _;
window._.str = str;
window.edx = window.edx || {};
window.edx.HtmlUtils = HtmlUtils;
window.edx.StringUtils = StringUtils;
// These are the tests that will be run // These are the tests that will be run
import './xblock/cms.runtime.v1_spec.js'; import './xblock/cms.runtime.v1_spec.js';
@@ -31,4 +24,12 @@ import '../../../js/spec/views/pages/course_outline_spec.js';
import '../../../js/spec/views/xblock_editor_spec.js'; import '../../../js/spec/views/xblock_editor_spec.js';
import '../../../js/spec/views/xblock_string_field_editor_spec.js'; import '../../../js/spec/views/xblock_string_field_editor_spec.js';
jasmine.getFixtures().fixturesPath = '/base/templates';
window._ = _;
window._.str = str;
window.edx = window.edx || {};
window.edx.HtmlUtils = HtmlUtils;
window.edx.StringUtils = StringUtils;
window.__karma__.start(); // eslint-disable-line no-underscore-dangle window.__karma__.start(); // eslint-disable-line no-underscore-dangle

View File

@@ -2,8 +2,8 @@
// http://tobyho.com/2012/01/30/write-a-jasmine-matcher/ // http://tobyho.com/2012/01/30/write-a-jasmine-matcher/
define(['jquery'], function($) { // eslint-disable-line no-unused-vars define(['jquery'], function($) { // eslint-disable-line no-unused-vars
'use strict'; 'use strict';
return function() { return function() {
jasmine.addMatchers({ jasmine.addMatchers({

View File

@@ -64,16 +64,16 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel
it('course mode selection updating the link successfully', function() { it('course mode selection updating the link successfully', function() {
selectDropDownByText(this.view.$(SELECTORS.course_modes), 'test1'); selectDropDownByText(this.view.$(SELECTORS.course_modes), 'test1');
expect(this.view.$(SELECTORS.preview_certificate).attr('href')). expect(this.view.$(SELECTORS.preview_certificate).attr('href'))
toEqual('/users/1/courses/orgX/009/2016?preview=test1'); .toEqual('/users/1/courses/orgX/009/2016?preview=test1');
selectDropDownByText(this.view.$(SELECTORS.course_modes), 'test2'); selectDropDownByText(this.view.$(SELECTORS.course_modes), 'test2');
expect(this.view.$(SELECTORS.preview_certificate).attr('href')). expect(this.view.$(SELECTORS.preview_certificate).attr('href'))
toEqual('/users/1/courses/orgX/009/2016?preview=test2'); .toEqual('/users/1/courses/orgX/009/2016?preview=test2');
selectDropDownByText(this.view.$(SELECTORS.course_modes), 'test3'); selectDropDownByText(this.view.$(SELECTORS.course_modes), 'test3');
expect(this.view.$(SELECTORS.preview_certificate).attr('href')). expect(this.view.$(SELECTORS.preview_certificate).attr('href'))
toEqual('/users/1/courses/orgX/009/2016?preview=test3'); .toEqual('/users/1/courses/orgX/009/2016?preview=test3');
}); });
it('toggle certificate activation event works fine', function() { it('toggle certificate activation event works fine', function() {

View File

@@ -21,6 +21,6 @@ export default function ContainerFactory(componentTemplates, XBlockInfoJson, act
var view = new ContainerPage(_.extend(main_options, options)); var view = new ContainerPage(_.extend(main_options, options));
view.render(); view.render();
}); });
}; }
export {ContainerFactory} export {ContainerFactory};

View File

@@ -1,3 +1,3 @@
import * as ContextCourse from 'js/models/course'; import * as ContextCourse from 'js/models/course';
export {ContextCourse} export {ContextCourse};

View File

@@ -21,6 +21,6 @@ export default function EditTabsFactory(courseLocation, explicitUrl) {
mast: $('.wrapper-mast') mast: $('.wrapper-mast')
}); });
}); });
}; }
export {EditTabsFactory} export {EditTabsFactory};

View File

@@ -24,6 +24,6 @@ export default function LibraryFactory(componentTemplates, XBlockInfoJson, optio
var view = new PagedContainerPage(_.extend(main_options, options)); var view = new PagedContainerPage(_.extend(main_options, options));
view.render(); view.render();
}); });
}; }
export {LibraryFactory} export {LibraryFactory};

View File

@@ -16,9 +16,9 @@ define([
// Toggle collapsibles when trigger is clicked // Toggle collapsibles when trigger is clicked
$('.collapsible .collapsible-trigger').click(function() { $('.collapsible .collapsible-trigger').click(function() {
const contentId = this.id.replace('-trigger', '-content') const contentId = this.id.replace('-trigger', '-content');
$(`#${contentId}`).toggleClass('collapsed') $(`#${contentId}`).toggleClass('collapsed');
}) });
model = new CourseDetailsModel(); model = new CourseDetailsModel();
model.urlRoot = detailsUrl; model.urlRoot = detailsUrl;

View File

@@ -19,6 +19,6 @@ export default function TextbooksFactory(textbooksJson) {
return gettext('You have unsaved changes. Do you really want to leave this page?'); return gettext('You have unsaved changes. Do you really want to leave this page?');
} }
}); });
}; }
export {TextbooksFactory} export {TextbooksFactory};

View File

@@ -16,6 +16,6 @@ export default function XBlockValidationFactory(validationMessages, hasEditingUr
if (!model.get('empty')) { if (!model.get('empty')) {
new XBlockValidationView({el: validationEle, model: model, root: isRoot}).render(); new XBlockValidationView({el: validationEle, model: model, root: isRoot}).render();
} }
}; }
export {XBlockValidationFactory} export {XBlockValidationFactory};

View File

@@ -10,7 +10,7 @@ define(['backbone', 'js/models/location', 'js/collections/course_grader', 'edx-u
grace_period: null, // either null or { hours: n, minutes: m, ...} grace_period: null, // either null or { hours: n, minutes: m, ...}
minimum_grade_credit: null, // either null or percentage minimum_grade_credit: null, // either null or percentage
assignment_count_info: [], // Object with keys mapping assignment type names to a list of assignment_count_info: [], // Object with keys mapping assignment type names to a list of
//assignment display names // assignment display names
}, },
parse: function(attributes) { parse: function(attributes) {
if (attributes.graders) { if (attributes.graders) {

View File

@@ -4,7 +4,7 @@ import 'jquery.smoothScroll';
'use strict'; 'use strict';
var toggleSock = function (e) { var toggleSock = function(e) {
e.preventDefault(); e.preventDefault();
var $btnShowSockLabel = $(this).find('.copy-show'); var $btnShowSockLabel = $(this).find('.copy-show');
@@ -33,9 +33,9 @@ var toggleSock = function (e) {
}); });
}; };
domReady(function () { domReady(function() {
// toggling footer additional support // toggling footer additional support
$('.cta-show-sock').bind('click', toggleSock); $('.cta-show-sock').bind('click', toggleSock);
}); });
export {toggleSock} export {toggleSock};

View File

@@ -147,7 +147,7 @@ define(['js/views/license', 'js/models/license', 'common/js/spec_helpers/templat
this.view = new LicenseView({model: this.model, showPreview: true}); this.view = new LicenseView({model: this.model, showPreview: true});
this.view.render(); this.view.render();
expect(this.view.$('.license-preview').length).toEqual(1); expect(this.view.$('.license-preview').length).toEqual(1);
// Expect default text to be "All Rights Reserved" // Expect default text to be "All Rights Reserved"
expect(this.view.$('.license-preview')).toContainText('All Rights Reserved'); expect(this.view.$('.license-preview')).toContainText('All Rights Reserved');
this.view.$('li[data-license=creative-commons] button').click(); this.view.$('li[data-license=creative-commons] button').click();
expect(this.view.$('.license-preview').length).toEqual(1); expect(this.view.$('.license-preview').length).toEqual(1);

View File

@@ -64,7 +64,7 @@ describe('ModuleEdit', function() {
}); });
}); });
describe('render', function() { describe('render', function() {
beforeEach(function () { beforeEach(function() {
edit_helpers.installEditTemplates(true); edit_helpers.installEditTemplates(true);
spyOn(this.moduleEdit, 'loadDisplay'); spyOn(this.moduleEdit, 'loadDisplay');
spyOn(this.moduleEdit, 'delegateEvents'); spyOn(this.moduleEdit, 'delegateEvents');

View File

@@ -343,15 +343,15 @@ describe('Container Subviews', function() {
it('renders the last published date and user when there are no changes', function() { it('renders the last published date and user when there are no changes', function() {
renderContainerPage(this, mockContainerXBlockHtml); renderContainerPage(this, mockContainerXBlockHtml);
fetch({published_on: 'Jul 01, 2014 at 12:45 UTC', published_by: 'amako'}); fetch({published_on: 'Jul 01, 2014 at 12:45 UTC', published_by: 'amako'});
expect(containerPage.$(lastDraftCss).text()). expect(containerPage.$(lastDraftCss).text())
toContain('Last published Jul 01, 2014 at 12:45 UTC by amako'); .toContain('Last published Jul 01, 2014 at 12:45 UTC by amako');
}); });
it('renders the last saved date and user when there are changes', function() { it('renders the last saved date and user when there are changes', function() {
renderContainerPage(this, mockContainerXBlockHtml); renderContainerPage(this, mockContainerXBlockHtml);
fetch({has_changes: true, edited_on: 'Jul 02, 2014 at 14:20 UTC', edited_by: 'joe'}); fetch({has_changes: true, edited_on: 'Jul 02, 2014 at 14:20 UTC', edited_by: 'joe'});
expect(containerPage.$(lastDraftCss).text()). expect(containerPage.$(lastDraftCss).text())
toContain('Draft saved on Jul 02, 2014 at 14:20 UTC by joe'); .toContain('Draft saved on Jul 02, 2014 at 14:20 UTC by joe');
}); });
describe('Release Date', function() { describe('Release Date', function() {
@@ -596,8 +596,8 @@ describe('Container Subviews', function() {
fetch({ fetch({
published: true, published_on: 'Jul 01, 2014 at 12:45 UTC', published_by: 'amako' published: true, published_on: 'Jul 01, 2014 at 12:45 UTC', published_by: 'amako'
}); });
expect(containerPage.$(lastPublishCss).text()). expect(containerPage.$(lastPublishCss).text())
toContain('Last published Jul 01, 2014 at 12:45 UTC by amako'); .toContain('Last published Jul 01, 2014 at 12:45 UTC by amako');
}); });
it('renders correctly when the block is published without publish info', function() { it('renders correctly when the block is published without publish info', function() {

View File

@@ -14,7 +14,7 @@ describe('CourseOutlinePage', function() {
selectVisibilitySettings, selectDiscussionSettings, selectAdvancedSettings, createMockCourseJSON, createMockSectionJSON, selectVisibilitySettings, selectDiscussionSettings, selectAdvancedSettings, createMockCourseJSON, createMockSectionJSON,
createMockSubsectionJSON, verifyTypePublishable, mockCourseJSON, mockEmptyCourseJSON, setSelfPaced, setSelfPacedCustomPLS, createMockSubsectionJSON, verifyTypePublishable, mockCourseJSON, mockEmptyCourseJSON, setSelfPaced, setSelfPacedCustomPLS,
mockSingleSectionCourseJSON, createMockVerticalJSON, createMockIndexJSON, mockCourseEntranceExamJSON, mockSingleSectionCourseJSON, createMockVerticalJSON, createMockIndexJSON, mockCourseEntranceExamJSON,
selectOnboardingExam, createMockCourseJSONWithReviewRules,mockCourseJSONWithReviewRules, selectOnboardingExam, createMockCourseJSONWithReviewRules, mockCourseJSONWithReviewRules,
mockOutlinePage = readFixtures('templates/mock/mock-course-outline-page.underscore'), mockOutlinePage = readFixtures('templates/mock/mock-course-outline-page.underscore'),
mockRerunNotification = readFixtures('templates/mock/mock-course-rerun-notification.underscore'); mockRerunNotification = readFixtures('templates/mock/mock-course-rerun-notification.underscore');
@@ -210,7 +210,7 @@ describe('CourseOutlinePage', function() {
setSelfPacedCustomPLS = function() { setSelfPacedCustomPLS = function() {
setSelfPaced(); setSelfPaced();
course.set('is_custom_relative_dates_active', true); course.set('is_custom_relative_dates_active', true);
} };
createCourseOutlinePage = function(test, courseJSON, createOnly) { createCourseOutlinePage = function(test, courseJSON, createOnly) {
requests = AjaxHelpers.requests(test); requests = AjaxHelpers.requests(test);
@@ -1458,7 +1458,7 @@ describe('CourseOutlinePage', function() {
$('.wrapper-modal-window .action-save').click(); $('.wrapper-modal-window .action-save').click();
}); });
it('can select the onboarding exam when a course supports onboarding', function () { it('can select the onboarding exam when a course supports onboarding', function() {
var mockCourseWithSpecialExamJSON = createMockCourseJSON({}, [ var mockCourseWithSpecialExamJSON = createMockCourseJSON({}, [
createMockSectionJSON({ createMockSectionJSON({
has_changes: true, has_changes: true,
@@ -2191,7 +2191,7 @@ describe('CourseOutlinePage', function() {
expect($modalWindow.find('.outline-subsection')).not.toExist(); expect($modalWindow.find('.outline-subsection')).not.toExist();
}); });
describe('Self Paced with Custom Personalized Learner Schedules (PLS)', function () { describe('Self Paced with Custom Personalized Learner Schedules (PLS)', function() {
beforeEach(function() { beforeEach(function() {
var mockCourseJSON = createMockCourseJSON({}, [ var mockCourseJSON = createMockCourseJSON({}, [
createMockSectionJSON({}, [ createMockSectionJSON({}, [
@@ -2210,7 +2210,7 @@ describe('CourseOutlinePage', function() {
selectRelativeWeeksSubsection = function(weeks) { selectRelativeWeeksSubsection = function(weeks) {
$('#due_in').val(weeks).trigger('keyup'); $('#due_in').val(weeks).trigger('keyup');
} };
mockCustomPacingServerValuesJson = createMockSectionJSON({ mockCustomPacingServerValuesJson = createMockSectionJSON({
release_date: 'Jan 01, 2970 at 05:00 UTC' release_date: 'Jan 01, 2970 at 05:00 UTC'
@@ -2235,7 +2235,7 @@ describe('CourseOutlinePage', function() {
]) ])
]); ]);
it('can show correct editors for self_paced course with custom pacing', function (){ it('can show correct editors for self_paced course with custom pacing', function() {
outlinePage.$('.outline-subsection .configure-button').click(); outlinePage.$('.outline-subsection .configure-button').click();
expect($('.edit-settings-release').length).toBe(0); expect($('.edit-settings-release').length).toBe(0);
// Due date input exists for custom pacing self paced courses // Due date input exists for custom pacing self paced courses
@@ -2295,7 +2295,7 @@ describe('CourseOutlinePage', function() {
expectShowCorrectness('never'); expectShowCorrectness('never');
}); });
it ('does not show relative date input when assignment is not graded', function() { it('does not show relative date input when assignment is not graded', function() {
outlinePage.$('.outline-subsection .configure-button').click(); outlinePage.$('.outline-subsection .configure-button').click();
$('#grading_type').val('Lab').trigger('change'); $('#grading_type').val('Lab').trigger('change');
$('#due_in').val('').trigger('change'); $('#due_in').val('').trigger('change');
@@ -2304,7 +2304,7 @@ describe('CourseOutlinePage', function() {
$('#grading_type').val('notgraded').trigger('change'); $('#grading_type').val('notgraded').trigger('change');
$('#due_in').val('').trigger('change'); $('#due_in').val('').trigger('change');
expect($('#relative_date_input').css('display')).toBe('none'); expect($('#relative_date_input').css('display')).toBe('none');
}) });
it('shows validation error on relative date', function() { it('shows validation error on relative date', function() {
outlinePage.$('.outline-subsection .configure-button').click(); outlinePage.$('.outline-subsection .configure-button').click();
@@ -2371,7 +2371,7 @@ describe('CourseOutlinePage', function() {
'Contains staff only content' 'Contains staff only content'
); );
}); });
}) });
}); });
// Note: most tests for units can be found in Bok Choy // Note: most tests for units can be found in Bok Choy
@@ -2470,13 +2470,12 @@ describe('CourseOutlinePage', function() {
expect(messages).toContainText('Contains staff only content'); expect(messages).toContainText('Contains staff only content');
}); });
describe('discussion settings', function () { describe('discussion settings', function() {
it('hides discussion settings if unit level discussions are disabled', function() { it('hides discussion settings if unit level discussions are disabled', function() {
getUnitStatus({}, {unit_level_discussions: false}); getUnitStatus({}, {unit_level_discussions: false});
outlinePage.$('.outline-unit .configure-button').click(); outlinePage.$('.outline-unit .configure-button').click();
expect($('.modal-section .edit-discussion')).not.toExist(); expect($('.modal-section .edit-discussion')).not.toExist();
}); });
}); });
verifyTypePublishable('unit', function(options) { verifyTypePublishable('unit', function(options) {

View File

@@ -110,8 +110,8 @@ define(['jquery', 'js/models/xblock_validation', 'js/views/xblock_validation', '
it('renders action info', function() { it('renders action info', function() {
expect(view.$('a.edit-button .action-button-text').text()).toContain('Summary Action'); expect(view.$('a.edit-button .action-button-text').text()).toContain('Summary Action');
expect(view.$('a.notification-action-button .action-button-text').text()). expect(view.$('a.notification-action-button .action-button-text').text())
toContain('First Message Action'); .toContain('First Message Action');
expect(view.$('a.notification-action-button').data('notification-action')).toBe('fix-up'); expect(view.$('a.notification-action-button').data('notification-action')).toBe('fix-up');
}); });

View File

@@ -138,4 +138,4 @@ export {
installEditTemplates, installEditTemplates,
showEditModal, showEditModal,
verifyXBlockRequest, verifyXBlockRequest,
} };

View File

@@ -1,66 +1,67 @@
define([ define([
"jquery", 'jquery',
"underscore", 'underscore',
"backbone", 'backbone',
"js/views/utils/xblock_utils", 'js/views/utils/xblock_utils',
"js/utils/templates", 'js/utils/templates',
"js/views/modals/course_outline_modals", 'js/views/modals/course_outline_modals',
"edx-ui-toolkit/js/utils/html-utils", 'edx-ui-toolkit/js/utils/html-utils',
], function ($, _, Backbone, XBlockViewUtils, TemplateUtils, CourseOutlineModalsFactory, HtmlUtils) { ], function($, _, Backbone, XBlockViewUtils, TemplateUtils, CourseOutlineModalsFactory, HtmlUtils) {
"use strict"; 'use strict';
var CourseVideoSharingEnableView = Backbone.View.extend({
events: {
"change #video-sharing-configuration-options": "handleVideoSharingConfigurationChange",
},
initialize: function () { var CourseVideoSharingEnableView = Backbone.View.extend({
this.template = TemplateUtils.loadTemplate("course-video-sharing-enable"); events: {
}, 'change #video-sharing-configuration-options': 'handleVideoSharingConfigurationChange',
getRequestData: function (value) {
return {
metadata: {
'video_sharing_options': value,
}, },
};
},
handleVideoSharingConfigurationChange: function (event) { initialize: function() {
if (event.type === "change") { this.template = TemplateUtils.loadTemplate('course-video-sharing-enable');
event.preventDefault(); },
this.updateVideoSharingConfiguration(event.target.value);
this.trackVideoSharingConfigurationChange(event.target.value);
}
},
updateVideoSharingConfiguration: function (value) { getRequestData: function(value) {
XBlockViewUtils.updateXBlockFields(this.model, this.getRequestData(value), { return {
success: this.refresh.bind(this) metadata: {
}); video_sharing_options: value,
}, },
};
},
trackVideoSharingConfigurationChange: function (value) { handleVideoSharingConfigurationChange: function(event) {
window.analytics.track( if (event.type === 'change') {
'edx.social.video_sharing_options.changed', event.preventDefault();
{ this.updateVideoSharingConfiguration(event.target.value);
course_id: this.model.id, this.trackVideoSharingConfigurationChange(event.target.value);
video_sharing_options: value }
} },
);
},
refresh: function () { updateVideoSharingConfiguration: function(value) {
this.model.fetch({ XBlockViewUtils.updateXBlockFields(this.model, this.getRequestData(value), {
success: this.render.bind(this), success: this.refresh.bind(this)
}); });
}, },
render: function () { trackVideoSharingConfigurationChange: function(value) {
var html = this.template(this.model.attributes); window.analytics.track(
HtmlUtils.setHtml(this.$el, HtmlUtils.HTML(html)); 'edx.social.video_sharing_options.changed',
return this; {
}, course_id: this.model.id,
}); video_sharing_options: value
}
);
},
return CourseVideoSharingEnableView; refresh: function() {
this.model.fetch({
success: this.render.bind(this),
});
},
render: function() {
var html = this.template(this.model.attributes);
HtmlUtils.setHtml(this.$el, HtmlUtils.HTML(html));
return this;
},
});
return CourseVideoSharingEnableView;
}); });

View File

@@ -313,7 +313,7 @@ define(
updateUrlFieldVisibility: function() { updateUrlFieldVisibility: function() {
const urlContainer = this.$el.find('.public-access-block-url-container'); const urlContainer = this.$el.find('.public-access-block-url-container');
if(this.getValueFromEditor()) { if (this.getValueFromEditor()) {
urlContainer.removeClass('is-hidden'); urlContainer.removeClass('is-hidden');
} else { } else {
urlContainer.addClass('is-hidden'); urlContainer.addClass('is-hidden');

View File

@@ -408,11 +408,11 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
if (!this.getValue() || !course.get('start')) { return; } if (!this.getValue() || !course.get('start')) { return; }
var startDate = new Date(course.get('start')); var startDate = new Date(course.get('start'));
// The value returned by toUTCString() is a string in the form Www, dd Mmm yyyy hh:mm:ss GMT // The value returned by toUTCString() is a string in the form Www, dd Mmm yyyy hh:mm:ss GMT
var startDateList = startDate.toUTCString().split(' ') var startDateList = startDate.toUTCString().split(' ');
// This text will look like Mmm dd, yyyy (i.e. Jul 26, 2021) // This text will look like Mmm dd, yyyy (i.e. Jul 26, 2021)
this.$('#relative_weeks_due_start_date').text(startDateList[2] + ' ' + startDateList[1] + ', ' + startDateList[3]); this.$('#relative_weeks_due_start_date').text(startDateList[2] + ' ' + startDateList[1] + ', ' + startDateList[3]);
var projectedDate = new Date(startDate) var projectedDate = new Date(startDate);
projectedDate.setDate(projectedDate.getDate() + this.getValue()*7); projectedDate.setDate(projectedDate.getDate() + this.getValue() * 7);
var projectedDateList = projectedDate.toUTCString().split(' '); var projectedDateList = projectedDate.toUTCString().split(' ');
this.$('#relative_weeks_due_projected_due_in').text(projectedDateList[2] + ' ' + projectedDateList[1] + ', ' + projectedDateList[3]); this.$('#relative_weeks_due_projected_due_in').text(projectedDateList[2] + ' ' + projectedDateList[1] + ', ' + projectedDateList[3]);
this.$('#relative_weeks_due_projected').show(); this.$('#relative_weeks_due_projected').show();
@@ -433,9 +433,9 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
afterRender: function() { afterRender: function() {
AbstractEditor.prototype.afterRender.call(this); AbstractEditor.prototype.afterRender.call(this);
if (this.model.get('graded')) { if (this.model.get('graded')) {
this.$('#relative_date_input').show() this.$('#relative_date_input').show();
} else { } else {
this.$('#relative_date_input').hide() this.$('#relative_date_input').hide();
} }
this.$('.field-due-in input').val(this.model.get('relative_weeks_due')); this.$('.field-due-in input').val(this.model.get('relative_weeks_due'));
this.$('#relative_weeks_due_projected').hide(); this.$('#relative_weeks_due_projected').hide();
@@ -444,12 +444,12 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
getRequestData: function() { getRequestData: function() {
// Grab all the sections, map them to their block_ids, then return as an Array // Grab all the sections, map them to their block_ids, then return as an Array
var sectionIds = $('.outline-section').map(function(){ return this.id; }).get() var sectionIds = $('.outline-section').map(function() { return this.id; }).get();
// Grab all the subsections, map them to their block_ids, then return as an Array // Grab all the subsections, map them to their block_ids, then return as an Array
var subsectionIds = $('.outline-subsection').map(function(){ return this.id; }).get() var subsectionIds = $('.outline-subsection').map(function() { return this.id; }).get();
var relative_weeks_due = null; var relative_weeks_due = null;
if (this.getValue() > 0 && $('#grading_type').val() !== 'notgraded') { if (this.getValue() > 0 && $('#grading_type').val() !== 'notgraded') {
relative_weeks_due = this.getValue() relative_weeks_due = this.getValue();
} }
window.analytics.track('edx.bi.studio.relative_date.saved', { window.analytics.track('edx.bi.studio.relative_date.saved', {
block_id: this.model.get('id'), block_id: this.model.get('id'),
@@ -944,16 +944,16 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
showTipText: function() { showTipText: function() {
if (this.model.get('published')) { if (this.model.get('published')) {
$('.un-published-tip').hide() $('.un-published-tip').hide();
} else { } else {
$('.un-published-tip').show() $('.un-published-tip').show();
} }
let enabledForGraded = course.get('discussions_settings').enable_graded_units let enabledForGraded = course.get('discussions_settings').enable_graded_units;
if (this.model.get('graded') && !enabledForGraded) { if (this.model.get('graded') && !enabledForGraded) {
$('#discussion_enabled').prop('disabled', true); $('#discussion_enabled').prop('disabled', true);
$('.graded-tip').show() $('.graded-tip').show();
} else { } else {
$('.graded-tip').hide() $('.graded-tip').hide();
} }
}, },

View File

@@ -109,7 +109,7 @@ function($, _, ViewUtils, ContainerView, ModuleUtils, gettext, NotificationView,
if (originalDone) { if (originalDone) {
originalDone(); originalDone();
} }
} };
self.handleXBlockFragment(fragment, options); self.handleXBlockFragment(fragment, options);
} }
}); });

View File

@@ -265,15 +265,15 @@ function($, _, Backbone, gettext, BasePage, ViewUtils, ContainerView, XBlockView
editXBlock: function(event, options) { editXBlock: function(event, options) {
event.preventDefault(); event.preventDefault();
if(!options || options.view !== 'visibility_view' ){ if (!options || options.view !== 'visibility_view') {
const primaryHeader = $(event.target).closest('.xblock-header-primary') const primaryHeader = $(event.target).closest('.xblock-header-primary');
var useNewTextEditor = primaryHeader.attr('use-new-editor-text'), var useNewTextEditor = primaryHeader.attr('use-new-editor-text'),
useNewVideoEditor = primaryHeader.attr('use-new-editor-video'), useNewVideoEditor = primaryHeader.attr('use-new-editor-video'),
useNewProblemEditor = primaryHeader.attr('use-new-editor-problem'), useNewProblemEditor = primaryHeader.attr('use-new-editor-problem'),
blockType = primaryHeader.attr('data-block-type'); blockType = primaryHeader.attr('data-block-type');
if( (useNewTextEditor === 'True' && blockType === 'html') if((useNewTextEditor === 'True' && blockType === 'html')
|| (useNewVideoEditor === 'True' && blockType === 'video') || (useNewVideoEditor === 'True' && blockType === 'video')
|| (useNewProblemEditor === 'True' && blockType === 'problem') || (useNewProblemEditor === 'True' && blockType === 'problem')
) { ) {
@@ -476,13 +476,13 @@ function($, _, Backbone, gettext, BasePage, ViewUtils, ContainerView, XBlockView
useNewProblemEditor = this.$('.xblock-header-primary').attr('use-new-editor-problem'); useNewProblemEditor = this.$('.xblock-header-primary').attr('use-new-editor-problem');
// find the block type in the locator if availible // find the block type in the locator if availible
if(data.hasOwnProperty('locator')){ if(data.hasOwnProperty('locator')) {
var matchBlockTypeFromLocator = /\@(.*?)\+/; var matchBlockTypeFromLocator = /\@(.*?)\+/;
var blockType = data.locator.match(matchBlockTypeFromLocator); var blockType = data.locator.match(matchBlockTypeFromLocator);
} }
if((useNewTextEditor === 'True' && blockType.includes('html')) if((useNewTextEditor === 'True' && blockType.includes('html'))
|| (useNewVideoEditor === 'True' && blockType.includes('video')) || (useNewVideoEditor === 'True' && blockType.includes('video'))
||(useNewProblemEditor === 'True' && blockType.includes('problem')) || (useNewProblemEditor === 'True' && blockType.includes('problem'))
){ ){
var destinationUrl = this.$('.xblock-header-primary').attr('authoring_MFE_base_url') + '/' + blockType[1] + '/' + encodeURI(data.locator); var destinationUrl = this.$('.xblock-header-primary').attr('authoring_MFE_base_url') + '/' + blockType[1] + '/' + encodeURI(data.locator);
window.location.href = destinationUrl; window.location.href = destinationUrl;

View File

@@ -125,7 +125,7 @@ function($, _, gettext, BasePage, XBlockViewUtils, CourseOutlineView, ViewUtils,
* at 100 millisecond intervals until element is found or * at 100 millisecond intervals until element is found or
* Polling is reached * Polling is reached
*/ */
scrollToElement: function () { scrollToElement: function() {
this.findElementPollingTimeout -= this.pollingDelay; this.findElementPollingTimeout -= this.pollingDelay;
const elementID = window.location.hash.replace('#', ''); const elementID = window.location.hash.replace('#', '');

View File

@@ -75,7 +75,7 @@ function(ValidatingView, _, $, ui, GraderView, StringUtils, HtmlUtils) {
this); this);
gradeCollection.each(function(gradeModel) { gradeCollection.each(function(gradeModel) {
var graderType = gradeModel.get('type'); var graderType = gradeModel.get('type');
var graderTypeAssignmentList = self.courseAssignmentLists[graderType] var graderTypeAssignmentList = self.courseAssignmentLists[graderType];
if (graderTypeAssignmentList === undefined) { if (graderTypeAssignmentList === undefined) {
graderTypeAssignmentList = []; graderTypeAssignmentList = [];
} }

View File

@@ -388,7 +388,7 @@ function(ValidatingView, CodeMirror, _, $, ui, DateUtils, FileUploadModel,
Hides and clears the certificate available date field if a display behavior that doesn't use it is Hides and clears the certificate available date field if a display behavior that doesn't use it is
chosen. Because we are clearing it, toggling back to "end_with_date" will require re-entering the date chosen. Because we are clearing it, toggling back to "end_with_date" will require re-entering the date
*/ */
if (!this.useV2CertDisplaySettings){ if (!this.useV2CertDisplaySettings) {
return; return;
} }
let showDatepicker = this.model.get('certificates_display_behavior') == 'end_with_date'; let showDatepicker = this.model.get('certificates_display_behavior') == 'end_with_date';
@@ -402,7 +402,7 @@ function(ValidatingView, CodeMirror, _, $, ui, DateUtils, FileUploadModel,
datepicker.prop('disabled', true); datepicker.prop('disabled', true);
datepicker.val(null); datepicker.val(null);
this.clearValidationErrors(); this.clearValidationErrors();
this.setAndValidate('certificate_available_date', null) this.setAndValidate('certificate_available_date', null);
certificateAvailableDateField.addClass('hidden'); certificateAvailableDateField.addClass('hidden');
} }
}, },

View File

@@ -6,6 +6,7 @@
'use strict'; 'use strict';
var path = require('path'); var path = require('path');
var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js')); var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js'));
var options = { var options = {

View File

@@ -6,6 +6,7 @@
'use strict'; 'use strict';
var path = require('path'); var path = require('path');
var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js')); var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js'));
var options = { var options = {

View File

@@ -6,6 +6,7 @@
'use strict'; 'use strict';
var path = require('path'); var path = require('path');
var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js')); var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js'));
var options = { var options = {

View File

@@ -34,7 +34,7 @@ const BlockType = PropTypes.shape({
}); });
export const BlockList = ({ export const BlockList = ({
blocks, selectedBlock, onSelectBlock, onChangeRoot blocks, selectedBlock, onSelectBlock, onChangeRoot,
}) => ( }) => (
<ul className="block-list"> <ul className="block-list">
{blocks.map(block => ( {blocks.map(block => (
@@ -48,11 +48,12 @@ export const BlockList = ({
label={block.display_name} label={block.display_name}
/> />
{block.children {block.children
&& <Button && (
onClick={() => onChangeRoot(block.id)} <Button
label={RightIcon} onClick={() => onChangeRoot(block.id)}
/> label={RightIcon}
} />
)}
</li> </li>
))} ))}
</ul> </ul>
@@ -71,7 +72,7 @@ BlockList.defaultProps = {
}; };
export const BlockBrowser = ({ export const BlockBrowser = ({
blocks, selectedBlock, onSelectBlock, onChangeRoot, className blocks, selectedBlock, onSelectBlock, onChangeRoot, className,
}) => !!blocks && ( }) => !!blocks && (
<div className={classNames('block-browser', className)}> <div className={classNames('block-browser', className)}>
<div className="header"> <div className="header">

View File

@@ -29,4 +29,4 @@ export const getCourseBlocks = courseId => fetch(`${COURSE_BLOCKS_API}?${buildQu
credentials: 'same-origin', credentials: 'same-origin',
method: 'get', method: 'get',
headers: HEADERS, headers: HEADERS,
},); });

View File

@@ -11,7 +11,7 @@ function NextArrow(props) {
} = props; } = props;
const showArrow = slideCount - currentSlide > displayedSlides; const showArrow = slideCount - currentSlide > displayedSlides;
const opts = { const opts = {
className: classNames('js-carousel-nav', 'carousel-arrow', 'next', 'btn btn-secondary', {'active': showArrow}), className: classNames('js-carousel-nav', 'carousel-arrow', 'next', 'btn btn-secondary', {active: showArrow}),
onClick onClick
}; };
@@ -22,8 +22,8 @@ function NextArrow(props) {
return ( return (
<button {...opts}> <button {...opts}>
<span>Next </span> <span>Next </span>
<span className="icon fa fa-chevron-right" aria-hidden="true"></span> <span className="icon fa fa-chevron-right" aria-hidden="true" />
<span className="sr">{ 'Scroll carousel forwards' }</span> <span className="sr">Scroll carousel forwards</span>
</button> </button>
); );
} }
@@ -32,7 +32,7 @@ function PrevArrow(props) {
const {currentSlide, onClick} = props; const {currentSlide, onClick} = props;
const showArrow = currentSlide > 0; const showArrow = currentSlide > 0;
const opts = { const opts = {
className: classNames('js-carousel-nav', 'carousel-arrow', 'prev', 'btn btn-secondary', {'active': showArrow}), className: classNames('js-carousel-nav', 'carousel-arrow', 'prev', 'btn btn-secondary', {active: showArrow}),
onClick onClick
}; };
@@ -41,10 +41,10 @@ function PrevArrow(props) {
} }
return ( return (
<button {...opts} > <button {...opts}>
<span className="icon fa fa-chevron-left" aria-hidden="true"></span> <span className="icon fa fa-chevron-left" aria-hidden="true" />
<span> Prev</span> <span> Prev</span>
<span className="sr">{ 'Scroll carousel backwards' }</span> <span className="sr">Scroll carousel backwards</span>
</button> </button>
); );
} }
@@ -87,7 +87,7 @@ export default class ExperimentalCarousel extends React.Component {
}, },
tabIndex: tabIndex, tabIndex: tabIndex,
className: 'carousel-item' className: 'carousel-item'
} };
return ( return (
<div {...carouselLinkProps}> <div {...carouselLinkProps}>
@@ -113,7 +113,7 @@ export default class ExperimentalCarousel extends React.Component {
}; };
return ( return (
<Slider {...carouselSettings} > <Slider {...carouselSettings}>
{this.getCarouselContent()} {this.getCarouselContent()}
</Slider> </Slider>
); );
@@ -122,4 +122,4 @@ export default class ExperimentalCarousel extends React.Component {
ExperimentalCarousel.propTypes = { ExperimentalCarousel.propTypes = {
slides: PropTypes.array.isRequired slides: PropTypes.array.isRequired
}; };

View File

@@ -208,7 +208,7 @@
Content.prototype.incrementVote = function(increment) { Content.prototype.incrementVote = function(increment) {
var newVotes; var newVotes;
newVotes = _.clone(this.get('votes')); newVotes = _.clone(this.get('votes'));
newVotes.up_count = newVotes.up_count + increment; newVotes.up_count += increment;
return this.set('votes', newVotes); return this.set('votes', newVotes);
}; };

View File

@@ -32,8 +32,8 @@
if (_.isUndefined(userId)) { if (_.isUndefined(userId)) {
userId = this.user ? this.user.id : void 0; userId = this.user ? this.user.id : void 0;
} }
if(_.isUndefined(this.roleIds)) { if (_.isUndefined(this.roleIds)) {
this.roleIds = {} this.roleIds = {};
} }
staff = _.union(this.roleIds.Moderator, this.roleIds.Administrator); staff = _.union(this.roleIds.Moderator, this.roleIds.Administrator);
return _.include(staff, parseInt(userId)); return _.include(staff, parseInt(userId));
@@ -77,7 +77,9 @@
DiscussionUtil.generateDiscussionLink = function(cls, txt, handler) { DiscussionUtil.generateDiscussionLink = function(cls, txt, handler) {
return $('<a>') return $('<a>')
.addClass('discussion-link').attr('href', '#') .addClass('discussion-link').attr('href', '#')
.addClass(cls).text(txt).click(function() { return handler(this); }); .addClass(cls)
.text(txt)
.click(function() { return handler(this); });
}; };
DiscussionUtil.urlFor = function(name, param, param1, param2) { DiscussionUtil.urlFor = function(name, param, param1, param2) {
@@ -484,7 +486,6 @@
element, element,
this.postMathJaxProcessor(this.markdownWithHighlight(element.text())) this.postMathJaxProcessor(this.markdownWithHighlight(element.text()))
); );
}; };
DiscussionUtil.typesetMathJax = function(element) { DiscussionUtil.typesetMathJax = function(element) {

View File

@@ -9,4 +9,4 @@ jasmine.getFixtures().fixturesPath = '/base/';
// Stub out modal dialog alerts, which will prevent // Stub out modal dialog alerts, which will prevent
// us from accessing the test results in the DOM // us from accessing the test results in the DOM
window.confirm = function() { return true; }; window.confirm = function() { return true; };
window.alert = function() { return; }; window.alert = function() { };

View File

@@ -3,8 +3,8 @@
initialized we can't override the ExceptionFormatter as Jasmine then uses the stored reference to the function */ initialized we can't override the ExceptionFormatter as Jasmine then uses the stored reference to the function */
(function() { (function() {
/* globals jasmineRequire */ /* globals jasmineRequire */
'use strict'; 'use strict';
var OldExceptionFormatter = jasmineRequire.ExceptionFormatter(), var OldExceptionFormatter = jasmineRequire.ExceptionFormatter(),
oldExceptionFormatter = new OldExceptionFormatter(), oldExceptionFormatter = new OldExceptionFormatter(),

View File

@@ -40,9 +40,11 @@
var path = require('path'); var path = require('path');
var _ = require('underscore'); var _ = require('underscore');
var appRoot = path.join(__dirname, '../../../../'); var appRoot = path.join(__dirname, '../../../../');
var webdriver = require('selenium-webdriver'); var webdriver = require('selenium-webdriver');
var firefox = require('selenium-webdriver/firefox'); var firefox = require('selenium-webdriver/firefox');
var webpackConfig = require(path.join(appRoot, 'webpack.dev.config.js')); var webpackConfig = require(path.join(appRoot, 'webpack.dev.config.js'));
// The following crazy bit is to work around the webpack.optimize.CommonsChunkPlugin // The following crazy bit is to work around the webpack.optimize.CommonsChunkPlugin

View File

@@ -57,11 +57,11 @@
_ref >= 0 ? _i <= _ref : _i >= _ref; _ref >= 0 ? _i <= _ref : _i >= _ref;
i = _ref >= 0 ? ++_i : --_i i = _ref >= 0 ? ++_i : --_i
) { ) {
threadData.body = threadData.body + imageTag; threadData.body += imageTag;
if (i === 0) { if (i === 0) {
expectedHtml = expectedHtml + imageTag; expectedHtml += imageTag;
} else { } else {
expectedHtml = expectedHtml + '<em>image omitted</em>'; expectedHtml += '<em>image omitted</em>';
} }
} }
} }

View File

@@ -80,8 +80,6 @@
callbackFunc(draggableObj); callbackFunc(draggableObj);
}, 0); }, 0);
}); });
return;
} else { } else {
if (draggableObj.originalConfigObj.label.length > 0) { if (draggableObj.originalConfigObj.label.length > 0) {
draggableObj.iconEl = $(HtmlUtils.joinHtml( draggableObj.iconEl = $(HtmlUtils.joinHtml(
@@ -101,8 +99,6 @@
setTimeout(function() { setTimeout(function() {
callbackFunc(draggableObj); callbackFunc(draggableObj);
}, 0); }, 0);
return;
} }
} }
} }

View File

@@ -1,15 +1,15 @@
describe('interpolate_ntext', function() { describe('interpolate_ntext', function() {
it('replaces placeholder values', function() { it('replaces placeholder values', function() {
expect(interpolate_ntext('contains {count} student', 'contains {count} students', 1, {count: 1})). expect(interpolate_ntext('contains {count} student', 'contains {count} students', 1, {count: 1}))
toBe('contains 1 student'); .toBe('contains 1 student');
expect(interpolate_ntext('contains {count} student', 'contains {count} students', 5, {count: 2})). expect(interpolate_ntext('contains {count} student', 'contains {count} students', 5, {count: 2}))
toBe('contains 2 students'); .toBe('contains 2 students');
}); });
}); });
describe('interpolate_text', function() { describe('interpolate_text', function() {
it('replaces placeholder values', function() { it('replaces placeholder values', function() {
expect(interpolate_text('contains {adjective} students', {adjective: 'awesome'})). expect(interpolate_text('contains {adjective} students', {adjective: 'awesome'}))
toBe('contains awesome students'); .toBe('contains awesome students');
}); });
}); });

View File

@@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import CookieBanner from '@edx/frontend-component-cookie-policy-banner'; import CookieBanner from '@edx/frontend-component-cookie-policy-banner';
export function CookiePolicyBanner() { return <CookieBanner />; }; // eslint-disable-next-line import/prefer-default-export
export function CookiePolicyBanner() { return <CookieBanner />; }

View File

@@ -151,7 +151,7 @@ var accessible_modal = function(trigger, closeButtonId, modalId, mainPageId) {
// see http://accessibility.oit.ncsu.edu/blog/2013/09/13/the-incredible-accessible-modal-dialog/ // see http://accessibility.oit.ncsu.edu/blog/2013/09/13/the-incredible-accessible-modal-dialog/
// for more information on managing modals // for more information on managing modals
// //
var initialFocus var initialFocus;
$(trigger).click(function() { $(trigger).click(function() {
$focusedElementBeforeModal = $(trigger); $focusedElementBeforeModal = $(trigger);

View File

@@ -6,6 +6,7 @@
'use strict'; 'use strict';
var path = require('path'); var path = require('path');
var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js')); var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js'));
var options = { var options = {

View File

@@ -6,6 +6,7 @@
'use strict'; 'use strict';
var path = require('path'); var path = require('path');
var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js')); var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js'));
var options = { var options = {

View File

@@ -1,17 +1,17 @@
module.exports = { module.exports = {
'globals': { globals: {
'gettext': (t) => { return t; }, gettext: (t) => t,
}, },
'modulePaths': [ modulePaths: [
'common/static/common/js/components', 'common/static/common/js/components',
], ],
'setupFilesAfterEnv': ['<rootDir>/setupTests.js'], setupFilesAfterEnv: ['<rootDir>/setupTests.js'],
'testMatch': [ testMatch: [
'/**/*.test.jsx', '/**/*.test.jsx',
'common/static/common/js/components/**/?(*.)+(spec|test).js?(x)', 'common/static/common/js/components/**/?(*.)+(spec|test).js?(x)',
], ],
'testEnvironment': 'jsdom', testEnvironment: 'jsdom',
'transform': { transform: {
'^.+\\.jsx$': 'babel-jest', '^.+\\.jsx$': 'babel-jest',
'^.+\\.js$': 'babel-jest', '^.+\\.js$': 'babel-jest',
}, },

View File

@@ -29,7 +29,7 @@ export default class Main extends React.Component {
this.props.problemResponsesEndpoint, this.props.problemResponsesEndpoint,
this.props.taskStatusEndpoint, this.props.taskStatusEndpoint,
this.props.reportDownloadEndpoint, this.props.reportDownloadEndpoint,
this.props.selectedBlock this.props.selectedBlock,
); );
} }

View File

@@ -44,7 +44,7 @@ describe('ProblemBrowser Main component', () => {
fetchCourseBlocks={jest.fn()} fetchCourseBlocks={jest.fn()}
problemResponsesEndpoint={problemResponsesEndpoint} problemResponsesEndpoint={problemResponsesEndpoint}
onSelectBlock={jest.fn()} onSelectBlock={jest.fn()}
selectedBlock={'some-selected-block'} selectedBlock="some-selected-block"
taskStatusEndpoint={taskStatusEndpoint} taskStatusEndpoint={taskStatusEndpoint}
/> />
</Provider>, </Provider>,
@@ -64,7 +64,7 @@ describe('ProblemBrowser Main component', () => {
fetchCourseBlocks={fetchCourseBlocksMock} fetchCourseBlocks={fetchCourseBlocksMock}
problemResponsesEndpoint={problemResponsesEndpoint} problemResponsesEndpoint={problemResponsesEndpoint}
onSelectBlock={jest.fn()} onSelectBlock={jest.fn()}
selectedBlock={'some-selected-block'} selectedBlock="some-selected-block"
taskStatusEndpoint={taskStatusEndpoint} taskStatusEndpoint={taskStatusEndpoint}
/> />
</Provider>, </Provider>,
@@ -83,7 +83,7 @@ describe('ProblemBrowser Main component', () => {
fetchCourseBlocks={jest.fn()} fetchCourseBlocks={jest.fn()}
problemResponsesEndpoint={problemResponsesEndpoint} problemResponsesEndpoint={problemResponsesEndpoint}
onSelectBlock={jest.fn()} onSelectBlock={jest.fn()}
selectedBlock={'some-selected-block'} selectedBlock="some-selected-block"
taskStatusEndpoint={taskStatusEndpoint} taskStatusEndpoint={taskStatusEndpoint}
/>, />,
); );

View File

@@ -13,7 +13,7 @@ const mapDispatchToProps = dispatch => ({
(courseId, excludeBlockTypes) => dispatch(fetchCourseBlocks(courseId, excludeBlockTypes)), (courseId, excludeBlockTypes) => dispatch(fetchCourseBlocks(courseId, excludeBlockTypes)),
createProblemResponsesReportTask: createProblemResponsesReportTask:
(problemResponsesEndpoint, taskStatusEndpoint, reportDownloadEndpoint, problemLocation) => dispatch( (problemResponsesEndpoint, taskStatusEndpoint, reportDownloadEndpoint, problemLocation) => dispatch(
createProblemResponsesReportTask(problemResponsesEndpoint, taskStatusEndpoint, reportDownloadEndpoint, problemLocation,), createProblemResponsesReportTask(problemResponsesEndpoint, taskStatusEndpoint, reportDownloadEndpoint, problemLocation),
), ),
}); });

View File

@@ -5,7 +5,7 @@ import * as PropTypes from 'prop-types';
import * as React from 'react'; import * as React from 'react';
const ReportStatus = ({ const ReportStatus = ({
error, succeeded, inProgress, reportPath error, succeeded, inProgress, reportPath,
}) => { }) => {
const progressMessage = ( const progressMessage = (
<div className="msg progress"> <div className="msg progress">

View File

@@ -23,8 +23,8 @@ describe('ReportStatus component', () => {
<ReportStatus <ReportStatus
error={null} error={null}
inProgress={false} inProgress={false}
reportName={'some-report-name'} reportName="some-report-name"
reportPath={'/some/report/path.csv'} reportPath="/some/report/path.csv"
succeeded succeeded
/>, />,
); );
@@ -35,7 +35,7 @@ describe('ReportStatus component', () => {
test('render error status', () => { test('render error status', () => {
const component = renderer.create( const component = renderer.create(
<ReportStatus <ReportStatus
error={'some error status'} error="some error status"
inProgress={false} inProgress={false}
reportName={null} reportName={null}
reportPath={null} reportPath={null}

View File

@@ -15,14 +15,14 @@ function initiateProblemResponsesRequest(endpoint, blockId) {
method: 'post', method: 'post',
headers: HEADERS, headers: HEADERS,
body: formData, body: formData,
},); });
} }
const fetchTaskStatus = (endpoint, taskId) => fetch(`${endpoint}/?task_id=${taskId}`, { const fetchTaskStatus = (endpoint, taskId) => fetch(`${endpoint}/?task_id=${taskId}`, {
credentials: 'same-origin', credentials: 'same-origin',
method: 'get', method: 'get',
headers: HEADERS, headers: HEADERS,
},); });
const fetchDownloadsList = (endpoint, reportName) => { const fetchDownloadsList = (endpoint, reportName) => {
const formData = new FormData(); const formData = new FormData();
@@ -33,7 +33,7 @@ const fetchDownloadsList = (endpoint, reportName) => {
method: 'POST', method: 'POST',
headers: HEADERS, headers: HEADERS,
body: formData, body: formData,
},); });
}; };
export { export {

View File

@@ -13,9 +13,9 @@ const mapStateToProps = state => ({
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
createEntitlement: ({ createEntitlement: ({
username, courseUuid, mode, comments username, courseUuid, mode, comments,
}) => dispatch(createEntitlement({ }) => dispatch(createEntitlement({
username, courseUuid, mode, comments username, courseUuid, mode, comments,
})), })),
reissueEntitlement: ({ entitlement, comments }) => dispatch(reissueEntitlement({ entitlement, comments })), reissueEntitlement: ({ entitlement, comments }) => dispatch(reissueEntitlement({ entitlement, comments })),
closeForm: () => dispatch(closeForm()), closeForm: () => dispatch(closeForm()),

View File

@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { import {
Button, InputSelect, InputText, TextArea Button, InputSelect, InputText, TextArea,
} from '@edx/paragon'; } from '@edx/paragon';
import { formTypes } from '../../data/constants/formTypes'; import { formTypes } from '../../data/constants/formTypes';
@@ -57,21 +57,21 @@ class EntitlementForm extends React.Component {
submitForm() { submitForm() {
const { const {
courseUuid, username, mode, comments courseUuid, username, mode, comments,
} = this.state; } = this.state;
const { formType, entitlement } = this.props; const { formType, entitlement } = this.props;
if (formType === formTypes.REISSUE) { // if there is an active entitlement we are updating an entitlement if (formType === formTypes.REISSUE) { // if there is an active entitlement we are updating an entitlement
this.props.reissueEntitlement({ entitlement, comments }); this.props.reissueEntitlement({ entitlement, comments });
} else { // if there is no active entitlement we are creating a new entitlement } else { // if there is no active entitlement we are creating a new entitlement
this.props.createEntitlement({ this.props.createEntitlement({
courseUuid, username, mode, comments courseUuid, username, mode, comments,
}); });
} }
} }
render() { render() {
const { const {
courseUuid, username, mode, comments courseUuid, username, mode, comments,
} = this.state; } = this.state;
const isReissue = this.props.formType === formTypes.REISSUE; const isReissue = this.props.formType === formTypes.REISSUE;
const title = isReissue ? 'Re-issue Entitlement' : 'Create Entitlement'; const title = isReissue ? 'Re-issue Entitlement' : 'Create Entitlement';

View File

@@ -47,7 +47,7 @@ const entitlementColumns = [
const parseEntitlementData = (entitlements, ecommerceUrl, openReissueForm) => entitlements.map((entitlement) => { const parseEntitlementData = (entitlements, ecommerceUrl, openReissueForm) => entitlements.map((entitlement) => {
const { const {
expiredAt, created, modified, orderNumber, enrollmentCourseRun expiredAt, created, modified, orderNumber, enrollmentCourseRun,
} = entitlement; } = entitlement;
return Object.assign({}, entitlement, { return Object.assign({}, entitlement, {
expiredAt: expiredAt ? moment(expiredAt).format('lll') : '', expiredAt: expiredAt ? moment(expiredAt).format('lll') : '',

View File

@@ -67,7 +67,7 @@ const createEntitlementSuccess = entitlement => ({
const createEntitlementFailure = error => dispatch => dispatch(displayError('Error Creating Entitlement', error)); const createEntitlementFailure = error => dispatch => dispatch(displayError('Error Creating Entitlement', error));
const createEntitlement = ({ const createEntitlement = ({
username, courseUuid, mode, comments username, courseUuid, mode, comments,
}) => (dispatch) => { }) => (dispatch) => {
postEntitlement({ postEntitlement({
username, username,

View File

@@ -12,10 +12,10 @@ const HEADERS = {
const getEntitlements = username => fetch(`${entitlementApi}?user=${username}`, { const getEntitlements = username => fetch(`${entitlementApi}?user=${username}`, {
credentials: 'same-origin', credentials: 'same-origin',
method: 'get', method: 'get',
},); });
const postEntitlement = ({ const postEntitlement = ({
username, courseUuid, mode, action, comments = null username, courseUuid, mode, action, comments = null,
}) => fetch(`${entitlementApi}`, { }) => fetch(`${entitlementApi}`, {
credentials: 'same-origin', credentials: 'same-origin',
method: 'post', method: 'post',
@@ -30,10 +30,10 @@ const postEntitlement = ({
comments, comments,
}], }],
}), }),
},); });
const patchEntitlement = ({ const patchEntitlement = ({
uuid, action, unenrolledRun = null, comments = null uuid, action, unenrolledRun = null, comments = null,
}) => fetch(`${entitlementApi}${uuid}`, { }) => fetch(`${entitlementApi}${uuid}`, {
credentials: 'same-origin', credentials: 'same-origin',
method: 'patch', method: 'patch',
@@ -46,7 +46,7 @@ const patchEntitlement = ({
comments, comments,
}], }],
}), }),
},); });
export { export {
getEntitlements, getEntitlements,

View File

@@ -1,5 +1,6 @@
import { formActions, entitlementActions } from '../constants/actionTypes'; import { formActions, entitlementActions } from '../constants/actionTypes';
import { formTypes } from '../constants/formTypes'; import { formTypes } from '../constants/formTypes';
const clearFormState = { const clearFormState = {
formType: '', formType: '',
isOpen: false, isOpen: false,
@@ -10,11 +11,11 @@ const form = (state = {}, action) => {
switch (action.type) { switch (action.type) {
case formActions.OPEN_REISSUE_FORM: case formActions.OPEN_REISSUE_FORM:
return { return {
...state, formType: formTypes.REISSUE, isOpen: true, activeEntitlement: action.entitlement ...state, formType: formTypes.REISSUE, isOpen: true, activeEntitlement: action.entitlement,
}; };
case formActions.OPEN_CREATION_FORM: case formActions.OPEN_CREATION_FORM:
return { return {
...state, formType: formTypes.CREATE, isOpen: true, activeEntitlement: null ...state, formType: formTypes.CREATE, isOpen: true, activeEntitlement: null,
}; };
case formActions.CLOSE_FORM: case formActions.CLOSE_FORM:
case entitlementActions.reissue.SUCCESS: case entitlementActions.reissue.SUCCESS:

View File

@@ -141,8 +141,7 @@ class FileUpload extends React.Component {
fileName={this.state.fileInProgress} fileName={this.state.fileInProgress}
request={this.state.currentRequest} request={this.state.currentRequest}
/> />
) )}
}
</div> </div>
<div className="uploaded-files"> <div className="uploaded-files">
{ {

View File

@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { import {
Button, InputText, TextArea, StatusAlert Button, InputText, TextArea, StatusAlert,
} from '@edx/paragon'; } from '@edx/paragon';
export const LinkProgramEnrollmentsSupportPage = props => ( export const LinkProgramEnrollmentsSupportPage = props => (

View File

@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { import {
Button, InputText, StatusAlert, InputSelect Button, InputText, StatusAlert, InputSelect,
} from '@edx/paragon'; } from '@edx/paragon';
/* /*
@@ -112,7 +112,7 @@ const renderEnrollmentsSection = enrollments => (
</div> </div>
)} )}
</div> </div>
) ),
)} )}
</div> </div>
))} ))}
@@ -152,7 +152,7 @@ export const ProgramEnrollmentsInspectorPage = props => (
dialog={props.error} dialog={props.error}
/> />
)} )}
<div id="input_alert" className={'alert alert-danger'} hidden> <div id="input_alert" className="alert alert-danger" hidden>
Search either by edx username or email, or Institution user key, but not both Search either by edx username or email, or Institution user key, but not both
</div> </div>
<div key="edX_accounts"> <div key="edX_accounts">
@@ -228,7 +228,7 @@ ProgramEnrollmentsInspectorPage.propTypes = {
is_active: PropTypes.bool, is_active: PropTypes.bool,
mode: PropTypes.string, mode: PropTypes.string,
}), }),
}) }),
), ),
}), }),
), ),

View File

@@ -150,7 +150,7 @@ class RenderForm extends React.Component {
{ {
id: this.props.context.customFields.referrer, id: this.props.context.customFields.referrer,
value: document.referrer ? document.referrer : 'Direct Contact Us Page Request', value: document.referrer ? document.referrer : 'Direct Contact Us Page Request',
} },
], ],
tags: this.props.context.tags, tags: this.props.context.tags,
}; };
@@ -175,6 +175,7 @@ class RenderForm extends React.Component {
this.scrollToTop(); this.scrollToTop();
}.bind(this); }.bind(this);
} }
validateFormData(formData) { validateFormData(formData) {
const { course, subject, message } = formData; const { course, subject, message } = formData;
@@ -273,21 +274,25 @@ class RenderForm extends React.Component {
let userElement, let userElement,
suggestionsListComponent = null; suggestionsListComponent = null;
if (this.userInformation) { if (this.userInformation) {
userElement = (<LoggedInUser userElement = (
userInformation={this.userInformation} <LoggedInUser
onChangeCallback={this.formOnChangeCallback} userInformation={this.userInformation}
handleClick={this.handleClick} onChangeCallback={this.formOnChangeCallback}
showWarning={this.showWarningMessage()} handleClick={this.handleClick}
showDiscussionButton={this.showDiscussionButton()} showWarning={this.showWarningMessage()}
reDirectUser={this.reDirectUser} showDiscussionButton={this.showDiscussionButton()}
errorList={this.getFormErrorsFromState()} reDirectUser={this.reDirectUser}
/>); errorList={this.getFormErrorsFromState()}
/>
);
} else { } else {
userElement = (<LoggedOutUser userElement = (
platformName={this.props.context.platformName} <LoggedOutUser
loginQuery={this.props.context.loginQuery} platformName={this.props.context.platformName}
supportEmail={this.props.context.supportEmail} loginQuery={this.props.context.loginQuery}
/>); supportEmail={this.props.context.supportEmail}
/>
);
} }
if (suggestions !== null && suggestions.length) { if (suggestions !== null && suggestions.length) {
suggestionsListComponent = ( suggestionsListComponent = (

View File

@@ -7,7 +7,7 @@ import PropTypes from 'prop-types';
import StringUtils from 'edx-ui-toolkit/js/utils/string-utils'; import StringUtils from 'edx-ui-toolkit/js/utils/string-utils';
function Success({ function Success({
platformName, homepageUrl, dashboardUrl, isLoggedIn platformName, homepageUrl, dashboardUrl, isLoggedIn,
}) { }) {
let btnText, let btnText,
btnUrl; btnUrl;

View File

@@ -11,7 +11,7 @@ export function markBlocksCompletedOnViewIfNeeded(runtime, containerElement) {
const tracker = new ViewedEventTracker(); const tracker = new ViewedEventTracker();
blockElements.forEach((blockElement) => { blockElements.forEach((blockElement) => {
const markCompletedOnViewAfterDelay = parseInt(blockElement.dataset.markCompletedOnViewAfterDelay, 10,); const markCompletedOnViewAfterDelay = parseInt(blockElement.dataset.markCompletedOnViewAfterDelay, 10);
if (markCompletedOnViewAfterDelay >= 0) { if (markCompletedOnViewAfterDelay >= 0) {
tracker.addElement(blockElement, markCompletedOnViewAfterDelay); tracker.addElement(blockElement, markCompletedOnViewAfterDelay);
} }

View File

@@ -123,7 +123,7 @@
this.before = this.before.replace(regex, this.before = this.before.replace(regex,
function(match) { function(match) {
chunkObj.startTag = chunkObj.startTag + match; chunkObj.startTag += match;
return ''; return '';
}); });
@@ -131,7 +131,7 @@
this.selection = this.selection.replace(regex, this.selection = this.selection.replace(regex,
function(match) { function(match) {
chunkObj.startTag = chunkObj.startTag + match; chunkObj.startTag += match;
return ''; return '';
}); });
} }
@@ -194,14 +194,14 @@
this.selection = this.selection.replace(/(^\n*)/, ''); this.selection = this.selection.replace(/(^\n*)/, '');
this.startTag = this.startTag + re.$1; this.startTag += re.$1;
this.selection = this.selection.replace(/(\n*$)/, ''); this.selection = this.selection.replace(/(\n*$)/, '');
this.endTag = this.endTag + re.$1; this.endTag += re.$1;
this.startTag = this.startTag.replace(/(^\n*)/, ''); this.startTag = this.startTag.replace(/(^\n*)/, '');
this.before = this.before + re.$1; this.before += re.$1;
this.endTag = this.endTag.replace(/(\n*$)/, ''); this.endTag = this.endTag.replace(/(\n*$)/, '');
this.after = this.after + re.$1; this.after += re.$1;
if (this.before) { if (this.before) {
regexText = replacementText = ''; regexText = replacementText = '';
@@ -236,7 +236,7 @@
function findAnEmptyToolbar(toolbarClassName) { function findAnEmptyToolbar(toolbarClassName) {
var toolbars = doc.getElementsByClassName(toolbarClassName); var toolbars = doc.getElementsByClassName(toolbarClassName);
for (var i=0; i < toolbars.length; ++i) { for (var i = 0; i < toolbars.length; ++i) {
var aToolbar = toolbars[i]; var aToolbar = toolbars[i];
if (aToolbar.children.length == 0) { if (aToolbar.children.length == 0) {
var anEmptyToolbar = aToolbar; var anEmptyToolbar = aToolbar;
@@ -524,7 +524,6 @@
var keyCodeChar = String.fromCharCode(keyCode); var keyCodeChar = String.fromCharCode(keyCode);
switch (keyCodeChar) { switch (keyCodeChar) {
case 'y': case 'y':
undoObj.redo(); undoObj.redo();
handled = true; handled = true;
@@ -548,7 +547,6 @@
if (window.event) { if (window.event) {
window.event.returnValue = false; window.event.returnValue = false;
} }
return;
} }
}; };
@@ -737,7 +735,7 @@
// Sets the TextareaState properties given a chunk of markdown. // Sets the TextareaState properties given a chunk of markdown.
this.setChunks = function(chunk) { this.setChunks = function(chunk) {
chunk.before = chunk.before + chunk.startTag; chunk.before += chunk.startTag;
chunk.after = chunk.endTag + chunk.after; chunk.after = chunk.endTag + chunk.after;
this.start = chunk.before.length; this.start = chunk.before.length;
@@ -1572,11 +1570,9 @@
// Add the true markup. // Add the true markup.
var markup = nStars <= 1 ? '*' : '**'; // shouldn't the test be = ? var markup = nStars <= 1 ? '*' : '**'; // shouldn't the test be = ?
chunk.before = chunk.before + markup; chunk.before += markup;
chunk.after = markup + chunk.after; chunk.after = markup + chunk.after;
} }
return;
}; };
commandProto.stripLinkDefs = function(text, defsToAdd) { commandProto.stripLinkDefs = function(text, defsToAdd) {
@@ -1663,7 +1659,9 @@
}); });
if (title) { if (title) {
title = title.trim ? title.trim() : title.replace(/^\s*/, '').replace(/\s*$/, ''); title = title.trim ? title.trim() : title.replace(/^\s*/, '').replace(/\s*$/, '');
title = $.trim(title).replace(/"/g, 'quot;').replace(/\(/g, '&#40;').replace(/\)/g, '&#41;').replace(/</g, '&lt;').replace(/>/g, '&gt;'); title = $.trim(title).replace(/"/g, 'quot;').replace(/\(/g, '&#40;').replace(/\)/g, '&#41;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
} }
return title ? link + ' "' + title + '"' : link; return title ? link + ' "' + title + '"' : link;
}); });

View File

@@ -19,11 +19,11 @@ export class StatusAlertRenderer {
*/ */
ReactDOM.render( ReactDOM.render(
<StatusAlert <StatusAlert
alertType='warning' alertType="warning"
dismissible={true} dismissible
open={true} open
dialog={message} dialog={message}
dismissable={true} dismissable
onClose={() => this.shiftFocus(afterselector)} onClose={() => this.shiftFocus(afterselector)}
/>, />,
document.querySelector(selector) document.querySelector(selector)

View File

@@ -49,9 +49,9 @@ $(function() {
}); });
if (cancel_submit) { if (cancel_submit) {
$('.status.message.submission-error'). $('.status.message.submission-error')
removeClass('is-hidden'). .removeClass('is-hidden')
focus(); .focus();
$('html, body').animate({scrollTop: 0}, 'fast'); $('html, body').animate({scrollTop: 0}, 'fast');
return false; return false;
} }
@@ -72,10 +72,10 @@ $(function() {
toggleSubmitButton(true); toggleSubmitButton(true);
json = $.parseJSON(jqXHR.responseText); json = $.parseJSON(jqXHR.responseText);
$('.status.message.submission-error').addClass('is-shown').focus(); $('.status.message.submission-error').addClass('is-shown').focus();
$('.status.message.submission-error .message-copy'). $('.status.message.submission-error .message-copy')
text(gettext('There has been an error processing your survey.')). .text(gettext('There has been an error processing your survey.'))
stop(). .stop()
css('display', 'block'); .css('display', 'block');
}); });
}); });
@@ -83,14 +83,14 @@ function toggleSubmitButton(enable) {
var $submitButton = $('form .form-actions #submit'); var $submitButton = $('form .form-actions #submit');
if (enable) { if (enable) {
$submitButton. $submitButton
removeClass('is-disabled'). .removeClass('is-disabled')
attr('aria-disabled', false). .attr('aria-disabled', false)
removeProp('disabled'); .removeProp('disabled');
} else { } else {
$submitButton. $submitButton
addClass('is-disabled'). .addClass('is-disabled')
attr('aria-disabled', true). .attr('aria-disabled', true)
prop('disabled', true); .prop('disabled', true);
} }
} }

View File

@@ -272,7 +272,7 @@ var edx = edx || {};
display: 'block', display: 'block',
'z-index': 0 'z-index': 0
}); });
$('#activate-account-modal').focus() $('#activate-account-modal').focus();
} }
$('.action-email-settings').each(function(index) { $('.action-email-settings').each(function(index) {

View File

@@ -4,13 +4,12 @@ import Cookies from 'js-cookie';
import {DemographicsCollectionModal} from './DemographicsCollectionModal'; import {DemographicsCollectionModal} from './DemographicsCollectionModal';
export class DemographicsCollectionBanner extends React.Component { export class DemographicsCollectionBanner extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
modalOpen: false, modalOpen: false,
hideBanner: false hideBanner: false
} };
this.dismissBanner = this.dismissBanner.bind(this); this.dismissBanner = this.dismissBanner.bind(this);
} }
@@ -65,30 +64,31 @@ export class DemographicsCollectionBanner extends React.Component {
{gettext('Want to make edX better for everyone?')} {gettext('Want to make edX better for everyone?')}
</div> </div>
<button className="demographics-banner-btn d-flex align-items-center bg-white font-weight-bold border-0 py-2 px-3 mx-2 mb-3 m-lg-0 shadow justify-content-center"> <button className="demographics-banner-btn d-flex align-items-center bg-white font-weight-bold border-0 py-2 px-3 mx-2 mb-3 m-lg-0 shadow justify-content-center">
<span className="fa fa-thumbs-up px-2" aria-hidden="true"></span> <span className="fa fa-thumbs-up px-2" aria-hidden="true" />
{gettext('Get started')} {gettext('Get started')}
</button> </button>
</div> </div>
<div className="demographics-dismiss-container md-flex justify-content-right align-self-start align-self-lg-center ml-lg-auto"> <div className="demographics-dismiss-container md-flex justify-content-right align-self-start align-self-lg-center ml-lg-auto">
<button type="button" className="demographics-dismiss-btn btn btn-default px-0" id="demographics-dismiss" aria-label="close"> <button type="button" className="demographics-dismiss-btn btn btn-default px-0" id="demographics-dismiss" aria-label="close">
<i className="fa fa-times-circle text-white px-2" aria-hidden="true" onClick={this.dismissBanner}></i> <i className="fa fa-times-circle text-white px-2" aria-hidden="true" onClick={this.dismissBanner} />
</button> </button>
</div> </div>
</div> </div>
</a> </a>
<div> <div>
{this.state.modalOpen {this.state.modalOpen
&& <DemographicsCollectionModal && (
{...this.props} <DemographicsCollectionModal
user={this.props.user} {...this.props}
open={this.state.modalOpen} user={this.props.user}
closeModal={() => this.setState({modalOpen: false})} open={this.state.modalOpen}
dismissBanner={this.dismissBanner} closeModal={() => this.setState({modalOpen: false})}
/> dismissBanner={this.dismissBanner}
} />
)}
</div> </div>
</div> </div>
) );
} else { } else {
return null; return null;
} }

View File

@@ -1,14 +1,14 @@
/* global gettext */ /* global gettext */
import React from 'react'; import React from 'react';
import get from 'lodash/get'; import get from 'lodash/get';
import Wizard from './Wizard';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import {SelectWithInput} from './SelectWithInput' import StringUtils from 'edx-ui-toolkit/js/utils/string-utils';
import FocusLock from 'react-focus-lock';
import Wizard from './Wizard';
import {SelectWithInput} from './SelectWithInput';
import {MultiselectDropdown} from './MultiselectDropdown'; import {MultiselectDropdown} from './MultiselectDropdown';
import AxiosJwtTokenService from '../jwt_auth/AxiosJwtTokenService'; import AxiosJwtTokenService from '../jwt_auth/AxiosJwtTokenService';
import StringUtils from 'edx-ui-toolkit/js/utils/string-utils';
import AxiosCsrfTokenService from '../jwt_auth/AxiosCsrfTokenService'; import AxiosCsrfTokenService from '../jwt_auth/AxiosCsrfTokenService';
import FocusLock from 'react-focus-lock';
const FIELD_NAMES = { const FIELD_NAMES = {
CURRENT_WORK: 'current_work_sector', CURRENT_WORK: 'current_work_sector',
@@ -66,7 +66,7 @@ class DemographicsCollectionModal extends React.Component {
accessToken, accessToken,
refreshUrl, refreshUrl,
); );
this.csrfTokenService = new AxiosCsrfTokenService(this.props.csrfTokenPath) this.csrfTokenService = new AxiosCsrfTokenService(this.props.csrfTokenPath);
} }
async componentDidMount() { async componentDidMount() {
@@ -108,7 +108,7 @@ class DemographicsCollectionModal extends React.Component {
}; };
try { try {
await this.jwtTokenService.getJwtToken(); await this.jwtTokenService.getJwtToken();
await fetch(url, options) await fetch(url, options);
} catch (error) { } catch (error) {
this.setState({loading: false, fieldError: true, errorMessage: error}); this.setState({loading: false, fieldError: true, errorMessage: error});
} }
@@ -129,13 +129,13 @@ class DemographicsCollectionModal extends React.Component {
this.setState(({selected}) => { this.setState(({selected}) => {
// decline was previously selected // decline was previously selected
if (selected[FIELD_NAMES.ETHNICITY].find(i => i === 'declined')) { if (selected[FIELD_NAMES.ETHNICITY].find(i => i === 'declined')) {
return {selected: {...selected, [FIELD_NAMES.ETHNICITY]: values.filter(value => value !== 'declined')}} return {selected: {...selected, [FIELD_NAMES.ETHNICITY]: values.filter(value => value !== 'declined')}};
// decline was just selected // decline was just selected
} else if (decline) { } else if (decline) {
return {selected: {...selected, [FIELD_NAMES.ETHNICITY]: [decline]}} return {selected: {...selected, [FIELD_NAMES.ETHNICITY]: [decline]}};
// anything else was selected // anything else was selected
} else { } else {
return {selected: {...selected, [FIELD_NAMES.ETHNICITY]: values}} return {selected: {...selected, [FIELD_NAMES.ETHNICITY]: values}};
} }
}); });
} }
@@ -174,7 +174,7 @@ class DemographicsCollectionModal extends React.Component {
// We gather the possible answers to any demographics questions from the OPTIONS of the api // We gather the possible answers to any demographics questions from the OPTIONS of the api
async getDemographicsQuestionOptions() { async getDemographicsQuestionOptions() {
try { try {
const optionsResponse = await fetch(`${this.props.demographicsBaseUrl}/demographics/api/v1/demographics/`, {method: 'OPTIONS'}) const optionsResponse = await fetch(`${this.props.demographicsBaseUrl}/demographics/api/v1/demographics/`, {method: 'OPTIONS'});
const demographicsOptions = await optionsResponse.json(); const demographicsOptions = await optionsResponse.json();
return demographicsOptions; return demographicsOptions;
} catch (error) { } catch (error) {
@@ -240,7 +240,7 @@ class DemographicsCollectionModal extends React.Component {
render() { render() {
if (this.state.loading) { if (this.state.loading) {
return <div className="demographics-collection-modal d-flex justify-content-center align-items-start" /> return <div className="demographics-collection-modal d-flex justify-content-center align-items-start" />;
} }
return ( return (
<FocusLock> <FocusLock>
@@ -261,8 +261,7 @@ class DemographicsCollectionModal extends React.Component {
currentPage: currentPage, currentPage: currentPage,
totalPages: totalPages totalPages: totalPages
} }
) )}
}
</p> </p>
<h2 className="mb-1 mt-4 font-weight-bold text-secondary"> <h2 className="mb-1 mt-4 font-weight-bold text-secondary">
{gettext('Help make edX better for everyone!')} {gettext('Help make edX better for everyone!')}
@@ -282,204 +281,209 @@ class DemographicsCollectionModal extends React.Component {
)} )}
</Wizard.Header> </Wizard.Header>
<Wizard.Page> <Wizard.Page>
{({wizardConsumer}) => <div className="demographics-form-container" data-hj-suppress> {({wizardConsumer}) => (
{/* Gender Identity */} <div className="demographics-form-container" data-hj-suppress>
<SelectWithInput {/* Gender Identity */}
selectName={FIELD_NAMES.GENDER} <SelectWithInput
selectId={FIELD_NAMES.GENDER} selectName={FIELD_NAMES.GENDER}
selectValue={wizardConsumer[FIELD_NAMES.GENDER]} selectId={FIELD_NAMES.GENDER}
selectOnChange={this.handleSelectChange} selectValue={wizardConsumer[FIELD_NAMES.GENDER]}
labelText={gettext('What is your gender identity?')} selectOnChange={this.handleSelectChange}
options={[ labelText={gettext('What is your gender identity?')}
<option value="default" key="default">{gettext('Select gender')}</option>, options={[
this.loadOptions(FIELD_NAMES.GENDER) <option value="default" key="default">{gettext('Select gender')}</option>,
]} this.loadOptions(FIELD_NAMES.GENDER)
showInput={wizardConsumer[FIELD_NAMES.GENDER] == 'self-describe'} ]}
inputName={FIELD_NAMES.GENDER_DESCRIPTION} showInput={wizardConsumer[FIELD_NAMES.GENDER] == 'self-describe'}
inputId={FIELD_NAMES.GENDER_DESCRIPTION} inputName={FIELD_NAMES.GENDER_DESCRIPTION}
inputType="text" inputId={FIELD_NAMES.GENDER_DESCRIPTION}
inputValue={wizardConsumer[FIELD_NAMES.GENDER_DESCRIPTION]} inputType="text"
inputOnChange={this.handleInputChange} inputValue={wizardConsumer[FIELD_NAMES.GENDER_DESCRIPTION]}
inputOnBlur={this.handleSelectChange} inputOnChange={this.handleInputChange}
disabled={this.state.fieldError} inputOnBlur={this.handleSelectChange}
/> disabled={this.state.fieldError}
{/* Ethnicity */} />
<MultiselectDropdown {/* Ethnicity */}
label={gettext('Which of the following describes you best?')} <MultiselectDropdown
emptyLabel={gettext('Check all that apply')} label={gettext('Which of the following describes you best?')}
options={get(this.state.options, FIELD_NAMES.ETHNICITY_OPTIONS, {choices: []}).choices} emptyLabel={gettext('Check all that apply')}
selected={wizardConsumer[FIELD_NAMES.ETHNICITY]} options={get(this.state.options, FIELD_NAMES.ETHNICITY_OPTIONS, {choices: []}).choices}
onChange={this.handleMultiselectChange} selected={wizardConsumer[FIELD_NAMES.ETHNICITY]}
disabled={this.state.fieldError} onChange={this.handleMultiselectChange}
onBlur={() => { disabled={this.state.fieldError}
onBlur={() => {
// we create a fake "event", and then use it to call our normal selection handler function that // we create a fake "event", and then use it to call our normal selection handler function that
// is used by the other dropdowns. // is used by the other dropdowns.
const e = { const e = {
target: { target: {
name: FIELD_NAMES.ETHNICITY, name: FIELD_NAMES.ETHNICITY,
value: wizardConsumer[FIELD_NAMES.ETHNICITY].map(ethnicity => ({ethnicity, value: ethnicity})), value: wizardConsumer[FIELD_NAMES.ETHNICITY].map(ethnicity => ({ethnicity, value: ethnicity})),
}
};
this.handleSelectChange(e);
}}
/>
{/* Family Income */}
<div className="d-flex flex-column pb-3">
<label htmlFor={FIELD_NAMES.INCOME}>
{gettext('What was the total combined income, during the last 12 months, of all members of your family? ')}
</label>
<select
onChange={this.handleSelectChange}
className="form-control"
name={FIELD_NAMES.INCOME}
id={FIELD_NAMES.INCOME}
value={wizardConsumer[FIELD_NAMES.INCOME]}
disabled={this.state.fieldError}
>
<option value="default">{gettext('Select income')}</option>
{
this.loadOptions(FIELD_NAMES.INCOME)
} }
} </select>
this.handleSelectChange(e); </div>
}}
/>
{/* Family Income */}
<div className="d-flex flex-column pb-3">
<label htmlFor={FIELD_NAMES.INCOME}>
{gettext('What was the total combined income, during the last 12 months, of all members of your family? ')}
</label>
<select
onChange={this.handleSelectChange}
className="form-control"
name={FIELD_NAMES.INCOME} id={FIELD_NAMES.INCOME}
value={wizardConsumer[FIELD_NAMES.INCOME]}
disabled={this.state.fieldError}
>
<option value="default">{gettext('Select income')}</option>
{
this.loadOptions(FIELD_NAMES.INCOME)
}
</select>
</div> </div>
</div> )}
}
</Wizard.Page> </Wizard.Page>
<Wizard.Page> <Wizard.Page>
{({wizardConsumer}) => <div className="demographics-form-container" data-hj-suppress> {({wizardConsumer}) => (
{/* Military History */} <div className="demographics-form-container" data-hj-suppress>
<div className="d-flex flex-column pb-3"> {/* Military History */}
<label htmlFor={FIELD_NAMES.MILITARY}> <div className="d-flex flex-column pb-3">
{gettext('Have you ever served on active duty in the U.S. Armed Forces, Reserves, or National Guard?')} <label htmlFor={FIELD_NAMES.MILITARY}>
</label> {gettext('Have you ever served on active duty in the U.S. Armed Forces, Reserves, or National Guard?')}
<select </label>
autoFocus <select
className="form-control" autoFocus
onChange={this.handleSelectChange} className="form-control"
name={FIELD_NAMES.MILITARY} onChange={this.handleSelectChange}
id={FIELD_NAMES.MILITARY} name={FIELD_NAMES.MILITARY}
value={wizardConsumer[FIELD_NAMES.MILITARY]} id={FIELD_NAMES.MILITARY}
disabled={this.state.fieldError} value={wizardConsumer[FIELD_NAMES.MILITARY]}
> disabled={this.state.fieldError}
<option value="default">{gettext('Select military status')}</option> >
{ <option value="default">{gettext('Select military status')}</option>
this.loadOptions(FIELD_NAMES.MILITARY) {
} this.loadOptions(FIELD_NAMES.MILITARY)
</select> }
</select>
</div>
</div> </div>
</div> )}
}
</Wizard.Page> </Wizard.Page>
<Wizard.Page> <Wizard.Page>
{({wizardConsumer}) => <div className="demographics-form-container" data-hj-suppress> {({wizardConsumer}) => (
{/* Learner Education Level */} <div className="demographics-form-container" data-hj-suppress>
<div className="d-flex flex-column pb-3"> {/* Learner Education Level */}
<label htmlFor={FIELD_NAMES.EDUCATION_LEVEL}> <div className="d-flex flex-column pb-3">
{gettext('What is the highest level of education that you have achieved so far?')} <label htmlFor={FIELD_NAMES.EDUCATION_LEVEL}>
</label> {gettext('What is the highest level of education that you have achieved so far?')}
<select </label>
className="form-control" <select
autoFocus className="form-control"
onChange={this.handleSelectChange} autoFocus
key="self-education" onChange={this.handleSelectChange}
name={FIELD_NAMES.EDUCATION_LEVEL} key="self-education"
id={FIELD_NAMES.EDUCATION_LEVEL} name={FIELD_NAMES.EDUCATION_LEVEL}
value={wizardConsumer[FIELD_NAMES.EDUCATION_LEVEL]} id={FIELD_NAMES.EDUCATION_LEVEL}
disabled={this.state.fieldError} value={wizardConsumer[FIELD_NAMES.EDUCATION_LEVEL]}
> disabled={this.state.fieldError}
<option value="default">{gettext('Select level of education')}</option> >
{ <option value="default">{gettext('Select level of education')}</option>
this.loadOptions(FIELD_NAMES.EDUCATION_LEVEL) {
} this.loadOptions(FIELD_NAMES.EDUCATION_LEVEL)
</select> }
</select>
</div>
{/* Parent/Guardian Education Level */}
<div className="d-flex flex-column pb-3">
<label htmlFor={FIELD_NAMES.PARENT_EDUCATION}>
{gettext('What is the highest level of education that any of your parents or guardians have achieved?')}
</label>
<select
className="form-control"
onChange={this.handleSelectChange}
name={FIELD_NAMES.PARENT_EDUCATION}
id={FIELD_NAMES.PARENT_EDUCATION}
value={wizardConsumer[FIELD_NAMES.PARENT_EDUCATION]}
disabled={this.state.fieldError}
>
<option value="default">{gettext('Select guardian education')}</option>
{
this.loadOptions(FIELD_NAMES.PARENT_EDUCATION)
}
</select>
</div>
</div> </div>
{/* Parent/Guardian Education Level */} )}
<div className="d-flex flex-column pb-3">
<label htmlFor={FIELD_NAMES.PARENT_EDUCATION}>
{gettext('What is the highest level of education that any of your parents or guardians have achieved?')}
</label>
<select
className="form-control"
onChange={this.handleSelectChange}
name={FIELD_NAMES.PARENT_EDUCATION}
id={FIELD_NAMES.PARENT_EDUCATION}
value={wizardConsumer[FIELD_NAMES.PARENT_EDUCATION]}
disabled={this.state.fieldError}
>
<option value="default">{gettext('Select guardian education')}</option>
{
this.loadOptions(FIELD_NAMES.PARENT_EDUCATION)
}
</select>
</div>
</div>
}
</Wizard.Page> </Wizard.Page>
<Wizard.Page> <Wizard.Page>
{({wizardConsumer}) => <div className="demographics-form-container" data-hj-suppress> {({wizardConsumer}) => (
{/* Employment Status */} <div className="demographics-form-container" data-hj-suppress>
<SelectWithInput {/* Employment Status */}
selectName={FIELD_NAMES.WORK_STATUS} <SelectWithInput
selectId={FIELD_NAMES.WORK_STATUS} selectName={FIELD_NAMES.WORK_STATUS}
selectValue={wizardConsumer[FIELD_NAMES.WORK_STATUS]} selectId={FIELD_NAMES.WORK_STATUS}
selectOnChange={this.handleSelectChange} selectValue={wizardConsumer[FIELD_NAMES.WORK_STATUS]}
labelText={'What is your current employment status?'} selectOnChange={this.handleSelectChange}
options={[ labelText="What is your current employment status?"
<option value="default" key="default">{gettext('Select employment status')}</option>, options={[
this.loadOptions(FIELD_NAMES.WORK_STATUS) <option value="default" key="default">{gettext('Select employment status')}</option>,
]} this.loadOptions(FIELD_NAMES.WORK_STATUS)
showInput={wizardConsumer[FIELD_NAMES.WORK_STATUS] == 'other'} ]}
inputName={FIELD_NAMES.WORK_STATUS_DESCRIPTION} showInput={wizardConsumer[FIELD_NAMES.WORK_STATUS] == 'other'}
inputId={FIELD_NAMES.WORK_STATUS_DESCRIPTION} inputName={FIELD_NAMES.WORK_STATUS_DESCRIPTION}
inputType="text" inputId={FIELD_NAMES.WORK_STATUS_DESCRIPTION}
inputValue={wizardConsumer[FIELD_NAMES.WORK_STATUS_DESCRIPTION]} inputType="text"
inputOnChange={this.handleInputChange} inputValue={wizardConsumer[FIELD_NAMES.WORK_STATUS_DESCRIPTION]}
inputOnBlur={this.handleSelectChange} inputOnChange={this.handleInputChange}
disabled={this.state.fieldError} inputOnBlur={this.handleSelectChange}
/>
{/* Current Work Industry */}
<div className="d-flex flex-column pb-3">
<label htmlFor={FIELD_NAMES.CURRENT_WORK}>
{gettext('What industry do you currently work in?')}
</label>
<select
className="form-control"
onChange={this.handleSelectChange}
name={FIELD_NAMES.CURRENT_WORK}
id={FIELD_NAMES.CURRENT_WORK}
value={wizardConsumer[FIELD_NAMES.CURRENT_WORK]}
disabled={this.state.fieldError} disabled={this.state.fieldError}
> />
<option value="default">{gettext('Select current industry')}</option> {/* Current Work Industry */}
{ <div className="d-flex flex-column pb-3">
this.loadOptions(FIELD_NAMES.CURRENT_WORK) <label htmlFor={FIELD_NAMES.CURRENT_WORK}>
} {gettext('What industry do you currently work in?')}
</select> </label>
<select
className="form-control"
onChange={this.handleSelectChange}
name={FIELD_NAMES.CURRENT_WORK}
id={FIELD_NAMES.CURRENT_WORK}
value={wizardConsumer[FIELD_NAMES.CURRENT_WORK]}
disabled={this.state.fieldError}
>
<option value="default">{gettext('Select current industry')}</option>
{
this.loadOptions(FIELD_NAMES.CURRENT_WORK)
}
</select>
</div>
{/* Future Work Industry */}
<div className="d-flex flex-column pb-3">
<label htmlFor={FIELD_NAMES.FUTURE_WORK}>
{gettext('What industry do you want to work in?')}
</label>
<select
className="form-control"
onChange={this.handleSelectChange}
name={FIELD_NAMES.FUTURE_WORK}
id={FIELD_NAMES.FUTURE_WORK}
value={wizardConsumer[FIELD_NAMES.FUTURE_WORK]}
disabled={this.state.fieldError}
>
<option value="default">{gettext('Select prospective industry')}</option>
{
this.loadOptions(FIELD_NAMES.FUTURE_WORK)
}
</select>
</div>
</div> </div>
{/* Future Work Industry */} )}
<div className="d-flex flex-column pb-3">
<label htmlFor={FIELD_NAMES.FUTURE_WORK}>
{gettext('What industry do you want to work in?')}
</label>
<select
className="form-control"
onChange={this.handleSelectChange}
name={FIELD_NAMES.FUTURE_WORK}
id={FIELD_NAMES.FUTURE_WORK}
value={wizardConsumer[FIELD_NAMES.FUTURE_WORK]}
disabled={this.state.fieldError}
>
<option value="default">{gettext('Select prospective industry')}</option>
{
this.loadOptions(FIELD_NAMES.FUTURE_WORK)
}
</select>
</div>
</div>
}
</Wizard.Page> </Wizard.Page>
<Wizard.Closer> <Wizard.Closer>
<div className="demographics-modal-closer m-sm-0"> <div className="demographics-modal-closer m-sm-0">
<i className="fa fa-check" aria-hidden="true"></i> <i className="fa fa-check" aria-hidden="true" />
<h3> <h3>
{gettext('Thank you! Youre helping make edX better for everyone.')} {gettext('Thank you! Youre helping make edX better for everyone.')}
</h3> </h3>
@@ -493,7 +497,7 @@ class DemographicsCollectionModal extends React.Component {
</Wizard> </Wizard>
</div> </div>
</FocusLock> </FocusLock>
) );
} }
} }

View File

@@ -13,7 +13,7 @@ class MultiselectDropdown extends React.Component {
this.buttonRef = null; this.buttonRef = null;
this.setButtonRef = (element) => { this.setButtonRef = (element) => {
this.buttonRef = element; this.buttonRef = element;
} };
this.focusButton = this.focusButton.bind(this); this.focusButton = this.focusButton.bind(this);
this.handleKeydown = this.handleKeydown.bind(this); this.handleKeydown = this.handleKeydown.bind(this);
@@ -27,7 +27,6 @@ class MultiselectDropdown extends React.Component {
} }
componentWillUnmount() { componentWillUnmount() {
document.removeEventListener('keydown', this.handleKeydown, false); document.removeEventListener('keydown', this.handleKeydown, false);
} }
@@ -87,7 +86,7 @@ class MultiselectDropdown extends React.Component {
.map(selected => this.findOption(selected).display_name) .map(selected => this.findOption(selected).display_name)
.join(', '); .join(', ');
if (selectedList.length > 60) { if (selectedList.length > 60) {
return selectedList.substring(0, 55) + '...' return selectedList.substring(0, 55) + '...';
} }
return selectedList; return selectedList;
} }
@@ -95,7 +94,7 @@ class MultiselectDropdown extends React.Component {
renderUnselect() { renderUnselect() {
return this.props.selected.length > 0 && ( return this.props.selected.length > 0 && (
<button id="unselect-button" disabled={this.props.disabled} aria-label="Clear all selected" onClick={this.handleRemoveAllClick}>{gettext('Clear all')}</button> <button id="unselect-button" disabled={this.props.disabled} aria-label="Clear all selected" onClick={this.handleRemoveAllClick}>{gettext('Clear all')}</button>
) );
} }
renderMenu() { renderMenu() {
@@ -112,15 +111,15 @@ class MultiselectDropdown extends React.Component {
<span className="pl-2">{option.display_name}</span> <span className="pl-2">{option.display_name}</span>
</label> </label>
</div> </div>
) );
}) });
return ( return (
<fieldset id="multiselect-dropdown-fieldset" disabled={this.props.disabled}> <fieldset id="multiselect-dropdown-fieldset" disabled={this.props.disabled}>
<legend className="sr-only">{this.props.label}</legend> <legend className="sr-only">{this.props.label}</legend>
{options} {options}
</fieldset> </fieldset>
) );
} }
render() { render() {
@@ -136,7 +135,7 @@ class MultiselectDropdown extends React.Component {
// and close the dropdown. // and close the dropdown.
if (!e.currentTarget.contains(e.relatedTarget)) { if (!e.currentTarget.contains(e.relatedTarget)) {
this.props.onBlur(e); this.props.onBlur(e);
this.setState({open: false}) this.setState({open: false});
} }
}} }}
> >
@@ -151,7 +150,7 @@ class MultiselectDropdown extends React.Component {
{this.renderMenu()} {this.renderMenu()}
</div> </div>
</div> </div>
) );
} }
} }

View File

@@ -32,19 +32,20 @@ export const SelectWithInput = (props) => {
{options} {options}
</select> </select>
{showInput {showInput
&& <input && (
className="form-control" <input
aria-label={`${selectName} description field`} className="form-control"
type={inputType} aria-label={`${selectName} description field`}
name={inputName} type={inputType}
id={inputId} name={inputName}
onChange={inputOnChange} id={inputId}
onBlur={inputOnBlur} onChange={inputOnChange}
value={inputValue} onBlur={inputOnBlur}
disabled={disabled} value={inputValue}
maxLength={255} disabled={disabled}
/> maxLength={255}
} />
)}
</div> </div>
) );
} };

View File

@@ -16,7 +16,7 @@ export default class Wizard extends React.Component {
totalPages: 0, totalPages: 0,
pages: [], pages: [],
wizardContext: {}, wizardContext: {},
} };
this.wizardComplete = this.wizardComplete.bind(this); this.wizardComplete = this.wizardComplete.bind(this);
} }
@@ -32,18 +32,18 @@ export default class Wizard extends React.Component {
handleNext() { handleNext() {
if (this.state.currentPage < this.props.children.length) { if (this.state.currentPage < this.props.children.length) {
this.setState(prevState => ({currentPage: prevState.currentPage + 1})) this.setState(prevState => ({currentPage: prevState.currentPage + 1}));
} }
} }
findSubComponentByType(type) { findSubComponentByType(type) {
return React.Children.toArray(this.props.children).filter(child => child.type.name === type) return React.Children.toArray(this.props.children).filter(child => child.type.name === type);
} }
// this needs to handle the case of no provided header // this needs to handle the case of no provided header
renderHeader() { renderHeader() {
const header = this.findSubComponentByType(Wizard.Header.name)[0]; const header = this.findSubComponentByType(Wizard.Header.name)[0];
return header.props.children({currentPage: this.state.currentPage, totalPages: this.state.totalPages}) return header.props.children({currentPage: this.state.currentPage, totalPages: this.state.totalPages});
} }
renderPage() { renderPage() {
@@ -74,7 +74,7 @@ export default class Wizard extends React.Component {
<button className="wizard-button colored" arial-label={gettext('close questionnaire')} onClick={this.props.onWizardComplete}>{gettext('Close')}</button> <button className="wizard-button colored" arial-label={gettext('close questionnaire')} onClick={this.props.onWizardComplete}>{gettext('Close')}</button>
</div> </div>
</div> </div>
) );
} }
/** /**

View File

@@ -181,7 +181,7 @@
_.each(modifiedUsers.changed, function(changedInfo) { _.each(modifiedUsers.changed, function(changedInfo) {
oldCohort = changedInfo.previous_cohort; oldCohort = changedInfo.previous_cohort;
if (oldCohort in movedByCohort) { if (oldCohort in movedByCohort) {
movedByCohort[oldCohort] = movedByCohort[oldCohort] + 1; movedByCohort[oldCohort] += 1;
} else { } else {
movedByCohort[oldCohort] = 1; movedByCohort[oldCohort] = 1;
} }

View File

@@ -8,8 +8,8 @@ function createMobileMenu() {
* Dynamically create a mobile menu from all specified mobile links * Dynamically create a mobile menu from all specified mobile links
* on the page. * on the page.
*/ */
'use strict'; 'use strict';
$('.mobile-nav-item').each(function() { $('.mobile-nav-item').each(function() {
var mobileNavItem = $(this).clone().addClass('mobile-nav-link'); var mobileNavItem = $(this).clone().addClass('mobile-nav-link');

View File

@@ -91,9 +91,9 @@ var onCertificatesReady = null;
var response = JSON.parse(jqXHR.responseText); var response = JSON.parse(jqXHR.responseText);
$certificate_regeneration_status.text(gettext(response.message)).addClass('message'); $certificate_regeneration_status.text(gettext(response.message)).addClass('message');
} catch (error) { } catch (error) {
$certificate_regeneration_status. $certificate_regeneration_status
text(gettext('Error while regenerating certificates. Please try again.')). .text(gettext('Error while regenerating certificates. Please try again.'))
addClass('message'); .addClass('message');
} }
} }
}); });

View File

@@ -1,6 +1,6 @@
(function($) { // eslint-disable-line wrap-iife (function($) { // eslint-disable-line wrap-iife
'use strict'; 'use strict';
$.fn.extend({ $.fn.extend({
/* /*

View File

@@ -81,13 +81,15 @@ class CircleChart extends React.Component {
lastY = nextY; lastY = nextY;
// eslint-disable-next-line react/jsx-indent // eslint-disable-next-line react/jsx-indent
return <path return (
d={d} <path
className={`slice-${sliceIndex}`} d={d}
key={index} className={`slice-${sliceIndex}`}
stroke={strokeColor} key={index}
strokeWidth={strokeWidth} stroke={strokeColor}
/>; strokeWidth={strokeWidth}
/>
);
}); });
} }

View File

@@ -50,6 +50,6 @@ class CircleChartLegend extends React.Component {
CircleChartLegend.propTypes = { CircleChartLegend.propTypes = {
data: PropTypes.array.isRequired data: PropTypes.array.isRequired
} };
export default CircleChartLegend; export default CircleChartLegend;

View File

@@ -72,7 +72,7 @@ class Discussions extends React.Component {
</div> </div>
<div className="post-counts"> <div className="post-counts">
<div className="votes-wrapper"> <div className="votes-wrapper">
<span className="fa fa-plus-square-o count-icon" aria-hidden="true"></span> <span className="fa fa-plus-square-o count-icon" aria-hidden="true" />
<span className="user-count">{thread_votes}</span> <span className="user-count">{thread_votes}</span>
<p className="label">Votes on your posts, comments, and replies</p> <p className="label">Votes on your posts, comments, and replies</p>
</div> </div>
@@ -85,6 +85,6 @@ class Discussions extends React.Component {
Discussions.propTypes = { Discussions.propTypes = {
content_authored: PropTypes.number.isRequired, content_authored: PropTypes.number.isRequired,
thread_votes: PropTypes.number.isRequired thread_votes: PropTypes.number.isRequired
} };
export default Discussions; export default Discussions;

View File

@@ -22,7 +22,7 @@ class DueDates extends React.Component {
getLabel(type) { getLabel(type) {
const {assignmentCounts} = this.props; const {assignmentCounts} = this.props;
if (assignmentCounts[type] < 2 ) { if (assignmentCounts[type] < 2) {
return type; return type;
} else { } else {
this.renderLabels[type] += 1; this.renderLabels[type] += 1;
@@ -35,14 +35,12 @@ class DueDates extends React.Component {
this.renderLabels = this.initLabelTracker(assignmentCounts); this.renderLabels = this.initLabelTracker(assignmentCounts);
return dates.sort((a, b) => new Date(a.due) > new Date(b.due)) return dates.sort((a, b) => new Date(a.due) > new Date(b.due))
.map(({format, due}, index) => { .map(({format, due}, index) => (
return ( <li className="date-item" key={index}>
<li className="date-item" key={index}> <div className="label">{this.getLabel(format)}</div>
<div className="label">{this.getLabel(format)}</div> <div className="data">{this.getDate(due)}</div>
<div className="data">{this.getDate(due)}</div> </li>
</li> ));
);
});
} }
initLabelTracker(list) { initLabelTracker(list) {
@@ -51,7 +49,7 @@ class DueDates extends React.Component {
return labels.reduce((accumulator, key) => { return labels.reduce((accumulator, key) => {
accumulator[key] = 0; accumulator[key] = 0;
return accumulator; return accumulator;
}, {}) }, {});
} }
renderList() { renderList() {
@@ -73,6 +71,6 @@ class DueDates extends React.Component {
DueDates.propTypes = { DueDates.propTypes = {
dates: PropTypes.array.isRequired dates: PropTypes.array.isRequired
} };
export default DueDates; export default DueDates;

View File

@@ -1,20 +1,21 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
const exGrades = [ const exGrades = [
{ {
'assignment_type':'Exam', assignment_type: 'Exam',
'total_possible':6.0, total_possible: 6.0,
'total_earned':3.0 total_earned: 3.0
}, },
{ {
'assignment_type':'Homework', assignment_type: 'Homework',
'total_possible':5.0, total_possible: 5.0,
}, },
{ {
'assignment_type':'Homework', assignment_type: 'Homework',
'total_possible':11.0, total_possible: 11.0,
'total_earned':0.0 total_earned: 0.0
} }
]; ];
@@ -26,7 +27,7 @@ class GradeTable extends React.Component {
getTableGroup(type, groupIndex) { getTableGroup(type, groupIndex) {
const {grades} = this.props; const {grades} = this.props;
const groupData = grades.filter(value => { const groupData = grades.filter(value => {
if (value['assignment_type'] === type) { if (value.assignment_type === type) {
return value; return value;
} }
}); });
@@ -68,15 +69,15 @@ class GradeTable extends React.Component {
</tr> </tr>
</tfoot> </tfoot>
</table> </table>
) );
} }
}; }
GradeTable.propTypes = { GradeTable.propTypes = {
assignmentTypes: PropTypes.array.isRequired, assignmentTypes: PropTypes.array.isRequired,
grades: PropTypes.array.isRequired, grades: PropTypes.array.isRequired,
passingGrade: PropTypes.number.isRequired, passingGrade: PropTypes.number.isRequired,
percentGrade: PropTypes.number.isRequired percentGrade: PropTypes.number.isRequired
} };
export default GradeTable; export default GradeTable;

View File

@@ -15,7 +15,7 @@ function arrayToObject(array) {
const key = Object.keys(obj)[0]; const key = Object.keys(obj)[0];
accumulator[key] = obj[key]; accumulator[key] = obj[key];
return accumulator; return accumulator;
}, {}) }, {});
} }
function countByType(type, assignments) { function countByType(type, assignments) {
@@ -24,7 +24,7 @@ function countByType(type, assignments) {
if (format === type) { if (format === type) {
count += 1; count += 1;
} }
}) });
return count; return count;
} }
@@ -34,18 +34,16 @@ function getActiveUserString(count) {
} }
function getAssignmentCounts(types, assignments) { function getAssignmentCounts(types, assignments) {
const countsArray = types.map((type) => { const countsArray = types.map((type) => ({
return { [type]: countByType(type, assignments)
[type]: countByType(type, assignments) }));
}
});
return arrayToObject(countsArray); return arrayToObject(countsArray);
} }
function getStreakIcons(count) { function getStreakIcons(count) {
return Array.apply(null, {length: count}).map((e, i) => ( return Array.apply(null, {length: count}).map((e, i) => (
<span className="fa fa-trophy" aria-hidden="true" key={i}></span> <span className="fa fa-trophy" aria-hidden="true" key={i} />
)); ));
} }
@@ -56,7 +54,7 @@ function getStreakEncouragement(count) {
} }
function getStreakString(count) { function getStreakString(count) {
const unit = (count ===1) ? 'week' : 'weeks'; const unit = (count === 1) ? 'week' : 'weeks';
return (count > 0) ? `Active ${count} ${unit} in a row` : false; return (count > 0) ? `Active ${count} ${unit} in a row` : false;
} }
@@ -64,16 +62,14 @@ export function LearnerAnalyticsDashboard(props) {
const { const {
grading_policy, grades, schedule, schedule_raw, week_streak, weekly_active_users, discussion_info, profile_images, passing_grade, percent_grade grading_policy, grades, schedule, schedule_raw, week_streak, weekly_active_users, discussion_info, profile_images, passing_grade, percent_grade
} = props; } = props;
const gradeBreakdown = grading_policy.GRADER.map(({type, weight}, index) => { const gradeBreakdown = grading_policy.GRADER.map(({type, weight}, index) => ({
return { value: weight,
value: weight, label: type,
label: type, sliceIndex: index + 1
sliceIndex: index + 1 }));
}
});
// Get a list of assignment types minus duplicates // Get a list of assignment types minus duplicates
const assignments = gradeBreakdown.map(value => value['label']); const assignments = gradeBreakdown.map(value => value.label);
const assignmentTypes = [...new Set(assignments)]; const assignmentTypes = [...new Set(assignments)];
const assignmentCounts = getAssignmentCounts(assignmentTypes, schedule); const assignmentCounts = getAssignmentCounts(assignmentTypes, schedule);
@@ -86,23 +82,23 @@ export function LearnerAnalyticsDashboard(props) {
<div className="analytics-group"> <div className="analytics-group">
<h2 className="group-heading">Grading</h2> <h2 className="group-heading">Grading</h2>
{gradeBreakdown {gradeBreakdown
&& <h3 className="section-heading">Weight</h3> && <h3 className="section-heading">Weight</h3>}
}
{gradeBreakdown {gradeBreakdown
&& <div className="grading-weight-wrapper"> && (
<div className="chart-wrapper"> <div className="grading-weight-wrapper">
<CircleChart <div className="chart-wrapper">
slices={gradeBreakdown} <CircleChart
centerHole={true} slices={gradeBreakdown}
sliceBorder={{ centerHole
strokeColor: '#f5f5f5', sliceBorder={{
strokeWidth: 2 strokeColor: '#f5f5f5',
}} strokeWidth: 2
/> }}
/>
</div>
<CircleChartLegend data={gradeBreakdown} />
</div> </div>
<CircleChartLegend data={gradeBreakdown} /> )}
</div>
}
<h3 className="section-heading">Graded Assignments</h3> <h3 className="section-heading">Graded Assignments</h3>
{/* TODO: LEARNER-3854: If implementing Learner Analytics, rename to graded-assignments-wrapper. */} {/* TODO: LEARNER-3854: If implementing Learner Analytics, rename to graded-assignments-wrapper. */}
@@ -125,8 +121,7 @@ export function LearnerAnalyticsDashboard(props) {
<div className="week-streak-wrapper"> <div className="week-streak-wrapper">
<h3 className="section-heading">Week streak</h3> <h3 className="section-heading">Week streak</h3>
{week_streak > 0 {week_streak > 0
&& <div className="streak-icon-wrapper" aria-hidden="true">{getStreakIcons(week_streak)}</div> && <div className="streak-icon-wrapper" aria-hidden="true">{getStreakIcons(week_streak)}</div>}
}
<p>{getStreakString(week_streak)}</p> <p>{getStreakString(week_streak)}</p>
<p className="streak-encouragement">{getStreakEncouragement(week_streak)}</p> <p className="streak-encouragement">{getStreakEncouragement(week_streak)}</p>
<ul className="streak-criteria"> <ul className="streak-criteria">
@@ -136,8 +131,8 @@ export function LearnerAnalyticsDashboard(props) {
</ul> </ul>
</div> </div>
<div className="active-users-wrapper"> <div className="active-users-wrapper">
<span className="fa fa-user count-icon" aria-hidden="true"></span> <span className="fa fa-user count-icon" aria-hidden="true" />
<span className="user-count">{weekly_active_users.toLocaleString('en', {useGrouping:true})}</span> <span className="user-count">{weekly_active_users.toLocaleString('en', {useGrouping: true})}</span>
<p className="label">{getActiveUserString(weekly_active_users)}</p> <p className="label">{getActiveUserString(weekly_active_users)}</p>
</div> </div>
</div> </div>

View File

@@ -117,7 +117,7 @@ class EnterpriseLearnerPortalModal extends React.Component {
gettext('You have access to the {enterpriseName} dashboard'), gettext('You have access to the {enterpriseName} dashboard'),
{ {
enterpriseName: this.props.enterpriseCustomerName, enterpriseName: this.props.enterpriseCustomerName,
} },
)} )}
</div> </div>
<p> <p>
@@ -125,7 +125,7 @@ class EnterpriseLearnerPortalModal extends React.Component {
gettext('To access the courses available to you through {enterpriseName}, visit the {enterpriseName} dashboard.'), gettext('To access the courses available to you through {enterpriseName}, visit the {enterpriseName} dashboard.'),
{ {
enterpriseName: this.props.enterpriseCustomerName, enterpriseName: this.props.enterpriseCustomerName,
} },
)} )}
</p> </p>
<div className="mt-4 d-flex align-content-center justify-content-end"> <div className="mt-4 d-flex align-content-center justify-content-end">

View File

@@ -217,7 +217,7 @@ describe('Course Enroll View', () => {
view.enrollSuccess(); view.enrollSuccess();
expect(CourseEnrollView.redirect).toHaveBeenCalledWith( expect(CourseEnrollView.redirect).toHaveBeenCalledWith(
view.trackSelectionUrl + courseCardModel.get('course_run_key') view.trackSelectionUrl + courseCardModel.get('course_run_key'),
); );
}); });

View File

@@ -83,7 +83,7 @@ describe('Course Entitlement View', () => {
it('Courses with an an enroll by date should indicate so on the selection option.', () => { it('Courses with an an enroll by date should indicate so on the selection option.', () => {
const enrollEndSetOptionIndex = entitlementAvailableSessions.findIndex( const enrollEndSetOptionIndex = entitlementAvailableSessions.findIndex(
session => session.enrollment_end !== null session => session.enrollment_end !== null,
); );
const enrollEndSetOption = selectOptions[enrollEndSetOptionIndex]; const enrollEndSetOption = selectOptions[enrollEndSetOptionIndex];
expect(enrollEndSetOption && enrollEndSetOption.text.includes('Open until')).toBe(true); expect(enrollEndSetOption && enrollEndSetOption.text.includes('Open until')).toBe(true);
@@ -123,7 +123,7 @@ describe('Course Entitlement View', () => {
it('Currently selected session should be specified in the dropdown options.', () => { it('Currently selected session should be specified in the dropdown options.', () => {
const selectedSessionIndex = entitlementAvailableSessions.findIndex( const selectedSessionIndex = entitlementAvailableSessions.findIndex(
session => initialSessionId === session.session_id session => initialSessionId === session.session_id,
); );
expect(selectOptions[selectedSessionIndex].text.includes('Currently Selected')).toBe(true); expect(selectOptions[selectedSessionIndex].text.includes('Currently Selected')).toBe(true);
}); });

View File

@@ -61,18 +61,18 @@ describe('Program Progress View', () => {
expect(view.$('.js-subscription-info')[0]).toBeInDOM(); expect(view.$('.js-subscription-info')[0]).toBeInDOM();
expect( expect(
view.$('.js-subscription-info .divider-heading').text().trim() view.$('.js-subscription-info .divider-heading').text().trim(),
).toEqual(heading); ).toEqual(heading);
expect( expect(
view.$('.js-subscription-info .subscription-section p:nth-child(1)') view.$('.js-subscription-info .subscription-section p:nth-child(1)'),
).toContainHtml(body); ).toContainHtml(body);
expect( expect(
view.$('.js-subscription-info .subscription-section p:nth-child(2)') view.$('.js-subscription-info .subscription-section p:nth-child(2)'),
).toContainText( ).toContainText(
/Need help\? Check out the.*Learner Help Center.*to troubleshoot issues or contact support/ /Need help\? Check out the.*Learner Help Center.*to troubleshoot issues or contact support/,
); );
expect( expect(
view.$('.js-subscription-info .subscription-section p:nth-child(2) .subscription-link').attr('href') view.$('.js-subscription-info .subscription-section p:nth-child(2) .subscription-link').attr('href'),
).toEqual('/learner'); ).toEqual('/learner');
}; };
@@ -235,18 +235,18 @@ describe('Program Progress View', () => {
testSubscriptionState( testSubscriptionState(
'pre', 'pre',
'Inactive subscription', 'Inactive subscription',
'If you had a subscription previously, your payment history is still available' 'If you had a subscription previously, your payment history is still available',
); );
}); });
it('should render active trial subscription info if subscription is active with trial', () => { it('should render active trial subscription info if subscription is active with trial', () => {
subscriptionData.trial_end = moment().add(3, 'days').utc().format( subscriptionData.trial_end = moment().add(3, 'days').utc().format(
'YYYY-MM-DDTHH:mm:ss[Z]' 'YYYY-MM-DDTHH:mm:ss[Z]',
); );
testSubscriptionState( testSubscriptionState(
'active', 'active',
'Trial subscription', 'Trial subscription',
'View your receipts or modify your subscription' 'View your receipts or modify your subscription',
); );
}); });
@@ -254,7 +254,7 @@ describe('Program Progress View', () => {
testSubscriptionState( testSubscriptionState(
'active', 'active',
'Active subscription', 'Active subscription',
'View your receipts or modify your subscription' 'View your receipts or modify your subscription',
); );
}); });
@@ -262,7 +262,7 @@ describe('Program Progress View', () => {
testSubscriptionState( testSubscriptionState(
'inactive', 'inactive',
'Inactive subscription', 'Inactive subscription',
'Restart your subscription for $100/month. Your payment history is still available' 'Restart your subscription for $100/month. Your payment history is still available',
); );
}); });
}); });

View File

@@ -524,7 +524,7 @@ describe('Program Details View', () => {
}; };
if (trial) { if (trial) {
subscriptionData.trial_end = moment().add(3, 'days').utc().format( subscriptionData.trial_end = moment().add(3, 'days').utc().format(
'YYYY-MM-DDTHH:mm:ss[Z]' 'YYYY-MM-DDTHH:mm:ss[Z]',
); );
} }
view = initView({ view = initView({
@@ -580,9 +580,9 @@ describe('Program Details View', () => {
expect(view.$('.program-heading-title').text()).toEqual('Your Program Journey'); expect(view.$('.program-heading-title').text()).toEqual('Your Program Journey');
expect(view.$('.program-heading-message').text().trim() expect(view.$('.program-heading-message').text().trim()
.replace(/\s+/g, ' ')).toEqual( .replace(/\s+/g, ' ')).toEqual(
'Track and plan your progress through the 3 courses in this program. ' 'Track and plan your progress through the 3 courses in this program. '
+ 'To complete the program, you must earn a verified certificate for each course.', + 'To complete the program, you must earn a verified certificate for each course.',
); );
}); });
it('should render the program heading congratulations message if all courses completed', () => { it('should render the program heading congratulations message if all courses completed', () => {
@@ -598,8 +598,8 @@ describe('Program Details View', () => {
expect(view.$('.program-heading-title').text()).toEqual('Congratulations!'); expect(view.$('.program-heading-title').text()).toEqual('Congratulations!');
expect(view.$('.program-heading-message').text().trim() expect(view.$('.program-heading-message').text().trim()
.replace(/\s+/g, ' ')).toEqual( .replace(/\s+/g, ' ')).toEqual(
'You have successfully completed all the requirements for the Test Course Title Test.', 'You have successfully completed all the requirements for the Test Course Title Test.',
); );
}); });
it('should render the course list headings', () => { it('should render the course list headings', () => {
@@ -695,7 +695,7 @@ describe('Program Details View', () => {
testSubscriptionState( testSubscriptionState(
'pre', 'pre',
'Start 7-day free trial', 'Start 7-day free trial',
'$100/month subscription after trial ends. Cancel anytime.' '$100/month subscription after trial ends. Cancel anytime.',
); );
}); });
@@ -704,7 +704,7 @@ describe('Program Details View', () => {
'active', 'active',
'Manage my subscription', 'Manage my subscription',
'Active trial ends', 'Active trial ends',
true true,
); );
}); });
@@ -712,7 +712,7 @@ describe('Program Details View', () => {
testSubscriptionState( testSubscriptionState(
'active', 'active',
'Manage my subscription', 'Manage my subscription',
'Your next billing date is' 'Your next billing date is',
); );
}); });
@@ -720,7 +720,7 @@ describe('Program Details View', () => {
testSubscriptionState( testSubscriptionState(
'inactive', 'inactive',
'Restart my subscription', 'Restart my subscription',
'Unlock verified access to all courses for $100/month. Cancel anytime.' 'Unlock verified access to all courses for $100/month. Cancel anytime.',
); );
}); });
}); });

View File

@@ -45,7 +45,7 @@ class CollectionListView extends Backbone.View {
StringUtils.interpolate(this.titleContext.title), StringUtils.interpolate(this.titleContext.title),
HtmlUtils.HTML('</'), HtmlUtils.HTML('</'),
this.titleContext.el, this.titleContext.el,
HtmlUtils.HTML('>') HtmlUtils.HTML('>'),
); );
return titleHtml; return titleHtml;
} }

View File

@@ -45,7 +45,7 @@ class ProgramDetailsView extends Backbone.View {
this.programModel = new Backbone.Model(this.options.programData); this.programModel = new Backbone.Model(this.options.programData);
this.courseData = new Backbone.Model(this.options.courseData); this.courseData = new Backbone.Model(this.options.courseData);
this.certificateCollection = new Backbone.Collection( this.certificateCollection = new Backbone.Collection(
this.options.certificateData this.options.certificateData,
); );
this.subscriptionModel = new SubscriptionModel({ this.subscriptionModel = new SubscriptionModel({
context: this.options, context: this.options,
@@ -92,7 +92,7 @@ class ProgramDetailsView extends Backbone.View {
const totalCount = completedCount + inProgressCount + remainingCount; const totalCount = completedCount + inProgressCount + remainingCount;
const buyButtonUrl = ProgramDetailsView.getUrl( const buyButtonUrl = ProgramDetailsView.getUrl(
this.options.urls.buy_button_url, this.options.urls.buy_button_url,
this.options.programData this.options.programData,
); );
let data = { let data = {

View File

@@ -2,7 +2,7 @@ import Backbone from 'backbone';
import HtmlUtils from 'edx-ui-toolkit/js/utils/html-utils'; import HtmlUtils from 'edx-ui-toolkit/js/utils/html-utils';
import progressViewTpl from '../../../templates/learner_dashboard//progress_circle_view.underscore'; import progressViewTpl from '../../../templates/learner_dashboard/progress_circle_view.underscore';
import progressSegmentTpl from '../../../templates/learner_dashboard/progress_circle_segment.underscore'; import progressSegmentTpl from '../../../templates/learner_dashboard/progress_circle_segment.underscore';
class ProgressCircleView extends Backbone.View { class ProgressCircleView extends Backbone.View {

View File

@@ -3,7 +3,6 @@
import Backbone from 'backbone'; import Backbone from 'backbone';
class UnenrollView extends Backbone.View { class UnenrollView extends Backbone.View {
constructor(options) { constructor(options) {
const defaults = { const defaults = {
el: '.unenroll-modal', el: '.unenroll-modal',

View File

@@ -101,7 +101,6 @@ function(Backbone, $, AjaxHelpers, TemplateHelpers, CohortsView, CohortCollectio
if (options && options.selectCohort) { if (options && options.selectCohort) {
cohortsView.$('.cohort-select').val(options.selectCohort.toString()).change(); cohortsView.$('.cohort-select').val(options.selectCohort.toString()).change();
} }
}; };
respondToRefresh = function(catCount, dogCount) { respondToRefresh = function(catCount, dogCount) {
@@ -262,8 +261,8 @@ function(Backbone, $, AjaxHelpers, TemplateHelpers, CohortsView, CohortCollectio
// But upload form should not be visible until toggle is clicked. // But upload form should not be visible until toggle is clicked.
expect(cohortsView.$(fileUploadFormCss).length).toBe(0); expect(cohortsView.$(fileUploadFormCss).length).toBe(0);
uploadCsvToggle = cohortsView.$('.toggle-cohort-management-secondary'); uploadCsvToggle = cohortsView.$('.toggle-cohort-management-secondary');
expect(uploadCsvToggle.text()). expect(uploadCsvToggle.text())
toContain('Assign learners to cohorts by uploading a CSV file'); .toContain('Assign learners to cohorts by uploading a CSV file');
uploadCsvToggle.click(); uploadCsvToggle.click();
// After toggle is clicked, it should be hidden. // After toggle is clicked, it should be hidden.
expect(uploadCsvToggle).toHaveClass('hidden'); expect(uploadCsvToggle).toHaveClass('hidden');

View File

@@ -133,17 +133,17 @@ function(Backbone, $, AjaxHelpers, TemplateHelpers, DiscussionsView, CourseDiscu
expect($inlineDiscussionsForm.length).toBe(1); expect($inlineDiscussionsForm.length).toBe(1);
expect($courseWideDiscussionsForm.length).toBe(1); expect($courseWideDiscussionsForm.length).toBe(1);
expect($courseWideDiscussionsForm.text()). expect($courseWideDiscussionsForm.text())
toContain('Course-Wide Discussion Topics'); .toContain('Course-Wide Discussion Topics');
expect($courseWideDiscussionsForm.text()). expect($courseWideDiscussionsForm.text())
toContain('Select the course-wide discussion topics that you want to divide.'); .toContain('Select the course-wide discussion topics that you want to divide.');
// Should see the inline discussions form and its content // Should see the inline discussions form and its content
expect($inlineDiscussionsForm.length).toBe(1); expect($inlineDiscussionsForm.length).toBe(1);
expect($inlineDiscussionsForm.text()). expect($inlineDiscussionsForm.text())
toContain('Content-Specific Discussion Topics'); .toContain('Content-Specific Discussion Topics');
expect($inlineDiscussionsForm.text()). expect($inlineDiscussionsForm.text())
toContain('Specify whether content-specific discussion topics are divided.'); .toContain('Specify whether content-specific discussion topics are divided.');
}; };
beforeEach(function() { beforeEach(function() {

View File

@@ -182,10 +182,10 @@ function($, AjaxHelpers, CertificateInvalidationModel, CertificateInvalidationVi
view.collection.add(model); view.collection.add(model);
expect(view.$el.find('table tbody tr').length).toBe(3); expect(view.$el.find('table tbody tr').length).toBe(3);
expect(view.$el.find('table tbody tr td:contains("' + user + '")').parent().html()). expect(view.$el.find('table tbody tr td:contains("' + user + '")').parent().html())
toMatch(notes); .toMatch(notes);
expect(view.$el.find('table tbody tr td:contains("' + user + '")').parent().html()). expect(view.$el.find('table tbody tr td:contains("' + user + '")').parent().html())
toMatch(user); .toMatch(user);
// Remove a model from collection // Remove a model from collection
var collection_model = view.collection.get({id: 2}); var collection_model = view.collection.get({id: 2});

View File

@@ -17,7 +17,6 @@ function($, id, AjaxHelper) {
dataDownload = window.InstructorDashboard.sections; dataDownload = window.InstructorDashboard.sections;
dataDownload.DataDownloadV2($('#data_download_2')); dataDownload.DataDownloadV2($('#data_download_2'));
window.InstructorDashboard.util.PendingInstructorTasks = function() { window.InstructorDashboard.util.PendingInstructorTasks = function() {
return;
}; };
requests = AjaxHelper.requests(this); requests = AjaxHelper.requests(this);
$selected = $('<option data-endpoint="api/url/fake"></option>'); $selected = $('<option data-endpoint="api/url/fake"></option>');

View File

@@ -2,8 +2,8 @@
define(['jquery', 'js/instructor_dashboard/student_admin', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers'], define(['jquery', 'js/instructor_dashboard/student_admin', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers'],
function($, StudentAdmin, AjaxHelpers) { function($, StudentAdmin, AjaxHelpers) {
// 'js/instructor_dashboard/student_admin' // 'js/instructor_dashboard/student_admin'
'use strict'; 'use strict';
describe('edx.instructor_dashboard.student_admin.StudentAdmin', function() { describe('edx.instructor_dashboard.student_admin.StudentAdmin', function() {
var studentadmin, dashboardApiUrl, uniqStudentIdentifier, alertMsg; var studentadmin, dashboardApiUrl, uniqStudentIdentifier, alertMsg;

View File

@@ -53,7 +53,6 @@ function(Backbone, $, _, AjaxHelpers, TemplateHelpers, FieldViewsSpecHelpers, He
Helpers.expectLoadingErrorIsVisible(accountSettingsView, true); Helpers.expectLoadingErrorIsVisible(accountSettingsView, true);
}); });
it('shows loading error when UserPreferencesModel fails to load', function() { it('shows loading error when UserPreferencesModel fails to load', function() {
requests = AjaxHelpers.requests(this); requests = AjaxHelpers.requests(this);
@@ -108,7 +107,7 @@ function(Backbone, $, _, AjaxHelpers, TemplateHelpers, FieldViewsSpecHelpers, He
AjaxHelpers.respondWithJson(requests, Helpers.createAccountSettingsData()); AjaxHelpers.respondWithJson(requests, Helpers.createAccountSettingsData());
AjaxHelpers.respondWithJson(requests, Helpers.TIME_ZONE_RESPONSE); AjaxHelpers.respondWithJson(requests, Helpers.TIME_ZONE_RESPONSE);
AjaxHelpers.respondWithJson(requests, Helpers.createUserPreferencesData()); AjaxHelpers.respondWithJson(requests, Helpers.createUserPreferencesData());
AjaxHelpers.respondWithJson(requests, {}); // Page viewed analytics event AjaxHelpers.respondWithJson(requests, {}); // Page viewed analytics event
var sectionsData = accountSettingsView.options.tabSections.aboutTabSections; var sectionsData = accountSettingsView.options.tabSections.aboutTabSections;
@@ -272,7 +271,7 @@ function(Backbone, $, _, AjaxHelpers, TemplateHelpers, FieldViewsSpecHelpers, He
AjaxHelpers.respondWithJson(requests, Helpers.createAccountSettingsData()); AjaxHelpers.respondWithJson(requests, Helpers.createAccountSettingsData());
AjaxHelpers.respondWithJson(requests, Helpers.TIME_ZONE_RESPONSE); AjaxHelpers.respondWithJson(requests, Helpers.TIME_ZONE_RESPONSE);
AjaxHelpers.respondWithJson(requests, Helpers.createUserPreferencesData()); AjaxHelpers.respondWithJson(requests, Helpers.createUserPreferencesData());
AjaxHelpers.respondWithJson(requests, {}); // Page viewed analytics event AjaxHelpers.respondWithJson(requests, {}); // Page viewed analytics event
sectionsData = accountSettingsView.options.tabSections.aboutTabSections; sectionsData = accountSettingsView.options.tabSections.aboutTabSections;
@@ -322,7 +321,7 @@ function(Backbone, $, _, AjaxHelpers, TemplateHelpers, FieldViewsSpecHelpers, He
title: view.options.title, title: view.options.title,
valueAttribute: view.options.valueAttribute, valueAttribute: view.options.valueAttribute,
helpMessage: '', helpMessage: '',
validValue: Helpers.FIELD_OPTIONS[1][0], // dummy option for dropdown field validValue: Helpers.FIELD_OPTIONS[1][0], // dummy option for dropdown field
invalidValue1: Helpers.FIELD_OPTIONS[2][0], // dummy option for dropdown field invalidValue1: Helpers.FIELD_OPTIONS[2][0], // dummy option for dropdown field
invalidValue2: Helpers.FIELD_OPTIONS[3][0], // dummy option for dropdown field invalidValue2: Helpers.FIELD_OPTIONS[3][0], // dummy option for dropdown field
validationError: 'Nope, this will not do!', validationError: 'Nope, this will not do!',

View File

@@ -45,8 +45,8 @@ function(Backbone, $, _, AjaxHelpers, TemplateHelpers, UserAccountModel, FieldVi
AjaxHelpers.respondWithJson(requests, {success: 'true'}); AjaxHelpers.respondWithJson(requests, {success: 'true'});
FieldViewsSpecHelpers.expectMessageContains( FieldViewsSpecHelpers.expectMessageContains(
view, view,
"We've sent a message to legolas@woodland.middlearth. " + "We've sent a message to legolas@woodland.middlearth. "
'Click the link in the message to reset your password.' + 'Click the link in the message to reset your password.'
); );
}); });

View File

@@ -21,8 +21,8 @@ function(Backbone, $, _, AjaxHelpers, TemplateHelpers, Helpers, FieldViews, User
{ {
title: 'Basic Account Information', title: 'Basic Account Information',
messageType: 'info', messageType: 'info',
message: 'Your profile settings are managed by Test Enterprise. ' + message: 'Your profile settings are managed by Test Enterprise. '
'Contact your administrator or <a href="https://support.edx.org/">edX Support</a> for help.', + 'Contact your administrator or <a href="https://support.edx.org/">edX Support</a> for help.',
fields: [ fields: [
{ {
view: new FieldViews.ReadonlyFieldView({ view: new FieldViews.ReadonlyFieldView({

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