From 4951a1f55653b69878382041edeeb3f758c433a6 Mon Sep 17 00:00:00 2001 From: Yusuf Musleh Date: Mon, 23 Oct 2023 16:48:15 +0300 Subject: [PATCH 1/4] feat: Add Units Taxonomy Tags drawer This adds "Manage Tags" action in the units' dropdown that opens up a side drawer containing an iframe to the course authoring mfe that will handle the taxonomy tags UI for the unit. Clicking outside the side drawer or on the x in the iframe closes the side drawer. --- cms/djangoapps/contentstore/utils.py | 15 ++++++++ cms/djangoapps/contentstore/views/course.py | 2 + cms/static/js/views/course_outline.js | 41 +++++++++++++++++++++ cms/static/sass/_build-v1.scss | 1 + cms/static/sass/elements/_drawer.scss | 30 +++++++++++++++ cms/templates/course_outline.html | 5 ++- cms/templates/js/course-outline.underscore | 3 ++ 7 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 cms/static/sass/elements/_drawer.scss diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py index 48fc2c962cf1..266cb4b6d437 100644 --- a/cms/djangoapps/contentstore/utils.py +++ b/cms/djangoapps/contentstore/utils.py @@ -446,6 +446,21 @@ def get_taxonomy_list_url(): return taxonomy_list_url +def get_taxonomy_tags_widget_url(course_locator) -> str: + """ + Gets course authoring microfrontend URL for taxonomy tags drawer widget view. + + The `content_id` needs to be appended to the end of the URL when using it. + """ + taxonomy_tags_widget_url = None + # Uses the same waffle flag as taxonomy list page + if use_tagging_taxonomy_list_page(): + mfe_base_url = get_course_authoring_url(course_locator) + if mfe_base_url: + taxonomy_tags_widget_url = f'{mfe_base_url}/tagging/components/widget/' + return taxonomy_tags_widget_url + + def course_import_olx_validation_is_enabled(): """ Check if course olx validation is enabled on course import. diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index a55bb3db9a53..b42c011c4b20 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -105,6 +105,7 @@ get_lms_link_for_item, get_proctored_exam_settings_url, get_course_outline_url, + get_taxonomy_tags_widget_url, get_studio_home_url, get_updates_url, get_advanced_settings_url, @@ -688,6 +689,7 @@ def course_index(request, course_key): 'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_block.id), 'advance_settings_url': reverse_course_url('advanced_settings_handler', course_block.id), 'proctoring_errors': proctoring_errors, + 'taxonomy_tags_widget_url': get_taxonomy_tags_widget_url(course_block.id), }) diff --git a/cms/static/js/views/course_outline.js b/cms/static/js/views/course_outline.js index 0351f2e175d1..91c990a1cfb5 100644 --- a/cms/static/js/views/course_outline.js +++ b/cms/static/js/views/course_outline.js @@ -458,6 +458,43 @@ function( event.stopPropagation(); }, + closeManageTagsDrawer(drawer, drawerCover) { + $(drawerCover).css('display', 'none'); + $(drawer).empty(); + $(drawer).css('display', 'none'); + $('body').removeClass('drawer-open'); + }, + + openManageTagsDrawer(event) { + const drawer = document.querySelector("#manage-tags-drawer"); + const drawerCover = document.querySelector(".drawer-cover") + const article = document.querySelector('[data-taxonomy-tags-widget-url]'); + const taxonomyTagsWidgetUrl = $(article).attr('data-taxonomy-tags-widget-url'); + const contentId = this.model.get('id'); + + // Add handler to close drawer when dark background is clicked + $(drawerCover).click(function() { + this.closeManageTagsDrawer(drawer, drawerCover); + }.bind(this)); + + // Add event listen to close drawer when close button is clicked from within the Iframe + window.addEventListener("message", function (event) { + if (event.data === 'closeManageTagsDrawer') { + this.closeManageTagsDrawer(drawer, drawerCover) + } + }.bind(this)); + + $(drawerCover).css('display', 'block'); + // xss-lint: disable=javascript-jquery-html + $(drawer).html( + `` + ); + $(drawer).css('display', 'block'); + + // Prevent background from being scrollable when drawer is open + $('body').addClass('drawer-open'); + }, + addButtonActions: function(element) { XBlockOutlineView.prototype.addButtonActions.apply(this, arguments); element.find('.configure-button').click(function(event) { @@ -478,6 +515,10 @@ function( event.preventDefault(); this.copyXBlock(); }); + element.find('.manage-tags-button').click((event) => { + event.preventDefault(); + this.openManageTagsDrawer(); + }); element.find('.paste-component-button').click((event) => { event.preventDefault(); this.pasteUnit(event); diff --git a/cms/static/sass/_build-v1.scss b/cms/static/sass/_build-v1.scss index fefd095e21a7..178f6b167473 100644 --- a/cms/static/sass/_build-v1.scss +++ b/cms/static/sass/_build-v1.scss @@ -55,6 +55,7 @@ @import 'elements/uploaded-assets'; // layout for asset tables @import 'elements/creative-commons'; @import 'elements/tooltip'; +@import 'elements/drawer'; // +Base - Specific Views // ==================== diff --git a/cms/static/sass/elements/_drawer.scss b/cms/static/sass/elements/_drawer.scss new file mode 100644 index 000000000000..c18073be9864 --- /dev/null +++ b/cms/static/sass/elements/_drawer.scss @@ -0,0 +1,30 @@ +// studio - elements - side drawers +// ==================== + +.drawer-cover { + @extend %ui-depth3; + + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.8); +} + +.drawer { + @extend %ui-depth4; + + display: none; + position: fixed; + top: 0; + right: 0; + width: 33.33vw; + height: 100vh; + background-color: $gray-l4; +} + +body.drawer-open { + overflow: hidden; +} diff --git a/cms/templates/course_outline.html b/cms/templates/course_outline.html index 0d1773e7c188..e5959867be86 100644 --- a/cms/templates/course_outline.html +++ b/cms/templates/course_outline.html @@ -281,7 +281,7 @@

${_("Page Actions")}

assets_url = reverse('assets_handler', kwargs={'course_key_string': str(course_locator.course_key)}) %>

${_("Course Outline")}

-
+
@@ -321,4 +321,7 @@

${_("Changing the content learners see")}

+ +
+
diff --git a/cms/templates/js/course-outline.underscore b/cms/templates/js/course-outline.underscore index fa3d562196b4..1b707182a31f 100644 --- a/cms/templates/js/course-outline.underscore +++ b/cms/templates/js/course-outline.underscore @@ -192,6 +192,9 @@ if (is_proctored_exam) { + <% } %> <% if (xblockInfo.isDuplicable()) { %> <% } %> + + <% if (xblockInfo.isVertical() && typeof useTaggingTaxonomyListPage !== "undefined" && useTaggingTaxonomyListPage) { %> +
  • + + + ? + <%- gettext('Manage Tags') %> + +
  • + <% } %> + <% if (typeof enableCopyPasteUnits !== "undefined" && enableCopyPasteUnits) { %>