chore: apply amnesty on existing not fixable issues (#32215)
* 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 * chore: apply amnesty on all existing issues * fix: failing xss-lint issues * refactor: apply amnesty on remaining issues * refactor: apply amnesty on new issues * fix: remove file level suppressions * refactor: apply amnesty on new issues
This commit is contained in:
committed by
GitHub
parent
e94af3c2d3
commit
8480dbc228
@@ -2,7 +2,9 @@ import { ViewedEventTracker } from './ViewedEvent';
|
||||
|
||||
const completedBlocksKeys = new Set();
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export function markBlocksCompletedOnViewIfNeeded(runtime, containerElement) {
|
||||
// eslint-disable-next-line no-undef
|
||||
const blockElements = $(containerElement).find(
|
||||
'.xblock-student_view[data-mark-completed-on-view-after-delay]',
|
||||
).get();
|
||||
@@ -21,6 +23,7 @@ export function markBlocksCompletedOnViewIfNeeded(runtime, containerElement) {
|
||||
const blockKey = blockElement.dataset.usageId;
|
||||
if (blockKey && !completedBlocksKeys.has(blockKey)) {
|
||||
if (event.elementHasBeenViewed) {
|
||||
// eslint-disable-next-line no-undef
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: runtime.handlerUrl(blockElement, 'publish_completion'),
|
||||
@@ -30,6 +33,7 @@ export function markBlocksCompletedOnViewIfNeeded(runtime, containerElement) {
|
||||
}).then(
|
||||
() => {
|
||||
completedBlocksKeys.add(blockKey);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
blockElement.dataset.markCompletedOnViewAfterDelay = 0;
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/** Ensure that a function is only run once every `wait` milliseconds */
|
||||
// eslint-disable-next-line max-classes-per-file
|
||||
function throttle(fn, wait) {
|
||||
let time = 0;
|
||||
function delay() {
|
||||
|
||||
@@ -13,43 +13,53 @@ describe('ViewedTracker', () => {
|
||||
it('calls the handlers when an element is viewed', () => {
|
||||
document.body.innerHTML = '<div id="d1"></div><div id="d2"></div><div id="d3"></div>';
|
||||
const tracker = new ViewedEventTracker();
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const element of document.getElementsByTagName('div')) {
|
||||
tracker.addElement(element, 1000);
|
||||
}
|
||||
// eslint-disable-next-line no-undef
|
||||
const handlerSpy = jasmine.createSpy('handlerSpy');
|
||||
tracker.addHandler(handlerSpy);
|
||||
const elvIter = tracker.elementViewings.values();
|
||||
// Pick two elements, and mock them so that one has met the criteria to be viewed,
|
||||
// and the other hasn't.
|
||||
const viewed = elvIter.next().value;
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(viewed, 'areViewedCriteriaMet').and.returnValue(true);
|
||||
viewed.checkIfViewed();
|
||||
expect(handlerSpy).toHaveBeenCalledWith(viewed.el, {
|
||||
elementHasBeenViewed: true,
|
||||
});
|
||||
const unviewed = elvIter.next().value;
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(unviewed, 'areViewedCriteriaMet').and.returnValue(false);
|
||||
unviewed.checkIfViewed();
|
||||
// eslint-disable-next-line no-undef
|
||||
expect(handlerSpy).not.toHaveBeenCalledWith(unviewed.el, jasmine.anything());
|
||||
});
|
||||
});
|
||||
|
||||
describe('ElementViewing', () => {
|
||||
beforeEach(() => {
|
||||
// eslint-disable-next-line no-undef
|
||||
jasmine.clock().install();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// eslint-disable-next-line no-undef
|
||||
jasmine.clock().uninstall();
|
||||
});
|
||||
|
||||
it('calls checkIfViewed when enough time has elapsed', () => {
|
||||
const viewing = new ElementViewing({}, 500, () => {});
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(viewing, 'checkIfViewed').and.callThrough();
|
||||
viewing.seenForMs = 250;
|
||||
viewing.handleVisible();
|
||||
// eslint-disable-next-line no-undef
|
||||
jasmine.clock().tick(249);
|
||||
expect(viewing.checkIfViewed).not.toHaveBeenCalled();
|
||||
// eslint-disable-next-line no-undef
|
||||
jasmine.clock().tick(1);
|
||||
expect(viewing.checkIfViewed).toHaveBeenCalled();
|
||||
});
|
||||
@@ -57,6 +67,7 @@ describe('ElementViewing', () => {
|
||||
it('has been viewed after the specified number of milliseconds', () => {
|
||||
const viewing = new ElementViewing({}, 500, () => {});
|
||||
viewing.seenForMs = 250;
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(Date, 'now').and.returnValue(750);
|
||||
viewing.handleVisible();
|
||||
viewing.markTopSeen();
|
||||
@@ -65,6 +76,7 @@ describe('ElementViewing', () => {
|
||||
viewing.checkIfViewed();
|
||||
expect(viewing.hasBeenViewed).toBeFalsy();
|
||||
Date.now.and.returnValue(1000);
|
||||
// eslint-disable-next-line no-undef
|
||||
jasmine.clock().tick(250);
|
||||
expect(viewing.hasBeenViewed).toBeTruthy();
|
||||
});
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
Markdown.Editor = function(markdownConverter, idPostfix, help, imageUploadHandler) {
|
||||
idPostfix = idPostfix || '';
|
||||
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
var hooks = this.hooks = new Markdown.HookCollection();
|
||||
hooks.addNoop('onPreviewPush'); // called with no arguments after the preview has been refreshed
|
||||
hooks.addNoop('postBlockquoteCreation'); // called with the user's selection *after* the blockquote was created; should return the actual to-be-inserted text
|
||||
@@ -102,6 +103,7 @@
|
||||
uiManager = new UIManager(idPostfix, panels, undoManager, previewManager, commandManager, help, imageUploadHandler);
|
||||
uiManager.setUndoRedoButtonStates();
|
||||
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
var forceRefresh = that.refreshPreview = function() { previewManager.refresh(true); };
|
||||
|
||||
forceRefresh();
|
||||
@@ -163,6 +165,7 @@
|
||||
var beforeReplacer, afterReplacer,
|
||||
that = this;
|
||||
if (remove) {
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
beforeReplacer = afterReplacer = '';
|
||||
} else {
|
||||
beforeReplacer = function(s) { that.before += s; return ''; };
|
||||
@@ -204,6 +207,7 @@
|
||||
this.after += re.$1;
|
||||
|
||||
if (this.before) {
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
regexText = replacementText = '';
|
||||
|
||||
while (nLinesBefore--) {
|
||||
@@ -218,6 +222,7 @@
|
||||
}
|
||||
|
||||
if (this.after) {
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
regexText = replacementText = '';
|
||||
|
||||
while (nLinesAfter--) {
|
||||
@@ -353,6 +358,7 @@
|
||||
position.getTop = function(elem, isInner) {
|
||||
var result = elem.offsetTop;
|
||||
if (!isInner) {
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
while (elem = elem.offsetParent) {
|
||||
result += elem.offsetTop;
|
||||
}
|
||||
@@ -523,6 +529,7 @@
|
||||
var keyCode = event.charCode || event.keyCode;
|
||||
var keyCodeChar = String.fromCharCode(keyCode);
|
||||
|
||||
// eslint-disable-next-line default-case
|
||||
switch (keyCodeChar) {
|
||||
case 'y':
|
||||
undoObj.redo();
|
||||
@@ -636,6 +643,7 @@
|
||||
|
||||
this.setInputAreaSelectionStartEnd();
|
||||
this.scrollTop = inputArea.scrollTop;
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
if (!this.text && inputArea.selectionStart || inputArea.selectionStart === 0) {
|
||||
this.text = inputArea.value;
|
||||
}
|
||||
@@ -862,7 +870,7 @@
|
||||
var sibling = preview.nextSibling;
|
||||
parent.removeChild(preview);
|
||||
preview.innerHTML = text;
|
||||
if (!sibling) { parent.appendChild(preview); } else { parent.insertBefore(preview, sibling); } // eslint-disable-line max-len, xss-lint: disable=javascript-jquery-insert-into-target
|
||||
if (!sibling) { parent.appendChild(preview); } else { parent.insertBefore(preview, sibling); } // xss-lint: disable=javascript-jquery-insert-into-target
|
||||
};
|
||||
|
||||
var nonSuckyBrowserPreviewSet = function(text) {
|
||||
@@ -965,8 +973,10 @@
|
||||
// It receives a single argument; either the entered text (if OK was chosen) or null (if Cancel
|
||||
// was chosen).
|
||||
ui.prompt = function(title,
|
||||
// eslint-disable-next-line no-shadow
|
||||
urlLabel,
|
||||
urlHelp,
|
||||
// eslint-disable-next-line no-shadow
|
||||
urlError,
|
||||
urlDescLabel,
|
||||
urlDescHelp,
|
||||
@@ -974,6 +984,7 @@
|
||||
urlDescError,
|
||||
defaultInputText,
|
||||
callback,
|
||||
// eslint-disable-next-line no-shadow
|
||||
imageIsDecorativeLabel,
|
||||
imageUploadHandler) {
|
||||
// These variables need to be declared at this level since they are used
|
||||
@@ -1045,7 +1056,7 @@
|
||||
}
|
||||
|
||||
document.getElementById('wmd-editor-dialog-form-errors').textContent = [
|
||||
interpolate( // eslint-disable-line no-undef, xss-lint: disable=javascript-interpolate
|
||||
interpolate( // xss-lint: disable=javascript-interpolate
|
||||
ngettext(
|
||||
// Translators: 'errorCount' is the number of errors found in the form.
|
||||
'%(errorCount)s error found in form.', '%(errorCount)s errors found in form.',
|
||||
@@ -1385,6 +1396,7 @@
|
||||
button.removeAttribute('aria-disabled');
|
||||
} else {
|
||||
image.style.backgroundPosition = button.XShift + ' ' + disabledYShift;
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
button.onmouseover = button.onmouseout = button.onclick = function() { };
|
||||
// This line does not appear in vanilla WMD. It was added by edX to improve accessibility.
|
||||
// It should become a separate commit applied to WMD's official HEAD if we remove this edited version
|
||||
@@ -1681,6 +1693,7 @@
|
||||
// *removing* a link, but *adding* one, so whatever findTags() found is now back to being part of the
|
||||
// link text. linkEnteredCallback takes care of escaping any brackets.
|
||||
chunk.selection = chunk.startTag + chunk.selection + chunk.endTag;
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
chunk.startTag = chunk.endTag = '';
|
||||
|
||||
if (/\n\n/.test(chunk.selection)) {
|
||||
@@ -1998,6 +2011,7 @@
|
||||
chunk.findTags(/`/, /`/);
|
||||
|
||||
if (!chunk.startTag && !chunk.endTag) {
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
chunk.startTag = chunk.endTag = '`';
|
||||
if (!chunk.selection) {
|
||||
chunk.selection = gettext('enter code here');
|
||||
@@ -2006,6 +2020,7 @@
|
||||
chunk.before += chunk.endTag;
|
||||
chunk.endTag = '';
|
||||
} else {
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
chunk.startTag = chunk.endTag = '';
|
||||
}
|
||||
}
|
||||
@@ -2130,6 +2145,7 @@
|
||||
if (/#+/.test(chunk.startTag)) {
|
||||
headerLevel = re.lastMatch.length;
|
||||
}
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
chunk.startTag = chunk.endTag = '';
|
||||
|
||||
// Try to get the current header level by looking for - and = in the line
|
||||
@@ -2143,6 +2159,7 @@
|
||||
}
|
||||
|
||||
// Skip to the next line so we can create the header markdown.
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
chunk.startTag = chunk.endTag = '';
|
||||
chunk.skipLines(1, 1);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
var output, Converter;
|
||||
if (typeof exports === 'object' && typeof require === 'function') { // we're in a CommonJS (e.g. Node.js) module
|
||||
output = exports;
|
||||
// eslint-disable-next-line global-require
|
||||
Converter = require('./Markdown.Converter').Converter;
|
||||
} else {
|
||||
output = window.Markdown;
|
||||
@@ -63,7 +64,8 @@
|
||||
tagname = tags[ctag].replace(/<\/?(\w+).*/, '$1');
|
||||
// skip any already paired tags
|
||||
// and skip tags in our ignore list; assume they're self-closed
|
||||
if (tagpaired[ctag] || ignoredtags.search('<' + tagname + '>') > -1) { continue; } // eslint-disable-line max-len, xss-lint: disable=javascript-concat-html
|
||||
// eslint-disable-next-line no-continue
|
||||
if (tagpaired[ctag] || ignoredtags.search('<' + tagname + '>') > -1) { continue; } // xss-lint: disable=javascript-concat-html
|
||||
|
||||
tag = tags[ctag];
|
||||
match = -1;
|
||||
@@ -72,14 +74,14 @@
|
||||
// this is an opening tag
|
||||
// search forwards (next tags), look for closing tags
|
||||
for (var ntag = ctag + 1; ntag < tagcount; ntag++) {
|
||||
if (!tagpaired[ntag] && tags[ntag] === '</' + tagname + '>') { // eslint-disable-line max-len, xss-lint: disable=javascript-concat-html
|
||||
if (!tagpaired[ntag] && tags[ntag] === '</' + tagname + '>') { // xss-lint: disable=javascript-concat-html
|
||||
match = ntag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line brace-style
|
||||
/* eslint-disable-next-line brace-style, no-multi-assign */
|
||||
if (match == -1) { needsRemoval = tagremove[ctag] = true; } // mark for removal
|
||||
else { tagpaired[match] = true; } // mark paired
|
||||
}
|
||||
@@ -89,6 +91,7 @@
|
||||
// delete all orphaned tags from the string
|
||||
|
||||
var ctag = 0;
|
||||
// eslint-disable-next-line no-shadow
|
||||
html = html.replace(re, function(match) {
|
||||
var res = tagremove[ctag] ? '' : match;
|
||||
ctag++;
|
||||
|
||||
@@ -6,6 +6,7 @@ import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {StatusAlert} from '@edx/paragon/static';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export class StatusAlertRenderer {
|
||||
constructor(message, selector, afterselector) {
|
||||
this.shiftFocus = this.shiftFocus.bind(this);
|
||||
|
||||
@@ -7,6 +7,7 @@ $(document).ajaxError(function(event, jXHR) {
|
||||
+ '(you must log in again to save your work).'
|
||||
);
|
||||
|
||||
// eslint-disable-next-line no-alert
|
||||
if (window.confirm(message)) {
|
||||
var currentLocation = window.location.pathname;
|
||||
window.location.href = '/login?next=' + encodeURIComponent(currentLocation);
|
||||
|
||||
@@ -336,6 +336,7 @@ var edx = edx || {};
|
||||
},
|
||||
|
||||
schedule_apply: function(nodes, f) {
|
||||
// eslint-disable-next-line array-callback-return
|
||||
nodes.map(function(node) {
|
||||
f(node);
|
||||
if (node !== undefined && node.children !== undefined) {
|
||||
@@ -460,15 +461,19 @@ var edx = edx || {};
|
||||
modal.find('input[name=time]').val(time);
|
||||
modal.find('form').off('submit').on('submit', function(event) {
|
||||
event.preventDefault();
|
||||
// eslint-disable-next-line no-shadow
|
||||
var date = $(this).find('input[name=date]').val(),
|
||||
// eslint-disable-next-line no-shadow
|
||||
time = $(this).find('input[name=time]').val();
|
||||
var valid_date = new Date(date);
|
||||
if (isNaN(valid_date.valueOf())) {
|
||||
// eslint-disable-next-line no-alert
|
||||
alert('Please enter a valid date');
|
||||
return;
|
||||
}
|
||||
var valid_time = /^\d{1,2}:\d{2}?$/;
|
||||
if (!time.match(valid_time)) {
|
||||
// eslint-disable-next-line no-alert
|
||||
alert('Please enter a valid time');
|
||||
return;
|
||||
}
|
||||
@@ -521,8 +526,10 @@ var edx = edx || {};
|
||||
unit = find_in(tree, chapter);
|
||||
units[units.length] = unit;
|
||||
if (sequential) {
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
units[units.length] = unit = find_in(unit.children, sequential);
|
||||
if (vertical) {
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
units[units.length] = unit = find_in(unit.children, vertical);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@
|
||||
// inner function generate div and display response messages.
|
||||
$('<div/>', {
|
||||
class: 'message ' + group
|
||||
}).appendTo('.bulk-exception-results').prepend( // eslint-disable-line max-len, xss-lint: disable=javascript-jquery-insert-into-target,javascript-jquery-prepend
|
||||
"<button type='button' id= '" + group + "' class='arrow'> + </button>" + heading) // eslint-disable-line max-len, xss-lint: disable=javascript-concat-html
|
||||
}).appendTo('.bulk-exception-results').prepend( // xss-lint: disable=javascript-jquery-insert-into-target,javascript-jquery-prepend
|
||||
"<button type='button' id= '" + group + "' class='arrow'> + </button>" + heading) // xss-lint: disable=javascript-concat-html
|
||||
.append($('<ul/>', {
|
||||
class: group
|
||||
}));
|
||||
@@ -91,7 +91,7 @@
|
||||
for (var i = 0; i < displayData.length; i++) { // eslint-disable-line vars-on-top
|
||||
$('<li/>', {
|
||||
text: displayData[i]
|
||||
}).appendTo('div.message > .' + group); // eslint-disable-line max-len, xss-lint: disable=javascript-jquery-insert-into-target
|
||||
}).appendTo('div.message > .' + group); // xss-lint: disable=javascript-jquery-insert-into-target
|
||||
}
|
||||
$('div.message > .' + group).hide();
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
gettext('The certificate for this learner has been re-validated and the system is re-running the grade for this learner.') // eslint-disable-line max-len
|
||||
);
|
||||
},
|
||||
// eslint-disable-next-line no-shadow
|
||||
error: function(model, response) {
|
||||
try {
|
||||
var response_data = JSON.parse(response.responseText);
|
||||
|
||||
@@ -22,6 +22,7 @@ var edx = edx || {};
|
||||
* @param {string} url - The URL where the form data will be submitted.
|
||||
* @param {Object} params - Form data, included as hidden inputs.
|
||||
*/
|
||||
// eslint-disable-next-line no-shadow
|
||||
var configureForm = function(form, method, url, params) {
|
||||
$('input', form).remove();
|
||||
form.attr('action', url);
|
||||
@@ -80,6 +81,7 @@ var edx = edx || {};
|
||||
* @param {string} params.course - The ID of the course for the donation.
|
||||
* @returns {DonationView}
|
||||
*/
|
||||
// eslint-disable-next-line no-shadow
|
||||
initialize: function(params) {
|
||||
this.$el = params.el;
|
||||
this.course = params.course;
|
||||
|
||||
@@ -15,6 +15,7 @@ var edx = edx || {};
|
||||
ariaExpandedState = ($dropdownButton.attr('aria-expanded') === 'true'),
|
||||
menuItems = $dropdown.find('a');
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
var catchKeyPress = function(object, event) {
|
||||
// get currently focused item
|
||||
var $focusedItem = $(':focus');
|
||||
|
||||
@@ -3,6 +3,7 @@ import React from 'react';
|
||||
import Cookies from 'js-cookie';
|
||||
import {DemographicsCollectionModal} from './DemographicsCollectionModal';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export class DemographicsCollectionBanner extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -51,6 +52,7 @@ export class DemographicsCollectionBanner extends React.Component {
|
||||
if (!(this.state.hideBanner)) {
|
||||
return (
|
||||
<div>
|
||||
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid, jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
|
||||
<a id="demographics-banner-link" className="btn" onClick={() => this.setState({modalOpen: true})}>
|
||||
<div
|
||||
className="demographics-banner d-flex justify-content-lg-between flex-row py-1 px-2 mb-2 mb-lg-4"
|
||||
@@ -63,6 +65,7 @@ export class DemographicsCollectionBanner extends React.Component {
|
||||
<div className="demographics-banner-prompt d-inline-block font-weight-bold text-white mr-4 py-3 px-2 px-lg-3">
|
||||
{gettext('Want to make edX better for everyone?')}
|
||||
</div>
|
||||
{/* eslint-disable-next-line react/button-has-type */}
|
||||
<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" />
|
||||
{gettext('Get started')}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* global gettext */
|
||||
import React from 'react';
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import get from 'lodash/get';
|
||||
import Cookies from 'js-cookie';
|
||||
import StringUtils from 'edx-ui-toolkit/js/utils/string-utils';
|
||||
@@ -35,8 +36,10 @@ class DemographicsCollectionModal extends React.Component {
|
||||
error: false,
|
||||
// an error for when a specific demographics question fails to save
|
||||
fieldError: false,
|
||||
// eslint-disable-next-line react/no-unused-state
|
||||
errorMessage: '',
|
||||
loading: true,
|
||||
// eslint-disable-next-line react/no-unused-state
|
||||
open: this.props.open,
|
||||
selected: {
|
||||
[FIELD_NAMES.CURRENT_WORK]: '',
|
||||
@@ -83,9 +86,11 @@ class DemographicsCollectionModal extends React.Component {
|
||||
document.body.classList.remove('modal-open');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
loadOptions(field) {
|
||||
const {choices} = get(this.state.options, field, {choices: []});
|
||||
if (choices.length) {
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
return choices.map((choice, i) => <option value={choice.value} key={choice.value + i}>{choice.display_name}</option>);
|
||||
}
|
||||
}
|
||||
@@ -110,6 +115,7 @@ class DemographicsCollectionModal extends React.Component {
|
||||
await this.jwtTokenService.getJwtToken();
|
||||
await fetch(url, options);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line react/no-unused-state
|
||||
this.setState({loading: false, fieldError: true, errorMessage: error});
|
||||
}
|
||||
|
||||
@@ -178,6 +184,7 @@ class DemographicsCollectionModal extends React.Component {
|
||||
const demographicsOptions = await optionsResponse.json();
|
||||
return demographicsOptions;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line react/no-unused-state
|
||||
this.setState({loading: false, error: true, errorMessage: error});
|
||||
}
|
||||
}
|
||||
@@ -198,6 +205,7 @@ class DemographicsCollectionModal extends React.Component {
|
||||
response = await fetch(`${this.props.demographicsBaseUrl}/demographics/api/v1/demographics/${this.props.user}/`, requestOptions);
|
||||
} catch (e) {
|
||||
// an error other than "no entry found" occured
|
||||
// eslint-disable-next-line react/no-unused-state
|
||||
this.setState({loading: false, error: true, errorMessage: e});
|
||||
}
|
||||
// an entry was not found in demographics, so we need to create one
|
||||
@@ -234,6 +242,7 @@ class DemographicsCollectionModal extends React.Component {
|
||||
const data = await postResponse.json();
|
||||
return data;
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line react/no-unused-state
|
||||
this.setState({loading: false, error: true, errorMessage: e});
|
||||
}
|
||||
}
|
||||
@@ -272,6 +281,7 @@ class DemographicsCollectionModal extends React.Component {
|
||||
<br />
|
||||
<span aria-hidden="true" className="fa fa-info-circle" />
|
||||
{/* Need to strip out extra '"' characters in the marketingSiteBaseUrl prop or it tries to setup the href as a relative URL */}
|
||||
{/* eslint-disable-next-line react/jsx-no-target-blank */}
|
||||
<a className="pl-3" target="_blank" rel="noopener" href={`${this.props.marketingSiteBaseUrl}/demographics`.replace(/"/g, '')}>
|
||||
{gettext('Why does edX collect this information?')}
|
||||
</a>
|
||||
@@ -354,6 +364,7 @@ class DemographicsCollectionModal extends React.Component {
|
||||
{gettext('Have you ever served on active duty in the U.S. Armed Forces, Reserves, or National Guard?')}
|
||||
</label>
|
||||
<select
|
||||
// eslint-disable-next-line jsx-a11y/no-autofocus
|
||||
autoFocus
|
||||
className="form-control"
|
||||
onChange={this.handleSelectChange}
|
||||
@@ -381,6 +392,7 @@ class DemographicsCollectionModal extends React.Component {
|
||||
</label>
|
||||
<select
|
||||
className="form-control"
|
||||
// eslint-disable-next-line jsx-a11y/no-autofocus
|
||||
autoFocus
|
||||
onChange={this.handleSelectChange}
|
||||
key="self-education"
|
||||
@@ -501,4 +513,5 @@ class DemographicsCollectionModal extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export {DemographicsCollectionModal};
|
||||
|
||||
@@ -30,6 +30,7 @@ class MultiselectDropdown extends React.Component {
|
||||
document.removeEventListener('keydown', this.handleKeydown, false);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
findOption(data) {
|
||||
return this.props.options.find((o) => o.value == data || o.display_name == data);
|
||||
}
|
||||
@@ -45,6 +46,7 @@ class MultiselectDropdown extends React.Component {
|
||||
}
|
||||
|
||||
handleButtonClick(e) {
|
||||
// eslint-disable-next-line react/no-access-state-in-setstate
|
||||
this.setState({open: !this.state.open});
|
||||
}
|
||||
|
||||
@@ -93,6 +95,7 @@ class MultiselectDropdown extends React.Component {
|
||||
|
||||
renderUnselect() {
|
||||
return this.props.selected.length > 0 && (
|
||||
// eslint-disable-next-line react/button-has-type
|
||||
<button id="unselect-button" disabled={this.props.disabled} aria-label="Clear all selected" onClick={this.handleRemoveAllClick}>{gettext('Clear all')}</button>
|
||||
);
|
||||
}
|
||||
@@ -105,7 +108,9 @@ class MultiselectDropdown extends React.Component {
|
||||
const options = this.props.options.map((option, index) => {
|
||||
const checked = this.props.selected.includes(option.value);
|
||||
return (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<div key={index} id={`${option.value}-option-container`} className="option-container">
|
||||
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
|
||||
<label className="option-label">
|
||||
<input id={`${option.value}-option-checkbox`} className="option-checkbox" type="checkbox" value={option.value} checked={checked} onChange={this.handleOptionClick} />
|
||||
<span className="pl-2">{option.display_name}</span>
|
||||
@@ -141,6 +146,7 @@ class MultiselectDropdown extends React.Component {
|
||||
>
|
||||
<label id="multiselect-dropdown-label" htmlFor="multiselect-dropdown">{this.props.label}</label>
|
||||
<div className="form-control d-flex">
|
||||
{/* eslint-disable-next-line react/button-has-type */}
|
||||
<button className="multiselect-dropdown-button" disabled={this.props.disabled} id="multiselect-dropdown-button" ref={this.setButtonRef} aria-haspopup="true" aria-expanded={this.state.open} aria-labelledby="multiselect-dropdown-label multiselect-dropdown-button" onClick={this.handleButtonClick}>
|
||||
{this.renderSelected()}
|
||||
</button>
|
||||
@@ -154,12 +160,17 @@ class MultiselectDropdown extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export {MultiselectDropdown};
|
||||
|
||||
MultiselectDropdown.propTypes = {
|
||||
// eslint-disable-next-line react/require-default-props
|
||||
label: PropTypes.string,
|
||||
// eslint-disable-next-line react/require-default-props
|
||||
emptyLabel: PropTypes.string,
|
||||
// eslint-disable-next-line react/forbid-prop-types
|
||||
options: PropTypes.array.isRequired,
|
||||
// eslint-disable-next-line react/forbid-prop-types
|
||||
selected: PropTypes.array.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export, react/function-component-definition
|
||||
export const SelectWithInput = (props) => {
|
||||
const {
|
||||
selectName,
|
||||
@@ -21,6 +22,7 @@ export const SelectWithInput = (props) => {
|
||||
<div className="d-flex flex-column pb-3">
|
||||
<label htmlFor={selectName}>{labelText}</label>
|
||||
<select
|
||||
// eslint-disable-next-line jsx-a11y/no-autofocus
|
||||
autoFocus
|
||||
className="form-control"
|
||||
name={selectName}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
/* global gettext */
|
||||
import React from 'react';
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import isFunction from 'lodash/isFunction';
|
||||
|
||||
const Page = ({children}) => children;
|
||||
// eslint-disable-next-line react/function-component-definition
|
||||
const Header = () => null;
|
||||
// eslint-disable-next-line react/function-component-definition
|
||||
const Closer = () => null;
|
||||
// eslint-disable-next-line react/function-component-definition
|
||||
const ErrorPage = () => null;
|
||||
export default class Wizard extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -15,6 +19,7 @@ export default class Wizard extends React.Component {
|
||||
currentPage: 1,
|
||||
totalPages: 0,
|
||||
pages: [],
|
||||
// eslint-disable-next-line react/no-unused-state
|
||||
wizardContext: {},
|
||||
};
|
||||
|
||||
@@ -27,6 +32,7 @@ export default class Wizard extends React.Component {
|
||||
const wizardContext = this.props.wizardContext;
|
||||
const closer = this.findSubComponentByType(Wizard.Closer.name)[0];
|
||||
pages.push(closer);
|
||||
// eslint-disable-next-line react/no-unused-state
|
||||
this.setState({pages, totalPages, wizardContext});
|
||||
}
|
||||
|
||||
@@ -41,6 +47,7 @@ export default class Wizard extends React.Component {
|
||||
}
|
||||
|
||||
// this needs to handle the case of no provided header
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
renderHeader() {
|
||||
const header = this.findSubComponentByType(Wizard.Header.name)[0];
|
||||
return header.props.children({currentPage: this.state.currentPage, totalPages: this.state.totalPages});
|
||||
@@ -71,6 +78,7 @@ export default class Wizard extends React.Component {
|
||||
{errorPage.props.children}
|
||||
</div>
|
||||
<div className="wizard-footer justify-content-end h-100 d-flex flex-column">
|
||||
{/* eslint-disable-next-line react/button-has-type, react/no-unknown-property */}
|
||||
<button className="wizard-button colored" arial-label={gettext('close questionnaire')} onClick={this.props.onWizardComplete}>{gettext('Close')}</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -110,7 +118,9 @@ export default class Wizard extends React.Component {
|
||||
</div>
|
||||
{this.renderPage()}
|
||||
<div className="wizard-footer justify-content-end h-100 d-flex flex-column">
|
||||
{/* eslint-disable-next-line react/button-has-type */}
|
||||
<button className={`wizard-button ${finalPage && 'colored'}`} onClick={this.wizardComplete} aria-label={gettext('finish later')}>{finalPage ? gettext('Return to my dashboard') : gettext('Finish later')}</button>
|
||||
{/* eslint-disable-next-line react/button-has-type */}
|
||||
<button className="wizard-button colored" hidden={finalPage} onClick={this.handleNext} aria-label={gettext('next page')}>{gettext('Next')}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
fetchXhr: null,
|
||||
|
||||
performSearch: function(searchTerm, facets) {
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
this.fetchXhr && this.fetchXhr.abort();
|
||||
this.searchTerm = searchTerm || '';
|
||||
this.selectedFacets = facets || {};
|
||||
@@ -37,6 +38,7 @@
|
||||
},
|
||||
|
||||
loadNextPage: function() {
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
this.fetchXhr && this.fetchXhr.abort();
|
||||
var data = this.preparePostData(this.page + 1);
|
||||
this.fetchXhr = this.fetch({
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
},
|
||||
|
||||
sendQuery: function(data) {
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
this.jqhxr && this.jqhxr.abort();
|
||||
this.jqhxr = this.discovery.fetch({
|
||||
type: 'POST',
|
||||
|
||||
@@ -24,12 +24,14 @@
|
||||
},
|
||||
|
||||
facetName: function(key) {
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
return this.meanings[key] && this.meanings[key].name || key;
|
||||
},
|
||||
|
||||
termName: function(facetKey, termKey) {
|
||||
return this.meanings[facetKey]
|
||||
&& this.meanings[facetKey].terms
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
&& this.meanings[facetKey].terms[termKey] || termKey;
|
||||
},
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -58,11 +58,13 @@
|
||||
if (!this.logLevel) {
|
||||
return false;
|
||||
}
|
||||
// eslint-disable-next-line prefer-spread
|
||||
this.updateHistory.apply(this, arguments);
|
||||
// Adds ID at the first place
|
||||
Array.prototype.unshift.call(args, this.id);
|
||||
if (console && console[logType]) {
|
||||
if (console[logType].apply) {
|
||||
// eslint-disable-next-line prefer-spread
|
||||
console[logType].apply(console, args);
|
||||
} else { // Do this for IE
|
||||
console[logType](args.join(' '));
|
||||
@@ -136,6 +138,7 @@
|
||||
if (timeout) {
|
||||
args.push(null, {timeout: timeout});
|
||||
}
|
||||
// eslint-disable-next-line prefer-spread
|
||||
return Logger.log.apply(Logger, args);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
@@ -61,6 +62,7 @@
|
||||
* @param {Array} plugins A list of plugins for the annotator.
|
||||
* @param {Object} options An options for the annotator.
|
||||
* */
|
||||
// eslint-disable-next-line no-shadow
|
||||
setupPlugins = function(annotator, plugins, options) {
|
||||
_.each(plugins, function(plugin) {
|
||||
var settings = options[plugin.toLowerCase()];
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
@@ -124,6 +125,7 @@
|
||||
if (jXHR.responseText) {
|
||||
try {
|
||||
message = $.parseJSON(jXHR.responseText).error;
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
@@ -22,6 +23,7 @@
|
||||
sectionView;
|
||||
if (sectionInfo) {
|
||||
sectionView = chapterView.addChild(sectionInfo);
|
||||
// eslint-disable-next-line no-shadow
|
||||
_.each(sectionInfo.children, function(location) {
|
||||
var notes = courseStructure.units[location];
|
||||
if (notes) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
@@ -94,6 +95,7 @@
|
||||
|
||||
_.each(sortedTagNames, function(tagName) {
|
||||
noteGroup = notesByTag[tagName];
|
||||
// eslint-disable-next-line no-shadow
|
||||
var tagTitle = interpolate_text(
|
||||
'{tagName} ({numberOfNotesWithTag})',
|
||||
{tagName: tagName, numberOfNotesWithTag: noteGroup.length}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function($, undefined) {
|
||||
var form_ext;
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
$.form_ext = form_ext = {
|
||||
ajax: function(options) {
|
||||
return $.ajax(options);
|
||||
@@ -12,6 +14,7 @@
|
||||
type: method || 'GET',
|
||||
data: data,
|
||||
dataType: 'text json',
|
||||
// eslint-disable-next-line no-shadow
|
||||
success: function(data, status, xhr) {
|
||||
element.trigger('ajax:success', [data, status, xhr]);
|
||||
},
|
||||
|
||||
@@ -272,6 +272,7 @@
|
||||
submitButtonText: gettext('Upload File and Assign Students'),
|
||||
extensions: '.csv',
|
||||
url: this.context.uploadCohortsCsvUrl,
|
||||
// eslint-disable-next-line no-shadow
|
||||
successNotification: function(file, event, data) {
|
||||
var message = interpolate_text(gettext(
|
||||
"Your file '{file}' has been uploaded. Allow a few minutes for processing."
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line no-shadow-restricted-names
|
||||
(function(define, undefined) {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@ $('.mobile-menu, .global-header').on('keydown', function(e) {
|
||||
|
||||
// Enable arrow functionality within the menu.
|
||||
if ((e.key === 'ArrowUp' || e.key === 'ArrowDown') && (isDropdownOption || isMobileOption
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
|| (isHamburgerMenu && $hamburgerMenu.hasClass('open')) || isToggle && $toggleUserDropdown.hasClass('open'))) {
|
||||
isNext = e.key === 'ArrowDown';
|
||||
if (isNext && !isHamburgerMenu && !isToggle && isLastItem) {
|
||||
|
||||
@@ -16,6 +16,7 @@ if (!Array.prototype.find) {
|
||||
o = Object(this);
|
||||
|
||||
// 2. Let len be ? ToLength(? Get(O, "length")).
|
||||
// eslint-disable-next-line no-bitwise
|
||||
len = o.length >>> 0;
|
||||
|
||||
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
|
||||
|
||||
@@ -22,6 +22,7 @@ var onCertificatesReady = null;
|
||||
confirmMessage = gettext('Prevent students from generating certificates in this course?');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-alert
|
||||
if (!confirm(confirmMessage)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
@@ -40,6 +41,7 @@ var onCertificatesReady = null;
|
||||
*/
|
||||
var $section = $('section#certificates');
|
||||
$section.on('click', '#btn-start-generating-certificates', function(event) {
|
||||
// eslint-disable-next-line no-alert
|
||||
if (!confirm(gettext('Start generating certificates for all students in this course?'))) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
@@ -65,6 +67,7 @@ var onCertificatesReady = null;
|
||||
* Start regenerating certificates for students.
|
||||
*/
|
||||
$section.on('click', '#btn-start-regenerating-certificates', function(event) {
|
||||
// eslint-disable-next-line no-alert
|
||||
if (!confirm(gettext('Start regenerating certificates for students in this course?'))) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
@@ -104,6 +107,7 @@ var onCertificatesReady = null;
|
||||
$(onCertificatesReady);
|
||||
|
||||
var Certificates = (function() {
|
||||
// eslint-disable-next-line no-shadow
|
||||
function Certificates($section) {
|
||||
$section.data('wrapper', this);
|
||||
this.instructor_tasks = new window.InstructorDashboard.util.PendingInstructorTasks($section);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
var CohortManagement;
|
||||
|
||||
CohortManagement = (function() {
|
||||
// eslint-disable-next-line no-shadow
|
||||
function CohortManagement($section) {
|
||||
this.$section = $section;
|
||||
this.$section.data('wrapper', this);
|
||||
|
||||
@@ -89,6 +89,7 @@ such that the value can be defined later than this assignment (file load order).
|
||||
return safeWaiter;
|
||||
}());
|
||||
|
||||
// eslint-disable-next-line new-parens
|
||||
sectionsHaveLoaded = new SafeWaiter;
|
||||
|
||||
$(function() {
|
||||
@@ -198,6 +199,7 @@ such that the value can be defined later than this assignment (file load order).
|
||||
$element: idashContent.find('.' + CSS_IDASH_SECTION + '#open_response_assessment')
|
||||
}
|
||||
];
|
||||
// eslint-disable-next-line no-void
|
||||
if (edx.instructor_dashboard.proctoring !== void 0) {
|
||||
sectionsToInitialize = sectionsToInitialize.concat([
|
||||
{
|
||||
|
||||
@@ -537,6 +537,7 @@ such that the value can be defined later than this assignment (file load order).
|
||||
if (successes.length && dataFromServer.action === 'remove') {
|
||||
// Translators: A list of users appears after this sentence;
|
||||
renderList(gettext('These users were successfully removed as beta testers:'), (function() {
|
||||
// eslint-disable-next-line no-shadow
|
||||
var j, len1, results;
|
||||
results = [];
|
||||
for (j = 0, len1 = successes.length; j < len1; j++) {
|
||||
@@ -549,6 +550,7 @@ such that the value can be defined later than this assignment (file load order).
|
||||
if (errors.length && dataFromServer.action === 'add') {
|
||||
// Translators: A list of users appears after this sentence;
|
||||
renderList(gettext('These users were not added as beta testers:'), (function() {
|
||||
// eslint-disable-next-line no-shadow
|
||||
var j, len1, results;
|
||||
results = [];
|
||||
for (j = 0, len1 = errors.length; j < len1; j++) {
|
||||
@@ -561,6 +563,7 @@ such that the value can be defined later than this assignment (file load order).
|
||||
if (errors.length && dataFromServer.action === 'remove') {
|
||||
// Translators: A list of users appears after this sentence;
|
||||
renderList(gettext('These users were not removed as beta testers:'), (function() {
|
||||
// eslint-disable-next-line no-shadow
|
||||
var j, len1, results;
|
||||
results = [];
|
||||
for (j = 0, len1 = errors.length; j < len1; j++) {
|
||||
@@ -575,6 +578,7 @@ such that the value can be defined later than this assignment (file load order).
|
||||
gettext('Users must create and activate their account before they can be promoted to beta tester.'))
|
||||
);
|
||||
return renderList(gettext('Could not find users associated with the following identifiers:'), (function() { // eslint-disable-line max-len
|
||||
// eslint-disable-next-line no-shadow
|
||||
var j, len1, results;
|
||||
results = [];
|
||||
for (j = 0, len1 = noUsers.length; j < len1; j++) {
|
||||
|
||||
@@ -674,6 +674,7 @@
|
||||
this.$request_err_ee.empty();
|
||||
this.$request_response_error_all.empty();
|
||||
return function() {
|
||||
// eslint-disable-next-line no-void
|
||||
return cb != null ? cb.apply(this, arguments) : void 0;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -105,6 +105,7 @@ export default class AxiosJwtTokenService {
|
||||
}
|
||||
|
||||
async getJwtToken() {
|
||||
// eslint-disable-next-line no-useless-catch
|
||||
try {
|
||||
const decodedJwtToken = this.decodeJwtCookie(this.tokenCookieName);
|
||||
if (!AxiosJwtTokenService.isTokenExpired(decodedJwtToken)) {
|
||||
@@ -115,6 +116,7 @@ export default class AxiosJwtTokenService {
|
||||
throw e;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-useless-catch
|
||||
try {
|
||||
return await this.refresh();
|
||||
} catch (e) {
|
||||
|
||||
@@ -57,6 +57,7 @@ const createRetryInterceptor = (options = {}) => {
|
||||
try {
|
||||
const backoffDelay = getBackoffMilliseconds(nthRetry);
|
||||
// Delay (wrapped in a promise so we can await the setTimeout)
|
||||
// eslint-disable-next-line no-promise-executor-return
|
||||
await new Promise(resolve => setTimeout(resolve, backoffDelay));
|
||||
// Make retry request
|
||||
retryResponse = await httpClient.request(config);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line padded-blocks
|
||||
(function($) { // eslint-disable-line wrap-iife
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -18,6 +18,7 @@ class CircleChart extends React.Component {
|
||||
getCenter() {
|
||||
const {centerHole, sliceBorder} = this.props;
|
||||
if (centerHole) {
|
||||
// eslint-disable-next-line no-shadow
|
||||
const size = center / 2;
|
||||
return (
|
||||
<circle cx={center} cy={center} r={size} fill={sliceBorder.strokeColor} />
|
||||
@@ -43,6 +44,7 @@ class CircleChart extends React.Component {
|
||||
cx={center}
|
||||
cy={center}
|
||||
className="slice-1"
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
@@ -85,6 +87,7 @@ class CircleChart extends React.Component {
|
||||
<path
|
||||
d={d}
|
||||
className={`slice-${sliceIndex}`}
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={index}
|
||||
stroke={strokeColor}
|
||||
strokeWidth={strokeWidth}
|
||||
@@ -115,8 +118,11 @@ CircleChart.defaultProps = {
|
||||
};
|
||||
|
||||
CircleChart.propTypes = {
|
||||
// eslint-disable-next-line react/forbid-prop-types
|
||||
slices: PropTypes.array.isRequired,
|
||||
// eslint-disable-next-line react/require-default-props
|
||||
centerHole: PropTypes.bool,
|
||||
// eslint-disable-next-line react/forbid-prop-types
|
||||
sliceBorder: PropTypes.object
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class CircleChartLegend extends React.Component {
|
||||
// eslint-disable-next-line no-useless-constructor
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
@@ -13,6 +14,7 @@ class CircleChartLegend extends React.Component {
|
||||
return data.map(({value, label, sliceIndex}, index) => {
|
||||
const swatchClass = `swatch-${sliceIndex}`;
|
||||
return (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<li className="legend-item" key={index}>
|
||||
<div
|
||||
className={classNames('color-swatch', swatchClass)}
|
||||
@@ -49,6 +51,7 @@ class CircleChartLegend extends React.Component {
|
||||
}
|
||||
|
||||
CircleChartLegend.propTypes = {
|
||||
// eslint-disable-next-line react/forbid-prop-types
|
||||
data: PropTypes.array.isRequired
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class Discussions extends React.Component {
|
||||
// eslint-disable-next-line no-useless-constructor
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
@@ -44,6 +45,7 @@ class Discussions extends React.Component {
|
||||
'chart-icon',
|
||||
{'fa fa-graduation-cap': !img}
|
||||
)}
|
||||
// eslint-disable-next-line no-extra-boolean-cast
|
||||
style={{backgroundImage: !!img ? `url(${img})` : 'none'}}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
@@ -6,6 +6,7 @@ const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
||||
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
|
||||
class DueDates extends React.Component {
|
||||
// eslint-disable-next-line no-useless-constructor
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
@@ -36,6 +37,7 @@ class DueDates extends React.Component {
|
||||
|
||||
return dates.sort((a, b) => new Date(a.due) > new Date(b.due))
|
||||
.map(({format, due}, index) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<li className="date-item" key={index}>
|
||||
<div className="label">{this.getLabel(format)}</div>
|
||||
<div className="data">{this.getDate(due)}</div>
|
||||
@@ -44,6 +46,7 @@ class DueDates extends React.Component {
|
||||
}
|
||||
|
||||
initLabelTracker(list) {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let labels = Object.keys(list);
|
||||
|
||||
return labels.reduce((accumulator, key) => {
|
||||
@@ -70,6 +73,7 @@ class DueDates extends React.Component {
|
||||
}
|
||||
|
||||
DueDates.propTypes = {
|
||||
// eslint-disable-next-line react/forbid-prop-types
|
||||
dates: PropTypes.array.isRequired
|
||||
};
|
||||
|
||||
|
||||
@@ -20,12 +20,14 @@ const exGrades = [
|
||||
];
|
||||
|
||||
class GradeTable extends React.Component {
|
||||
// eslint-disable-next-line no-useless-constructor
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
getTableGroup(type, groupIndex) {
|
||||
const {grades} = this.props;
|
||||
// eslint-disable-next-line array-callback-return
|
||||
const groupData = grades.filter(value => {
|
||||
if (value.assignment_type === type) {
|
||||
return value;
|
||||
@@ -38,6 +40,7 @@ class GradeTable extends React.Component {
|
||||
}, index) => {
|
||||
const label = multipleAssignments ? `${assignment_type} ${index + 1}` : assignment_type;
|
||||
return (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<tr key={index}>
|
||||
<td>{label}</td>
|
||||
<td>{passing_grade}/{total_possible}</td>
|
||||
@@ -74,7 +77,9 @@ class GradeTable extends React.Component {
|
||||
}
|
||||
|
||||
GradeTable.propTypes = {
|
||||
// eslint-disable-next-line react/forbid-prop-types
|
||||
assignmentTypes: PropTypes.array.isRequired,
|
||||
// eslint-disable-next-line react/forbid-prop-types
|
||||
grades: PropTypes.array.isRequired,
|
||||
passingGrade: PropTypes.number.isRequired,
|
||||
percentGrade: PropTypes.number.isRequired
|
||||
|
||||
@@ -4,9 +4,11 @@ import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import classNames from 'classnames';
|
||||
// eslint-disable-next-line import/no-named-as-default, import/no-named-as-default-member
|
||||
import CircleChart from './CircleChart';
|
||||
import CircleChartLegend from './CircleChartLegend';
|
||||
import GradeTable from './GradeTable';
|
||||
// eslint-disable-next-line import/no-named-as-default, import/no-named-as-default-member
|
||||
import DueDates from './DueDates';
|
||||
import Discussions from './Discussions';
|
||||
|
||||
@@ -20,6 +22,7 @@ function arrayToObject(array) {
|
||||
|
||||
function countByType(type, assignments) {
|
||||
let count = 0;
|
||||
// eslint-disable-next-line array-callback-return
|
||||
assignments.map(({format}) => {
|
||||
if (format === type) {
|
||||
count += 1;
|
||||
@@ -42,7 +45,9 @@ function getAssignmentCounts(types, assignments) {
|
||||
}
|
||||
|
||||
function getStreakIcons(count) {
|
||||
// eslint-disable-next-line prefer-spread
|
||||
return Array.apply(null, {length: count}).map((e, i) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<span className="fa fa-trophy" aria-hidden="true" key={i} />
|
||||
));
|
||||
}
|
||||
@@ -58,6 +63,7 @@ function getStreakString(count) {
|
||||
return (count > 0) ? `Active ${count} ${unit} in a row` : false;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export function LearnerAnalyticsDashboard(props) {
|
||||
const {
|
||||
grading_policy, grades, schedule, schedule_raw, week_streak, weekly_active_users, discussion_info, profile_images, passing_grade, percent_grade
|
||||
|
||||
@@ -18,6 +18,7 @@ class EnterpriseLearnerPortalModal extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// eslint-disable-next-line react/prop-types
|
||||
const storageKey = `enterprise_learner_portal_modal__${this.props.enterpriseCustomerUUID}`;
|
||||
const hasViewedModal = window.sessionStorage.getItem(storageKey);
|
||||
if (!hasViewedModal) {
|
||||
@@ -60,6 +61,7 @@ class EnterpriseLearnerPortalModal extends React.Component {
|
||||
const { key } = e;
|
||||
if (key === 'Escape') {
|
||||
window.analytics.track('edx.ui.enterprise.lms.dashboard.learner_portal_modal.closed', {
|
||||
// eslint-disable-next-line react/prop-types
|
||||
enterpriseUUID: this.props.enterpriseCustomerUUID,
|
||||
source: 'Escape',
|
||||
});
|
||||
@@ -67,6 +69,7 @@ class EnterpriseLearnerPortalModal extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
closeModal() {
|
||||
this.setState({
|
||||
isModalOpen: false,
|
||||
@@ -75,6 +78,7 @@ class EnterpriseLearnerPortalModal extends React.Component {
|
||||
|
||||
openModal() {
|
||||
window.analytics.track('edx.ui.enterprise.lms.dashboard.learner_portal_modal.opened', {
|
||||
// eslint-disable-next-line react/prop-types
|
||||
enterpriseUUID: this.props.enterpriseCustomerUUID,
|
||||
});
|
||||
this.setState({
|
||||
@@ -83,6 +87,7 @@ class EnterpriseLearnerPortalModal extends React.Component {
|
||||
}
|
||||
|
||||
getLearnerPortalUrl() {
|
||||
// eslint-disable-next-line react/prop-types
|
||||
const baseUrlWithSlug = `${this.props.enterpriseLearnerPortalBaseUrl}/${this.props.enterpriseCustomerSlug}`;
|
||||
return `${baseUrlWithSlug}?utm_source=lms_dashboard_modal`;
|
||||
}
|
||||
@@ -90,6 +95,7 @@ class EnterpriseLearnerPortalModal extends React.Component {
|
||||
handleLearnerPortalDashboardClick(e) {
|
||||
e.preventDefault();
|
||||
window.analytics.track('edx.ui.enterprise.lms.dashboard.learner_portal_modal.dashboard_cta.clicked', {
|
||||
// eslint-disable-next-line react/prop-types
|
||||
enterpriseUUID: this.props.enterpriseCustomerUUID,
|
||||
});
|
||||
setTimeout(() => {
|
||||
@@ -116,6 +122,7 @@ class EnterpriseLearnerPortalModal extends React.Component {
|
||||
{StringUtils.interpolate(
|
||||
gettext('You have access to the {enterpriseName} dashboard'),
|
||||
{
|
||||
// eslint-disable-next-line react/prop-types
|
||||
enterpriseName: this.props.enterpriseCustomerName,
|
||||
},
|
||||
)}
|
||||
@@ -124,15 +131,18 @@ class EnterpriseLearnerPortalModal extends React.Component {
|
||||
{StringUtils.interpolate(
|
||||
gettext('To access the courses available to you through {enterpriseName}, visit the {enterpriseName} dashboard.'),
|
||||
{
|
||||
// eslint-disable-next-line react/prop-types
|
||||
enterpriseName: this.props.enterpriseCustomerName,
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
<div className="mt-4 d-flex align-content-center justify-content-end">
|
||||
{/* eslint-disable-next-line react/button-has-type */}
|
||||
<button
|
||||
className="btn-link mr-3"
|
||||
onClick={() => {
|
||||
window.analytics.track('edx.ui.enterprise.lms.dashboard.learner_portal_modal.closed', {
|
||||
// eslint-disable-next-line react/prop-types
|
||||
enterpriseUUID: this.props.enterpriseCustomerUUID,
|
||||
source: 'Cancel button',
|
||||
});
|
||||
@@ -158,4 +168,5 @@ class EnterpriseLearnerPortalModal extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export { EnterpriseLearnerPortalModal };
|
||||
|
||||
@@ -1,20 +1,26 @@
|
||||
// eslint-disable-next-line no-undef
|
||||
$(document).ready(() => {
|
||||
'use strict';
|
||||
|
||||
const requestButtons = document.getElementsByClassName('request-cert');
|
||||
|
||||
for (let i = 0; i < requestButtons.length; i++) {
|
||||
// eslint-disable-next-line no-loop-func
|
||||
requestButtons[i].addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
const endpoint = !!event.target.dataset.endpoint && event.target.dataset.endpoint;
|
||||
// eslint-disable-next-line no-undef
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: endpoint,
|
||||
dataType: 'text',
|
||||
success: () => {
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
location.reload();
|
||||
},
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
error: (jqXHR, textStatus, errorThrown) => {
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
location.reload();
|
||||
},
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ class CourseCardCollection extends Backbone.Collection {
|
||||
const defaults = {
|
||||
model: CourseCard,
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(models, Object.assign({}, defaults, options));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ class ProgramCollection extends Backbone.Collection {
|
||||
const defaults = {
|
||||
model: Program,
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(models, Object.assign({}, defaults, options));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ class CourseCardModel extends Backbone.Model {
|
||||
desiredCourseRun = enrolledCourseRun;
|
||||
} else if (openEnrollmentCourseRuns.length > 0) {
|
||||
if (openEnrollmentCourseRuns.length === 1) {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
desiredCourseRun = openEnrollmentCourseRuns[0];
|
||||
} else {
|
||||
desiredCourseRun = CourseCardModel.getUnselectedCourseRun(openEnrollmentCourseRuns);
|
||||
@@ -56,6 +57,7 @@ class CourseCardModel extends Backbone.Model {
|
||||
if (courseRuns && courseRuns.length > 0) {
|
||||
const courseRun = courseRuns[0];
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
$.extend(unselectedRun, {
|
||||
marketing_url: courseRun.marketing_url,
|
||||
is_enrollment_open: courseRun.is_enrollment_open,
|
||||
@@ -76,6 +78,7 @@ class CourseCardModel extends Backbone.Model {
|
||||
));
|
||||
|
||||
// Deep copy to avoid mutating this.context.
|
||||
// eslint-disable-next-line no-undef
|
||||
const enrollableCourseRuns = $.extend(true, [], rawCourseRuns);
|
||||
|
||||
// These are raw course runs from the server. The start
|
||||
@@ -128,6 +131,7 @@ class CourseCardModel extends Backbone.Model {
|
||||
if (upgradeableSeats.length > 0) {
|
||||
const upgradeableSeat = upgradeableSeats[0];
|
||||
if (upgradeableSeat) {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
const currency = upgradeableSeat.currency;
|
||||
if (currency === 'USD') {
|
||||
return `$${upgradeableSeat.price}`;
|
||||
|
||||
@@ -9,6 +9,7 @@ class CourseEnrollModel extends Backbone.Model {
|
||||
course_id: '',
|
||||
optIn: false,
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, attrs), ...args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ class CourseEntitlementModel extends Backbone.Model {
|
||||
expiredAt: null,
|
||||
daysUntilExpiration: Number.MAX_VALUE,
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, attrs), ...args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import Backbone from 'backbone';
|
||||
|
||||
import CollectionListView from './views/collection_list_view';
|
||||
// eslint-disable-next-line import/no-named-as-default, import/no-named-as-default-member
|
||||
import ProgramCardView from './views/program_card_view';
|
||||
import ProgramCollection from './collections/program_collection';
|
||||
import ProgressCollection from './collections/program_progress_collection';
|
||||
import SidebarView from './views/sidebar_view';
|
||||
// eslint-disable-next-line import/no-named-as-default, import/no-named-as-default-member
|
||||
import HeaderView from './views/program_list_header_view';
|
||||
|
||||
function ProgramListFactory(options) {
|
||||
@@ -29,32 +31,35 @@ function ProgramListFactory(options) {
|
||||
}
|
||||
|
||||
const activeSubscriptions = options.programsSubscriptionData
|
||||
// eslint-disable-next-line camelcase
|
||||
.filter(({ subscription_state }) => subscription_state === 'active')
|
||||
.sort((a, b) => new Date(b.created) - new Date(a.created));
|
||||
|
||||
// Sort programs so programs with active subscriptions are at the top
|
||||
if (activeSubscriptions.length) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
options.programsData = options.programsData
|
||||
.map((programsData) => ({
|
||||
...programsData,
|
||||
subscriptionIndex: activeSubscriptions.findIndex(
|
||||
// eslint-disable-next-line camelcase
|
||||
({ resource_id }) => resource_id === programsData.uuid,
|
||||
),
|
||||
}))
|
||||
.sort(({ subscriptionIndex: indexA }, { subscriptionIndex: indexB }) => {
|
||||
switch (true) {
|
||||
case indexA === -1 && indexB === -1:
|
||||
// Maintain the original order for non-subscription programs
|
||||
return 0;
|
||||
case indexA === -1:
|
||||
// Move non-subscription program to the end
|
||||
return 1;
|
||||
case indexB === -1:
|
||||
// Keep non-subscription program to the end
|
||||
return -1;
|
||||
default:
|
||||
// Sort by subscriptionIndex in ascending order
|
||||
return indexA - indexB;
|
||||
case indexA === -1 && indexB === -1:
|
||||
// Maintain the original order for non-subscription programs
|
||||
return 0;
|
||||
case indexA === -1:
|
||||
// Move non-subscription program to the end
|
||||
return 1;
|
||||
case indexB === -1:
|
||||
// Keep non-subscription program to the end
|
||||
return -1;
|
||||
default:
|
||||
// Sort by subscriptionIndex in ascending order
|
||||
return indexA - indexB;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ describe('Collection List View', () => {
|
||||
const $cards = view.$el.find('.program-card');
|
||||
expect($cards.length).toBe(2);
|
||||
$cards.each((index, el) => {
|
||||
// eslint-disable-next-line newline-per-chained-call
|
||||
/* eslint-disable-next-line newline-per-chained-call, no-undef */
|
||||
expect($(el).find('.title').html().trim()).toEqual(context.programsData[index].title);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ describe('Course Card View', () => {
|
||||
const endDate = 'May 30, 2017';
|
||||
|
||||
const setupView = (data, isEnrolled, collectionCourseStatus) => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const programData = $.extend({}, data);
|
||||
const context = {
|
||||
programData,
|
||||
@@ -155,6 +156,7 @@ describe('Course Card View', () => {
|
||||
});
|
||||
|
||||
it('should allow enrollment in future runs when the user has an expired enrollment', () => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const newRun = $.extend({}, course.course_runs[0]);
|
||||
const newRunKey = 'course-v1:foo+bar+baz';
|
||||
const advertisedStart = 'Summer';
|
||||
|
||||
@@ -32,6 +32,7 @@ describe('Course Enroll View', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
// Stub analytics tracking
|
||||
// eslint-disable-next-line no-undef
|
||||
window.analytics = jasmine.createSpyObj('analytics', ['track']);
|
||||
|
||||
// NOTE: This data is redefined prior to each test case so that tests
|
||||
@@ -115,6 +116,7 @@ describe('Course Enroll View', () => {
|
||||
urlModel = new Backbone.Model(urlMap);
|
||||
}
|
||||
view = new CourseEnrollView({
|
||||
// eslint-disable-next-line no-undef
|
||||
$parentEl: $('.course-actions'),
|
||||
model: courseCardModel,
|
||||
enrollModel: courseEnrollModel,
|
||||
@@ -184,6 +186,7 @@ describe('Course Enroll View', () => {
|
||||
|
||||
expect(view.$('.enroll-button').length).toBe(1);
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(courseEnrollModel, 'save');
|
||||
|
||||
view.$('.enroll-button').click();
|
||||
@@ -194,6 +197,7 @@ describe('Course Enroll View', () => {
|
||||
it('should enroll learner when enroll button is clicked with multiple course runs available', () => {
|
||||
setupView(multiCourseRunList);
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(courseEnrollModel, 'save');
|
||||
|
||||
view.$('.run-select').val(multiCourseRunList[1].key);
|
||||
@@ -212,6 +216,7 @@ describe('Course Enroll View', () => {
|
||||
expect(view.$('.enroll-button').length).toBe(1);
|
||||
expect(view.trackSelectionUrl).toBeDefined();
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(CourseEnrollView, 'redirect');
|
||||
|
||||
view.enrollSuccess();
|
||||
@@ -230,6 +235,7 @@ describe('Course Enroll View', () => {
|
||||
expect(view.$('.enroll-button').length).toBe(1);
|
||||
expect(view.trackSelectionUrl).toBeDefined();
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(CourseEnrollView, 'redirect');
|
||||
|
||||
view.enrollSuccess();
|
||||
@@ -250,6 +256,7 @@ describe('Course Enroll View', () => {
|
||||
expect(view.dashboardUrl).not.toBeDefined();
|
||||
expect(view.trackSelectionUrl).not.toBeDefined();
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(CourseEnrollView, 'redirect');
|
||||
|
||||
view.enrollSuccess();
|
||||
@@ -263,6 +270,7 @@ describe('Course Enroll View', () => {
|
||||
expect(view.$('.enroll-button').length).toBe(1);
|
||||
expect(view.trackSelectionUrl).toBeDefined();
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(CourseEnrollView, 'redirect');
|
||||
|
||||
view.enrollError(courseEnrollModel, { status: 500 });
|
||||
@@ -284,6 +292,7 @@ describe('Course Enroll View', () => {
|
||||
expect(view.$('.enroll-button').length).toBe(1);
|
||||
expect(view.trackSelectionUrl).toBeDefined();
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(CourseEnrollView, 'redirect');
|
||||
|
||||
view.enrollError(courseEnrollModel, response);
|
||||
@@ -295,6 +304,7 @@ describe('Course Enroll View', () => {
|
||||
|
||||
it('sends analytics event when enrollment succeeds', () => {
|
||||
setupView(singleCourseRunList, urls);
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(CourseEnrollView, 'redirect');
|
||||
view.enrollSuccess();
|
||||
expect(window.analytics.track).toHaveBeenCalledWith(
|
||||
|
||||
@@ -36,10 +36,15 @@ describe('EntitlementUnenrollmentView', () => {
|
||||
|
||||
describe('when an unenroll link is clicked', () => {
|
||||
it('should reset the modal and set the correct values for header/submit', () => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const $link1 = $('#link1');
|
||||
// eslint-disable-next-line no-undef
|
||||
const $link2 = $('#link2');
|
||||
// eslint-disable-next-line no-undef
|
||||
const $headerTxt = $('.js-entitlement-unenrollment-modal-header-text');
|
||||
// eslint-disable-next-line no-undef
|
||||
const $errorTxt = $('.js-entitlement-unenrollment-modal-error-text');
|
||||
// eslint-disable-next-line no-undef
|
||||
const $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
|
||||
|
||||
$link1.trigger('click');
|
||||
@@ -66,11 +71,13 @@ describe('EntitlementUnenrollmentView', () => {
|
||||
|
||||
describe('when the unenroll submit button is clicked', () => {
|
||||
it('should send a DELETE request to the configured apiEndpoint', () => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
|
||||
const apiEndpoint = '/test/api/endpoint/1';
|
||||
|
||||
view.setSubmitData(apiEndpoint);
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn($, 'ajax').and.callFake((opts) => {
|
||||
expect(opts.url).toEqual(apiEndpoint);
|
||||
expect(opts.method).toEqual('DELETE');
|
||||
@@ -78,11 +85,14 @@ describe('EntitlementUnenrollmentView', () => {
|
||||
});
|
||||
|
||||
$submitBtn.trigger('click');
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($.ajax).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set an error and disable submit if the apiEndpoint has not been properly set', () => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const $errorTxt = $('.js-entitlement-unenrollment-modal-error-text');
|
||||
// eslint-disable-next-line no-undef
|
||||
const $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
|
||||
|
||||
expect($submitBtn.data()).toEqual({});
|
||||
@@ -90,8 +100,10 @@ describe('EntitlementUnenrollmentView', () => {
|
||||
expect($errorTxt.html()).toEqual('');
|
||||
expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(false);
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn($, 'ajax');
|
||||
$submitBtn.trigger('click');
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($.ajax).not.toHaveBeenCalled();
|
||||
|
||||
expect($submitBtn.data()).toEqual({});
|
||||
@@ -102,11 +114,13 @@ describe('EntitlementUnenrollmentView', () => {
|
||||
|
||||
describe('when the unenroll request is complete', () => {
|
||||
it('should redirect to the dashboard if the request was successful', () => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
|
||||
const apiEndpoint = '/test/api/endpoint/1';
|
||||
|
||||
view.setSubmitData(apiEndpoint);
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn($, 'ajax').and.callFake((opts) => {
|
||||
expect(opts.url).toEqual(apiEndpoint);
|
||||
expect(opts.method).toEqual('DELETE');
|
||||
@@ -117,19 +131,23 @@ describe('EntitlementUnenrollmentView', () => {
|
||||
responseJSON: { detail: 'success' },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(EntitlementUnenrollmentView, 'redirectTo');
|
||||
|
||||
$submitBtn.trigger('click');
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($.ajax).toHaveBeenCalled();
|
||||
expect(EntitlementUnenrollmentView.redirectTo).toHaveBeenCalledWith(view.dashboardPath);
|
||||
});
|
||||
|
||||
it('should redirect to the login page if the request failed with an auth error', () => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
|
||||
const apiEndpoint = '/test/api/endpoint/1';
|
||||
|
||||
view.setSubmitData(apiEndpoint);
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn($, 'ajax').and.callFake((opts) => {
|
||||
expect(opts.url).toEqual(apiEndpoint);
|
||||
expect(opts.method).toEqual('DELETE');
|
||||
@@ -140,9 +158,11 @@ describe('EntitlementUnenrollmentView', () => {
|
||||
responseJSON: { detail: 'Authentication credentials were not provided.' },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(EntitlementUnenrollmentView, 'redirectTo');
|
||||
|
||||
$submitBtn.trigger('click');
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($.ajax).toHaveBeenCalled();
|
||||
expect(EntitlementUnenrollmentView.redirectTo).toHaveBeenCalledWith(
|
||||
`${view.signInPath}?next=${encodeURIComponent(view.dashboardPath)}`,
|
||||
@@ -150,12 +170,15 @@ describe('EntitlementUnenrollmentView', () => {
|
||||
});
|
||||
|
||||
it('should set an error and disable submit if a non-auth error occurs', () => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const $errorTxt = $('.js-entitlement-unenrollment-modal-error-text');
|
||||
// eslint-disable-next-line no-undef
|
||||
const $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
|
||||
const apiEndpoint = '/test/api/endpoint/1';
|
||||
|
||||
view.setSubmitData(apiEndpoint);
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn($, 'ajax').and.callFake((opts) => {
|
||||
expect(opts.url).toEqual(apiEndpoint);
|
||||
expect(opts.method).toEqual('DELETE');
|
||||
@@ -166,6 +189,7 @@ describe('EntitlementUnenrollmentView', () => {
|
||||
responseJSON: { detail: 'Bad request.' },
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(EntitlementUnenrollmentView, 'redirectTo');
|
||||
|
||||
expect($submitBtn.prop('disabled')).toBe(false);
|
||||
@@ -178,6 +202,7 @@ describe('EntitlementUnenrollmentView', () => {
|
||||
expect($errorTxt.html()).toEqual(view.genericErrorMsg);
|
||||
expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(true);
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($.ajax).toHaveBeenCalled();
|
||||
expect(EntitlementUnenrollmentView.redirectTo).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -40,19 +40,19 @@ describe('Program Alert List View', () => {
|
||||
|
||||
it('should render no enrollement alert', () => {
|
||||
expect(view.$('.alert:first .alert-heading').text().trim()).toEqual(
|
||||
'Enroll in a Test Program\'s course'
|
||||
'Enroll in a Test Program\'s course',
|
||||
);
|
||||
expect(view.$('.alert:first .alert-message').text().trim()).toEqual(
|
||||
'You have an active subscription to the Test Program program but are not enrolled in any courses. Enroll in a remaining course and enjoy verified access.'
|
||||
'You have an active subscription to the Test Program program but are not enrolled in any courses. Enroll in a remaining course and enjoy verified access.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should render subscription trial is expiring alert', () => {
|
||||
expect(view.$('.alert:last .alert-heading').text().trim()).toEqual(
|
||||
'Subscription trial expires in 2 days'
|
||||
'Subscription trial expires in 2 days',
|
||||
);
|
||||
expect(view.$('.alert:last .alert-message').text().trim()).toEqual(
|
||||
'Your Test Program trial will expire in 2 days at 5:59 am on Apr 20, 2023 and the card on file will be charged $100/month USD.'
|
||||
'Your Test Program trial will expire in 2 days at 5:59 am on Apr 20, 2023 and the card on file will be charged $100/month USD.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -58,6 +58,7 @@ describe('Program card View', () => {
|
||||
not_started: 3,
|
||||
},
|
||||
];
|
||||
// eslint-disable-next-line no-undef
|
||||
const subscriptionCollection = new Backbone.Collection([{
|
||||
resource_id: 'a87e5eac-3c93-45a1-a8e1-4c79ca8401c8',
|
||||
subscription_state: 'active',
|
||||
@@ -99,6 +100,7 @@ describe('Program card View', () => {
|
||||
});
|
||||
|
||||
it('should call reEvaluatePicture if reLoadBannerImage is called', () => {
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(ProgramCardView, 'reEvaluatePicture');
|
||||
view.reLoadBannerImage();
|
||||
expect(ProgramCardView.reEvaluatePicture).toHaveBeenCalled();
|
||||
@@ -107,6 +109,7 @@ describe('Program card View', () => {
|
||||
it('should handle exceptions from reEvaluatePicture', () => {
|
||||
const message = 'Picturefill had exceptions';
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
spyOn(ProgramCardView, 'reEvaluatePicture').and.callFake(() => {
|
||||
const error = { name: message };
|
||||
|
||||
|
||||
@@ -56,7 +56,9 @@ describe('Program Progress View', () => {
|
||||
const testSubscriptionState = (state, heading, body) => {
|
||||
isSubscriptionEligible = true;
|
||||
subscriptionData.subscription_state = state;
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
view = initView();
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
body += ' on the <a class="subscription-link" href="/orders">Orders and subscriptions</a> page';
|
||||
|
||||
expect(view.$('.js-subscription-info')[0]).toBeInDOM();
|
||||
@@ -164,6 +166,7 @@ describe('Program Progress View', () => {
|
||||
expect(view.$('.course-list-heading').html()).toEqual('Earned Certificates');
|
||||
expect($certificates).toHaveLength(certificateCollection.length);
|
||||
$certificates.each((i, el) => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const $link = $(el).find('.certificate-link');
|
||||
const model = certificateCollection.at(i);
|
||||
|
||||
|
||||
@@ -527,7 +527,9 @@ describe('Program Details View', () => {
|
||||
'YYYY-MM-DDTHH:mm:ss[Z]',
|
||||
);
|
||||
}
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
view = initView({
|
||||
// eslint-disable-next-line no-undef
|
||||
programData: $.extend({}, options.programData, {
|
||||
subscription_eligible: true,
|
||||
}),
|
||||
@@ -543,6 +545,7 @@ describe('Program Details View', () => {
|
||||
};
|
||||
|
||||
const initView = (updates) => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const viewOptions = $.extend({}, options, updates);
|
||||
|
||||
return new ProgramDetailsView(viewOptions);
|
||||
@@ -588,6 +591,7 @@ describe('Program Details View', () => {
|
||||
it('should render the program heading congratulations message if all courses completed', () => {
|
||||
view = initView({
|
||||
// Remove remaining courses so all courses are complete
|
||||
// eslint-disable-next-line no-undef
|
||||
courseData: $.extend({}, options.courseData, {
|
||||
in_progress: [],
|
||||
not_started: [],
|
||||
@@ -614,26 +618,34 @@ describe('Program Details View', () => {
|
||||
it('should render the basic course card information', () => {
|
||||
view = initView();
|
||||
view.render();
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($(view.$('.course-title')[0]).text().trim()).toEqual('Star Trek: The Next Generation');
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($(view.$('.enrolled')[0]).text().trim()).toEqual('Enrolled:');
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($(view.$('.run-period')[0]).text().trim()).toEqual('Mar 20, 2017 - Mar 31, 2017');
|
||||
});
|
||||
|
||||
it('should render certificate information', () => {
|
||||
view = initView();
|
||||
view.render();
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($(view.$('.upgrade-message .card-msg')).text().trim()).toEqual('Certificate Status:');
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($(view.$('.upgrade-message .price')).text().trim()).toEqual('$10.00');
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($(view.$('.upgrade-button.single-course-run')[0]).text().trim()).toEqual('Upgrade to Verified');
|
||||
});
|
||||
|
||||
it('should render full program purchase link', () => {
|
||||
view = initView({
|
||||
// eslint-disable-next-line no-undef
|
||||
programData: $.extend({}, options.programData, {
|
||||
is_learner_eligible_for_one_click_purchase: true,
|
||||
}),
|
||||
});
|
||||
view.render();
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($(view.$('.upgrade-button.complete-program')).text().trim()
|
||||
.replace(/\s+/g, ' '))
|
||||
.toEqual(
|
||||
@@ -643,6 +655,7 @@ describe('Program Details View', () => {
|
||||
|
||||
it('should render partial program purchase link', () => {
|
||||
view = initView({
|
||||
// eslint-disable-next-line no-undef
|
||||
programData: $.extend({}, options.programData, {
|
||||
is_learner_eligible_for_one_click_purchase: true,
|
||||
discount_data: {
|
||||
@@ -655,6 +668,7 @@ describe('Program Details View', () => {
|
||||
}),
|
||||
});
|
||||
view.render();
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($(view.$('.upgrade-button.complete-program')).text().trim()
|
||||
.replace(/\s+/g, ' '))
|
||||
.toEqual(
|
||||
@@ -666,7 +680,9 @@ describe('Program Details View', () => {
|
||||
view = initView();
|
||||
view.render();
|
||||
expect(view.$('.run-select')[0].options.length).toEqual(2);
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($(view.$('.select-choice')[0]).attr('for')).toEqual($(view.$('.run-select')[0]).attr('id'));
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($(view.$('.enroll-button button')[0]).text().trim()).toEqual('Enroll Now');
|
||||
});
|
||||
|
||||
@@ -677,12 +693,14 @@ describe('Program Details View', () => {
|
||||
uuid: '0ffff5d6-0177-4690-9a48-aa2fecf94610',
|
||||
};
|
||||
view = initView({
|
||||
// eslint-disable-next-line no-undef
|
||||
programData: $.extend({}, options.programData, {
|
||||
is_learner_eligible_for_one_click_purchase: true,
|
||||
variant: 'partial',
|
||||
}),
|
||||
});
|
||||
view.render();
|
||||
// eslint-disable-next-line no-undef
|
||||
$('.complete-program').click();
|
||||
// Verify that analytics event fires when the purchase button is clicked.
|
||||
expect(window.analytics.track).toHaveBeenCalledWith(
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import Backbone from 'backbone';
|
||||
|
||||
import ProgressCollection from '../collections/program_progress_collection';
|
||||
// eslint-disable-next-line import/no-named-as-default, import/no-named-as-default-member
|
||||
import ProgramListHeaderView from '../views/program_list_header_view';
|
||||
|
||||
describe('Program List Header View', () => {
|
||||
@@ -54,10 +55,10 @@ describe('Program List Header View', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
context.subscriptionCollection = new Backbone.Collection(
|
||||
context.programsSubscriptionData
|
||||
context.programsSubscriptionData,
|
||||
);
|
||||
context.progressCollection = new ProgressCollection(
|
||||
context.userProgress
|
||||
context.userProgress,
|
||||
);
|
||||
setFixtures('<div class="js-program-list-header"></div>');
|
||||
view = new ProgramListHeaderView({
|
||||
@@ -80,15 +81,15 @@ describe('Program List Header View', () => {
|
||||
|
||||
it('should render a program alert', () => {
|
||||
expect(
|
||||
view.$('.js-program-list-alerts .alert .alert-heading').html().trim()
|
||||
view.$('.js-program-list-alerts .alert .alert-heading').html().trim(),
|
||||
).toEqual('Enroll in a Test Program\'s course');
|
||||
expect(
|
||||
view.$('.js-program-list-alerts .alert .alert-message')
|
||||
view.$('.js-program-list-alerts .alert .alert-message'),
|
||||
).toContainHtml(
|
||||
'According to our records, you are not enrolled in any courses included in your Test Program program subscription. Enroll in a course from the <i>Program Details</i> page.'
|
||||
'According to our records, you are not enrolled in any courses included in your Test Program program subscription. Enroll in a course from the <i>Program Details</i> page.',
|
||||
);
|
||||
expect(
|
||||
view.$('.js-program-list-alerts .alert .view-button').attr('href')
|
||||
view.$('.js-program-list-alerts .alert .view-button').attr('href'),
|
||||
).toEqual('/dashboard/programs/b90d70d5-f981-4508-bdeb-5b792d930c03/');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -41,6 +41,7 @@ describe('Progress Circle View', () => {
|
||||
});
|
||||
|
||||
const initView = (progress) => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const data = $.extend({}, context, {
|
||||
progress,
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('Sidebar View', () => {
|
||||
context: {
|
||||
...context,
|
||||
isUserB2CSubscriptionsEnabled: false,
|
||||
}
|
||||
},
|
||||
});
|
||||
view.render();
|
||||
expect(view.$('.js-subscription-upsell')[0]).not.toBeInDOM();
|
||||
@@ -53,7 +53,7 @@ describe('Sidebar View', () => {
|
||||
.toMatch(/^Monthly program subscriptions . more flexible, more affordable$/);
|
||||
expect(view.$('.js-subscription-upsell .advertise-message').html().trim())
|
||||
.toEqual(
|
||||
'Now available for many popular programs, affordable monthly subscription pricing can help you manage your budget more effectively. Subscriptions start at $39/month USD per program, after a 7-day full access free trial. Cancel at any time.'
|
||||
'Now available for many popular programs, affordable monthly subscription pricing can help you manage your budget more effectively. Subscriptions start at $39/month USD per program, after a 7-day full access free trial. Cancel at any time.',
|
||||
);
|
||||
expect(view.$('.js-subscription-upsell a span:last').html().trim())
|
||||
.toEqual('Explore subscription options');
|
||||
@@ -64,7 +64,7 @@ describe('Sidebar View', () => {
|
||||
it('should load the exploration panel given a marketing URL', () => {
|
||||
expect(view.$('.program-advertise .advertise-message').html().trim())
|
||||
.toEqual(
|
||||
'Browse recently launched courses and see what\'s new in your favorite subjects'
|
||||
'Browse recently launched courses and see what\'s new in your favorite subjects',
|
||||
);
|
||||
expect(view.$('.program-advertise a').attr('href'))
|
||||
.toEqual(context.marketingUrl);
|
||||
|
||||
@@ -29,11 +29,15 @@ describe('Unenroll View', () => {
|
||||
|
||||
it('switch between slides', () => {
|
||||
view = initView();
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($('.slide1').hasClass('hidden')).toEqual(true);
|
||||
view.switchToSlideOne();
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($('.slide1').hasClass('hidden')).toEqual(false);
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($('.slide2').hasClass('hidden')).toEqual(true);
|
||||
view.switchToSlideTwo();
|
||||
// eslint-disable-next-line no-undef
|
||||
expect($('.slide2').hasClass('hidden')).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,6 +16,7 @@ class CertificateStatusView extends Backbone.View {
|
||||
render() {
|
||||
let data = this.model.toJSON();
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
data = $.extend(data, { certificateSvg: this.iconTpl() });
|
||||
HtmlUtils.setHtml(this.$el, this.statusTpl(data));
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ class CourseCardView extends Backbone.View {
|
||||
const defaults = {
|
||||
className: 'program-course-card',
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, options));
|
||||
}
|
||||
|
||||
@@ -40,6 +41,7 @@ class CourseCardView extends Backbone.View {
|
||||
}
|
||||
|
||||
render() {
|
||||
// eslint-disable-next-line no-undef
|
||||
const data = $.extend(this.model.toJSON(), {
|
||||
enrolled: this.context.enrolled || '',
|
||||
});
|
||||
|
||||
@@ -13,6 +13,7 @@ class CourseEnrollView extends Backbone.View {
|
||||
'change .run-select': 'updateEnrollUrl',
|
||||
},
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, options));
|
||||
}
|
||||
|
||||
@@ -94,8 +95,10 @@ class CourseEnrollView extends Backbone.View {
|
||||
|
||||
updateEnrollUrl() {
|
||||
if (this.model.get('is_mobile_only') === true) {
|
||||
// eslint-disable-next-line no-undef
|
||||
const courseRunKey = $('.run-select').val();
|
||||
const href = `edxapp://enroll?course_id=${courseRunKey}&email_opt_in=true`;
|
||||
// eslint-disable-next-line no-undef
|
||||
$('.enroll-course-button').attr('href', href);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ class CourseEntitlementView extends Backbone.View {
|
||||
'click .popover-dismiss': 'hideDialog',
|
||||
},
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, options));
|
||||
}
|
||||
|
||||
@@ -51,16 +52,23 @@ class CourseEntitlementView extends Backbone.View {
|
||||
|
||||
// Grab elements from the parent card that work with this view
|
||||
this.$parentEl = options.$parentEl; // Containing course card (must be a backbone view root el)
|
||||
// eslint-disable-next-line no-undef
|
||||
this.$enterCourseBtn = $(options.enterCourseBtn); // Button link to course home page
|
||||
// eslint-disable-next-line no-undef
|
||||
this.$courseCardMessages = $(options.courseCardMessages); // Additional session messages
|
||||
// eslint-disable-next-line no-undef
|
||||
this.$courseTitleLink = $(options.courseTitleLink); // Title link to course home page
|
||||
// eslint-disable-next-line no-undef
|
||||
this.$courseImageLink = $(options.courseImageLink); // Image link to course home page
|
||||
// eslint-disable-next-line no-undef
|
||||
this.$policyMsg = $(options.policyMsg); // Message for policy information
|
||||
|
||||
// Bind action elements with associated events to objects outside this view
|
||||
this.$dateDisplayField = this.$parentEl ? this.$parentEl.find(options.dateDisplayField)
|
||||
// eslint-disable-next-line no-undef
|
||||
: $(options.dateDisplayField); // Displays current session dates
|
||||
this.$triggerOpenBtn = this.$parentEl ? this.$parentEl.find(options.triggerOpenBtn)
|
||||
// eslint-disable-next-line no-undef
|
||||
: $(options.triggerOpenBtn); // Opens/closes session selection view
|
||||
this.$triggerOpenBtn.on('click', this.toggleSessionSelectionPanel.bind(this));
|
||||
|
||||
@@ -77,14 +85,17 @@ class CourseEntitlementView extends Backbone.View {
|
||||
|
||||
postRender() {
|
||||
// Close any visible popovers on click-away
|
||||
// eslint-disable-next-line no-undef
|
||||
$(document).on('click', (e) => {
|
||||
if (this.$('.popover:visible').length
|
||||
// eslint-disable-next-line no-undef
|
||||
&& !($(e.target).closest('.enroll-btn-initial, .popover').length)) {
|
||||
this.hideDialog(this.$('.enroll-btn-initial'));
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize focus to cancel button on popover load
|
||||
// eslint-disable-next-line no-undef
|
||||
$(document).on('shown.bs.popover', () => {
|
||||
this.$('.final-confirmation-btn:first').focus();
|
||||
});
|
||||
@@ -110,6 +121,7 @@ class CourseEntitlementView extends Backbone.View {
|
||||
HtmlUtils.HTML('<span class="fa fa-spinner fa-spin" aria-hidden="true"></span>'),
|
||||
);
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
$.ajax({
|
||||
type: isLeavingSession ? 'DELETE' : 'POST',
|
||||
url: this.enrollUrl,
|
||||
@@ -330,6 +342,7 @@ class CourseEntitlementView extends Backbone.View {
|
||||
|
||||
removeDialog(el) {
|
||||
/* Removes the Bootstrap v4 dialog modal from the update session enrollment button. */
|
||||
// eslint-disable-next-line no-undef
|
||||
const $el = el instanceof jQuery ? el : this.$('.enroll-btn-initial');
|
||||
if (this.$('popover').length) {
|
||||
$el.popover('dispose');
|
||||
@@ -338,6 +351,7 @@ class CourseEntitlementView extends Backbone.View {
|
||||
|
||||
hideDialog(el, returnFocus) {
|
||||
/* Hides the modal if it is visible without removing it from the DOM. */
|
||||
// eslint-disable-next-line no-undef
|
||||
const $el = el instanceof jQuery ? el : this.$('.enroll-btn-initial');
|
||||
if (this.$('.popover:visible').length) {
|
||||
$el.popover('hide');
|
||||
@@ -350,7 +364,9 @@ class CourseEntitlementView extends Backbone.View {
|
||||
handleVerificationPopoverA11y(e) {
|
||||
/* Ensure that the second step verification popover is treated as an a11y compliant dialog */
|
||||
let $nextButton;
|
||||
// eslint-disable-next-line no-undef
|
||||
const $verificationOption = $(e.target);
|
||||
// eslint-disable-next-line no-undef
|
||||
const openButton = $(e.target).closest('.course-entitlement-selection-container')
|
||||
.find('.enroll-btn-initial');
|
||||
if (e.key === 'Tab') {
|
||||
|
||||
@@ -9,6 +9,7 @@ class EntitlementUnenrollmentView extends Backbone.View {
|
||||
const defaults = {
|
||||
el: '.js-entitlement-unenrollment-modal',
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, options));
|
||||
}
|
||||
|
||||
@@ -29,14 +30,20 @@ class EntitlementUnenrollmentView extends Backbone.View {
|
||||
this.browseCourses = options.browseCourses;
|
||||
this.isEdx = options.isEdx;
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
this.$submitButton = $(this.submitButtonSelector);
|
||||
// eslint-disable-next-line no-undef
|
||||
this.$closeButton = $(this.closeButtonSelector);
|
||||
// eslint-disable-next-line no-undef
|
||||
this.$headerText = $(this.headerTextSelector);
|
||||
// eslint-disable-next-line no-undef
|
||||
this.$errorText = $(this.errorTextSelector);
|
||||
|
||||
this.$submitButton.on('click', this.handleSubmit.bind(this));
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
$(this.triggerSelector).each(function setUpTrigger() {
|
||||
// eslint-disable-next-line no-undef
|
||||
const $trigger = $(this);
|
||||
|
||||
$trigger.on('click', view.handleTrigger.bind(view));
|
||||
@@ -54,6 +61,7 @@ class EntitlementUnenrollmentView extends Backbone.View {
|
||||
}
|
||||
|
||||
handleTrigger(event) {
|
||||
// eslint-disable-next-line no-undef
|
||||
const $trigger = $(event.target);
|
||||
const courseName = $trigger.data('courseName');
|
||||
const courseNumber = $trigger.data('courseNumber');
|
||||
@@ -76,6 +84,7 @@ class EntitlementUnenrollmentView extends Backbone.View {
|
||||
}
|
||||
|
||||
this.$submitButton.prop('disabled', true);
|
||||
// eslint-disable-next-line no-undef
|
||||
$.ajax({
|
||||
url: apiEndpoint,
|
||||
method: 'DELETE',
|
||||
@@ -170,6 +179,7 @@ class EntitlementUnenrollmentView extends Backbone.View {
|
||||
}
|
||||
|
||||
onComplete(xhr) {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
const status = xhr.status;
|
||||
const message = xhr.responseJSON && xhr.responseJSON.detail;
|
||||
|
||||
|
||||
@@ -9,12 +9,14 @@ class ExploreNewProgramsView extends Backbone.View {
|
||||
const defaults = {
|
||||
el: '.program-advertise',
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, options));
|
||||
}
|
||||
|
||||
initialize(data) {
|
||||
this.tpl = HtmlUtils.template(exploreTpl);
|
||||
this.context = data.context;
|
||||
// eslint-disable-next-line no-undef
|
||||
this.$parentEl = $(this.parentEl);
|
||||
|
||||
if (this.context.marketingUrl) {
|
||||
|
||||
@@ -11,6 +11,7 @@ class ProgramAlertListView extends Backbone.View {
|
||||
const defaults = {
|
||||
el: '.js-program-details-alerts',
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, options));
|
||||
}
|
||||
|
||||
@@ -34,45 +35,53 @@ class ProgramAlertListView extends Backbone.View {
|
||||
const alertList = this.enrollmentAlerts.map(
|
||||
({ title: programName, url }) => ({
|
||||
url,
|
||||
// eslint-disable-next-line no-undef
|
||||
urlText: gettext('View program'),
|
||||
title: StringUtils.interpolate(
|
||||
// eslint-disable-next-line no-undef
|
||||
gettext('Enroll in a {programName}\'s course'),
|
||||
{ programName }
|
||||
{ programName },
|
||||
),
|
||||
message: this.pageType === 'programDetails'
|
||||
? StringUtils.interpolate(
|
||||
// eslint-disable-next-line no-undef
|
||||
gettext('You have an active subscription to the {programName} program but are not enrolled in any courses. Enroll in a remaining course and enjoy verified access.'),
|
||||
{ programName }
|
||||
{ programName },
|
||||
)
|
||||
: HtmlUtils.interpolateHtml(
|
||||
// eslint-disable-next-line no-undef
|
||||
gettext('According to our records, you are not enrolled in any courses included in your {programName} program subscription. Enroll in a course from the {i_start}Program Details{i_end} page.'),
|
||||
{
|
||||
programName,
|
||||
i_start: HtmlUtils.HTML('<i>'),
|
||||
i_end: HtmlUtils.HTML('</i>'),
|
||||
}
|
||||
},
|
||||
),
|
||||
})
|
||||
}),
|
||||
);
|
||||
return alertList.concat(this.trialEndingAlerts.map(
|
||||
({ title: programName, remainingDays, ...data }) => ({
|
||||
title: StringUtils.interpolate(
|
||||
remainingDays < 1
|
||||
// eslint-disable-next-line no-undef
|
||||
? gettext('Subscription trial expires in less than 24 hours')
|
||||
// eslint-disable-next-line no-undef
|
||||
: ngettext('Subscription trial expires in {remainingDays} day', 'Subscription trial expires in {remainingDays} days', remainingDays),
|
||||
{ remainingDays }
|
||||
{ remainingDays },
|
||||
),
|
||||
message: StringUtils.interpolate(
|
||||
remainingDays < 1
|
||||
// eslint-disable-next-line no-undef
|
||||
? gettext('Your {programName} trial will expire at {trialEndTime} on {trialEndDate} and the card on file will be charged {subscriptionPrice}.')
|
||||
// eslint-disable-next-line no-undef
|
||||
: ngettext('Your {programName} trial will expire in {remainingDays} day at {trialEndTime} on {trialEndDate} and the card on file will be charged {subscriptionPrice}.', 'Your {programName} trial will expire in {remainingDays} days at {trialEndTime} on {trialEndDate} and the card on file will be charged {subscriptionPrice}.', remainingDays),
|
||||
{
|
||||
programName,
|
||||
remainingDays,
|
||||
...data,
|
||||
}
|
||||
},
|
||||
),
|
||||
})
|
||||
}),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ class ProgramCardView extends Backbone.View {
|
||||
};
|
||||
},
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, options));
|
||||
}
|
||||
|
||||
@@ -38,6 +39,7 @@ class ProgramCardView extends Backbone.View {
|
||||
|
||||
render() {
|
||||
const orgList = this.model.get('authoring_organizations').map(org => gettext(org.key));
|
||||
// eslint-disable-next-line no-undef
|
||||
const data = $.extend(
|
||||
this.model.toJSON(),
|
||||
this.getProgramProgress(),
|
||||
|
||||
@@ -18,6 +18,7 @@ class ProgramDetailsSidebarView extends Backbone.View {
|
||||
'click .pathway-button': 'trackPathwayClicked',
|
||||
},
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, options));
|
||||
}
|
||||
|
||||
@@ -37,6 +38,7 @@ class ProgramDetailsSidebarView extends Backbone.View {
|
||||
}
|
||||
|
||||
render() {
|
||||
// eslint-disable-next-line no-undef
|
||||
const data = $.extend(
|
||||
{},
|
||||
this.model.toJSON(),
|
||||
@@ -114,7 +116,9 @@ class ProgramDetailsSidebarView extends Backbone.View {
|
||||
// Credentials uses the uuid without dashes so we are converting here for consistency
|
||||
program_uuid: this.programModel.attributes.uuid.replace(/-/g, ''),
|
||||
program_name: this.programModel.attributes.title,
|
||||
// eslint-disable-next-line no-undef
|
||||
pathway_link_uuid: $(button).data('pathwayUuid').replace(/-/g, ''),
|
||||
// eslint-disable-next-line no-undef
|
||||
pathway_name: $(button).data('pathwayName'),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,10 +7,12 @@ import HtmlUtils from 'edx-ui-toolkit/js/utils/html-utils';
|
||||
import CollectionListView from './collection_list_view';
|
||||
import CourseCardCollection from '../collections/course_card_collection';
|
||||
import CourseCardView from './course_card_view';
|
||||
// eslint-disable-next-line import/no-named-as-default, import/no-named-as-default-member
|
||||
import HeaderView from './program_header_view';
|
||||
import SidebarView from './program_details_sidebar_view';
|
||||
import AlertListView from './program_alert_list_view';
|
||||
|
||||
// eslint-disable-next-line import/no-named-as-default, import/no-named-as-default-member
|
||||
import SubscriptionModel from '../models/program_subscription_model';
|
||||
|
||||
import launchIcon from '../../../images/launch-icon.svg';
|
||||
@@ -28,6 +30,7 @@ class ProgramDetailsView extends Backbone.View {
|
||||
'click .js-subscription-cta': 'trackSubscriptionCTA',
|
||||
},
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, options));
|
||||
}
|
||||
|
||||
@@ -66,6 +69,7 @@ class ProgramDetailsView extends Backbone.View {
|
||||
|
||||
this.render();
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const $courseUpsellButton = $('#program_dashboard_course_upsell_all_button');
|
||||
trackECommerceEvents.trackUpsellClick($courseUpsellButton, 'program_dashboard_program', {
|
||||
linkType: 'button',
|
||||
@@ -107,6 +111,7 @@ class ProgramDetailsView extends Backbone.View {
|
||||
launchIcon,
|
||||
restartIcon,
|
||||
};
|
||||
// eslint-disable-next-line no-undef
|
||||
data = $.extend(
|
||||
data,
|
||||
this.programModel.toJSON(),
|
||||
@@ -140,6 +145,7 @@ class ProgramDetailsView extends Backbone.View {
|
||||
el: '.js-course-list-remaining',
|
||||
childView: CourseCardView,
|
||||
collection: this.remainingCourseCollection,
|
||||
// eslint-disable-next-line no-undef
|
||||
context: $.extend(this.options, { collectionCourseStatus: 'remaining' }),
|
||||
}).render();
|
||||
}
|
||||
@@ -149,6 +155,7 @@ class ProgramDetailsView extends Backbone.View {
|
||||
el: '.js-course-list-completed',
|
||||
childView: CourseCardView,
|
||||
collection: this.completedCourseCollection,
|
||||
// eslint-disable-next-line no-undef
|
||||
context: $.extend(this.options, { collectionCourseStatus: 'completed' }),
|
||||
}).render();
|
||||
}
|
||||
@@ -159,6 +166,7 @@ class ProgramDetailsView extends Backbone.View {
|
||||
el: '.js-course-list-in-progress',
|
||||
childView: CourseCardView,
|
||||
collection: this.inProgressCourseCollection,
|
||||
// eslint-disable-next-line no-undef
|
||||
context: $.extend(
|
||||
this.options,
|
||||
{ enrolled: gettext('Enrolled'), collectionCourseStatus: 'in_progress' },
|
||||
@@ -179,8 +187,10 @@ class ProgramDetailsView extends Backbone.View {
|
||||
urls: this.options.urls,
|
||||
});
|
||||
let hasIframe = false;
|
||||
// eslint-disable-next-line no-undef
|
||||
$('#live-tab').click(() => {
|
||||
if (!hasIframe) {
|
||||
// eslint-disable-next-line no-undef
|
||||
$('#live').html(HtmlUtils.HTML(this.options.live_fragment.iframe).toString());
|
||||
hasIframe = true;
|
||||
}
|
||||
@@ -194,8 +204,8 @@ class ProgramDetailsView extends Backbone.View {
|
||||
];
|
||||
const isSomeCoursePurchasable = courseCollections.some((collection) => (
|
||||
collection.some((course) => (
|
||||
course.get('upgrade_url') &&
|
||||
!(course.get('expired') === true)
|
||||
course.get('upgrade_url')
|
||||
&& !(course.get('expired') === true)
|
||||
))
|
||||
));
|
||||
const programPurchasedWithoutSubscription = (
|
||||
@@ -224,8 +234,8 @@ class ProgramDetailsView extends Backbone.View {
|
||||
});
|
||||
}
|
||||
if (
|
||||
this.subscriptionModel.get('remainingDays') <= 7 &&
|
||||
this.subscriptionModel.get('hasActiveTrial')
|
||||
this.subscriptionModel.get('remainingDays') <= 7
|
||||
&& this.subscriptionModel.get('hasActiveTrial')
|
||||
) {
|
||||
alerts.trialEndingAlerts.push({
|
||||
title: this.programModel.get('title'),
|
||||
@@ -251,7 +261,7 @@ class ProgramDetailsView extends Backbone.View {
|
||||
if (state === 'active') {
|
||||
window.analytics.track(
|
||||
'edx.bi.user.subscription.program-detail-page.manage.clicked',
|
||||
this.subscriptionEventParams
|
||||
this.subscriptionEventParams,
|
||||
);
|
||||
} else {
|
||||
const isNewSubscription = state !== 'inactive';
|
||||
@@ -262,7 +272,7 @@ class ProgramDetailsView extends Backbone.View {
|
||||
is_new_subscription: isNewSubscription,
|
||||
is_trial_eligible: isNewSubscription,
|
||||
...this.subscriptionEventParams,
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -271,7 +281,7 @@ class ProgramDetailsView extends Backbone.View {
|
||||
if (this.options.isSubscriptionEligible) {
|
||||
window.analytics.track(
|
||||
'edx.bi.user.subscription.program-detail-page.viewed',
|
||||
this.subscriptionEventParams
|
||||
this.subscriptionEventParams,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ class ProgramHeaderView extends Backbone.View {
|
||||
const defaults = {
|
||||
el: '.js-program-header',
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, options));
|
||||
}
|
||||
|
||||
@@ -27,6 +28,7 @@ class ProgramHeaderView extends Backbone.View {
|
||||
}
|
||||
|
||||
getLogo() {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
const type = this.model.get('programData').type;
|
||||
let logo = false;
|
||||
|
||||
@@ -51,6 +53,7 @@ class ProgramHeaderView extends Backbone.View {
|
||||
}
|
||||
|
||||
render() {
|
||||
// eslint-disable-next-line no-undef
|
||||
const data = $.extend(this.model.toJSON(), {
|
||||
breakpoints: this.breakpoints,
|
||||
logo: this.getLogo(),
|
||||
|
||||
@@ -26,6 +26,7 @@ class ProgressCircleView extends Backbone.View {
|
||||
}
|
||||
|
||||
render() {
|
||||
// eslint-disable-next-line no-undef
|
||||
const data = $.extend({}, this.model.toJSON(), {
|
||||
circleSegments: this.getProgressSegments(),
|
||||
x: this.x,
|
||||
@@ -62,6 +63,7 @@ class ProgressCircleView extends Backbone.View {
|
||||
};
|
||||
|
||||
for (let i = 0; i < total; i += 1) {
|
||||
// eslint-disable-next-line no-undef
|
||||
const segmentData = $.extend({}, data, {
|
||||
classList: (i >= this.model.get('progress').completed) ? 'incomplete' : 'complete',
|
||||
degrees: data.degrees + (i * degreeInc),
|
||||
|
||||
@@ -15,6 +15,7 @@ class SidebarView extends Backbone.View {
|
||||
'click .js-subscription-upsell-cta ': 'trackSubscriptionUpsellCTA',
|
||||
},
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, options));
|
||||
}
|
||||
|
||||
@@ -42,7 +43,7 @@ class SidebarView extends Backbone.View {
|
||||
|
||||
trackSubscriptionUpsellCTA() {
|
||||
window.analytics.track(
|
||||
'edx.bi.user.subscription.program-dashboard.upsell.clicked'
|
||||
'edx.bi.user.subscription.program-dashboard.upsell.clicked',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ class SubscriptionUpsellView extends Backbone.View {
|
||||
const defaults = {
|
||||
el: '.js-subscription-upsell',
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, options));
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ class UnenrollView extends Backbone.View {
|
||||
const defaults = {
|
||||
el: '.unenroll-modal',
|
||||
};
|
||||
// eslint-disable-next-line prefer-object-spread
|
||||
super(Object.assign({}, defaults, options));
|
||||
}
|
||||
|
||||
@@ -37,6 +38,7 @@ class UnenrollView extends Backbone.View {
|
||||
|
||||
switchToSlideTwo() {
|
||||
let reason = this.$(".reasons_survey input[name='reason']:checked").attr('val');
|
||||
// eslint-disable-next-line no-undef
|
||||
const courserunKey = $('#unenroll_course_id').val() + $('#unenroll_course_number').val();
|
||||
if (reason === 'Other') {
|
||||
reason = this.$('.other_text').val();
|
||||
@@ -69,20 +71,25 @@ class UnenrollView extends Backbone.View {
|
||||
unenrollComplete(event, xhr) {
|
||||
if (xhr.status === 200) {
|
||||
if (!this.isEdx) {
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
location.href = this.urls.dashboard;
|
||||
} else {
|
||||
this.switchToSlideOne();
|
||||
this.$('.reasons_survey:first .submit_reasons').click(this.switchToSlideTwo.bind(this));
|
||||
}
|
||||
} else if (xhr.status === 400) {
|
||||
// eslint-disable-next-line no-undef
|
||||
$('#unenroll_error').text(
|
||||
xhr.responseText,
|
||||
).stop()
|
||||
.css('display', 'block');
|
||||
} else if (xhr.status === 403) {
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
location.href = `${this.urls.signInUser}?course_id=${
|
||||
// eslint-disable-next-line no-undef
|
||||
encodeURIComponent($('#unenroll_course_id').val())}&enrollment_action=unenroll`;
|
||||
} else {
|
||||
// eslint-disable-next-line no-undef
|
||||
$('#unenroll_error').text(
|
||||
gettext('Unable to determine whether we should give you a refund because'
|
||||
+ ' of System Error. Please try again later.'),
|
||||
@@ -101,16 +108,20 @@ class UnenrollView extends Backbone.View {
|
||||
this.isEdx = options.isEdx;
|
||||
|
||||
this.closeButtonSelector = '.unenroll-modal .close-modal';
|
||||
// eslint-disable-next-line no-undef
|
||||
this.$closeButton = $(this.closeButtonSelector);
|
||||
this.modalId = `#${this.$el.attr('id')}`;
|
||||
this.mainPageSelector = '#dashboard-main';
|
||||
|
||||
this.triggerSelector = '.action-unenroll';
|
||||
// eslint-disable-next-line no-undef
|
||||
$(this.triggerSelector).each((index, element) => {
|
||||
// eslint-disable-next-line no-undef
|
||||
$(element).on('click', view.handleTrigger.bind($(element)));
|
||||
});
|
||||
|
||||
this.$('.submit .submit-button').on('click', this.startSubmit.bind(this));
|
||||
// eslint-disable-next-line no-undef
|
||||
$('#unenroll_form').on('ajax:complete', this.unenrollComplete.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user