310 lines
18 KiB
HTML
310 lines
18 KiB
HTML
<%page expression_filter="h"/>
|
|
<%!
|
|
from django.utils.translation import gettext as _
|
|
from openedx.core.djangolib.markup import Text
|
|
from cms.djangoapps.contentstore.helpers import xblock_studio_url
|
|
from cms.djangoapps.contentstore.utils import is_visible_to_specific_partition_groups, get_editor_page_base_url, determine_label
|
|
from lms.lib.utils import is_unit
|
|
from openedx.core.djangolib.js_utils import (
|
|
dump_js_escaped_json, js_escaped_string
|
|
)
|
|
from cms.djangoapps.contentstore.toggles import use_new_video_editor, use_video_gallery_flow
|
|
from cms.lib.xblock.upstream_sync import UpstreamLink
|
|
from openedx.core.djangoapps.content_tagging.toggles import is_tagging_feature_disabled
|
|
%>
|
|
<%
|
|
use_new_editor_video = use_new_video_editor(xblock.context_key)
|
|
use_new_video_gallery_flow = use_video_gallery_flow()
|
|
use_tagging = not is_tagging_feature_disabled()
|
|
xblock_url = xblock_studio_url(xblock)
|
|
show_inline = xblock.has_children and not xblock_url
|
|
section_class = "level-nesting" if show_inline else "level-element"
|
|
label = determine_label(xblock.display_name_with_default, xblock.scope_ids.block_type)
|
|
messages = xblock.validate().to_json()
|
|
has_not_configured_message = messages.get('summary',{}).get('type', None) == 'not-configured'
|
|
block_is_unit = is_unit(xblock)
|
|
|
|
upstream_info = UpstreamLink.try_get_for_block(xblock, log_error=False)
|
|
can_unlink = upstream_info.upstream_ref and not upstream_info.has_top_level_parent
|
|
%>
|
|
|
|
<%namespace name='static' file='static_content.html'/>
|
|
|
|
<%block name="header_extras">
|
|
<script type="text/template" id="xblock-validation-messages-tpl">
|
|
<%static:include path="js/xblock-validation-messages.underscore" />
|
|
</script>
|
|
<script type="text/template" id="tag-count-tpl">
|
|
<%static:include path="js/tag-count.underscore" />
|
|
</script>
|
|
</%block>
|
|
|
|
<script type="text/javascript">
|
|
XBlockValidationFactory(
|
|
${messages | n, dump_js_escaped_json},
|
|
${bool(xblock_url) | n, dump_js_escaped_json}, // xblock_url will be None or a string
|
|
${bool(is_root) | n, dump_js_escaped_json}, // is_root will be None or a boolean
|
|
${bool(block_is_unit) | n, dump_js_escaped_json}, // block_is_unit will be None or a boolean
|
|
$('div.xblock-validation-messages[data-locator="${xblock.location | n, js_escaped_string}"]')
|
|
);
|
|
</script>
|
|
|
|
<%static:webpack entry="js/factories/tag_count">
|
|
TagCountFactory({
|
|
tags_count: "${tags_count | n, js_escaped_string}",
|
|
content_id: "${xblock.location | n, js_escaped_string}",
|
|
course_authoring_url: "${course_authoring_url | n, js_escaped_string}",
|
|
},
|
|
$('li.tag-count[data-locator="${xblock.location | n, js_escaped_string}"]')
|
|
);
|
|
</%static:webpack>
|
|
|
|
% if not is_root:
|
|
% if is_reorderable:
|
|
<li class="studio-xblock-wrapper is-draggable" id="${xblock.location}" data-locator="${xblock.location}" data-course-key="${xblock.location.course_key}">
|
|
% else:
|
|
<div class="studio-xblock-wrapper" id="${xblock.location}" data-locator="${xblock.location}" data-course-key="${xblock.location.course_key}">
|
|
% endif
|
|
|
|
<section class="wrapper-xblock is-collapsible ${section_class}
|
|
% if is_visible_to_specific_partition_groups(xblock):
|
|
has-group-visibility-set
|
|
% endif
|
|
">
|
|
<div class="ui-loading ${'is-hidden' if not is_loading else ''}">
|
|
<p><span class="spin"><span class="icon fa fa-refresh" aria-hidden="true"></span></span> <span class="copy">${_("Importing components")}</span></p>
|
|
</div>
|
|
% endif
|
|
|
|
<header class="xblock-header xblock-header-${xblock.category} ${'is-hidden' if is_loading else ''}">
|
|
<div class="xblock-header-primary
|
|
% if not show_preview:
|
|
is-collapsed
|
|
% endif
|
|
"
|
|
use-new-editor-video = ${use_new_editor_video}
|
|
use-video-gallery-flow = ${use_new_video_gallery_flow}
|
|
authoring_MFE_base_url = ${get_editor_page_base_url(xblock.location.course_key)}
|
|
data-block-type = ${xblock.scope_ids.block_type}
|
|
data-usage-id = ${xblock.scope_ids.usage_id}
|
|
% if upstream_info.upstream_ref:
|
|
data-upstream-ref = ${upstream_info.upstream_ref}
|
|
data-version-synced = ${upstream_info.version_synced}
|
|
data-is-modified = ${len(upstream_info.downstream_customized) > 0}
|
|
%endif
|
|
>
|
|
<div class="header-details">
|
|
% if show_inline:
|
|
<a href="#" data-tooltip="${_('Expand or Collapse')}" class="action expand-collapse collapse">
|
|
<span class="icon fa fa-caret-down ui-toggle-expansion" aria-hidden="true"></span>
|
|
<span class="sr">${_('Expand or Collapse')}</span>
|
|
</a>
|
|
% endif
|
|
<div class="xblock-display-title">
|
|
% if selectable:
|
|
<input type="checkbox" name="library-component" id="${xblock.location}"
|
|
class="header-library-checkbox" ${'checked="checked"' if is_selected else ''}>
|
|
<label for="${xblock.location}" class="xblock-display-name header-library-checkbox-label">
|
|
<span class="sr-only">${_("Select this problem")}</span>
|
|
${label}
|
|
</label>
|
|
% else:
|
|
% if upstream_info.upstream_ref:
|
|
% if upstream_info.error_message:
|
|
<div class="library-info-icon two-icons" data-tooltip="${_("The referenced library or library object is not available.")}">
|
|
<!-- "library" icon from https://fonts.google.com/icons?selected=Material+Symbols+Outlined:newsstand:FILL@0;wght@400;GRAD@0;opsz@24&icon.size=24 -->
|
|
<svg role="img" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 -960 960 960" fill="currentColor" style="vertical-align: middle;">
|
|
<path d="M80-160v-80h800v80H80Zm80-160v-320h80v320h-80Zm160 0v-480h80v480h-80Zm160 0v-480h80v480h-80Zm280 0L600-600l70-40 160 280-70 40Z"/>
|
|
</svg>
|
|
<!-- "broken link" icon from https://fonts.google.com/icons?selected=Material+Symbols+Outlined:link_off:FILL@0;wght@400;GRAD@0;opsz@24&icon.size=24&icon.color=%235f6368&icon.query=link -->
|
|
<svg role="img" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 -960 960 960" fill="currentColor" style="vertical-align: middle;">
|
|
<path d="m770-302-60-62q40-11 65-42.5t25-73.5q0-50-35-85t-85-35H520v-80h160q83 0 141.5 58.5T880-480q0 57-29.5 105T770-302ZM634-440l-80-80h86v80h-6ZM792-56 56-792l56-56 736 736-56 56ZM440-280H280q-83 0-141.5-58.5T80-480q0-69 42-123t108-71l74 74h-24q-50 0-85 35t-35 85q0 50 35 85t85 35h160v80ZM320-440v-80h65l79 80H320Z"/>
|
|
</svg>
|
|
<span class="sr-only">${_("The referenced library or library object is not available.")}</span>
|
|
</div>
|
|
% elif upstream_info.ready_to_sync:
|
|
<button class="library-info-icon two-icons library-sync-button sync-state" data-tooltip="${Text(_("The linked {upstream_name} has updates available.")).format(upstream_name=upstream_info.upstream_name)}">
|
|
<!-- "library" icon from https://fonts.google.com/icons?selected=Material+Symbols+Outlined:newsstand:FILL@0;wght@400;GRAD@0;opsz@24&icon.size=24 -->
|
|
<svg role="img" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 -960 960 960" fill="currentColor" style="vertical-align: middle;">
|
|
<path d="M80-160v-80h800v80H80Zm80-160v-320h80v320h-80Zm160 0v-480h80v480h-80Zm160 0v-480h80v480h-80Zm280 0L600-600l70-40 160 280-70 40Z"/>
|
|
</svg>
|
|
<!-- "sync" icon from https://fonts.google.com/icons?selected=Material+Symbols+Outlined:sync:FILL@0;wght@400;GRAD@0;opsz@24&icon.size=24&icon.color=%235f6368&icon.query=sync&icon.platform=web -->
|
|
<svg role="img" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 -960 960 960" fill="currentColor" style="vertical-align: middle;">
|
|
<path d="M160-160v-80h110l-16-14q-52-46-73-105t-21-119q0-111 66.5-197.5T400-790v84q-72 26-116 88.5T240-478q0 45 17 87.5t53 78.5l10 10v-98h80v240H160Zm400-10v-84q72-26 116-88.5T720-482q0-45-17-87.5T650-648l-10-10v98h-80v-240h240v80H690l16 14q49 49 71.5 106.5T800-482q0 111-66.5 197.5T560-170Z"/>
|
|
</svg>
|
|
<span class="sr-only">${_("The linked library object has updates available.")}</span>
|
|
</button>
|
|
% elif len(upstream_info.downstream_customized) > 0:
|
|
<div class="library-info-icon two-icons" data-tooltip="${_("This library reference has course overrides applied.")}">
|
|
<!-- "library" icon from https://fonts.google.com/icons?selected=Material+Symbols+Outlined:newsstand:FILL@0;wght@400;GRAD@0;opsz@24&icon.size=24 -->
|
|
<svg role="img" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 -960 960 960" fill="currentColor" style="vertical-align: middle;">
|
|
<path d="M80-160v-80h800v80H80Zm80-160v-320h80v320h-80Zm160 0v-480h80v480h-80Zm160 0v-480h80v480h-80Zm280 0L600-600l70-40 160 280-70 40Z"/>
|
|
</svg>
|
|
<!-- "call split" icon from https://fonts.google.com/icons?selected=Material+Symbols+Outlined:call_split:FILL@0;wght@400;GRAD@0;opsz@24&icon.size=24&icon.color=%235f6368&icon.query=fork -->
|
|
<svg role="img" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 -960 960 960" fill="currentColor" style="vertical-align: middle;">
|
|
<path d="M440-160v-304L240-664v104h-80v-240h240v80H296l224 224v336h-80Zm154-376-58-58 128-126H560v-80h240v240h-80v-104L594-536Z"/>
|
|
</svg>
|
|
<span class="sr-only">${_("This library reference has course overrides applied.")}</span>
|
|
</div>
|
|
% else:
|
|
<div class="library-info-icon" data-tooltip="${Text(_("This is referenced via {upstream_name}")).format(upstream_name=upstream_info.upstream_name)}">
|
|
<!-- "library" icon from https://fonts.google.com/icons?selected=Material+Symbols+Outlined:newsstand:FILL@0;wght@400;GRAD@0;opsz@24&icon.size=24 -->
|
|
<svg role="img" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 -960 960 960" fill="currentColor" style="vertical-align: middle;">
|
|
<path d="M80-160v-80h800v80H80Zm80-160v-320h80v320h-80Zm160 0v-480h80v480h-80Zm160 0v-480h80v480h-80Zm280 0L600-600l70-40 160 280-70 40Z"/>
|
|
</svg>
|
|
<span class="sr-only">${_("This item is linked to a library item.")}</span>
|
|
</div>
|
|
% endif
|
|
% endif
|
|
<span class="xblock-display-name">${label}</span>
|
|
% endif
|
|
% if selected_groups_label:
|
|
<p class="xblock-group-visibility-label">${selected_groups_label}</p>
|
|
% endif
|
|
</div>
|
|
</div>
|
|
<div class="header-actions">
|
|
<ul class="actions-list nav-dd ui-right">
|
|
% if can_edit_title and not can_edit:
|
|
<li class="action-item action-edit">
|
|
<button data-tooltip=${_('Edit Title')} class="btn-default action-edit title-edit-button only-for-lib-components">
|
|
<span class="icon fa fa-pencil" aria-hidden="true"></span>
|
|
<span class="action-button-text">${_("Edit Title")}</span>
|
|
</button>
|
|
</li>
|
|
% endif
|
|
% if not is_root:
|
|
% if upstream_info.ready_to_sync:
|
|
<li class="action-item">
|
|
<button
|
|
class="btn-default library-sync-button action-button"
|
|
data-tooltip="${_("Update available - click to sync")}"
|
|
>
|
|
<span class="icon fa fa-refresh" aria-hidden="true"></span>
|
|
<span class="action-button-text">${_("Update available")}</span>
|
|
</button>
|
|
</li>
|
|
% endif
|
|
% if use_tagging:
|
|
<li class="action-item tag-count" data-locator="${xblock.location}"></li>
|
|
% endif
|
|
% if not show_inline and can_edit:
|
|
<li class="action-item action-edit">
|
|
<button class="btn-default edit-button action-button" data-usage-id=${xblock.scope_ids.usage_id}>
|
|
<span class="icon fa fa-pencil" aria-hidden="true"></span>
|
|
<span class="action-button-text">${_("Edit")}</span>
|
|
</button>
|
|
</li>
|
|
% endif
|
|
<li class="action-item action-actions-menu nav-item">
|
|
<button data-tooltip="${_("Actions")}" class="btn-default show-actions-menu-button action-button">
|
|
<span class="icon fa fa-ellipsis-v" aria-hidden="true"></span>
|
|
<span class="sr">${_("Actions")}</span>
|
|
</button>
|
|
<div class="wrapper wrapper-nav-sub" style="right: -10px; top: 45px;">
|
|
<div class="nav-sub">
|
|
<ul>
|
|
% if not show_inline:
|
|
% if can_edit_visibility:
|
|
<li class="nav-item">
|
|
<a class="access-button" href="#" role="button">${_("Manage Access")}</a>
|
|
</li>
|
|
% endif
|
|
% if can_move:
|
|
<li class="nav-item">
|
|
<a class="move-button" href="#" role="button">${_("Move")}</a>
|
|
</li>
|
|
% endif
|
|
% if use_tagging:
|
|
<li class="nav-item">
|
|
<a class="manage-tags-button" href="#" role="button">${_("Manage Tags")}</a>
|
|
</li>
|
|
% endif
|
|
% if is_course:
|
|
<!--
|
|
Only show the "Copy to Clipboard" button for xblocks inside courses since
|
|
the copy/paste functionality is not yet implemented for LibraryContent.
|
|
-->
|
|
<li class="nav-item">
|
|
<a class="copy-button" href="#" role="button">${_("Copy to Clipboard")}</a>
|
|
</li>
|
|
% endif
|
|
% if can_add:
|
|
<li class="nav-item">
|
|
<a class="duplicate-button" href="#" role="button">${_("Duplicate")}</a>
|
|
</li>
|
|
% endif
|
|
% endif
|
|
% if can_delete:
|
|
<li class="nav-item">
|
|
<a class="delete-button" href="#" role="button">${_("Delete")}</a>
|
|
</li>
|
|
% endif
|
|
% if can_unlink:
|
|
<li class="nav-item">
|
|
<a class="unlink-button" href="#" role="button">${_("Unlink from Library")}</a>
|
|
</li>
|
|
% endif
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
% if is_reorderable and can_move:
|
|
<li class="action-item action-drag">
|
|
<span data-tooltip="${_('Drag to reorder')}" class="drag-handle action"></span>
|
|
</li>
|
|
% endif
|
|
% endif
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
% if not is_root:
|
|
<div class="wrapper-xblock-message xblock-validation-messages" data-locator="${xblock.location}"/>
|
|
% if xblock_url and not has_not_configured_message:
|
|
<div class="xblock-header-secondary">
|
|
<div class="meta-info">${_('This block contains multiple components.')}</div>
|
|
<ul class="actions-list">
|
|
<li class="action-item action-view">
|
|
<a href="${xblock_url}" class="action-button xblock-view-action-button">
|
|
## Translators: this is a verb describing the action of viewing more details
|
|
<span class="action-button-text">${('View')}</span>
|
|
<span class="icon fa fa-arrow-right" aria-hidden="true"></span>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
% endif
|
|
% endif
|
|
</header>
|
|
|
|
% if is_root:
|
|
<div class="wrapper-xblock-message xblock-validation-messages" data-locator="${xblock.location}"/>
|
|
% endif
|
|
|
|
% if show_preview:
|
|
% if is_root or not xblock_url:
|
|
% if not is_root and language:
|
|
<article class="xblock-render" lang="${language}">
|
|
% else:
|
|
<article class="xblock-render">
|
|
% endif
|
|
${content | n, decode.utf8}
|
|
</article>
|
|
% else:
|
|
<div class="xblock-message-area">
|
|
${content | n, decode.utf8}
|
|
</div>
|
|
% endif
|
|
% endif
|
|
|
|
% if not is_root:
|
|
<!-- footer for xblock_aside -->
|
|
</section>
|
|
|
|
% if is_reorderable:
|
|
</li>
|
|
% else:
|
|
</div>
|
|
% endif
|
|
% endif
|