From 5549db4d80dfc80ab90d529346c7c3efc9b801ee Mon Sep 17 00:00:00 2001 From: Syed Ali Abbas Zaidi <88369802+Syed-Ali-Abbas-Zaidi@users.noreply.github.com> Date: Thu, 2 Mar 2023 16:16:50 +0500 Subject: [PATCH] fix: migrate remaining eslint-config-edx (#31760) * fix: migrate remaining eslint-config-edx * refactor: updated eslint rules according to eslint-config-edx-es5 * refactor: add custom rules to suppress unnecessary eslint issues * refactor: add custom rules to internal eslint configs * fix: fix all indentation issues * chore: update lock file --- .eslintignore | 2 + .eslintrc.json | 68 +- cms/static/cms/js/spec/main_spec.js | 148 +- cms/static/cms/js/xblock/cms.runtime.v1.js | 290 +- cms/static/js/base.js | 230 +- .../factories/certificates_page_factory.js | 2 +- .../js/certificates/models/certificate.js | 162 +- .../spec/views/certificate_details_spec.js | 2 +- .../spec/views/certificate_editor_spec.js | 2 +- .../spec/views/certificates_list_spec.js | 4 +- .../certificates/views/certificate_details.js | 2 +- .../certificates/views/certificate_editor.js | 2 +- .../certificates/views/signatory_details.js | 2 +- .../js/certificates/views/signatory_editor.js | 4 +- cms/static/js/collections/textbook.js | 12 +- cms/static/js/factories/base.js | 6 +- .../js/factories/group_configurations.js | 8 +- cms/static/js/factories/index.js | 8 +- cms/static/js/factories/manage_users.js | 58 +- cms/static/js/factories/manage_users_lib.js | 66 +- cms/static/js/features/import/views/import.js | 6 +- cms/static/js/features_jsx/.eslintrc.js | 17 +- .../studio/CourseOrLibraryListing.jsx | 140 +- cms/static/js/index.js | 360 +- .../js/maintenance/force_publish_course.js | 38 +- cms/static/js/models/asset.js | 2 +- cms/static/js/models/license.js | 4 +- .../js/models/settings/course_details.js | 278 +- .../js/models/settings/course_grader.js | 8 +- .../models/settings/course_grading_policy.js | 24 +- cms/static/js/models/textbook.js | 160 +- cms/static/js/models/uploads.js | 40 +- cms/static/js/models/xblock_info.js | 304 +- .../js/spec/utils/drag_and_drop_spec.js | 730 +- .../spec/utils/handle_iframe_binding_spec.js | 72 +- .../spec/video/file_uploader_editor_spec.js | 344 +- .../js/spec/video/transcripts/editor_spec.js | 780 +- .../video/transcripts/file_uploader_spec.js | 390 +- .../video/transcripts/message_manager_spec.js | 456 +- .../js/spec/video/transcripts/utils_spec.js | 464 +- .../spec/video/transcripts/videolist_spec.js | 1378 +- .../js/spec/video/translations_editor_spec.js | 548 +- cms/static/js/spec/views/assets_spec.js | 814 +- cms/static/js/spec/views/license_spec.js | 256 +- .../views/modals/move_xblock_modal_spec.js | 136 +- cms/static/js/spec/views/move_xblock_spec.js | 4 +- .../js/spec/views/paged_container_spec.js | 994 +- .../js/spec/views/pages/container_spec.js | 138 +- .../spec/views/pages/course_outline_spec.js | 4 +- .../js/spec/views/pages/course_rerun_spec.js | 390 +- cms/static/js/spec/views/pages/index_spec.js | 288 +- cms/static/js/spec/views/paging_spec.js | 712 +- cms/static/js/spec/views/unit_outline_spec.js | 250 +- .../js/spec/views/video_thumbnail_spec.js | 8 +- .../js/spec/views/video_transcripts_spec.js | 4 +- cms/static/js/spec/views/xblock_spec.js | 188 +- .../views/xblock_string_field_editor_spec.js | 2 +- .../js/spec/views/xblock_validation_spec.js | 4 +- .../js/spec_helpers/assertion_helpers.js | 142 +- cms/static/js/spec_helpers/edit_helpers.js | 6 +- cms/static/js/utils/date_utils.js | 216 +- cms/static/js/utils/drag_and_drop.js | 640 +- .../js/views/active_video_upload_list.js | 784 +- cms/static/js/views/asset.js | 172 +- cms/static/js/views/assets.js | 646 +- cms/static/js/views/baseview.js | 126 +- cms/static/js/views/components/add_xblock.js | 138 +- cms/static/js/views/container.js | 270 +- .../js/views/course_highlights_enable.js | 92 +- cms/static/js/views/course_info_edit.js | 6 +- cms/static/js/views/course_info_handout.js | 4 +- cms/static/js/views/course_info_update.js | 524 +- cms/static/js/views/course_outline.js | 444 +- cms/static/js/views/course_rerun.js | 150 +- cms/static/js/views/course_video_settings.js | 12 +- cms/static/js/views/edit_chapter.js | 154 +- cms/static/js/views/edit_textbook.js | 176 +- cms/static/js/views/export.js | 4 +- .../js/views/group_configuration_details.js | 2 +- cms/static/js/views/instructor_info.js | 140 +- cms/static/js/views/learning_info.js | 2 +- cms/static/js/views/list_textbooks.js | 98 +- cms/static/js/views/manage_users_and_roles.js | 578 +- cms/static/js/views/metadata.js | 1074 +- .../js/views/modals/course_outline_modals.js | 26 +- cms/static/js/views/modals/edit_xblock.js | 444 +- .../js/views/modals/move_xblock_modal.js | 2 +- cms/static/js/views/move_xblock_list.js | 2 +- cms/static/js/views/paged_container.js | 500 +- cms/static/js/views/pages/container.js | 690 +- .../js/views/pages/container_subviews.js | 506 +- cms/static/js/views/pages/course_outline.js | 394 +- cms/static/js/views/paging_header.js | 26 +- .../js/views/partition_group_details.js | 2 +- cms/static/js/views/previous_video_upload.js | 2 +- cms/static/js/views/settings/advanced.js | 336 +- cms/static/js/views/settings/grader.js | 132 +- cms/static/js/views/settings/grading.js | 754 +- cms/static/js/views/settings/main.js | 872 +- cms/static/js/views/show_textbook.js | 128 +- cms/static/js/views/tabs.js | 332 +- cms/static/js/views/uploads.js | 238 +- .../js/views/utils/move_xblock_utils.js | 64 +- cms/static/js/views/utils/xblock_utils.js | 452 +- cms/static/js/views/validation.js | 288 +- .../js/views/video/transcripts/editor.js | 320 +- .../views/video/transcripts/file_uploader.js | 240 +- .../video/transcripts/message_manager.js | 276 +- .../video/transcripts/metadata_videolist.js | 496 +- .../js/views/video/transcripts/utils.js | 34 +- .../js/views/video/translations_editor.js | 528 +- cms/static/js/views/video_thumbnail.js | 12 +- cms/static/js/views/video_transcripts.js | 4 +- cms/static/js/views/xblock.js | 384 +- cms/static/js/views/xblock_editor.js | 284 +- cms/static/js/views/xblock_outline.js | 582 +- .../js/components/BlockBrowser/.eslintrc.js | 23 +- .../components/BlockBrowser/BlockBrowser.jsx | 154 +- .../BlockBrowser/BlockBrowser.test.jsx | 74 +- .../BlockBrowser/BlockBrowserContainer.jsx | 10 +- .../BlockBrowser/data/actions/constants.js | 12 +- .../BlockBrowser/data/actions/courseBlocks.js | 44 +- .../BlockBrowser/data/api/client.js | 42 +- .../BlockBrowser/data/reducers/index.js | 60 +- .../BlockBrowser/data/selectors/index.js | 20 +- .../js/components/BlockBrowser/data/store.js | 6 +- .../js/components/BlockBrowser/index.jsx | 6 +- .../js/components/ExperimentalCarousel.jsx | 180 +- .../common/js/components/utils/view_utils.js | 428 +- .../common/js/components/views/feedback.js | 318 +- .../js/components/views/feedback_alert.js | 4 +- .../js/components/views/paging_footer.js | 128 +- .../js/components/views/search_field.js | 140 +- common/static/common/js/discussion/utils.js | 4 +- .../views/discussion_thread_list_view.js | 2 +- .../js/spec/components/feedback_spec.js | 12 +- .../js/spec/components/paging_header_spec.js | 12 +- .../js/spec/components/tabbed_view_spec.js | 276 +- .../js/spec/components/view_utils_spec.js | 200 +- .../js/spec/utils/edx.utils.validate_spec.js | 44 +- .../common/js/spec_helpers/view_helpers.js | 250 +- .../common/js/utils/edx.utils.validate.js | 258 +- .../static/common/js/utils/require-serial.js | 4 +- common/static/js/capa/design-protein-2d.js | 2 +- common/static/js/capa/drag_and_drop.js | 12 +- .../js/capa/drag_and_drop/base_image.js | 2 +- .../js/capa/drag_and_drop/config_parser.js | 42 +- .../js/capa/drag_and_drop/draggable_events.js | 24 +- .../js/capa/drag_and_drop/draggable_logic.js | 122 +- .../js/capa/drag_and_drop/draggables.js | 28 +- common/static/js/capa/drag_and_drop/main.js | 164 +- .../static/js/capa/drag_and_drop/scroller.js | 128 +- common/static/js/capa/drag_and_drop/state.js | 24 +- .../static/js/capa/drag_and_drop/targets.js | 8 +- .../js/capa/drag_and_drop/update_input.js | 28 +- common/static/js/capa/schematicinput.js | 4 +- .../spec/formula_equation_preview_spec.js | 2 +- common/static/js/capa/src/jschannel.js | 12 +- .../js/capa/symbolic_mathjax_preprocessor.js | 14 +- .../js/spec/accessibility_tools_spec.js | 16 +- common/static/js/src/CSS3_workarounds.js | 6 +- common/static/js/src/ReactRenderer.jsx | 94 +- common/static/js/src/accessibility_tools.js | 30 +- common/static/js/src/lang_edx.js | 12 +- err.txt | 29941 ++++++++++++++++ .../discussion/js/discussion_board_factory.js | 2 +- .../discussion_user_profile_view_spec.js | 2 +- .../js/views/discussion_board_view.js | 16 +- .../js/views/discussion_user_profile_view.js | 112 +- .../instructor/static/instructor/.eslintrc.js | 27 +- .../ProblemBrowser/components/Main/Main.jsx | 164 +- .../components/Main/Main.test.jsx | 154 +- .../components/Main/MainContainer.jsx | 22 +- .../components/ReportStatus/ReportStatus.jsx | 70 +- .../ReportStatus/ReportStatus.test.jsx | 78 +- .../ReportStatus/ReportStatusContainer.jsx | 12 +- .../data/actions/problemResponses.js | 148 +- .../ProblemBrowser/data/api/client.js | 46 +- .../ProblemBrowser/data/reducers/index.js | 58 +- .../instructor/ProblemBrowser/index.jsx | 6 +- .../js/spec/views/certificates_spec.js | 2 +- .../support/static/support/jsx/.eslintrc.js | 27 +- .../components/EntitlementForm/container.jsx | 20 +- .../components/EntitlementForm/index.jsx | 282 +- .../jsx/entitlements/components/Main/Main.jsx | 92 +- .../components/Main/MainContainer.jsx | 12 +- .../entitlements/components/Search/Search.jsx | 62 +- .../components/Search/SearchContainer.jsx | 8 +- .../Table/EntitlementSupportTable.jsx | 156 +- .../EntitlementSupportTableContainer.jsx | 8 +- .../entitlements/data/actions/entitlement.js | 158 +- .../jsx/entitlements/data/actions/error.js | 10 +- .../jsx/entitlements/data/actions/form.js | 14 +- .../jsx/entitlements/data/api/client.js | 76 +- .../jsx/entitlements/data/api/endpoints.js | 2 +- .../data/constants/actionTypes.js | 34 +- .../entitlements/data/constants/formTypes.js | 4 +- .../data/reducers/entitlements.js | 22 +- .../jsx/entitlements/data/reducers/error.js | 10 +- .../jsx/entitlements/data/reducers/form.js | 18 +- .../support/jsx/entitlements/data/store.js | 24 +- .../static/support/jsx/entitlements/index.jsx | 6 +- .../static/support/jsx/errors_list.jsx | 30 +- .../static/support/jsx/file_upload.jsx | 280 +- .../static/support/jsx/logged_in_user.jsx | 302 +- .../static/support/jsx/logged_out_user.jsx | 58 +- .../support/jsx/program_enrollments/index.jsx | 82 +- .../jsx/program_enrollments/inspector.jsx | 390 +- .../support/jsx/single_support_form.jsx | 712 +- .../support/static/support/jsx/success.jsx | 74 +- .../static/support/jsx/upload_progress.jsx | 52 +- .../spec/collections/topic_collection_spec.js | 80 +- .../teams/js/spec/teams_tab_factory_spec.js | 86 +- .../teams/js/spec/views/edit_team_spec.js | 6 +- .../teams/js/spec/views/team_card_spec.js | 288 +- .../teams/js/spec/views/teams_tab_spec.js | 8 +- .../teams/js/spec/views/topic_card_spec.js | 66 +- .../teams/static/teams/js/views/edit_team.js | 408 +- .../teams/js/views/edit_team_members.js | 188 +- .../static/teams/js/views/instructor_tools.js | 116 +- .../static/teams/js/views/team_profile.js | 270 +- .../js/views/team_profile_header_actions.js | 258 +- .../teams/static/teams/js/views/team_utils.js | 176 +- .../teams/static/teams/js/views/teams_tab.js | 1140 +- .../teams/static/teams/js/views/topic_card.js | 98 +- .../static/teams/js/views/topic_teams.js | 6 +- lms/static/completion/js/.eslintrc.js | 17 +- .../completion/js/CompletionOnViewService.js | 66 +- lms/static/completion/js/ViewedEvent.js | 252 +- .../completion/js/spec/ViewedEvent_spec.js | 166 +- lms/static/js/Markdown.Editor.js | 80 +- .../accessible_components/StatusBarAlert.jsx | 46 +- lms/static/js/ccx/schedule.js | 148 +- .../collections/certificate_allowlist.js | 90 +- .../certificate_allowlist_factory.js | 50 +- .../models/certificate_exception.js | 40 +- .../views/certificate_allowlist.js | 186 +- .../views/certificate_allowlist_editor.js | 188 +- .../views/certificate_bulk_allowlist.js | 396 +- lms/static/js/components/card/views/card.js | 150 +- lms/static/js/course_survey.js | 6 +- .../js/courseware/courseware_factory.js | 28 +- lms/static/js/dashboard/dropdown.js | 10 +- lms/static/js/dashboard/legacy.js | 386 +- .../DemographicsCollectionBanner.jsx | 144 +- .../DemographicsCollectionModal.jsx | 930 +- .../MultiselectDropdown.jsx | 284 +- .../SelectWithInput.jsx | 88 +- .../js/demographics_collection/Wizard.jsx | 182 +- lms/static/js/discovery/discovery_factory.js | 178 +- .../js/discovery/models/search_state.js | 4 +- .../js/discovery/views/refine_sidebar.js | 22 +- lms/static/js/discovery/views/search_form.js | 14 +- .../views/discussions.js | 438 +- .../views/divided_discussions_course_wide.js | 132 +- .../views/divided_discussions_inline.js | 214 +- lms/static/js/edxnotes/collections/notes.js | 2 +- lms/static/js/edxnotes/models/note.js | 4 +- .../js/edxnotes/plugins/caret_navigation.js | 24 +- lms/static/js/edxnotes/plugins/events.js | 72 +- lms/static/js/edxnotes/plugins/scroller.js | 12 +- .../edxnotes/plugins/store_error_handler.js | 6 +- lms/static/js/edxnotes/utils/logger.js | 26 +- lms/static/js/edxnotes/views/note_group.js | 2 +- lms/static/js/edxnotes/views/notes_factory.js | 6 +- lms/static/js/edxnotes/views/notes_page.js | 12 +- lms/static/js/edxnotes/views/page_factory.js | 4 +- lms/static/js/edxnotes/views/search_box.js | 14 +- lms/static/js/edxnotes/views/shim.js | 226 +- lms/static/js/edxnotes/views/tab_item.js | 92 +- lms/static/js/edxnotes/views/tab_panel.js | 136 +- lms/static/js/edxnotes/views/tab_view.js | 26 +- .../js/edxnotes/views/tabs/search_results.js | 4 +- lms/static/js/edxnotes/views/tabs/tags.js | 34 +- .../views/financial_assistance_form_view.js | 250 +- lms/static/js/groups/views/cohort_editor.js | 566 +- lms/static/js/groups/views/cohort_form.js | 326 +- lms/static/js/groups/views/cohorts.js | 514 +- .../groups/views/cohorts_dashboard_factory.js | 62 +- .../instructor_dashboard/data_download_2.js | 6 +- .../js/instructor_dashboard/membership.js | 2 +- lms/static/js/instructor_dashboard/util.js | 30 +- lms/static/js/jwt_auth/.eslintrc.js | 23 +- .../js/jwt_auth/AxiosCsrfTokenService.js | 96 +- .../js/jwt_auth/AxiosJwtTokenService.js | 206 +- .../interceptors/createRetryInterceptor.js | 106 +- lms/static/js/jwt_auth/utils.js | 172 +- lms/static/js/leanModal.js | 2 +- .../CircleChart.jsx | 156 +- .../CircleChartLegend.jsx | 72 +- .../Discussions.jsx | 138 +- .../learner_analytics_dashboard/DueDates.jsx | 110 +- .../GradeTable.jsx | 126 +- .../LearnerAnalyticsDashboard.jsx | 192 +- lms/static/js/learner_dashboard/.eslintrc.js | 23 +- .../EnterpriseLearnerPortalModal.jsx | 280 +- .../RecommendationsPanel.jsx | 182 +- .../js/learner_dashboard/Static2UCallouts.jsx | 380 +- .../js/learner_dashboard/certificate_api.js | 38 +- .../collections/course_card_collection.js | 12 +- .../collections/program_collection.js | 12 +- .../course_entitlement_factory.js | 2 +- .../entitlement_unenrollment_factory.js | 2 +- .../models/course_card_model.js | 470 +- .../models/course_enroll_model.js | 14 +- .../models/course_entitlement_model.js | 22 +- .../learner_dashboard/models/program_model.js | 42 +- .../program_details_factory.js | 2 +- .../learner_dashboard/program_list_factory.js | 42 +- .../spec/collection_list_view_spec.js | 312 +- .../spec/course_card_view_spec.js | 408 +- .../spec/course_enroll_view_spec.js | 556 +- .../spec/course_entitlement_view_spec.js | 294 +- .../entitlement_unenrollment_view_spec.js | 312 +- .../spec/program_card_view_spec.js | 282 +- .../spec/program_details_header_spec.js | 120 +- .../spec/program_details_sidebar_view_spec.js | 254 +- .../spec/program_details_view_spec.js | 1268 +- .../spec/progress_circle_view_spec.js | 156 +- .../spec/sidebar_view_spec.js | 70 +- .../spec/unenroll_view_spec.js | 56 +- .../learner_dashboard/unenrollment_factory.js | 2 +- .../views/certificate_list_view.js | 24 +- .../views/certificate_status_view.js | 22 +- .../views/collection_list_view.js | 80 +- .../views/course_card_view.js | 182 +- .../views/course_enroll_view.js | 152 +- .../views/course_entitlement_view.js | 612 +- .../views/entitlement_unenrollment_view.js | 336 +- .../views/expired_notification_view.js | 18 +- .../views/explore_new_programs_view.js | 44 +- .../views/program_card_view.js | 148 +- .../views/program_details_sidebar_view.js | 178 +- .../views/program_details_view.js | 262 +- .../views/program_header_view.js | 78 +- .../views/progress_circle_view.js | 130 +- .../learner_dashboard/views/sidebar_view.js | 38 +- .../learner_dashboard/views/unenroll_view.js | 188 +- .../views/upgrade_message_view.js | 30 +- lms/static/js/pdf-analytics.js | 2 +- lms/static/js/query-params.js | 2 +- .../js/spec/components/card/card_spec.js | 128 +- .../js/spec/components/header/header_spec.js | 84 +- lms/static/js/spec/dashboard/donation.js | 320 +- .../js/spec/dashboard/track_events_spec.js | 2 +- .../views/tabs/search_results_spec.js | 36 +- .../financial_assistance_form_view_spec.js | 18 +- .../js/spec/groups/views/cohorts_spec.js | 1794 +- .../js/spec/groups/views/discussions_spec.js | 862 +- .../certificates_bulk_exception_spec.js | 242 +- .../certificates_exception_spec.js | 746 +- .../certificates_invalidation_spec.js | 436 +- .../instructor_dashboard/certificates_spec.js | 162 +- .../data_download_spec.js | 284 +- .../membership_auth_spec.js | 206 +- .../instructor_dashboard/membership_spec.js | 12 +- .../js/spec/staff_debug_actions_spec.js | 376 +- .../js/spec/student_account/access_spec.js | 282 +- .../account_settings_factory_spec.js | 566 +- .../account_settings_fields_helpers.js | 42 +- .../account_settings_fields_spec.js | 336 +- .../account_settings_view_spec.js | 138 +- .../spec/student_account/finish_auth_spec.js | 214 +- .../spec/student_account/hinted_login_spec.js | 132 +- .../student_account/institution_login_spec.js | 118 +- .../js/spec/student_account/login_spec.js | 464 +- .../logistration_factory_spec.js | 180 +- .../multiple_enterprise_spec.js | 280 +- .../student_account/password_reset_spec.js | 188 +- .../js/spec/student_account/register_spec.js | 926 +- .../make_payment_step_view_ab_testing_spec.js | 386 +- .../make_payment_step_view_spec.js | 470 +- .../spec/verify_student/reverify_view_spec.js | 118 +- .../review_photos_step_view_spec.js | 212 +- .../verify_student/webcam_photo_view_spec.js | 310 +- lms/static/js/spec/views/fields_helpers.js | 608 +- lms/static/js/spec/views/fields_spec.js | 642 +- .../js/spec/views/file_uploader_spec.js | 308 +- .../js/spec/views/message_banner_spec.js | 36 +- lms/static/js/staff_debug_actions.js | 26 +- .../js/student_account/AccountsClient.js | 26 +- .../StudentAccountDeletionInitializer.js | 44 +- .../student_account/components/.eslintrc.js | 23 +- .../components/PasswordResetConfirmation.jsx | 216 +- .../components/PasswordResetInput.jsx | 26 +- .../components/StudentAccountDeletion.jsx | 332 +- .../StudentAccountDeletionModal.jsx | 404 +- .../components/removeLoggedInCookies.js | 38 +- .../spec/PasswordResetConfirmation_spec.js | 112 +- .../student_account/logistration_factory.js | 12 +- .../models/AccountRecoveryModel.js | 2 +- .../models/PasswordResetModel.js | 2 +- .../student_account/models/RegisterModel.js | 8 +- .../models/user_account_model.js | 2 +- .../js/student_account/views/AccessView.js | 514 +- .../js/student_account/views/FormView.js | 12 +- .../student_account/views/HintedLoginView.js | 6 +- .../js/student_account/views/LoginView.js | 14 +- .../views/PasswordResetView.js | 58 +- .../js/student_account/views/RegisterView.js | 1116 +- .../views/account_settings_factory.js | 30 +- lms/static/js/toggle_login_modal.js | 8 +- lms/static/js/utils/navigation.js | 16 +- .../js/verify_student/incourse_reverify.js | 32 +- .../models/verification_model.js | 88 +- lms/static/js/verify_student/reverify.js | 60 +- .../js/verify_student/views/error_view.js | 66 +- .../verify_student/views/image_input_view.js | 154 +- .../views/incourse_reverify_view.js | 124 +- .../views/pay_and_verify_view.js | 4 +- .../views/reverify_success_step_view.js | 16 +- .../js/verify_student/views/reverify_view.js | 150 +- .../views/review_photos_step_view.js | 2 +- .../js/verify_student/views/step_view.js | 88 +- .../verify_student/views/webcam_photo_view.js | 464 +- lms/static/js/views/fields.js | 18 +- lms/static/js/views/image_field.js | 2 +- lms/static/js/wiki/CodeMirror.init.js | 2 +- .../announcements/jsx/Announcements.jsx | 224 +- .../announcements/jsx/Announcements.test.jsx | 32 +- .../js/spec/bookmark_button_view_spec.js | 288 +- .../js/spec/bookmarks_list_view_spec.js | 488 +- .../js/spec/course_bookmarks_factory_spec.js | 52 +- .../js/spec_helpers/bookmark_helpers.js | 4 +- .../js/views/bookmarks_list.js | 180 +- .../features/course_experience/.eslintrc.js | 23 +- .../static/course_experience/js/CourseSock.js | 138 +- .../static/course_experience/js/currency.js | 88 +- .../js/spec/Currency_spec.js | 96 +- .../course_search/js/course_search_factory.js | 88 +- .../js/dashboard_search_factory.js | 78 +- .../js/views/search_item_view.js | 2 +- .../js/spec/learner_profile_factory_spec.js | 2 +- .../spec/views/badge_list_container_spec.js | 160 +- .../js/spec/views/badge_list_view_spec.js | 130 +- .../js/spec/views/badge_view_spec.js | 206 +- .../spec/views/learner_profile_fields_spec.js | 2 +- .../spec/views/learner_profile_view_spec.js | 4 +- .../js/views/badge_list_view.js | 90 +- package-lock.json | 2 +- package.json | 2 +- webpack.prod.config.js | 66 +- .../LibrarySourcedBlockPicker.jsx | 390 +- xmodule/assets/word_cloud/.eslintrc.js | 20 +- .../word_cloud/src/js/word_cloud_main.js | 432 +- xmodule/assets/word_cloud/webpack.config.js | 92 +- xmodule/js/spec/helper.js | 2 +- xmodule/js/spec/sequence/display_spec.js | 10 +- xmodule/js/spec/video/async_process_spec.js | 144 +- xmodule/js/spec/video/general_spec.js | 24 +- xmodule/js/spec/video/html5_video_spec.js | 22 +- xmodule/js/spec/video/initialize_spec.js | 574 +- xmodule/js/spec/video/iterator_spec.js | 178 +- xmodule/js/spec/video/resizer_spec.js | 428 +- xmodule/js/spec/video/sjson_spec.js | 124 +- xmodule/js/spec/video/video_caption_spec.js | 6 +- .../js/spec/video/video_focus_grabber_spec.js | 4 +- xmodule/js/spec/video/video_player_spec.js | 2050 +- .../spec/video/video_quality_control_spec.js | 36 +- .../video/video_save_state_plugin_spec.js | 2 +- .../js/spec/video/video_speed_control_spec.js | 82 +- xmodule/js/spec/video/video_storage_spec.js | 146 +- .../spec/video/video_volume_control_spec.js | 10 +- xmodule/js/src/html/imageModal.js | 28 +- xmodule/js/src/poll/poll_main.js | 164 +- xmodule/js/src/video/00_async_process.js | 76 +- xmodule/js/src/video/00_component.js | 100 +- xmodule/js/src/video/00_i18n.js | 60 +- xmodule/js/src/video/00_iterator.js | 94 +- xmodule/js/src/video/00_resizer.js | 422 +- xmodule/js/src/video/00_sjson.js | 168 +- xmodule/js/src/video/00_video_storage.js | 116 +- xmodule/js/src/video/01_initialize.js | 1354 +- xmodule/js/src/video/025_focus_grabber.js | 188 +- xmodule/js/src/video/02_html5_hls_video.js | 206 +- xmodule/js/src/video/02_html5_video.js | 606 +- .../js/src/video/035_video_accessible_menu.js | 114 +- xmodule/js/src/video/03_video_player.js | 1576 +- xmodule/js/src/video/04_video_full_screen.js | 74 +- .../js/src/video/05_video_quality_control.js | 280 +- .../js/src/video/06_video_progress_slider.js | 688 +- .../js/src/video/07_video_volume_control.js | 786 +- .../js/src/video/08_video_speed_control.js | 610 +- .../js/src/video/095_video_context_menu.js | 1276 +- xmodule/js/src/video/09_bumper.js | 4 +- .../js/src/video/09_events_bumper_plugin.js | 2 +- xmodule/js/src/video/09_events_plugin.js | 6 +- xmodule/js/src/video/09_play_pause_control.js | 22 +- xmodule/js/src/video/09_play_placeholder.js | 14 +- xmodule/js/src/video/09_play_skip_control.js | 16 +- xmodule/js/src/video/09_save_state_plugin.js | 2 +- xmodule/js/src/video/09_skip_control.js | 104 +- xmodule/js/src/video/09_video_caption.js | 90 +- xmodule/js/src/video/10_commands.js | 4 +- xmodule/js/src/video/10_main.js | 2 +- 495 files changed, 74392 insertions(+), 44320 deletions(-) create mode 100644 err.txt diff --git a/.eslintignore b/.eslintignore index 82cdcd00dc..9044a0cc71 100644 --- a/.eslintignore +++ b/.eslintignore @@ -64,5 +64,7 @@ xmodule/js/spec/problem/edit_spec_hint.js xmodule/js/spec/problem/edit_spec.js xmodule/js/spec/tabs/edit.js +xmodule/js/public/js +xmodule/assets/*/public/js !**/.eslintrc.js diff --git a/.eslintrc.json b/.eslintrc.json index c5ca21f9b9..009e9db2fe 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -18,6 +18,72 @@ "spyOnEvent": true, // used by our requirejs implementation - "RequireJS": true + "RequireJS": true, + + // enable jquery + "$": true + }, + "rules": { + "func-names": "off", + "indent": ["error", 4], + "new-cap": "off", + "no-else-return": "off", + "no-shadow": "error", + "object-curly-spacing": ["error", "never"], + "one-var": "off", + "one-var-declaration-per-line": ["error", "initializations"], + "space-before-function-paren": ["error", "never"], + "strict": "off", + + // Temporary Rules (Will be removed one-by-one to minimize file changes) + "block-scoped-var": "off", + "camelcase": "off", + "comma-dangle": "off", + "consistent-return": "off", + "curly": "off", + "eqeqeq": "off", + "function-call-argument-newline": "off", + "function-paren-newline": "off", + "implicit-arrow-linebreak": "off", + "import/extensions": "off", + "import/no-amd": "off", + "import/no-dynamic-require": "off", + "import/no-unresolved": "off", + "linebreak-style": "off", + "lines-around-directive": "off", + "max-len": "off", + "newline-per-chained-call": "off", + "no-console": "off", + "no-lonely-if": "off", + "no-multi-spaces": "off", + "no-multiple-empty-lines": "off", + "no-param-reassign": "off", + "no-proto": "off", + "no-prototype-builtins": "off", + "no-redeclare": "off", + "no-restricted-globals": "off", + "no-restricted-syntax": "off", + "no-throw-literal": "off", + "no-undef": "off", + "no-underscore-dangle": "off", + "no-unused-vars": "off", + "no-use-before-define": "off", + "no-useless-escape": "off", + "no-var": "off", + "object-curly-newline": "off", + "object-shorthand": "off", + "operator-linebreak": "off", + "prefer-arrow-callback": "off", + "prefer-destructuring": "off", + "prefer-rest-params": "off", + "prefer-template": "off", + "quotes": "off", + "radix": "off", + "react/jsx-indent": "off", + "react/jsx-indent-props": "off", + "react/jsx-wrap-multilines": "off", + "react/prop-types": "off", + "semi": "off", + "vars-on-top": "off" } } diff --git a/cms/static/cms/js/spec/main_spec.js b/cms/static/cms/js/spec/main_spec.js index ed01a312b2..451f465409 100644 --- a/cms/static/cms/js/spec/main_spec.js +++ b/cms/static/cms/js/spec/main_spec.js @@ -3,80 +3,80 @@ (function(sandbox) { 'use strict'; require(['jquery', 'backbone', 'cms/js/main', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers', 'jquery.cookie'], - function($, Backbone, main, AjaxHelpers) { - describe('CMS', function() { - it('should initialize URL', function() { - expect(window.CMS.URL).toBeDefined(); - }); - }); - describe('main helper', function() { - beforeEach(function() { - this.previousAjaxSettings = $.extend(true, {}, $.ajaxSettings); - spyOn($, 'cookie').and.callFake(function(param) { - if (param === 'csrftoken') { - return 'stubCSRFToken'; - } - }); - return main(); - }); - afterEach(function() { - $.ajaxSettings = this.previousAjaxSettings; - return $.ajaxSettings; - }); - it('turn on Backbone emulateHTTP', function() { - expect(Backbone.emulateHTTP).toBeTruthy(); - }); - it('setup AJAX CSRF token', function() { - expect($.ajaxSettings.headers['X-CSRFToken']).toEqual('stubCSRFToken'); - }); - }); - describe('AJAX Errors', function() { - var server; - server = null; - beforeEach(function() { - appendSetFixtures(sandbox({ - id: 'page-notification' - })); - }); - afterEach(function() { - return server && server.restore(); - }); - it('successful AJAX request does not pop an error notification', function() { - server = AjaxHelpers.server([ - 200, { - 'Content-Type': 'application/json' - }, '{}' - ]); - expect($('#page-notification')).toBeEmpty(); - $.ajax('/test'); - expect($('#page-notification')).toBeEmpty(); - server.respond(); - expect($('#page-notification')).toBeEmpty(); - }); - it('AJAX request with error should pop an error notification', function() { - server = AjaxHelpers.server([ - 500, { - 'Content-Type': 'application/json' - }, '{}' - ]); - $.ajax('/test'); - server.respond(); - expect($('#page-notification')).not.toBeEmpty(); - expect($('#page-notification')).toContainElement('div.wrapper-notification-error'); - }); - it('can override AJAX request with error so it does not pop an error notification', function() { - server = AjaxHelpers.server([ - 500, { - 'Content-Type': 'application/json' - }, '{}' - ]); - $.ajax({ - url: '/test', - notifyOnError: false - }); - server.respond(); - expect($('#page-notification')).toBeEmpty(); - }); + function($, Backbone, main, AjaxHelpers) { + describe('CMS', function() { + it('should initialize URL', function() { + expect(window.CMS.URL).toBeDefined(); }); }); + describe('main helper', function() { + beforeEach(function() { + this.previousAjaxSettings = $.extend(true, {}, $.ajaxSettings); + spyOn($, 'cookie').and.callFake(function(param) { + if (param === 'csrftoken') { + return 'stubCSRFToken'; + } + }); + return main(); + }); + afterEach(function() { + $.ajaxSettings = this.previousAjaxSettings; + return $.ajaxSettings; + }); + it('turn on Backbone emulateHTTP', function() { + expect(Backbone.emulateHTTP).toBeTruthy(); + }); + it('setup AJAX CSRF token', function() { + expect($.ajaxSettings.headers['X-CSRFToken']).toEqual('stubCSRFToken'); + }); + }); + describe('AJAX Errors', function() { + var server; + server = null; + beforeEach(function() { + appendSetFixtures(sandbox({ + id: 'page-notification' + })); + }); + afterEach(function() { + return server && server.restore(); + }); + it('successful AJAX request does not pop an error notification', function() { + server = AjaxHelpers.server([ + 200, { + 'Content-Type': 'application/json' + }, '{}' + ]); + expect($('#page-notification')).toBeEmpty(); + $.ajax('/test'); + expect($('#page-notification')).toBeEmpty(); + server.respond(); + expect($('#page-notification')).toBeEmpty(); + }); + it('AJAX request with error should pop an error notification', function() { + server = AjaxHelpers.server([ + 500, { + 'Content-Type': 'application/json' + }, '{}' + ]); + $.ajax('/test'); + server.respond(); + expect($('#page-notification')).not.toBeEmpty(); + expect($('#page-notification')).toContainElement('div.wrapper-notification-error'); + }); + it('can override AJAX request with error so it does not pop an error notification', function() { + server = AjaxHelpers.server([ + 500, { + 'Content-Type': 'application/json' + }, '{}' + ]); + $.ajax({ + url: '/test', + notifyOnError: false + }); + server.respond(); + expect($('#page-notification')).toBeEmpty(); + }); + }); + }); }).call(this, sandbox); diff --git a/cms/static/cms/js/xblock/cms.runtime.v1.js b/cms/static/cms/js/xblock/cms.runtime.v1.js index ce362ba584..be4ab8c6ad 100644 --- a/cms/static/cms/js/xblock/cms.runtime.v1.js +++ b/cms/static/cms/js/xblock/cms.runtime.v1.js @@ -1,182 +1,182 @@ define(['jquery', 'backbone', 'xblock/runtime.v1', 'URI', 'gettext', 'js/utils/modal', 'common/js/components/views/feedback_notification'], - function($, Backbone, XBlock, URI, gettext, ModalUtils, NotificationView) { - 'use strict'; +function($, Backbone, XBlock, URI, gettext, ModalUtils, NotificationView) { + 'use strict'; - var __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { - var key; - for (key in parent) { - if (__hasProp.call(parent, key)) { - child[key] = parent[key]; - } + var __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { + var key; + for (key in parent) { + if (__hasProp.call(parent, key)) { + child[key] = parent[key]; } - function Ctor() { - this.constructor = child; - } - Ctor.prototype = parent.prototype; - child.prototype = new Ctor(); - child.__super__ = parent.prototype; - return child; - }, - BaseRuntime = {}, - PreviewRuntime = {}, - StudioRuntime = {}; - - BaseRuntime.v1 = (function(_super) { - __extends(v1, _super); - - v1.prototype.handlerUrl = function(element, handlerName, suffix, query) { - var uri; - uri = URI(this.handlerPrefix) - .segment($(element).data('usage-id')) - .segment('handler') - .segment(handlerName); - if (suffix !== null) { - uri.segment(suffix); - } - if (query !== null) { - uri.search(query); - } - return uri.toString(); - }; - - function v1() { - v1.__super__.constructor.call(this); - this.dispatcher = _.clone(Backbone.Events); - this.listenTo('save', this._handleSave); - this.listenTo('cancel', this._handleCancel); - this.listenTo('error', this._handleError); - this.listenTo('modal-shown', function(data) { - this.modal = data; - }); - this.listenTo('modal-hidden', function() { - this.modal = null; - }); - this.listenTo('page-shown', function(data) { - this.page = data; - }); } + function Ctor() { + this.constructor = child; + } + Ctor.prototype = parent.prototype; + child.prototype = new Ctor(); + child.__super__ = parent.prototype; + return child; + }, + BaseRuntime = {}, + PreviewRuntime = {}, + StudioRuntime = {}; - /** + BaseRuntime.v1 = (function(_super) { + __extends(v1, _super); + + v1.prototype.handlerUrl = function(element, handlerName, suffix, query) { + var uri; + uri = URI(this.handlerPrefix) + .segment($(element).data('usage-id')) + .segment('handler') + .segment(handlerName); + if (suffix !== null) { + uri.segment(suffix); + } + if (query !== null) { + uri.search(query); + } + return uri.toString(); + }; + + function v1() { + v1.__super__.constructor.call(this); + this.dispatcher = _.clone(Backbone.Events); + this.listenTo('save', this._handleSave); + this.listenTo('cancel', this._handleCancel); + this.listenTo('error', this._handleError); + this.listenTo('modal-shown', function(data) { + this.modal = data; + }); + this.listenTo('modal-hidden', function() { + this.modal = null; + }); + this.listenTo('page-shown', function(data) { + this.page = data; + }); + } + + /** * Notify the Studio client-side runtime of an event so that it * can update the UI in a consistent way. * * @param {string} name The name of the event. * @param {object} data A JSON representation of the data to be included with the event. */ - v1.prototype.notify = function(name, data) { - this.dispatcher.trigger(name, data); - }; + v1.prototype.notify = function(name, data) { + this.dispatcher.trigger(name, data); + }; - /** + /** * Listen to a Studio event and invoke the specified callback when it is triggered. * * @param {string} name The name of the event. * @param {function} callback The callback to be invoked. */ - v1.prototype.listenTo = function(name, callback) { - this.dispatcher.bind(name, callback, this); - }; + v1.prototype.listenTo = function(name, callback) { + this.dispatcher.bind(name, callback, this); + }; - /** + /** * Refresh the view for the xblock represented by the specified element. * * @param {element} element The element representing the XBlock. */ - v1.prototype.refreshXBlock = function(element) { - if (this.page) { - this.page.refreshXBlock(element); - } - }; + v1.prototype.refreshXBlock = function(element) { + if (this.page) { + this.page.refreshXBlock(element); + } + }; - v1.prototype._handleError = function(data) { - var message, title; - message = data.message || data.msg; - if (message) { - // TODO: remove 'Open Assessment' specific default title - title = data.title || gettext('OpenAssessment Save Error'); - this.alert = new NotificationView.Error({ - title: title, - message: message, - closeIcon: false, - shown: false - }); - this.alert.show(); - } - }; + v1.prototype._handleError = function(data) { + var message, title; + message = data.message || data.msg; + if (message) { + // TODO: remove 'Open Assessment' specific default title + title = data.title || gettext('OpenAssessment Save Error'); + this.alert = new NotificationView.Error({ + title: title, + message: message, + closeIcon: false, + shown: false + }); + this.alert.show(); + } + }; - v1.prototype._handleSave = function(data) { - var message; - // Starting to save, so show a notification - if (data.state === 'start') { - message = data.message || gettext('Saving'); - this.notification = new NotificationView.Mini({ - title: message - }); - this.notification.show(); - } else if (data.state === 'end') { - // Finished saving, so hide the notification and refresh appropriately - this._hideAlerts(); - - if (this.modal && this.modal.onSave) { - // Notify the modal that the save has completed so that it can hide itself - // and then refresh the xblock. - this.modal.onSave(); - } else if (data.element) { - // ... else ask it to refresh the newly saved xblock - this.refreshXBlock(data.element); - } - this.notification.hide(); - } - }; - - v1.prototype._handleCancel = function() { + v1.prototype._handleSave = function(data) { + var message; + // Starting to save, so show a notification + if (data.state === 'start') { + message = data.message || gettext('Saving'); + this.notification = new NotificationView.Mini({ + title: message + }); + this.notification.show(); + } else if (data.state === 'end') { + // Finished saving, so hide the notification and refresh appropriately this._hideAlerts(); - if (this.modal) { - this.modal.cancel(); - this.notify('modal-hidden'); - } - }; - /** + if (this.modal && this.modal.onSave) { + // Notify the modal that the save has completed so that it can hide itself + // and then refresh the xblock. + this.modal.onSave(); + } else if (data.element) { + // ... else ask it to refresh the newly saved xblock + this.refreshXBlock(data.element); + } + this.notification.hide(); + } + }; + + v1.prototype._handleCancel = function() { + this._hideAlerts(); + if (this.modal) { + this.modal.cancel(); + this.notify('modal-hidden'); + } + }; + + /** * Hide any alerts that are being shown. */ - v1.prototype._hideAlerts = function() { - if (this.alert && this.alert.options.shown) { - this.alert.hide(); - } - }; - - return v1; - }(XBlock.Runtime.v1)); - - PreviewRuntime.v1 = (function(_super) { - __extends(v1, _super); - - function v1() { - return v1.__super__.constructor.apply(this, arguments); + v1.prototype._hideAlerts = function() { + if (this.alert && this.alert.options.shown) { + this.alert.hide(); } + }; - v1.prototype.handlerPrefix = '/preview/xblock'; + return v1; + }(XBlock.Runtime.v1)); - return v1; - }(BaseRuntime.v1)); + PreviewRuntime.v1 = (function(_super) { + __extends(v1, _super); - StudioRuntime.v1 = (function(_super) { - __extends(v1, _super); + function v1() { + return v1.__super__.constructor.apply(this, arguments); + } - function v1() { - return v1.__super__.constructor.apply(this, arguments); - } + v1.prototype.handlerPrefix = '/preview/xblock'; - v1.prototype.handlerPrefix = '/xblock'; + return v1; + }(BaseRuntime.v1)); - return v1; - }(BaseRuntime.v1)); + StudioRuntime.v1 = (function(_super) { + __extends(v1, _super); - // Install the runtime's into the global namespace - window.BaseRuntime = BaseRuntime; - window.PreviewRuntime = PreviewRuntime; - window.StudioRuntime = StudioRuntime; - }); + function v1() { + return v1.__super__.constructor.apply(this, arguments); + } + + v1.prototype.handlerPrefix = '/xblock'; + + return v1; + }(BaseRuntime.v1)); + + // Install the runtime's into the global namespace + window.BaseRuntime = BaseRuntime; + window.PreviewRuntime = PreviewRuntime; + window.StudioRuntime = StudioRuntime; +}); diff --git a/cms/static/js/base.js b/cms/static/js/base.js index 7ef8b9f47c..8992ac7d12 100644 --- a/cms/static/js/base.js +++ b/cms/static/js/base.js @@ -14,121 +14,121 @@ define([ 'jquery.form', 'jquery.smoothScroll' ], - function( - domReady, - $, - _, - gettext, - NotificationView, - PromptView, - DateUtils, - ModuleUtils, - IframeUtils, - DropdownMenuView - ) { - 'use strict'; - var $body; +function( + domReady, + $, + _, + gettext, + NotificationView, + PromptView, + DateUtils, + ModuleUtils, + IframeUtils, + DropdownMenuView +) { + 'use strict'; + var $body; - function smoothScrollLink(e) { - (e).preventDefault(); + function smoothScrollLink(e) { + (e).preventDefault(); - $.smoothScroll({ - offset: -200, - easing: 'swing', - speed: 1000, - scrollElement: null, - scrollTarget: $(this).attr('href') - }); - } - - function hideNotification(e) { - (e).preventDefault(); - $(this) - .closest('.wrapper-notification') - .removeClass('is-shown') - .addClass('is-hiding') - .attr('aria-hidden', 'true'); - } - - function hideAlert(e) { - (e).preventDefault(); - $(this).closest('.wrapper-alert').removeClass('is-shown'); - } - - domReady(function() { - var dropdownMenuView; - - $body = $('body'); - - $body.on('click', '.embeddable-xml-input', function() { - $(this).select(); - }); - - $body.addClass('js'); - - // alerts/notifications - manual close - $('.action-alert-close, .alert.has-actions .nav-actions a').bind('click', hideAlert); - $('.action-notification-close').bind('click', hideNotification); - - // nav - dropdown related - $body.click(function() { - $('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown'); - $('.nav-dd .nav-item .title').removeClass('is-selected'); - }); - - $('.nav-dd .nav-item, .filterable-column .nav-item').click(function(e) { - var $subnav = $(this).find('.wrapper-nav-sub'), - $title = $(this).find('.title'); - - if ($subnav.hasClass('is-shown')) { - $subnav.removeClass('is-shown'); - $title.removeClass('is-selected'); - } else { - $('.nav-dd .nav-item .title').removeClass('is-selected'); - $('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown'); - $title.addClass('is-selected'); - $subnav.addClass('is-shown'); - // if propagation is not stopped, the event will bubble up to the - // body element, which will close the dropdown. - e.stopPropagation(); - } - }); - - // general link management - new window/tab - $('a[rel="external"]:not([title])') - .attr('title', gettext('This link will open in a new browser window/tab')); - $('a[rel="external"]').attr({ - rel: 'noopener external', - target: '_blank' - }); - - // general link management - lean modal window - $('a[rel="modal"]').attr('title', gettext('This link will open in a modal window')).leanModal({ - overlay: 0.50, - closeButton: '.action-modal-close' - }); - $('.action-modal-close').click(function(e) { - (e).preventDefault(); - }); - - // general link management - smooth scrolling page links - $('a[rel*="view"][href^="#"]').bind('click', smoothScrollLink); - - IframeUtils.iframeBinding(); - - // disable ajax caching in IE so that backbone fetches work - if ($.browser.msie) { - $.ajaxSetup({cache: false}); - } - - // Initiate the edx tool kit dropdown menu - if ($('.js-header-user-menu').length) { - dropdownMenuView = new DropdownMenuView({ - el: '.js-header-user-menu' - }); - dropdownMenuView.postRender(); - } - - window.studioNavMenuActive = true; + $.smoothScroll({ + offset: -200, + easing: 'swing', + speed: 1000, + scrollElement: null, + scrollTarget: $(this).attr('href') }); - }); // end require() + } + + function hideNotification(e) { + (e).preventDefault(); + $(this) + .closest('.wrapper-notification') + .removeClass('is-shown') + .addClass('is-hiding') + .attr('aria-hidden', 'true'); + } + + function hideAlert(e) { + (e).preventDefault(); + $(this).closest('.wrapper-alert').removeClass('is-shown'); + } + + domReady(function() { + var dropdownMenuView; + + $body = $('body'); + + $body.on('click', '.embeddable-xml-input', function() { + $(this).select(); + }); + + $body.addClass('js'); + + // alerts/notifications - manual close + $('.action-alert-close, .alert.has-actions .nav-actions a').bind('click', hideAlert); + $('.action-notification-close').bind('click', hideNotification); + + // nav - dropdown related + $body.click(function() { + $('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown'); + $('.nav-dd .nav-item .title').removeClass('is-selected'); + }); + + $('.nav-dd .nav-item, .filterable-column .nav-item').click(function(e) { + var $subnav = $(this).find('.wrapper-nav-sub'), + $title = $(this).find('.title'); + + if ($subnav.hasClass('is-shown')) { + $subnav.removeClass('is-shown'); + $title.removeClass('is-selected'); + } else { + $('.nav-dd .nav-item .title').removeClass('is-selected'); + $('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown'); + $title.addClass('is-selected'); + $subnav.addClass('is-shown'); + // if propagation is not stopped, the event will bubble up to the + // body element, which will close the dropdown. + e.stopPropagation(); + } + }); + + // general link management - new window/tab + $('a[rel="external"]:not([title])') + .attr('title', gettext('This link will open in a new browser window/tab')); + $('a[rel="external"]').attr({ + rel: 'noopener external', + target: '_blank' + }); + + // general link management - lean modal window + $('a[rel="modal"]').attr('title', gettext('This link will open in a modal window')).leanModal({ + overlay: 0.50, + closeButton: '.action-modal-close' + }); + $('.action-modal-close').click(function(e) { + (e).preventDefault(); + }); + + // general link management - smooth scrolling page links + $('a[rel*="view"][href^="#"]').bind('click', smoothScrollLink); + + IframeUtils.iframeBinding(); + + // disable ajax caching in IE so that backbone fetches work + if ($.browser.msie) { + $.ajaxSetup({cache: false}); + } + + // Initiate the edx tool kit dropdown menu + if ($('.js-header-user-menu').length) { + dropdownMenuView = new DropdownMenuView({ + el: '.js-header-user-menu' + }); + dropdownMenuView.postRender(); + } + + window.studioNavMenuActive = true; + }); +}); // end require() diff --git a/cms/static/js/certificates/factories/certificates_page_factory.js b/cms/static/js/certificates/factories/certificates_page_factory.js index a367f52cce..5c13f73e8e 100644 --- a/cms/static/js/certificates/factories/certificates_page_factory.js +++ b/cms/static/js/certificates/factories/certificates_page_factory.js @@ -21,7 +21,7 @@ define([ function($, CertificatesCollection, Certificate, CertificatesPage, CertificatePreview) { 'use strict'; return function(certificatesJson, certificateUrl, courseOutlineUrl, courseModes, certificateWebViewUrl, - isActive, certificateActivationHandlerUrl) { + isActive, certificateActivationHandlerUrl) { // Initialize the model collection, passing any necessary options to the constructor var certificatesCollection = new CertificatesCollection(certificatesJson, { parse: true, diff --git a/cms/static/js/certificates/models/certificate.js b/cms/static/js/certificates/models/certificate.js index d0e6ae6e9f..97a2735d71 100644 --- a/cms/static/js/certificates/models/certificate.js +++ b/cms/static/js/certificates/models/certificate.js @@ -10,89 +10,89 @@ define([ 'js/certificates/models/signatory', 'js/certificates/collections/signatories' ], - function(_, Backbone, BackboneRelational, BackboneAssociations, gettext, CoffeeSrcMain, - SignatoryModel, SignatoryCollection) { - 'use strict'; - var Certificate = Backbone.RelationalModel.extend({ - idAttribute: 'id', - defaults: { - // Metadata fields currently displayed in web forms - course_title: '', +function(_, Backbone, BackboneRelational, BackboneAssociations, gettext, CoffeeSrcMain, + SignatoryModel, SignatoryCollection) { + 'use strict'; + var Certificate = Backbone.RelationalModel.extend({ + idAttribute: 'id', + defaults: { + // Metadata fields currently displayed in web forms + course_title: '', - // Metadata fields not currently displayed in web forms - name: 'Name of the certificate', - description: 'Description of the certificate', + // Metadata fields not currently displayed in web forms + name: 'Name of the certificate', + description: 'Description of the certificate', - // Internal-use only, not displayed in web forms - version: 1, - is_active: false - }, + // Internal-use only, not displayed in web forms + version: 1, + is_active: false + }, - // Certificate child collection/model mappings (backbone-relational) - relations: [{ - type: Backbone.HasMany, - key: 'signatories', - relatedModel: SignatoryModel, - collectionType: SignatoryCollection, - reverseRelation: { - key: 'certificate', - includeInJSON: 'id' - } - }], - - initialize: function(attributes, options) { - // Set up the initial state of the attributes set for this model instance - this.canBeEmpty = options && options.canBeEmpty; - if (options.add && !attributes.signatories) { - // Ensure at least one child Signatory model is defined for any new Certificate model - attributes.signatories = new SignatoryModel({certificate: this}); - } - this.setOriginalAttributes(); - return this; - }, - - parse: function(response) { - // Parse must be defined for the model, but does not need to do anything special right now - return response; - }, - - setOriginalAttributes: function() { - // Remember the current state of this model (enables edit->cancel use cases) - this._originalAttributes = this.parse(this.toJSON()); - - this.get('signatories').each(function(modelSignatory) { - modelSignatory.setOriginalAttributes(); - }); - - // If no url is defined for the signatories child collection we'll need to create that here as well - if (!this.isNew() && !this.get('signatories').url) { - this.get('signatories').url = this.collection.url + '/' + this.get('id') + '/signatories'; - } - }, - - validate: function(attrs) { - // Ensure the provided attributes set meets our expectations for format, type, etc. - if (!attrs.name.trim()) { - return { - message: gettext('Certificate name is required.'), - attributes: {name: true} - }; - } - var allSignatoriesValid = _.every(attrs.signatories.models, function(signatory) { - return signatory.isValid(); - }); - if (!allSignatoriesValid) { - return { - message: gettext('Signatory field(s) has invalid data.'), - attributes: {signatories: attrs.signatories.models} - }; - } - }, - - reset: function() { - // Revert the attributes of this model instance back to initial state - this.set(this._originalAttributes, {parse: true, validate: true}); + // Certificate child collection/model mappings (backbone-relational) + relations: [{ + type: Backbone.HasMany, + key: 'signatories', + relatedModel: SignatoryModel, + collectionType: SignatoryCollection, + reverseRelation: { + key: 'certificate', + includeInJSON: 'id' } - }); - return Certificate; + }], + + initialize: function(attributes, options) { + // Set up the initial state of the attributes set for this model instance + this.canBeEmpty = options && options.canBeEmpty; + if (options.add && !attributes.signatories) { + // Ensure at least one child Signatory model is defined for any new Certificate model + attributes.signatories = new SignatoryModel({certificate: this}); + } + this.setOriginalAttributes(); + return this; + }, + + parse: function(response) { + // Parse must be defined for the model, but does not need to do anything special right now + return response; + }, + + setOriginalAttributes: function() { + // Remember the current state of this model (enables edit->cancel use cases) + this._originalAttributes = this.parse(this.toJSON()); + + this.get('signatories').each(function(modelSignatory) { + modelSignatory.setOriginalAttributes(); + }); + + // If no url is defined for the signatories child collection we'll need to create that here as well + if (!this.isNew() && !this.get('signatories').url) { + this.get('signatories').url = this.collection.url + '/' + this.get('id') + '/signatories'; + } + }, + + validate: function(attrs) { + // Ensure the provided attributes set meets our expectations for format, type, etc. + if (!attrs.name.trim()) { + return { + message: gettext('Certificate name is required.'), + attributes: {name: true} + }; + } + var allSignatoriesValid = _.every(attrs.signatories.models, function(signatory) { + return signatory.isValid(); + }); + if (!allSignatoriesValid) { + return { + message: gettext('Signatory field(s) has invalid data.'), + attributes: {signatories: attrs.signatories.models} + }; + } + }, + + reset: function() { + // Revert the attributes of this model instance back to initial state + this.set(this._originalAttributes, {parse: true, validate: true}); + } }); + return Certificate; +}); diff --git a/cms/static/js/certificates/spec/views/certificate_details_spec.js b/cms/static/js/certificates/spec/views/certificate_details_spec.js index 7a0332bda8..d1c810f2aa 100644 --- a/cms/static/js/certificates/spec/views/certificate_details_spec.js +++ b/cms/static/js/certificates/spec/views/certificate_details_spec.js @@ -15,7 +15,7 @@ define([ 'js/certificates/spec/custom_matchers' ], function(_, Course, CertificatesCollection, CertificateModel, CertificateDetailsView, CertificatePreview, - Notification, AjaxHelpers, TemplateHelpers, ViewHelpers, ValidationHelpers, CustomMatchers) { + Notification, AjaxHelpers, TemplateHelpers, ViewHelpers, ValidationHelpers, CustomMatchers) { 'use strict'; var SELECTORS = { diff --git a/cms/static/js/certificates/spec/views/certificate_editor_spec.js b/cms/static/js/certificates/spec/views/certificate_editor_spec.js index 39416e56a8..64ef492c82 100644 --- a/cms/static/js/certificates/spec/views/certificate_editor_spec.js +++ b/cms/static/js/certificates/spec/views/certificate_editor_spec.js @@ -15,7 +15,7 @@ define([ 'js/certificates/spec/custom_matchers' ], function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, CertificateEditorView, - Notification, AjaxHelpers, TemplateHelpers, ViewHelpers, ValidationHelpers, CustomMatchers) { + Notification, AjaxHelpers, TemplateHelpers, ViewHelpers, ValidationHelpers, CustomMatchers) { 'use strict'; var MAX_SIGNATORIES_LIMIT = 10; diff --git a/cms/static/js/certificates/spec/views/certificates_list_spec.js b/cms/static/js/certificates/spec/views/certificates_list_spec.js index 7925810897..fec1829611 100644 --- a/cms/static/js/certificates/spec/views/certificates_list_spec.js +++ b/cms/static/js/certificates/spec/views/certificates_list_spec.js @@ -16,8 +16,8 @@ define([ 'js/certificates/spec/custom_matchers' ], function(_, Course, CertificatesCollection, CertificateModel, CertificateDetailsView, CertificateEditorView, - CertificateItemView, CertificatesListView, CertificatePreview, Notification, AjaxHelpers, TemplateHelpers, - CustomMatchers) { + CertificateItemView, CertificatesListView, CertificatePreview, Notification, AjaxHelpers, TemplateHelpers, + CustomMatchers) { 'use strict'; var SELECTORS = { diff --git a/cms/static/js/certificates/views/certificate_details.js b/cms/static/js/certificates/views/certificate_details.js index 121be569db..4c62c5fa0c 100644 --- a/cms/static/js/certificates/views/certificate_details.js +++ b/cms/static/js/certificates/views/certificate_details.js @@ -13,7 +13,7 @@ define([ 'text!templates/certificate-details.underscore' ], function($, _, str, gettext, BaseView, SignatoryModel, SignatoryDetailsView, ViewUtils, smoothScroll, - certificateDetailsTemplate) { + certificateDetailsTemplate) { 'use strict'; var CertificateDetailsView = BaseView.extend({ tagName: 'div', diff --git a/cms/static/js/certificates/views/certificate_editor.js b/cms/static/js/certificates/views/certificate_editor.js index fa19bd2de2..6b0365ffbf 100644 --- a/cms/static/js/certificates/views/certificate_editor.js +++ b/cms/static/js/certificates/views/certificate_editor.js @@ -12,7 +12,7 @@ define([ 'edx-ui-toolkit/js/utils/html-utils' ], function($, _, Backbone, gettext, - ListItemEditorView, SignatoryModel, SignatoryEditorView, certificateEditorTemplate, HtmlUtils) { + ListItemEditorView, SignatoryModel, SignatoryEditorView, certificateEditorTemplate, HtmlUtils) { 'use strict'; // If signatories limit is required to specific value then we can change it. diff --git a/cms/static/js/certificates/views/signatory_details.js b/cms/static/js/certificates/views/signatory_details.js index 9286b28259..e3186ea7fe 100644 --- a/cms/static/js/certificates/views/signatory_details.js +++ b/cms/static/js/certificates/views/signatory_details.js @@ -15,7 +15,7 @@ define([ 'edx-ui-toolkit/js/utils/html-utils' ], function($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, SignatoryEditorView, - signatoryDetailsTemplate, signatoryActionsTemplate, HtmlUtils) { + signatoryDetailsTemplate, signatoryActionsTemplate, HtmlUtils) { 'use strict'; var SignatoryDetailsView = BaseView.extend({ tagName: 'div', diff --git a/cms/static/js/certificates/views/signatory_editor.js b/cms/static/js/certificates/views/signatory_editor.js index 9c70e68a44..1e64a058be 100644 --- a/cms/static/js/certificates/views/signatory_editor.js +++ b/cms/static/js/certificates/views/signatory_editor.js @@ -15,8 +15,8 @@ define([ 'edx-ui-toolkit/js/utils/html-utils' ], function($, _, Backbone, gettext, - TemplateUtils, ViewUtils, PromptView, NotificationView, FileUploadModel, FileUploadDialog, - signatoryEditorTemplate, HtmlUtils) { + TemplateUtils, ViewUtils, PromptView, NotificationView, FileUploadModel, FileUploadDialog, + signatoryEditorTemplate, HtmlUtils) { 'use strict'; var SignatoryEditorView = Backbone.View.extend({ tagName: 'div', diff --git a/cms/static/js/collections/textbook.js b/cms/static/js/collections/textbook.js index 9554a36393..d388ca9800 100644 --- a/cms/static/js/collections/textbook.js +++ b/cms/static/js/collections/textbook.js @@ -1,8 +1,8 @@ define(['backbone', 'js/models/textbook'], - function(Backbone, TextbookModel) { - var TextbookCollection = Backbone.Collection.extend({ - model: TextbookModel, - url: function() { return CMS.URL.TEXTBOOKS; } - }); - return TextbookCollection; + function(Backbone, TextbookModel) { + var TextbookCollection = Backbone.Collection.extend({ + model: TextbookModel, + url: function() { return CMS.URL.TEXTBOOKS; } }); + return TextbookCollection; + }); diff --git a/cms/static/js/factories/base.js b/cms/static/js/factories/base.js index 2a952f94db..ea0602cbdd 100644 --- a/cms/static/js/factories/base.js +++ b/cms/static/js/factories/base.js @@ -2,7 +2,7 @@ // of RequireJS define(['js/base', 'cms/js/main', 'js/src/logger', 'datepair', 'accessibility', 'ieshim', 'tooltip_manager', 'lang_edx', 'js/models/course', 'jquery_extend_patch'], - function() { - 'use strict'; - } +function() { + 'use strict'; +} ); diff --git a/cms/static/js/factories/group_configurations.js b/cms/static/js/factories/group_configurations.js index 424f60a50c..285e23f2d6 100644 --- a/cms/static/js/factories/group_configurations.js +++ b/cms/static/js/factories/group_configurations.js @@ -3,10 +3,10 @@ define([ ], function(GroupConfigurationCollection, GroupConfigurationModel, GroupConfigurationsPage) { 'use strict'; return function(experimentsEnabled, - experimentGroupConfigurationsJson, - allGroupConfigurationJson, - groupConfigurationUrl, - courseOutlineUrl) { + experimentGroupConfigurationsJson, + allGroupConfigurationJson, + groupConfigurationUrl, + courseOutlineUrl) { var experimentGroupConfigurations = new GroupConfigurationCollection( experimentGroupConfigurationsJson, {parse: true} ), diff --git a/cms/static/js/factories/index.js b/cms/static/js/factories/index.js index 10f395ef1d..9fa8071a13 100644 --- a/cms/static/js/factories/index.js +++ b/cms/static/js/factories/index.js @@ -6,9 +6,9 @@ define(['jquery.form', 'js/index'], function() { e.preventDefault(); $(this) .closest('.wrapper-creationrights') - .toggleClass('is-shown') + .toggleClass('is-shown') .find('.ui-toggle-control') - .toggleClass('current'); + .toggleClass('current'); }); var reloadPage = function() { @@ -19,10 +19,10 @@ define(['jquery.form', 'js/index'], function() { $('#request-coursecreator-submit') .toggleClass('has-error') .find('.label') - .text('Sorry, there was error with your request'); + .text('Sorry, there was error with your request'); $('#request-coursecreator-submit') .find('.fa-cog') - .toggleClass('fa-spin'); + .toggleClass('fa-spin'); }; $('#request-coursecreator').ajaxForm({ diff --git a/cms/static/js/factories/manage_users.js b/cms/static/js/factories/manage_users.js index 837ea6fec7..ba364ee38e 100644 --- a/cms/static/js/factories/manage_users.js +++ b/cms/static/js/factories/manage_users.js @@ -2,34 +2,34 @@ Code for editing users and assigning roles within a course team context. */ define(['underscore', 'gettext', 'js/views/manage_users_and_roles'], -function(_, gettext, ManageUsersAndRoles) { - 'use strict'; - return function(containerName, users, tplUserURL, current_user_id, allow_actions) { - function updateMessages(messages) { - var local_messages = _.extend({}, messages); - local_messages.alreadyMember.title = gettext('Already a course team member'); - local_messages.deleteUser.messageTpl = gettext( - 'Are you sure you want to delete {email} from the course team for “{container}”?' - ); - return local_messages; - } - // Roles order are important: first role is considered initial role (the role added to user when (s)he's added - // Last role is considered an admin role (unrestricted access + ability to manage other users' permissions) - // Changing roles is performed in promote-demote fashion, so moves only to adjacent roles is allowed - var roles = [{key: 'staff', name: gettext('Staff')}, {key: 'instructor', name: gettext('Admin')}]; + function(_, gettext, ManageUsersAndRoles) { + 'use strict'; + return function(containerName, users, tplUserURL, current_user_id, allow_actions) { + function updateMessages(messages) { + var local_messages = _.extend({}, messages); + local_messages.alreadyMember.title = gettext('Already a course team member'); + local_messages.deleteUser.messageTpl = gettext( + 'Are you sure you want to delete {email} from the course team for “{container}”?' + ); + return local_messages; + } + // Roles order are important: first role is considered initial role (the role added to user when (s)he's added + // Last role is considered an admin role (unrestricted access + ability to manage other users' permissions) + // Changing roles is performed in promote-demote fashion, so moves only to adjacent roles is allowed + var roles = [{key: 'staff', name: gettext('Staff')}, {key: 'instructor', name: gettext('Admin')}]; - var options = { - el: $('#content'), - containerName: containerName, - tplUserURL: tplUserURL, - roles: roles, - users: users, - messages_modifier: updateMessages, - current_user_id: current_user_id, - allow_actions: allow_actions + var options = { + el: $('#content'), + containerName: containerName, + tplUserURL: tplUserURL, + roles: roles, + users: users, + messages_modifier: updateMessages, + current_user_id: current_user_id, + allow_actions: allow_actions + }; + + var view = new ManageUsersAndRoles(options); + view.render(); }; - - var view = new ManageUsersAndRoles(options); - view.render(); - }; -}); + }); diff --git a/cms/static/js/factories/manage_users_lib.js b/cms/static/js/factories/manage_users_lib.js index 8bfe07134d..a2ffc86362 100644 --- a/cms/static/js/factories/manage_users_lib.js +++ b/cms/static/js/factories/manage_users_lib.js @@ -2,38 +2,38 @@ Code for editing users and assigning roles within a library context. */ define(['underscore', 'gettext', 'js/views/manage_users_and_roles'], -function(_, gettext, ManageUsersAndRoles) { - 'use strict'; - return function(containerName, users, tplUserURL, current_user_id, allow_actions) { - function updateMessages(messages) { - var local_messages = _.extend({}, messages); - local_messages.alreadyMember.title = gettext('Already a library team member'); - local_messages.deleteUser.messageTpl = gettext( - 'Are you sure you want to delete {email} from the library “{container}”?' - ); - return local_messages; - } - // Roles order are important: first role is considered initial role (the role added to user when (s)he's added - // Last role is considered an admin role (unrestricted access + ability to manage other users' permissions) - // Changing roles is performed in promote-demote fashion, so moves only to adjacent roles is allowed - var roles = [ - {key: 'library_user', name: gettext('Library User')}, - {key: 'staff', name: gettext('Staff')}, - {key: 'instructor', name: gettext('Admin')} - ]; + function(_, gettext, ManageUsersAndRoles) { + 'use strict'; + return function(containerName, users, tplUserURL, current_user_id, allow_actions) { + function updateMessages(messages) { + var local_messages = _.extend({}, messages); + local_messages.alreadyMember.title = gettext('Already a library team member'); + local_messages.deleteUser.messageTpl = gettext( + 'Are you sure you want to delete {email} from the library “{container}”?' + ); + return local_messages; + } + // Roles order are important: first role is considered initial role (the role added to user when (s)he's added + // Last role is considered an admin role (unrestricted access + ability to manage other users' permissions) + // Changing roles is performed in promote-demote fashion, so moves only to adjacent roles is allowed + var roles = [ + {key: 'library_user', name: gettext('Library User')}, + {key: 'staff', name: gettext('Staff')}, + {key: 'instructor', name: gettext('Admin')} + ]; - var options = { - el: $('#content'), - containerName: containerName, - tplUserURL: tplUserURL, - roles: roles, - users: users, - messages_modifier: updateMessages, - current_user_id: current_user_id, - allow_actions: allow_actions + var options = { + el: $('#content'), + containerName: containerName, + tplUserURL: tplUserURL, + roles: roles, + users: users, + messages_modifier: updateMessages, + current_user_id: current_user_id, + allow_actions: allow_actions + }; + + var view = new ManageUsersAndRoles(options); + view.render(); }; - - var view = new ManageUsersAndRoles(options); - view.render(); - }; -}); + }); diff --git a/cms/static/js/features/import/views/import.js b/cms/static/js/features/import/views/import.js index 94e31d6394..ee1af307d6 100644 --- a/cms/static/js/features/import/views/import.js +++ b/cms/static/js/features/import/views/import.js @@ -150,13 +150,13 @@ define( _.map($dom.stages, completeStage); $dom.successStage - .find('.item-progresspoint-success-date') - .text('(' + date + ' at ' + time + ' UTC)'); + .find('.item-progresspoint-success-date') + .text('(' + date + ' at ' + time + ' UTC)'); break; case STATE.ERROR: - // Make all stages up to, and including, the error stage 'complete'. + // Make all stages up to, and including, the error stage 'complete'. $prev = $dom.stages.slice(0, current.stage + 1); $curr = $dom.stages.eq(current.stage); $next = $dom.stages.slice(current.stage + 1); diff --git a/cms/static/js/features_jsx/.eslintrc.js b/cms/static/js/features_jsx/.eslintrc.js index 15de20e01b..0a86988ebb 100644 --- a/cms/static/js/features_jsx/.eslintrc.js +++ b/cms/static/js/features_jsx/.eslintrc.js @@ -1,7 +1,14 @@ module.exports = { - extends: '@edx/eslint-config', - root: true, - settings: { - 'import/resolver': 'webpack', - }, + extends: '@edx/eslint-config', + root: true, + settings: { + 'import/resolver': 'webpack', + }, + rules: { + indent: ['error', 4], + 'import/extensions': 'off', + 'import/no-unresolved': 'off', + 'react/jsx-indent': 'off', + 'react/jsx-indent-props': 'off', + }, }; diff --git a/cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx b/cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx index 7e7326ffe3..dd00984dc0 100644 --- a/cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx +++ b/cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx @@ -6,83 +6,83 @@ import React from 'react'; import ReactDOM from 'react-dom'; export function CourseOrLibraryListing(props) { - const allowReruns = props.allowReruns; - const linkClass = props.linkClass; - const idBase = props.idBase; + const allowReruns = props.allowReruns; + const linkClass = props.linkClass; + const idBase = props.idBase; - const renderCourseMetadata = (item, i) => ( -
-

{item.display_name}

-
- - {gettext('Organization:')} - {item.org} - - - {gettext('Course Number:')} - {item.number} - - { item.run && + const renderCourseMetadata = (item, i) => ( +
+

{item.display_name}

+
+ + {gettext('Organization:')} + {item.org} + + + {gettext('Course Number:')} + {item.number} + + { item.run && - {gettext('Course Run:')} - {item.run} + {gettext('Course Run:')} + {item.run} - } - { item.can_edit === false && - {gettext('(Read-only)')} - } -
-
- ); - - return ( -
+
+ ); + + return ( + - ); + } + + ), + ) + } + + ); } CourseOrLibraryListing.propTypes = { - allowReruns: PropTypes.bool.isRequired, - idBase: PropTypes.string.isRequired, - items: PropTypes.arrayOf(PropTypes.object).isRequired, - linkClass: PropTypes.string.isRequired, + allowReruns: PropTypes.bool.isRequired, + idBase: PropTypes.string.isRequired, + items: PropTypes.arrayOf(PropTypes.object).isRequired, + linkClass: PropTypes.string.isRequired, }; diff --git a/cms/static/js/index.js b/cms/static/js/index.js index 09c7de843e..7a7d34284b 100644 --- a/cms/static/js/index.js +++ b/cms/static/js/index.js @@ -1,210 +1,210 @@ define(['domReady', 'jquery', 'underscore', 'js/utils/cancel_on_escape', 'js/views/utils/create_course_utils', 'js/views/utils/create_library_utils', 'common/js/components/utils/view_utils'], - function(domReady, $, _, CancelOnEscape, CreateCourseUtilsFactory, CreateLibraryUtilsFactory, ViewUtils) { - 'use strict'; - var CreateCourseUtils = new CreateCourseUtilsFactory({ - name: '.new-course-name', - org: '.new-course-org', - number: '.new-course-number', - run: '.new-course-run', - save: '.new-course-save', - errorWrapper: '.create-course .wrap-error', - errorMessage: '#course_creation_error', - tipError: '.create-course span.tip-error', - error: '.create-course .error', - allowUnicode: '.allow-unicode-course-id' - }, { - shown: 'is-shown', - showing: 'is-showing', - hiding: 'is-hiding', - disabled: 'is-disabled', - error: 'error' - }); +function(domReady, $, _, CancelOnEscape, CreateCourseUtilsFactory, CreateLibraryUtilsFactory, ViewUtils) { + 'use strict'; + var CreateCourseUtils = new CreateCourseUtilsFactory({ + name: '.new-course-name', + org: '.new-course-org', + number: '.new-course-number', + run: '.new-course-run', + save: '.new-course-save', + errorWrapper: '.create-course .wrap-error', + errorMessage: '#course_creation_error', + tipError: '.create-course span.tip-error', + error: '.create-course .error', + allowUnicode: '.allow-unicode-course-id' + }, { + shown: 'is-shown', + showing: 'is-showing', + hiding: 'is-hiding', + disabled: 'is-disabled', + error: 'error' + }); - var CreateLibraryUtils = new CreateLibraryUtilsFactory({ - name: '.new-library-name', - org: '.new-library-org', - number: '.new-library-number', - save: '.new-library-save', - errorWrapper: '.create-library .wrap-error', - errorMessage: '#library_creation_error', - tipError: '.create-library span.tip-error', - error: '.create-library .error', - allowUnicode: '.allow-unicode-library-id' - }, { - shown: 'is-shown', - showing: 'is-showing', - hiding: 'is-hiding', - disabled: 'is-disabled', - error: 'error' - }); + var CreateLibraryUtils = new CreateLibraryUtilsFactory({ + name: '.new-library-name', + org: '.new-library-org', + number: '.new-library-number', + save: '.new-library-save', + errorWrapper: '.create-library .wrap-error', + errorMessage: '#library_creation_error', + tipError: '.create-library span.tip-error', + error: '.create-library .error', + allowUnicode: '.allow-unicode-library-id' + }, { + shown: 'is-shown', + showing: 'is-showing', + hiding: 'is-hiding', + disabled: 'is-disabled', + error: 'error' + }); - var saveNewCourse = function(e) { - e.preventDefault(); + var saveNewCourse = function(e) { + e.preventDefault(); - if (CreateCourseUtils.hasInvalidRequiredFields()) { - return; - } + if (CreateCourseUtils.hasInvalidRequiredFields()) { + return; + } - var $newCourseForm = $(this).closest('#create-course-form'); - var display_name = $newCourseForm.find('.new-course-name').val(); - var org = $newCourseForm.find('.new-course-org').val(); - var number = $newCourseForm.find('.new-course-number').val(); - var run = $newCourseForm.find('.new-course-run').val(); + var $newCourseForm = $(this).closest('#create-course-form'); + var display_name = $newCourseForm.find('.new-course-name').val(); + var org = $newCourseForm.find('.new-course-org').val(); + var number = $newCourseForm.find('.new-course-number').val(); + var run = $newCourseForm.find('.new-course-run').val(); - var course_info = { - org: org, - number: number, - display_name: display_name, - run: run - }; - - analytics.track('Created a Course', course_info); - CreateCourseUtils.create(course_info, function(errorMessage) { - var msg = edx.HtmlUtils.joinHtml(edx.HtmlUtils.HTML('

'), errorMessage, edx.HtmlUtils.HTML('

')); - $('.create-course .wrap-error').addClass('is-shown'); - edx.HtmlUtils.setHtml($('#course_creation_error'), msg); - $('.new-course-save').addClass('is-disabled').attr('aria-disabled', true); - }); + var course_info = { + org: org, + number: number, + display_name: display_name, + run: run }; - var rtlTextDirection = function() { - var Selectors = { - new_course_run: '#new-course-run' - }; - - if ($('body').hasClass('rtl')) { - $(Selectors.new_course_run).addClass('course-run-text-direction placeholder-text-direction'); - $(Selectors.new_course_run).on('input', function() { - if (this.value === '') { - $(Selectors.new_course_run).addClass('placeholder-text-direction'); - } else { - $(Selectors.new_course_run).removeClass('placeholder-text-direction'); - } - }); - } - }; - - var makeCancelHandler = function(addType) { - return function(e) { - e.preventDefault(); - $('.new-' + addType + '-button').removeClass('is-disabled').attr('aria-disabled', false); - $('.wrapper-create-' + addType).removeClass('is-shown'); - // Clear out existing fields and errors - $('#create-' + addType + '-form input[type=text]').val(''); - $('#' + addType + '_creation_error').html(''); - $('.create-' + addType + ' .wrap-error').removeClass('is-shown'); - $('.new-' + addType + '-save').off('click'); - }; - }; - - var addNewCourse = function(e) { - var $newCourse, - $cancelButton, - $courseName; - e.preventDefault(); - $('.new-course-button').addClass('is-disabled').attr('aria-disabled', true); + analytics.track('Created a Course', course_info); + CreateCourseUtils.create(course_info, function(errorMessage) { + var msg = edx.HtmlUtils.joinHtml(edx.HtmlUtils.HTML('

'), errorMessage, edx.HtmlUtils.HTML('

')); + $('.create-course .wrap-error').addClass('is-shown'); + edx.HtmlUtils.setHtml($('#course_creation_error'), msg); $('.new-course-save').addClass('is-disabled').attr('aria-disabled', true); - $newCourse = $('.wrapper-create-course').addClass('is-shown'); - $cancelButton = $newCourse.find('.new-course-cancel'); - $courseName = $('.new-course-name'); - $courseName.focus().select(); - $('.new-course-save').on('click', saveNewCourse); - $cancelButton.bind('click', makeCancelHandler('course')); - CancelOnEscape($cancelButton); - CreateCourseUtils.setupOrgAutocomplete(); - CreateCourseUtils.configureHandlers(); - rtlTextDirection(); + }); + }; + + var rtlTextDirection = function() { + var Selectors = { + new_course_run: '#new-course-run' }; - var saveNewLibrary = function(e) { - e.preventDefault(); - - if (CreateLibraryUtils.hasInvalidRequiredFields()) { - return; - } - - var $newLibraryForm = $(this).closest('#create-library-form'); - var display_name = $newLibraryForm.find('.new-library-name').val(); - var org = $newLibraryForm.find('.new-library-org').val(); - var number = $newLibraryForm.find('.new-library-number').val(); - - var lib_info = { - org: org, - number: number, - display_name: display_name - }; - - analytics.track('Created a Library', lib_info); - CreateLibraryUtils.create(lib_info, function(errorMessage) { - var msg = edx.HtmlUtils.joinHtml(edx.HtmlUtils.HTML('

'), errorMessage, edx.HtmlUtils.HTML('

')); - $('.create-library .wrap-error').addClass('is-shown'); - edx.HtmlUtils.setHtml($('#library_creation_error'), msg); - $('.new-library-save').addClass('is-disabled').attr('aria-disabled', true); + if ($('body').hasClass('rtl')) { + $(Selectors.new_course_run).addClass('course-run-text-direction placeholder-text-direction'); + $(Selectors.new_course_run).on('input', function() { + if (this.value === '') { + $(Selectors.new_course_run).addClass('placeholder-text-direction'); + } else { + $(Selectors.new_course_run).removeClass('placeholder-text-direction'); + } }); - }; + } + }; - var addNewLibrary = function(e) { + var makeCancelHandler = function(addType) { + return function(e) { e.preventDefault(); - $('.new-library-button').addClass('is-disabled').attr('aria-disabled', true); - $('.new-library-save').addClass('is-disabled').attr('aria-disabled', true); - var $newLibrary = $('.wrapper-create-library').addClass('is-shown'); - var $cancelButton = $newLibrary.find('.new-library-cancel'); - var $libraryName = $('.new-library-name'); - $libraryName.focus().select(); - $('.new-library-save').on('click', saveNewLibrary); - $cancelButton.bind('click', makeCancelHandler('library')); - CancelOnEscape($cancelButton); + $('.new-' + addType + '-button').removeClass('is-disabled').attr('aria-disabled', false); + $('.wrapper-create-' + addType).removeClass('is-shown'); + // Clear out existing fields and errors + $('#create-' + addType + '-form input[type=text]').val(''); + $('#' + addType + '_creation_error').html(''); + $('.create-' + addType + ' .wrap-error').removeClass('is-shown'); + $('.new-' + addType + '-save').off('click'); + }; + }; - CreateLibraryUtils.configureHandlers(); + var addNewCourse = function(e) { + var $newCourse, + $cancelButton, + $courseName; + e.preventDefault(); + $('.new-course-button').addClass('is-disabled').attr('aria-disabled', true); + $('.new-course-save').addClass('is-disabled').attr('aria-disabled', true); + $newCourse = $('.wrapper-create-course').addClass('is-shown'); + $cancelButton = $newCourse.find('.new-course-cancel'); + $courseName = $('.new-course-name'); + $courseName.focus().select(); + $('.new-course-save').on('click', saveNewCourse); + $cancelButton.bind('click', makeCancelHandler('course')); + CancelOnEscape($cancelButton); + CreateCourseUtils.setupOrgAutocomplete(); + CreateCourseUtils.configureHandlers(); + rtlTextDirection(); + }; + + var saveNewLibrary = function(e) { + e.preventDefault(); + + if (CreateLibraryUtils.hasInvalidRequiredFields()) { + return; + } + + var $newLibraryForm = $(this).closest('#create-library-form'); + var display_name = $newLibraryForm.find('.new-library-name').val(); + var org = $newLibraryForm.find('.new-library-org').val(); + var number = $newLibraryForm.find('.new-library-number').val(); + + var lib_info = { + org: org, + number: number, + display_name: display_name }; - var showTab = function(tab) { - return function(e) { - e.preventDefault(); - window.location.hash = tab; - $('.courses-tab').toggleClass('active', tab === 'courses-tab'); - $('.archived-courses-tab').toggleClass('active', tab === 'archived-courses-tab'); - $('.libraries-tab').toggleClass('active', tab === 'libraries-tab'); + analytics.track('Created a Library', lib_info); + CreateLibraryUtils.create(lib_info, function(errorMessage) { + var msg = edx.HtmlUtils.joinHtml(edx.HtmlUtils.HTML('

'), errorMessage, edx.HtmlUtils.HTML('

')); + $('.create-library .wrap-error').addClass('is-shown'); + edx.HtmlUtils.setHtml($('#library_creation_error'), msg); + $('.new-library-save').addClass('is-disabled').attr('aria-disabled', true); + }); + }; + + var addNewLibrary = function(e) { + e.preventDefault(); + $('.new-library-button').addClass('is-disabled').attr('aria-disabled', true); + $('.new-library-save').addClass('is-disabled').attr('aria-disabled', true); + var $newLibrary = $('.wrapper-create-library').addClass('is-shown'); + var $cancelButton = $newLibrary.find('.new-library-cancel'); + var $libraryName = $('.new-library-name'); + $libraryName.focus().select(); + $('.new-library-save').on('click', saveNewLibrary); + $cancelButton.bind('click', makeCancelHandler('library')); + CancelOnEscape($cancelButton); + + CreateLibraryUtils.configureHandlers(); + }; + + var showTab = function(tab) { + return function(e) { + e.preventDefault(); + window.location.hash = tab; + $('.courses-tab').toggleClass('active', tab === 'courses-tab'); + $('.archived-courses-tab').toggleClass('active', tab === 'archived-courses-tab'); + $('.libraries-tab').toggleClass('active', tab === 'libraries-tab'); // Also toggle this course-related notice shown below the course tab, if it is present: - $('.wrapper-creationrights').toggleClass('is-hidden', tab !== 'courses-tab'); - }; + $('.wrapper-creationrights').toggleClass('is-hidden', tab !== 'courses-tab'); }; + }; - var onReady = function() { - var courseTabHref = $('#course-index-tabs .courses-tab a').attr('href'); - var libraryTabHref = $('#course-index-tabs .libraries-tab a').attr('href'); - var ArchivedTabHref = $('#course-index-tabs .archived-courses-tab a').attr('href'); + var onReady = function() { + var courseTabHref = $('#course-index-tabs .courses-tab a').attr('href'); + var libraryTabHref = $('#course-index-tabs .libraries-tab a').attr('href'); + var ArchivedTabHref = $('#course-index-tabs .archived-courses-tab a').attr('href'); - $('.new-course-button').bind('click', addNewCourse); - $('.new-library-button').bind('click', addNewLibrary); + $('.new-course-button').bind('click', addNewCourse); + $('.new-library-button').bind('click', addNewLibrary); - $('.dismiss-button').bind('click', ViewUtils.deleteNotificationHandler(function() { - ViewUtils.reload(); - })); + $('.dismiss-button').bind('click', ViewUtils.deleteNotificationHandler(function() { + ViewUtils.reload(); + })); - $('.action-reload').bind('click', ViewUtils.reload); + $('.action-reload').bind('click', ViewUtils.reload); - if (courseTabHref === '#') { - $('#course-index-tabs .courses-tab').bind('click', showTab('courses-tab')); - } + if (courseTabHref === '#') { + $('#course-index-tabs .courses-tab').bind('click', showTab('courses-tab')); + } - if (libraryTabHref === '#') { - $('#course-index-tabs .libraries-tab').bind('click', showTab('libraries-tab')); - } + if (libraryTabHref === '#') { + $('#course-index-tabs .libraries-tab').bind('click', showTab('libraries-tab')); + } - if (ArchivedTabHref === '#') { - $('#course-index-tabs .archived-courses-tab').bind('click', showTab('archived-courses-tab')); - } - if (window.location.hash) { - $(window.location.hash.replace('#', '.')).first('a').trigger('click'); - } - }; + if (ArchivedTabHref === '#') { + $('#course-index-tabs .archived-courses-tab').bind('click', showTab('archived-courses-tab')); + } + if (window.location.hash) { + $(window.location.hash.replace('#', '.')).first('a').trigger('click'); + } + }; - domReady(onReady); + domReady(onReady); - return { - onReady: onReady - }; - }); + return { + onReady: onReady + }; +}); diff --git a/cms/static/js/maintenance/force_publish_course.js b/cms/static/js/maintenance/force_publish_course.js index e7eed221d6..c7b29bc8d0 100644 --- a/cms/static/js/maintenance/force_publish_course.js +++ b/cms/static/js/maintenance/force_publish_course.js @@ -54,29 +54,29 @@ function($, _, gettext, ViewUtils, StringUtils, HtmlUtils) { dataType: 'json', data: data }) - .done(function(response) { - if (response.error) { - showError('#course-id-container', response.msg); - } else { - if (response.msg) { - showError('#result-error', response.msg); + .done(function(response) { + if (response.error) { + showError('#course-id-container', response.msg); } else { - attrs = $.extend({}, response, {StringUtils: StringUtils}); - forcePublishedTemplate = HtmlUtils.template( - $('#force-published-course-response-tpl').text() - ); - HtmlUtils.setHtml($('#result-container'), forcePublishedTemplate(attrs)); + if (response.msg) { + showError('#result-error', response.msg); + } else { + attrs = $.extend({}, response, {StringUtils: StringUtils}); + forcePublishedTemplate = HtmlUtils.template( + $('#force-published-course-response-tpl').text() + ); + HtmlUtils.setHtml($('#result-container'), forcePublishedTemplate(attrs)); + } } - } - }) - .fail(function() { + }) + .fail(function() { // response.responseText here because it would show some strange output, it may output Traceback // sometimes if unexpected issue arises. Better to show just internal error when getting 500 error. - showError('#result-error', gettext('Internal Server Error.')); - }) - .always(function() { - deferred.resolve(); - }); + showError('#result-error', gettext('Internal Server Error.')); + }) + .always(function() { + deferred.resolve(); + }); }); }; }); diff --git a/cms/static/js/models/asset.js b/cms/static/js/models/asset.js index 3ad7020421..044c07d90f 100644 --- a/cms/static/js/models/asset.js +++ b/cms/static/js/models/asset.js @@ -1,5 +1,5 @@ define(['backbone'], function(Backbone) { - /** + /** * Simple model for an asset. */ var Asset = Backbone.Model.extend({ diff --git a/cms/static/js/models/license.js b/cms/static/js/models/license.js index ff90c60b8d..e60c174e2a 100644 --- a/cms/static/js/models/license.js +++ b/cms/static/js/models/license.js @@ -80,10 +80,10 @@ define(['backbone', 'underscore'], function(Backbone, _) { } var eqIndex = optionString.indexOf('='); if (eqIndex == -1) { - // this is a boolean flag + // this is a boolean flag optionsObj[optionString] = true; } else { - // this is a key-value pair + // this is a key-value pair var optionKey = optionString.substring(0, eqIndex); var optionVal = optionString.substring(eqIndex + 1); optionsObj[optionKey] = optionVal; diff --git a/cms/static/js/models/settings/course_details.js b/cms/static/js/models/settings/course_details.js index 560816fabc..803b307600 100644 --- a/cms/static/js/models/settings/course_details.js +++ b/cms/static/js/models/settings/course_details.js @@ -1,167 +1,167 @@ define(['backbone', 'underscore', 'gettext', 'js/models/validation_helpers', 'js/utils/date_utils', 'edx-ui-toolkit/js/utils/string-utils' ], - function(Backbone, _, gettext, ValidationHelpers, DateUtils, StringUtils) { - 'use strict'; - var CourseDetails = Backbone.Model.extend({ - defaults: { - org: '', - course_id: '', - run: '', - language: '', - start_date: null, // maps to 'start' - end_date: null, // maps to 'end' - certificates_display_behavior: "", - certificate_available_date: null, - enrollment_start: null, - enrollment_end: null, - syllabus: null, - title: '', - subtitle: '', - duration: '', - description: '', - short_description: '', - overview: '', - intro_video: null, - effort: null, // an int or null, - license: null, - course_image_name: '', // the filename - course_image_asset_path: '', // the full URL (/c4x/org/course/num/asset/filename) - banner_image_name: '', - banner_image_asset_path: '', - video_thumbnail_image_name: '', - video_thumbnail_image_asset_path: '', - pre_requisite_courses: [], - entrance_exam_enabled: '', - entrance_exam_minimum_score_pct: '50', - learning_info: [], - instructor_info: {}, - self_paced: null - }, +function(Backbone, _, gettext, ValidationHelpers, DateUtils, StringUtils) { + 'use strict'; + var CourseDetails = Backbone.Model.extend({ + defaults: { + org: '', + course_id: '', + run: '', + language: '', + start_date: null, // maps to 'start' + end_date: null, // maps to 'end' + certificates_display_behavior: "", + certificate_available_date: null, + enrollment_start: null, + enrollment_end: null, + syllabus: null, + title: '', + subtitle: '', + duration: '', + description: '', + short_description: '', + overview: '', + intro_video: null, + effort: null, // an int or null, + license: null, + course_image_name: '', // the filename + course_image_asset_path: '', // the full URL (/c4x/org/course/num/asset/filename) + banner_image_name: '', + banner_image_asset_path: '', + video_thumbnail_image_name: '', + video_thumbnail_image_asset_path: '', + pre_requisite_courses: [], + entrance_exam_enabled: '', + entrance_exam_minimum_score_pct: '50', + learning_info: [], + instructor_info: {}, + self_paced: null + }, - validate: function(newattrs) { + validate: function(newattrs) { // Returns either nothing (no return call) so that validate works or an object of {field: errorstring} pairs // A bit funny in that the video key validation is asynchronous; so, it won't stop the validation. - var errors = {}; - const CERTIFICATES_DISPLAY_BEHAVIOR_OPTIONS = { - END: "end", - END_WITH_DATE: "end_with_date", - EARLY_NO_INFO: "early_no_info" - }; + var errors = {}; + const CERTIFICATES_DISPLAY_BEHAVIOR_OPTIONS = { + END: "end", + END_WITH_DATE: "end_with_date", + EARLY_NO_INFO: "early_no_info" + }; - newattrs = DateUtils.convertDateStringsToObjects( - newattrs, - ['start_date', 'end_date', 'certificate_available_date', 'enrollment_start', 'enrollment_end'] - ); + newattrs = DateUtils.convertDateStringsToObjects( + newattrs, + ['start_date', 'end_date', 'certificate_available_date', 'enrollment_start', 'enrollment_end'] + ); - if (newattrs.start_date === null) { - errors.start_date = gettext('The course must have an assigned start date.'); - } + if (newattrs.start_date === null) { + errors.start_date = gettext('The course must have an assigned start date.'); + } - if (newattrs.start_date && newattrs.end_date && newattrs.start_date >= newattrs.end_date) { - errors.end_date = gettext('The course end date must be later than the course start date.'); - } - if (newattrs.start_date && newattrs.enrollment_start && + if (newattrs.start_date && newattrs.end_date && newattrs.start_date >= newattrs.end_date) { + errors.end_date = gettext('The course end date must be later than the course start date.'); + } + if (newattrs.start_date && newattrs.enrollment_start && newattrs.start_date < newattrs.enrollment_start) { - errors.enrollment_start = gettext( - 'The course start date must be later than the enrollment start date.' - ); - } - if (newattrs.enrollment_start && newattrs.enrollment_end && + errors.enrollment_start = gettext( + 'The course start date must be later than the enrollment start date.' + ); + } + if (newattrs.enrollment_start && newattrs.enrollment_end && newattrs.enrollment_start >= newattrs.enrollment_end) { - errors.enrollment_end = gettext( - 'The enrollment start date cannot be after the enrollment end date.' - ); - } - if (newattrs.end_date && newattrs.enrollment_end && newattrs.end_date < newattrs.enrollment_end) { - errors.enrollment_end = gettext('The enrollment end date cannot be after the course end date.'); - } - if (this.showCertificateAvailableDate && newattrs.end_date && newattrs.certificate_available_date && + errors.enrollment_end = gettext( + 'The enrollment start date cannot be after the enrollment end date.' + ); + } + if (newattrs.end_date && newattrs.enrollment_end && newattrs.end_date < newattrs.enrollment_end) { + errors.enrollment_end = gettext('The enrollment end date cannot be after the course end date.'); + } + if (this.showCertificateAvailableDate && newattrs.end_date && newattrs.certificate_available_date && newattrs.certificate_available_date < newattrs.end_date) { - errors.certificate_available_date = gettext( - 'The certificate available date must be later than the course end date.' + errors.certificate_available_date = gettext( + 'The certificate available date must be later than the course end date.' + ); + } + + if (this.useV2CertDisplaySettings){ + if ( + newattrs.certificates_display_behavior + && !(Object.values(CERTIFICATES_DISPLAY_BEHAVIOR_OPTIONS).includes(newattrs.certificates_display_behavior)) + ) { + + errors.certificates_display_behavior = StringUtils.interpolate( + gettext( + "The certificate display behavior must be one of: {behavior_options}" + ), + { + behavior_options: Object.values(CERTIFICATES_DISPLAY_BEHAVIOR_OPTIONS).join(', ') + } ); } - if (this.useV2CertDisplaySettings){ - if ( - newattrs.certificates_display_behavior - && !(Object.values(CERTIFICATES_DISPLAY_BEHAVIOR_OPTIONS).includes(newattrs.certificates_display_behavior)) - ) { - - errors.certificates_display_behavior = StringUtils.interpolate( - gettext( - "The certificate display behavior must be one of: {behavior_options}" - ), - { - behavior_options: Object.values(CERTIFICATES_DISPLAY_BEHAVIOR_OPTIONS).join(', ') - } - ); - } - - // Throw error if there's a value for certificate_available_date - if( - (newattrs.certificate_available_date && newattrs.certificates_display_behavior != CERTIFICATES_DISPLAY_BEHAVIOR_OPTIONS.END_WITH_DATE) + // Throw error if there's a value for certificate_available_date + if( + (newattrs.certificate_available_date && newattrs.certificates_display_behavior != CERTIFICATES_DISPLAY_BEHAVIOR_OPTIONS.END_WITH_DATE) || (!newattrs.certificate_available_date && newattrs.certificates_display_behavior == CERTIFICATES_DISPLAY_BEHAVIOR_OPTIONS.END_WITH_DATE) - ){ - errors.certificates_display_behavior = StringUtils.interpolate( - gettext( - "The certificates display behavior must be {valid_option} if certificate available date is set." - ), - { - valid_option: CERTIFICATES_DISPLAY_BEHAVIOR_OPTIONS.END_WITH_DATE - } - ); - } + ){ + errors.certificates_display_behavior = StringUtils.interpolate( + gettext( + "The certificates display behavior must be {valid_option} if certificate available date is set." + ), + { + valid_option: CERTIFICATES_DISPLAY_BEHAVIOR_OPTIONS.END_WITH_DATE + } + ); } + } - if (newattrs.intro_video && newattrs.intro_video !== this.get('intro_video')) { - if (this._videokey_illegal_chars.exec(newattrs.intro_video)) { - errors.intro_video = gettext('Key should only contain letters, numbers, _, or -'); - } + if (newattrs.intro_video && newattrs.intro_video !== this.get('intro_video')) { + if (this._videokey_illegal_chars.exec(newattrs.intro_video)) { + errors.intro_video = gettext('Key should only contain letters, numbers, _, or -'); + } // TODO check if key points to a real video using google's youtube api + } + if (_.has(newattrs, 'entrance_exam_minimum_score_pct')) { + var range = { + min: 1, + max: 100 + }; + if (!ValidationHelpers.validateIntegerRange(newattrs.entrance_exam_minimum_score_pct, range)) { + errors.entrance_exam_minimum_score_pct = StringUtils.interpolate(gettext( + 'Please enter an integer between %(min)s and %(max)s.' + ), range, true); } - if (_.has(newattrs, 'entrance_exam_minimum_score_pct')) { - var range = { - min: 1, - max: 100 - }; - if (!ValidationHelpers.validateIntegerRange(newattrs.entrance_exam_minimum_score_pct, range)) { - errors.entrance_exam_minimum_score_pct = StringUtils.interpolate(gettext( - 'Please enter an integer between %(min)s and %(max)s.' - ), range, true); - } - } - if (!_.isEmpty(errors)) return errors; + } + if (!_.isEmpty(errors)) return errors; // NOTE don't return empty errors as that will be interpreted as an error state - }, + }, - _videokey_illegal_chars: /[^a-zA-Z0-9_-]/g, + _videokey_illegal_chars: /[^a-zA-Z0-9_-]/g, - set_videosource: function(newsource) { + set_videosource: function(newsource) { // newsource either is