chore: fix a few JS lint issues that eslint is warning about (#36177)

This commit is contained in:
Braden MacDonald
2025-03-13 10:08:02 -07:00
committed by GitHub
parent 75185c0c86
commit 3b5edaa1ad
7 changed files with 197 additions and 248 deletions

View File

@@ -355,9 +355,9 @@
}
},
config: {
text: {
useXhr: () => true
}
text: {
useXhr: () => true
}
}
});
}).call(this, require, define);

View File

@@ -15,180 +15,138 @@ define(
category: null,
data: null,
metadata: null,
/**
* The Studio URL for this xblock, or null if it doesn't have one.
*/
/** The Studio URL for this xblock, or null if it doesn't have one. */
studio_url: null,
/**
* An optional object with information about the children as well as about
* the primary xblock type that is supported as a child.
*/
* An optional object with information about the children as well as about
* the primary xblock type that is supported as a child.
*/
child_info: null,
/**
* An optional object with information about each of the ancestors.
*/
/** An optional object with information about each of the ancestors. */
ancestor_info: null,
/**
* Date of the last edit to this xblock or any of its descendants.
*/
/** Date of the last edit to this xblock or any of its descendants. */
edited_on: null,
/**
* User who last edited the xblock or any of its descendants. Will only be present if
* publishing info was explicitly requested.
*/
* User who last edited the xblock or any of its descendants. Will only be present if
* publishing info was explicitly requested.
*/
edited_by: null,
/**
* True iff a published version of the xblock exists.
*/
/** True iff a published version of the xblock exists. */
published: null,
/**
* Date of the last publish of this xblock, or null if never published.
*/
/** Date of the last publish of this xblock, or null if never published. */
published_on: null,
/**
* User who last published the xblock, or null if never published. Will only be present if
* publishing info was explicitly requested.
*/
* User who last published the xblock, or null if never published. Will only be present if
* publishing info was explicitly requested.
*/
published_by: null,
/**
* True if the xblock is a parentable xblock.
*/
/** True if the xblock is a parentable xblock. */
has_children: null,
/**
* True if the xblock has changes.
* Note: this is not always provided as a performance optimization. It is only provided for
* verticals functioning as units.
*/
* True if the xblock has changes.
* Note: this is not always provided as a performance optimization. It is only provided for
* verticals functioning as units.
*/
has_changes: null,
/**
* Represents the possible publish states for an xblock. See the documentation
* for XBlockVisibility to see a comprehensive enumeration of the states.
*/
* Represents the possible publish states for an xblock. See the documentation
* for XBlockVisibility to see a comprehensive enumeration of the states.
*/
visibility_state: null,
/**
* True if the release date of the xblock is in the past.
*/
* True if the release date of the xblock is in the past.
*/
released_to_students: null,
/**
* If the xblock is published, the date on which it will be released to students.
* This can be null if the release date is unscheduled.
*/
* If the xblock is published, the date on which it will be released to students.
* This can be null if the release date is unscheduled.
*/
release_date: null,
/**
* The xblock which is determining the release date. For instance, for a unit,
* this will either be the parent subsection or the grandparent section.
* This can be null if the release date is unscheduled. Will only be present if
* publishing info was explicitly requested.
*/
* The xblock which is determining the release date. For instance, for a unit,
* this will either be the parent subsection or the grandparent section.
* This can be null if the release date is unscheduled. Will only be present if
* publishing info was explicitly requested.
*/
release_date_from: null,
/**
* True if this xblock is currently visible to students. This is computed server-side
* so that the logic isn't duplicated on the client. Will only be present if
* publishing info was explicitly requested.
*/
* True if this xblock is currently visible to students. This is computed server-side
* so that the logic isn't duplicated on the client. Will only be present if
* publishing info was explicitly requested.
*/
currently_visible_to_students: null,
/**
* If xblock is graded, the date after which student assessment will be evaluated.
* It has same format as release date, for example: 'Jan 02, 2015 at 00:00 UTC'.
*/
* If xblock is graded, the date after which student assessment will be evaluated.
* It has same format as release date, for example: 'Jan 02, 2015 at 00:00 UTC'.
*/
due_date: null,
/**
* Grading policy for xblock.
*/
/** Grading policy for xblock. */
format: null,
/**
* List of course graders names.
*/
/** List of course graders names. */
course_graders: null,
/**
* True if this xblock contributes to the final course grade.
*/
/** True if this xblock contributes to the final course grade. */
graded: null,
/**
* The same as `release_date` but as an ISO-formatted date string.
*/
/** The same as `release_date` but as an ISO-formatted date string. */
start: null,
/**
* The same as `due_date` but as an ISO-formatted date string.
*/
/** The same as `due_date` but as an ISO-formatted date string. */
due: null,
/**
* True iff this xblock is explicitly staff locked.
*/
/** True iff this xblock is explicitly staff locked. */
has_explicit_staff_lock: null,
/**
* True iff this any of this xblock's ancestors are staff locked.
*/
/** True iff this any of this xblock's ancestors are staff locked. */
ancestor_has_staff_lock: null,
/**
* The xblock which is determining the staff lock value. For instance, for a unit,
* this will either be the parent subsection or the grandparent section.
* This can be null if the xblock has no inherited staff lock. Will only be present if
* publishing info was explicitly requested.
*/
* The xblock which is determining the staff lock value. For instance, for a unit,
* this will either be the parent subsection or the grandparent section.
* This can be null if the xblock has no inherited staff lock. Will only be present if
* publishing info was explicitly requested.
*/
staff_lock_from: null,
/**
* True iff this xblock should display a "Contains staff only content" message.
*/
/** True iff this xblock should display a "Contains staff only content" message. */
staff_only_message: null,
/**
* True iff this xblock is a unit, and it has children that are only visible to certain
* user partition groups. Note that this is not a recursive property. Will only be present if
* publishing info was explicitly requested.
*/
* True iff this xblock is a unit, and it has children that are only visible to certain
* user partition groups. Note that this is not a recursive property. Will only be present if
* publishing info was explicitly requested.
*/
has_partition_group_components: null,
/**
* actions defines the state of delete, drag and child add functionality for a xblock.
* currently, each xblock has default value of 'True' for keys: deletable, draggable and childAddable.
*/
* actions defines the state of delete, drag and child add functionality for a xblock.
* currently, each xblock has default value of 'True' for keys: deletable, draggable and childAddable.
*/
actions: null,
/**
* Header visible to UI.
*/
/** Header visible to UI. */
is_header_visible: null,
/**
* Optional explanatory message about the xblock.
*/
/** Optional explanatory message about the xblock. */
explanatory_message: null,
/**
* The XBlock's group access rules. This is a dictionary keyed to user partition IDs,
* where the values are lists of group IDs.
*/
* The XBlock's group access rules. This is a dictionary keyed to user partition IDs,
* where the values are lists of group IDs.
*/
group_access: null,
/**
* User partition dictionary. This is pre-processed by Studio, so it contains
* some additional fields that are not stored in the course descriptor
* (for example, which groups are selected for this particular XBlock).
*/
* User partition dictionary. This is pre-processed by Studio, so it contains
* some additional fields that are not stored in the course descriptor
* (for example, which groups are selected for this particular XBlock).
*/
user_partitions: null,
/**
* This xBlock's Highlights to message to learners.
*/
/** This xBlock's Highlights to message to learners. */
highlights: [],
highlights_enabled: false,
highlights_enabled_for_messaging: false,
highlights_preview_only: true,
highlights_doc_url: '',
/**
* True if summary configuration is enabled.
*/
/** True if summary configuration is enabled. */
summary_configuration_enabled: null,
/**
* List of tags of the unit. This list is managed by the content_tagging module.
*/
tags: null,
/**
* True if the xblock is not visible to students only via links.
*/
hide_from_toc: null,
/**
* True iff this xblock should display a "Contains staff only content" message.
*/
hide_from_toc_message: null,
/** List of tags of the unit. This list is managed by the content_tagging module. */
tags: null,
/** True if the xblock is not visible to students only via links. */
hide_from_toc: null,
/** True iff this xblock should display a "Contains staff only content" message. */
hide_from_toc_message: null,
},
initialize: function() {
// Extend our Model by helper methods.
// Extend our Model by helper methods.
_.extend(this, this.getCategoryHelpers());
},
@@ -245,9 +203,9 @@ define(
},
/**
* Return true if action is required e.g. delete, drag, add new child etc or if given key is not present.
* @return {boolean}
*/
* Return true if action is required e.g. delete, drag, add new child etc or if given key is not present.
* @return {boolean}
*/
isActionRequired: function(actionName) {
var actions = this.get('actions');
if (actions !== null) {
@@ -259,9 +217,9 @@ define(
},
/**
* Return a list of convenience methods to check affiliation to the category.
* @return {Array}
*/
* Return a list of convenience methods to check affiliation to the category.
* @return {Array}
*/
getCategoryHelpers: function() {
var categories = ['course', 'chapter', 'sequential', 'vertical'],
helpers = {};
@@ -276,9 +234,9 @@ define(
},
/**
* Check if we can edit current XBlock or not on Course Outline page.
* @return {Boolean}
*/
* Check if we can edit current XBlock or not on Course Outline page.
* @return {Boolean}
*/
isEditableOnCourseOutline: function() {
return this.isSequential() || this.isChapter() || this.isVertical();
}

View File

@@ -581,7 +581,6 @@ describe('Container Subviews', function() {
});
});
describe('Message Area', function() {
var messageSelector = '.container-message .warning',
warningMessage = 'Caution: The last published version of this unit is live. '

View File

@@ -2540,7 +2540,7 @@ describe('CourseOutlinePage', function() {
hide_from_toc: null
}
});
})
});
});
verifyTypePublishable('unit', function(options) {

View File

@@ -1,31 +1,32 @@
define(["jquery"], function ($) {
"use strict";
function copyToClipboard(id, textToCopy) {
if (navigator.clipboard) {
navigator.clipboard.writeText(textToCopy);
changeButtonText(id);
return;
define(['jquery'], function($) {
'use strict';
function copyToClipboard(id, textToCopy) {
if (navigator.clipboard) {
navigator.clipboard.writeText(textToCopy);
changeButtonText(id);
return;
}
const textArea = document.createElement('textarea');
textArea.value = textToCopy;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
changeButtonText(id);
}
const textArea = document.createElement("textarea");
textArea.value = textToCopy;
document.body.appendChild(textArea);
textArea.select();
document.execCommand("copy");
document.body.removeChild(textArea);
changeButtonText(id);
}
function changeButtonText(id, delay = 2000) {
const buttonId = `#${id}`;
const textClass = ".copy-link-button-text";
function changeButtonText(id, delay = 2000) {
const buttonId = `#${id}`;
const textClass = '.copy-link-button-text';
const previewShareLinkText = $(buttonId).find(textClass).html();
const shareLinkCopiedText = gettext("Copied");
$(buttonId).find(textClass).text(shareLinkCopiedText);
const previewShareLinkText = $(buttonId).find(textClass).html();
const shareLinkCopiedText = gettext('Copied');
$(buttonId).find(textClass).text(shareLinkCopiedText);
setTimeout(() => {
$(buttonId).find(textClass).text(previewShareLinkText);
}, delay);
}
return { copyToClipboard };
setTimeout(() => {
$(buttonId).find(textClass).text(previewShareLinkText);
}, delay);
}
return {copyToClipboard};
});

View File

@@ -237,46 +237,44 @@ function(
/** Copy a Unit to the clipboard */
copyXBlock() {
const clipboardEndpoint = "/api/content-staging/v1/clipboard/";
const clipboardEndpoint = '/api/content-staging/v1/clipboard/';
// Start showing a "Copying" notification:
ViewUtils.runOperationShowingMessage(gettext('Copying'), () => {
return $.postJSON(
clipboardEndpoint,
{ usage_key: this.model.get('id') }
).then((data) => {
// const status = data.content?.status;
const status = data.content && data.content.status;
// ^ platform's old require.js/esprima breaks on newer syntax in some JS files but not all.
if (status === "ready") {
// The Unit has been copied and is ready to use.
this.clipboardManager.updateUserClipboard(data); // This will update the UI and notify other tabs
return data;
} else if (status === "loading") {
// The clipboard is being loaded asynchronously.
// Poll the endpoint until the copying process is complete:
const deferred = $.Deferred();
const checkStatus = () => {
$.getJSON(clipboardEndpoint, (pollData) => {
// const newStatus = pollData.content?.status;
const newStatus = pollData.content && pollData.content.status;
if (newStatus === "ready") {
this.clipboardManager.updateUserClipboard(pollData);
deferred.resolve(pollData);
} else if (newStatus === "loading") {
setTimeout(checkStatus, 1000);
} else {
deferred.reject();
throw new Error(`Unexpected clipboard status "${newStatus}" in successful API response.`);
}
})
}
setTimeout(checkStatus, 1000);
return deferred;
} else {
throw new Error(`Unexpected clipboard status "${status}" in successful API response.`);
}
});
});
ViewUtils.runOperationShowingMessage(gettext('Copying'), () => $.postJSON(
clipboardEndpoint,
{usage_key: this.model.get('id')}
).then((data) => {
// const status = data.content?.status;
const status = data.content && data.content.status;
// ^ platform's old require.js/esprima breaks on newer syntax in some JS files but not all.
if (status === 'ready') {
// The Unit has been copied and is ready to use.
this.clipboardManager.updateUserClipboard(data); // This will update the UI and notify other tabs
return data;
} else if (status === 'loading') {
// The clipboard is being loaded asynchronously.
// Poll the endpoint until the copying process is complete:
const deferred = $.Deferred();
const checkStatus = () => {
$.getJSON(clipboardEndpoint, (pollData) => {
// const newStatus = pollData.content?.status;
const newStatus = pollData.content && pollData.content.status;
if (newStatus === 'ready') {
this.clipboardManager.updateUserClipboard(pollData);
deferred.resolve(pollData);
} else if (newStatus === 'loading') {
setTimeout(checkStatus, 1000);
} else {
deferred.reject();
throw new Error(`Unexpected clipboard status "${newStatus}" in successful API response.`);
}
});
};
setTimeout(checkStatus, 1000);
return deferred;
} else {
throw new Error(`Unexpected clipboard status "${status}" in successful API response.`);
}
}));
},
initializePasteButton(element) {
@@ -285,11 +283,11 @@ function(
// We should have the user's clipboard status from CourseOutlinePage, whose clipboardManager manages
// the clipboard data on behalf of all the XBlocks in the outline.
this.refreshPasteButton(this.clipboardManager.userClipboard);
this.clipboardManager.addEventListener("update", (event) => {
this.clipboardManager.addEventListener('update', (event) => {
this.refreshPasteButton(event.detail);
});
} else {
this.$(".paste-component").hide();
this.$('.paste-component').hide();
}
}
},
@@ -301,41 +299,38 @@ function(
// 'data' is the same data returned by the "get clipboard status" API endpoint
// i.e. /api/content-staging/v1/clipboard/
if (this.options.canEdit && data.content) {
if (data.content.status === "expired") {
if (data.content.status === 'expired') {
// This has expired and can no longer be pasted.
this.$(".paste-component").hide();
this.$('.paste-component').hide();
} else if (data.content.block_type === 'vertical') {
// This is suitable for pasting as a unit.
const detailsPopupEl = this.$(".clipboard-details-popup")[0];
const detailsPopupEl = this.$('.clipboard-details-popup')[0];
// Only Units should have the paste button initialized
if (detailsPopupEl !== undefined) {
const detailsPopupEl = this.$(".clipboard-details-popup")[0];
detailsPopupEl.querySelector(".detail-block-name").innerText = data.content.display_name;
detailsPopupEl.querySelector(".detail-block-type").innerText = data.content.block_type_display;
detailsPopupEl.querySelector(".detail-course-name").innerText = data.source_context_title;
detailsPopupEl.querySelector('.detail-block-name').innerText = data.content.display_name;
detailsPopupEl.querySelector('.detail-block-type').innerText = data.content.block_type_display;
detailsPopupEl.querySelector('.detail-course-name').innerText = data.source_context_title;
if (data.source_edit_url) {
detailsPopupEl.setAttribute("href", data.source_edit_url);
detailsPopupEl.classList.remove("no-edit-link");
detailsPopupEl.setAttribute('href', data.source_edit_url);
detailsPopupEl.classList.remove('no-edit-link');
} else {
detailsPopupEl.setAttribute("href", "#");
detailsPopupEl.classList.add("no-edit-link");
detailsPopupEl.setAttribute('href', '#');
detailsPopupEl.classList.add('no-edit-link');
}
this.$('.paste-component').show()
this.$('.paste-component').show();
}
} else {
this.$('.paste-component').hide()
this.$('.paste-component').hide();
}
} else {
this.$('.paste-component').hide();
}
},
createPlaceholderElementForPaste(category, componentDisplayName) {
const nameStr = StringUtils.interpolate(gettext("Copy of '{componentDisplayName}'"), { componentDisplayName }, true);
const el = document.createElement("li");
el.classList.add("outline-item", "outline-" + category, "has-warnings", "is-draggable");
const nameStr = StringUtils.interpolate(gettext('Copy of "{componentDisplayName}"'), {componentDisplayName}, true);
const el = document.createElement('li');
el.classList.add('outline-item', 'outline-' + category, 'has-warnings', 'is-draggable');
el.innerHTML = `
<div class="${category}-header">
<h3 class="${category}-header-details" style="width: 50%">
@@ -369,17 +364,15 @@ function(
$listPanel.append($placeholderEl);
// Start showing a "Pasting" notification:
ViewUtils.runOperationShowingMessage(gettext('Pasting'), () => {
return $.postJSON(this.model.urlRoot + '/', {
parent_locator: parentLocator,
staged_content: "clipboard",
}).then((data) => {
this.refresh(); // Update this and replace the placeholder with the actual pasted unit.
return data;
}).fail(() => {
$placeholderEl.remove();
});
}).done((data) => {
ViewUtils.runOperationShowingMessage(gettext('Pasting'), () => $.postJSON(this.model.urlRoot + '/', {
parent_locator: parentLocator,
staged_content: 'clipboard',
}).then((data) => {
this.refresh(); // Update this and replace the placeholder with the actual pasted unit.
return data;
}).fail(() => {
$placeholderEl.remove();
})).done((data) => {
const {
conflicting_files: conflictingFiles,
error_files: errorFiles,
@@ -389,32 +382,32 @@ function(
const notices = [];
if (errorFiles.length) {
notices.push((next) => new PromptView.Error({
title: gettext("Some errors occurred"),
title: gettext('Some errors occurred'),
message: (
gettext("The following required files could not be added to the course:") +
" " + errorFiles.join(", ")
gettext('The following required files could not be added to the course:')
+ ' ' + errorFiles.join(', ')
),
actions: {primary: {text: gettext("OK"), click: (x) => { x.hide(); next(); }}},
actions: {primary: {text: gettext('OK'), click: (x) => { x.hide(); next(); }}},
}));
}
if (conflictingFiles.length) {
notices.push((next) => new PromptView.Warning({
title: gettext("You may need to update a file(s) manually"),
title: gettext('You may need to update a file(s) manually'),
message: (
gettext(
"The following files already exist in this course but don't match the " +
"version used by the component you pasted:"
) + " " + conflictingFiles.join(", ")
'The following files already exist in this course but don\'t match the '
+ 'version used by the component you pasted:'
) + ' ' + conflictingFiles.join(', ')
),
actions: {primary: {text: gettext("OK"), click: (x) => { x.hide(); next(); }}},
actions: {primary: {text: gettext('OK'), click: (x) => { x.hide(); next(); }}},
}));
}
if (newFiles.length) {
notices.push(() => new NotificationView.Info({
title: gettext("New file(s) added to Files & Uploads."),
title: gettext('New file(s) added to Files & Uploads.'),
message: (
gettext("The following required files were imported to this course:") +
" " + newFiles.join(", ")
gettext('The following required files were imported to this course:')
+ ' ' + newFiles.join(', ')
),
actions: {
primary: {
@@ -423,7 +416,6 @@ function(
const article = document.querySelector('[data-course-assets]');
const assetsUrl = $(article).attr('data-course-assets');
window.location.href = assetsUrl;
return;
}
},
secondary: {
@@ -440,7 +432,7 @@ function(
const showNext = () => {
const view = notices.shift()(showNext);
view.show();
}
};
// Delay to avoid conflict with the "Pasting..." notification.
setTimeout(showNext, 1250);
}
@@ -478,14 +470,13 @@ function(
* If the new "Actions" menu is enabled, most actions like Configure,
* Duplicate, Move, Delete, etc. are moved into this menu. For this
* event, we just toggle displaying the menu.
* @param {*} event
*/
showActionsMenu(event) {
const showActionsButton = event.currentTarget;
const subMenu = showActionsButton.parentElement.querySelector(".wrapper-nav-sub");
const subMenu = showActionsButton.parentElement.querySelector('.wrapper-nav-sub');
// Close all open dropdowns
const elements = document.querySelectorAll("li.action-item.action-actions-menu.nav-item");
const elements = document.querySelectorAll('li.action-item.action-actions-menu.nav-item');
elements.forEach(element => {
if (element !== showActionsButton.parentElement) {
element.querySelector('.wrapper-nav-sub').classList.remove('is-shown');
@@ -494,7 +485,7 @@ function(
// Code in 'base.js' normally handles toggling these dropdowns but since this one is
// not present yet during the domReady event, we have to handle displaying it ourselves.
subMenu.classList.toggle("is-shown");
subMenu.classList.toggle('is-shown');
// if propagation is not stopped, the event will bubble up to the
// body element, which will close the dropdown.
event.stopPropagation();

View File

@@ -25,7 +25,7 @@ def run_eslint():
Runs eslint on static asset directories.
If limit option is passed, fails build if more violations than the limit are found.
"""
violations_limit = 734
violations_limit = 625
command = [
"node",