Files
edx-platform/cms/templates/container.html
Kyle McCormick 8e9f94424d feat!: Flip Studio MFE Waffle Flags to be On-By-Default (#36495)
This makes nearly all of Studio React-by-default by replacing the
"opt-in-to-React" flags with a set of parallel
"opt-out-of-React-and-use-the-legacy-experience" flags. Here is the
mapping:

* `contentstore.new_studio_mfe.use_new_unit_page` ->
  `!legacy_studio.unit_editor`
* `new_core_editors.use_new_problem_editor` ->
  `!legacy_studio.problem_editor`
* `new_core_editors.use_new_text_editor` ->
  `!legacy_studio.text_editor`
* `new_core_editors.use_new_video_editor` ->
  `!legacy_studio.video_editor`
* `new_studio_mfe.use_new_home_page` ->
  `!legacy_studio.home`
* `contentstore.new_studio_mfe.use_new_custom_pages` ->
  `!legacy_studio.custom_pages`
* `contentstore.new_studio_mfe.use_new_schedule_details_page` ->
  `!legacy_studio.schedule_details`
* `contentstore.new_studio_mfe.use_new_advanced_settings_page` ->
  `!legacy_studio.advanced_settings`
* `contentstore.new_studio_mfe.use_new_grading_page` ->
  `!legacy_studio.grading`
* `contentstore.new_studio_mfe.use_new_updates_page` ->
  `!legacy_studio.updates`
* `contentstore.new_studio_mfe.use_new_import_page` ->
  `!legacy_studio.import`
* `contentstore.new_studio_mfe.use_new_export_page` ->
  `!legacy_studio.export`
* `contentstore.new_studio_mfe.use_new_files_uploads_page` ->
  `!legacy_studio.files_uploads`
* `contentstore.new_studio_mfe.use_new_course_outline_page` ->
  `!legacy_studio.course_outline`
* `contentstore.new_studio_mfe.use_new_course_team_page` ->
  `!legacy_studio.course_team`
* `contentstore.new_studio_mfe.use_new_certificates_page` ->
  `!legacy_studio.certificates`
* `contentstore.new_studio_mfe.use_new_textbooks_page` ->
  `!legacy_studio.textbooks`
* `contentstore.new_studio_mfe.use_new_group_configurations_page` ->
  `!legacy_studio.configurations`

Part of: https://github.com/openedx/edx-platform/issues/36275
2025-04-24 12:34:35 -04:00

304 lines
15 KiB
HTML

<%page expression_filter="h"/>
<%inherit file="base.html" />
<%def name="online_help_token()">
<%
if is_unit_page:
return "unit"
else:
return "container"
%>
</%def>
<%!
from django.urls import reverse
from django.utils.translation import gettext as _
from cms.djangoapps.contentstore.helpers import xblock_studio_url, xblock_type_display_name
from cms.djangoapps.contentstore.toggles import use_new_text_editor, use_new_problem_editor, use_new_video_editor, use_video_gallery_flow
from cms.djangoapps.contentstore.utils import get_editor_page_base_url
from openedx.core.djangolib.js_utils import (
dump_js_escaped_json, js_escaped_string
)
from openedx.core.djangolib.markup import HTML, Text
%>
<%block name="title">${xblock.display_name_with_default} ${xblock_type_display_name(xblock)}</%block>
<%block name="bodyclass">is-signedin course container view-container</%block>
<%namespace name='static' file='static_content.html'/>
<%block name="header_extras">
% for template_name in templates:
<script type="text/template" id="${template_name}-tpl">
<%static:include path="js/${template_name}.underscore" />
</script>
% endfor
<script type="text/template" id="image-modal-tpl">
<%static:include path="common/templates/image-modal.underscore" />
</script>
<link rel="stylesheet" type="text/css" href="${static.url('js/vendor/timepicker/jquery.timepicker.css')}" />
% if not settings.STUDIO_FRONTEND_CONTAINER_URL:
<link rel="stylesheet" type="text/css" href="${static.url('common/css/vendor/common.min.css')}" />
<link rel="stylesheet" type="text/css" href="${static.url('common/css/vendor/editImageModal.min.css')}" />
% endif
</%block>
<%block name="page_bundle">
<%static:webpack entry="js/factories/container">
ContainerFactory(
${component_templates | n, dump_js_escaped_json},
${xblock_info | n, dump_js_escaped_json},
"${action | n, js_escaped_string}",
{
isUnitPage: ${is_unit_page | n, dump_js_escaped_json},
canEdit: true,
outlineURL: "${outline_url | n, js_escaped_string}",
libraryContentPickerUrl: "${library_content_picker_url | n, js_escaped_string}",
clipboardData: ${user_clipboard | n, dump_js_escaped_json},
}
);
require(["js/models/xblock_info", "js/views/xblock", "js/views/utils/xblock_utils", "common/js/components/utils/view_utils", "gettext"], function (XBlockInfo, XBlockView, XBlockUtils, ViewUtils, gettext) {
var model = new XBlockInfo({
id: '${subsection.location|n, decode.utf8}'
});
var xblockView = new XBlockView({
model: model,
el: $('#sequence-nav'),
view: 'author_view?position=${position|n, decode.utf8}&next_url=${next_url|n, decode.utf8}&prev_url=${prev_url|n, decode.utf8}',
clipboardData: ${user_clipboard | n, dump_js_escaped_json},
});
xblockView.xblockReady = function() {
var toggleCaretButton = function(clipboardData) {
if (clipboardData && clipboardData.content && clipboardData.source_usage_key.includes("vertical")) {
$('.dropdown-toggle-button').show();
} else {
$('.dropdown-toggle-button').hide();
$('.dropdown-options').hide();
}
};
this.clipboardBroadcastChannel = new BroadcastChannel("studio_clipboard_channel");
this.clipboardBroadcastChannel.onmessage = (event) => {
toggleCaretButton(event.data);
};
toggleCaretButton(this.options.clipboardData);
$('#new-unit-button').on('click', function(event) {
event.preventDefault();
XBlockUtils.addXBlock($(this)).done(function(locator) {
ViewUtils.redirect('/container/' + locator + '?action=new');
});
});
$('.custom-dropdown .dropdown-toggle-button').on('click', function(event) {
event.stopPropagation(); // Prevent the event from closing immediately when we open it
$(this).next('.dropdown-options').slideToggle('fast'); // This toggles the dropdown visibility
var isExpanded = $(this).attr('aria-expanded') === 'true';
$(this).attr('aria-expanded', !isExpanded);
});
$('.seq_paste_unit').on('click', function(event) {
event.preventDefault();
$('.dropdown-options').hide();
XBlockUtils.pasteXBlock($(this)).done(function(data) {
ViewUtils.redirect('/container/' + data.locator + '?action=new');
});
});
};
xblockView.render();
});
</%static:webpack>
</%block>
<%block name="content">
<%
use_new_editor_text = use_new_text_editor(xblock_locator.course_key)
use_new_editor_video = use_new_video_editor(xblock_locator.course_key)
use_new_editor_problem = use_new_problem_editor(xblock_locator.course_key)
use_new_video_gallery_flow = use_video_gallery_flow()
%>
<script type="text/javascript">
window.STUDIO_FRONTEND_IN_CONTEXT_IMAGE_SELECTION = true;
</script>
<div class="wrapper-mast wrapper">
<header class="mast has-actions has-navigation has-subtitle">
<div class="jump-nav">
<nav class="nav-dd title ui-left">
<ol>
% for block in ancestor_xblocks:
<li class="nav-item">
<span class="title label">${block['title']}
<span class="icon fa fa-caret-down ui-toggle-dd" aria-hidden="true"></span>
</span>
% if not block['is_last']:
<span class="spacer"> &rsaquo;</span>
% endif
<div class="wrapper wrapper-nav-sub">
<div class="nav-sub">
<ul>
% for child in block['children']:
<%
# Not all xblock has their own studio page
# Check if siblings has any url to their own studio
# page, otherwise avoid including them in dropdown.
url = xblock_studio_url(child)
%>
% if url:
<li class="nav-item">
<a href="${url}">${child.display_name_with_default}</a>
</li>
% endif
% endfor
</ul>
</div>
</div>
</li>
% endfor
</ol>
</nav>
<div class="wrapper-xblock-field incontext-editor is-editable"
data-field="display_name" data-field-display-name="${_("Display Name")}">
<h1 class="page-header-title xblock-field-value incontext-editor-value"><span class="title-value">${xblock.display_name_with_default}</span></h1>
</div>
<div class="container-access">
</div>
</div>
<nav class="nav-actions" aria-label="${_('Page Actions')}"
use-new-editor-text = ${use_new_editor_text}
use-new-editor-video = ${use_new_editor_video}
use-new-editor-problem = ${use_new_editor_problem}
use-video-gallery-flow = ${use_new_video_gallery_flow}
authoring_MFE_base_url = ${get_editor_page_base_url(xblock_locator.course_key)}
data-block-type = ${xblock.scope_ids.block_type}
data-usage-id = ${xblock.scope_ids.usage_id}
>
<h3 class="sr">${_("Page Actions")}</h3>
<ul>
## Hide the sequence navigation when we've browsed into a child of the unit, e.g. showing the child blocks of a problem-builder xblock
% if is_unit_page:
<li class="action-item action-view nav-item">
<a href="${published_preview_link}" class="button button-view action-button is-disabled" aria-disabled="true" rel="external" title="${_('Open the courseware in the LMS')}">
<span class="action-button-text">${_("View Live Version")}</span>
</a>
</li>
<li class="action-item action-preview nav-item">
<a href="${draft_preview_link}" class="button button-preview action-button" rel="external" title="${_('Preview the courseware in the LMS')}">
<span class="action-button-text">${_("Preview")}</span>
</a>
</li>
% else:
<li class="action-item action-edit nav-item">
<a href="#" class="button button-edit action-button edit-button">
<span class="icon fa fa-pencil" aria-hidden="true"></span>
<span class="action-button-text">${_("Edit")}</span>
</a>
</li>
% if is_collapsible:
<li class="action-item action-toggle-preview nav-item">
<a href="#" class="button button-toggle-preview action-button">
<span class="icon fa fa-arrow-up" aria-hidden="true"></span>
<span class="action-button-text preview-text">${_("Collapse All")}</span>
</a>
</li>
% endif
% endif
</ul>
</nav>
% if is_unit_page:
<div id="sequence-nav"></div>
% endif
</header>
</div>
<div class="wrapper-content wrapper">
<div class="inner-wrapper">
<section class="content-area">
<article class="content-primary ${'content-primary-fullwidth' if is_fullwidth_content else ''}">
<div class="container-message wrapper-message"></div>
<%
assets_url = reverse('assets_handler', kwargs={'course_key_string': str(xblock_locator.course_key)})
%>
<section class="wrapper-xblock level-page is-hidden studio-xblock-wrapper" data-locator="${xblock_locator}" data-course-key="${xblock_locator.course_key}" data-course-assets="${assets_url}">
</section>
<div class="ui-loading">
<p><span class="spin"><span class="icon fa fa-refresh" aria-hidden="true"></span></span> <span class="copy">${_("Loading")}</span></p>
</div>
</article>
<aside class="content-supplementary" role="complementary">
% if xblock.category == 'split_test':
<div class="bit">
<h3 class="title-3">${_("Adding components")}</h3>
<p>${Text(_("Select a component type under {strong_start}Add New Component{strong_end}. Then select a template.")).format(
strong_start=HTML('<strong>'),
strong_end=HTML("</strong>"),
)}</p>
<p>${_("The new component is added at the bottom of the page or group. You can then edit and move the component.")}</p>
<h3 class="title-3">${_("Editing components")}</h3>
<p>${Text(_("Click the {strong_start}Edit{strong_end} icon in a component to edit its content.")).format(
strong_start=HTML('<strong>'),
strong_end=HTML("</strong>"),
)}</p>
<h3 class="title-3">${_("Reorganizing components")}</h3>
<p>${_("Drag components to new locations within this component.")}</p>
<p>${_("For content experiments, you can drag components to other groups.")}</p>
<h3 class="title-3">${_("Working with content experiments")}</h3>
<p>${_("Confirm that you have properly configured content in each of your experiment groups.")}</p>
</div>
<div class="bit external-help">
<a href="${get_online_help_info(online_help_token())['doc_url']}" rel="noopener" target="_blank" class="button external-help-button">${_("Learn more about component containers")}</a>
</div>
% elif is_unit_page:
<div id="publish-unit"></div>
<div id="publish-history" class="unit-publish-history"></div>
<div class="unit-location is-hidden">
<h4 class="bar-mod-title">${_("Unit Location")}</h4>
<div class="wrapper-unit-id bar-mod-content">
<h5 class="title">${_("Location ID")}</h5>
<p class="unit-id">
<span class="unit-id-value" id="unit-location-id-input">${unit.location.block_id}</span>
<span class="tip"><span class="sr">Tip: </span>${Text(_('To create a link to this unit from an HTML component in this course, enter {unit_link} as the URL value.')).format(
unit_link="/jump_to_id/{}".format(unit.location.block_id)
)}</span>
</p>
</div>
</div>
% if show_unit_tags:
<div class="unit-tags is-hidden"></div>
% endif
% endif
</aside>
</section>
<div id="edit-image-modal">
<%static:studiofrontend entry="editImageModal">
{
"course": {
"id": "${context_course.id | n, js_escaped_string}",
"name": "${context_course.display_name_with_default | n, js_escaped_string}",
"url_name": "${context_course.location.block_id | n, js_escaped_string}",
"org": "${context_course.location.org | n, js_escaped_string}",
"num": "${context_course.location.course | n, js_escaped_string}",
"display_course_number": "${context_course.display_coursenumber | n, js_escaped_string}",
"revision": "${context_course.location.revision | n, js_escaped_string}"
},
"help_tokens": {
"image_accessibility": "${get_online_help_info('image_accessibility')['doc_url'] | n, js_escaped_string}"
},
"lang": "${language_code | n, js_escaped_string}"
}
</%static:studiofrontend>
</div>
</div>
</div>
<div id="manage-tags-drawer" class="drawer"></div>
<div class="drawer-cover gray-cover"></div>
</%block>