Files
edx-platform/lms/templates/courseware/courseware.html
Michael Terry ce5f1bb343 feat!: drop legacy course home view and related code
This was the "outline tab" view of the course. Preceded by the
course info view, succeeded by the MFE outline tab.

In addition to the course home view itself, this drops related
features:
- Legacy version of Course Goals (MFE has a newer implementation)
- Course home in-course search (MFE has no search)

The old course info view and course about views survive for now.

This also drops a few now-unused feature toggles:
- course_experience.latest_update
- course_experience.show_upgrade_msg_on_course_home
- course_experience.upgrade_deadline_message
- course_home.course_home_use_legacy_frontend

With this change, just the progress and courseware tabs are still
supported in legacy form, if you opt-in with waffle flags. The
outline and dates tabs are offered only by the MFE.

AA-798

(This is identical to previous commit be5c1a6, just reintroduced
now that the e2e tests have been fixed)
2022-04-14 15:18:31 -04:00

354 lines
13 KiB
HTML

<%page expression_filter="h"/>
<%inherit file="/main.html" />
<%namespace name='static' file='/static_content.html'/>
<%def name="online_help_token()"><% return "courseware" %></%def>
<%!
import six
import waffle
from django.conf import settings
from django.urls import reverse
from django.utils.translation import ugettext as _
from lms.djangoapps.edxnotes.helpers import is_feature_enabled as is_edxnotes_enabled
from openedx.core.djangolib.js_utils import js_escaped_string
from openedx.core.djangolib.markup import HTML
from openedx.features.course_experience import course_home_page_title, DISABLE_COURSE_OUTLINE_PAGE_FLAG
%>
<%
include_special_exams = (
request.user.is_authenticated and
settings.FEATURES.get('ENABLE_SPECIAL_EXAMS', False) and
(course.enable_proctored_exams or course.enable_timed_exams)
)
completion_aggregator_url = settings.COMPLETION_AGGREGATOR_URL if settings.FEATURES.get("SHOW_PROGRESS_BAR", False) else ""
%>
<%def name="course_name()">
<% return _("{course_number} Courseware").format(course_number=course.display_number_with_default) %>
</%def>
<%block name="bodyclass">view-in-course view-courseware courseware ${course.css_class or ''}</%block>
<%block name="title">
<title data-base-title="${static.get_page_title_breadcrumbs(section_title, course_name())}">
${static.get_page_title_breadcrumbs(sequence_title, section_title, course_name())}
</title>
</%block>
<%block name="header_extras">
% for template_name in ["image-modal"]:
<script type="text/template" id="${template_name}-tpl">
<%static:include path="common/templates/${template_name}.underscore" />
</script>
% endfor
% if include_special_exams is not UNDEFINED and include_special_exams:
% for template_name in ["proctored-exam-status"]:
<script type="text/template" id="${template_name}-tpl">
<%static:include path="courseware/${template_name}.underscore" />
</script>
% endfor
% endif
</%block>
<%block name="headextra">
<%static:css group='style-course-vendor'/>
<%static:css group='style-course'/>
## Utility: Notes
% if is_edxnotes_enabled(course, request.user):
<%static:css group='style-student-notes'/>
% endif
<script type="text/javascript" src="${static.url('js/jquery.autocomplete.js')}"></script>
<script type="text/javascript" src="${static.url('js/src/tooltip_manager.js')}"></script>
<link href="${static.url('css/vendor/jquery.autocomplete.css')}" rel="stylesheet" type="text/css">
${HTML(fragment.head_html())}
</%block>
<%block name="js_extra">
<script type="text/javascript" src="${static.url('common/js/vendor/jquery.scrollTo.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script>
<%static:js group='courseware'/>
<%include file="/mathjax_include.html" args="disable_fast_preview=True"/>
% if show_search:
<%static:require_module module_name="course_search/js/course_search_factory" class_name="CourseSearchFactory">
var courseId = $('.courseware-results').data('courseId');
CourseSearchFactory({
courseId: courseId,
searchHeader: $('.search-bar')
});
</%static:require_module>
% endif
<%static:require_module module_name="js/courseware/courseware_factory" class_name="CoursewareFactory">
CoursewareFactory();
</%static:require_module>
% if staff_access:
<%include file="xqa_interface.html"/>
% endif
<script type="text/javascript">
var $$course_id = "${course.id | n, js_escaped_string}";
</script>
% if not request.user.is_authenticated:
<script type="text/javascript">
// Disable discussions
$('.xblock-student_view-discussion button.discussion-show').attr('disabled', true);
// Insert message informing user discussions are only available to logged in users.
$('.discussion-module')
</script>
% endif
<script type="text/javascript">
/* Helper function isInViewport checks whether
the given element is in viewport vertically or not */
function isInViewport(el) {
const scroll = window.scrollY || window.pageYOffset
const elementTop = el.getBoundingClientRect().top + scroll
const viewport = {
top: scroll,
bottom: scroll + window.innerHeight,
}
const elementMid = elementTop + el.clientHeight/2
// Returns true if the middle of the element is in the viewport.
return elementMid >= viewport.top && elementMid <= viewport.bottom
}
/* Add a jQuery plugin to override the focus behavior.
When focused, if the element in not in the viewport then
the element will be scrolled to the bottom of the viewport.
*/
(function ($) {
$.fn.extend({
focus: (function(orig) {
return function(delay, fn) {
orig.apply(this, arguments);
this.each(function(){
var elem = this;
// Scroll only when the element is not in the viewport and it contains the notification-btn.
if (elem.classList.contains('notification-btn') && !isInViewport(elem)) {
this.scrollIntoView({
behaviour: 'auto',
block: 'end',
})
}
})
return this;
}
})($.fn.focus),
})
})(jQuery)
</script>
${HTML(fragment.foot_html())}
</%block>
<div class="message-banner" aria-live="polite"></div>
% if default_tab:
<%include file="/courseware/course_navigation.html" />
% else:
<%include file="/courseware/course_navigation.html" args="active_page='courseware'" />
% endif
<div class="container"
% if getattr(course, 'language'):
lang="${course.language}"
% endif
>
<div class="course-wrapper" role="presentation">
% if disable_accordion is UNDEFINED or not disable_accordion:
<div class="course-index">
<div class="wrapper-course-modes">
<div class="courseware-bookmarks-button">
<a class="bookmarks-list-button" href="${reverse('openedx.course_bookmarks.home', args=[course.id])}">
${_('Bookmarks')}
</a>
</div>
% if show_search:
<div id="courseware-search-bar" class="search-bar courseware-search-bar" role="search" aria-label="Course">
<form class="search-form">
<label for="course-search-input" class="sr">${_('Course Search')}</label>
<div class="search-field-wrapper">
<input id="course-search-input" type="text" class="search-field"/>
<button type="submit" class="search-button">${_('Search')}</button>
<button type="button" class="cancel-button" title="${_('Clear search')}">
<span class="icon fa fa-remove" aria-hidden="true"></span>
</button>
</div>
</form>
</div>
% endif
</div>
<div class="accordion">
<nav class="course-navigation" aria-label="${_('Course')}">
% if accordion.strip():
${HTML(accordion)}
% else:
<div class="chapter">${_("No content has been added to this course")}</div>
% endif
</nav>
</div>
</div>
% endif
<section class="course-content" id="course-content">
<header class="page-header has-secondary">
<div class="page-header-main">
<nav aria-label="${_('Course')}" class="sr-is-focusable" tabindex="-1">
<div class="has-breadcrumbs">
<div class="breadcrumbs">
% if not DISABLE_COURSE_OUTLINE_PAGE_FLAG.is_enabled(course.id):
<span class="nav-item nav-item-course">
<a href="${course_url}">${course_home_page_title(course)}</a>
</span>
<span class="icon fa fa-angle-right" aria-hidden="true"></span>
% endif
% if chapter:
<span class="nav-item nav-item-chapter" data-course-position="${course.position}" data-chapter-position="${chapter.position}">
<a href="${course_url}#${six.text_type(chapter.location)}">${chapter.display_name_with_default}</a>
</span>
<span class="icon fa fa-angle-right" aria-hidden="true"></span>
% endif
% if section:
<span class="nav-item nav-item-section">
<a href="${course_url}#${six.text_type(section.location)}">${section.display_name_with_default}</a>
</span>
<span class="icon fa fa-angle-right" aria-hidden="true"></span>
% endif
% if sequence_title:
<span class="nav-item nav-item-sequence">${sequence_title}</span>
% endif
</div>
% if settings.FEATURES.get("SHOW_PROGRESS_BAR", False):
<div class="container">
<iframe style="border: none; height: 50px; position: relative; top: 10px; width: -webkit-fill-available" src="${completion_aggregator_url}/${course.id}/">
</iframe>
</div>
% endif
</div>
</nav>
</div>
</header>
<main id="main" tabindex="-1" aria-label="Content">
% if getattr(course, 'entrance_exam_enabled') and \
getattr(course, 'entrance_exam_minimum_score_pct') and \
entrance_exam_current_score is not UNDEFINED:
% if not entrance_exam_passed:
<p class="sequential-status-message">
${_('To access course materials, you must score {required_score}% or higher on this \
exam. Your current score is {current_score}%.').format(
required_score=int(round(course.entrance_exam_minimum_score_pct * 100)),
current_score=int(round(entrance_exam_current_score * 100))
)}
</p>
<script type="text/javascript">
$(document).ajaxSuccess(function(event, xhr, settings) {
if (settings.url.indexOf("xmodule_handler/problem_check") > -1) {
var data = JSON.parse(xhr.responseText);
if (data.entrance_exam_passed){
location.reload();
}
}
});
</script>
% else:
<p class="sequential-status-message">
${_('Your score is {current_score}%. You have passed the entrance exam.').format(
current_score=int(round(entrance_exam_current_score * 100))
)}
</p>
% endif
% endif
${HTML(fragment.body_html())}
</main>
</section>
<section class="courseware-results-wrapper">
<div id="loading-message" aria-live="polite" aria-relevant="all"></div>
<div id="error-message" aria-live="polite"></div>
<div class="courseware-results search-results" data-course-id="${course.id}" data-lang-code="${language_preference}"></div>
</section>
</div>
${HTML(course_sock_fragment.body_html())}
</div>
<div class="container-footer">
% if settings.FEATURES.get("LICENSING", False):
<div class="course-license">
% if getattr(course, "license", None):
<%include file="../license.html" args="license=course.license" />
% else:
## Default course license: All Rights Reserved, if none is explicitly set.
<%include file="../license.html" args="license='all-rights-reserved'" />
% endif
</div>
% endif
</div>
% if course.show_calculator or is_edxnotes_enabled(course, request.user):
<nav class="nav-utilities ${"has-utility-calculator" if course.show_calculator else ""}" aria-label="${_('Course Utilities')}">
## Utility: Notes
% if is_edxnotes_enabled(course, request.user):
<%include file="/edxnotes/toggle_notes.html" args="course=course"/>
% endif
## Utility: Calc
% if course.show_calculator:
<%include file="/calculator/toggle_calculator.html" />
% endif
</nav>
% endif
<%static:require_module_async module_name="js/commerce/track_ecommerce_events" class_name="TrackECommerceEvents">
var fbeLink = $("#FBE_banner");
var welcomeLink = $("#welcome");
var accessDeniedUpsellLink = $("#accessDeniedUpsell");
var sockLink = $("#sock");
TrackECommerceEvents.trackUpsellClick(fbeLink, 'in_course_audit_access_expires', {
pageName: "in_course",
linkType: "link",
linkCategory: "FBE_banner"
});
TrackECommerceEvents.trackUpsellClick(welcomeLink, 'in_course_welcome', {
pageName: "in_course",
linkType: "link",
linkCategory: "welcome"
});
TrackECommerceEvents.trackUpsellClick(accessDeniedUpsellLink, 'in_course_upgrade', {
pageName: "in_course",
linkType: "link",
linkCategory: "(none)"
});
TrackECommerceEvents.trackUpsellClick(sockLink, 'in_course_sock', {
pageName: "in_course",
linkType: "button",
linkCategory: "green_upgrade"
});
</%static:require_module_async>