feat: adds Library Content (v2) button to Studio Unit page (#35670)

Requires that v2 libraries are enabled.
This commit is contained in:
Navin Karkera
2024-10-21 23:02:54 +05:30
committed by GitHub
parent e2d6765637
commit 7e8fb4393e
16 changed files with 220 additions and 45 deletions

View File

@@ -0,0 +1,68 @@
/**
* Provides utilities to open and close the library content picker.
*
*/
define(['jquery', 'underscore', 'gettext', 'js/views/modals/base_modal'],
function($, _, gettext, BaseModal) {
'use strict';
var AddLibraryContent = BaseModal.extend({
options: $.extend({}, BaseModal.prototype.options, {
modalName: 'add-component-from-library',
modalSize: 'lg',
view: 'studio_view',
viewSpecificClasses: 'modal-add-component-picker confirm',
// Translators: "title" is the name of the current component being edited.
titleFormat: gettext('Add library content'),
addPrimaryActionButton: false,
}),
initialize: function() {
BaseModal.prototype.initialize.call(this);
// Add event listen to close picker when the iframe tells us to
const handleMessage = (event) => {
if (event.data?.type === 'pickerComponentSelected') {
var requestData = {
library_content_key: event.data.usageKey,
category: event.data.category,
}
this.refreshFunction(requestData);
this.hide();
}
};
this.messageListener = window.addEventListener("message", handleMessage);
this.cleanupListener = () => { window.removeEventListener("message", handleMessage) };
},
hide: function() {
BaseModal.prototype.hide.call(this);
this.cleanupListener();
},
/**
* Adds the action buttons to the modal.
*/
addActionButtons: function() {
this.addActionButton('cancel', gettext('Cancel'));
},
/**
* Show a component picker modal from library.
* @param contentPickerUrl Url for component picker
* @param refreshFunction A function to refresh the block after it has been updated
*/
showComponentPicker: function(contentPickerUrl, refreshFunction) {
this.contentPickerUrl = contentPickerUrl;
this.refreshFunction = refreshFunction;
this.render();
this.show();
},
getContentHtml: function() {
return `<iframe src="${this.contentPickerUrl}" onload="this.contentWindow.focus()" frameborder="0" style="width: 100%; height: 100%;"/>`;
},
});
return AddLibraryContent;
});

View File

@@ -3,8 +3,9 @@
*/
define(['jquery', 'underscore', 'gettext', 'js/views/baseview', 'common/js/components/utils/view_utils',
'js/views/components/add_xblock_button', 'js/views/components/add_xblock_menu',
'js/views/components/add_library_content',
'edx-ui-toolkit/js/utils/html-utils'],
function($, _, gettext, BaseView, ViewUtils, AddXBlockButton, AddXBlockMenu, HtmlUtils) {
function($, _, gettext, BaseView, ViewUtils, AddXBlockButton, AddXBlockMenu, AddLibraryContent, HtmlUtils) {
'use strict';
var AddXBlockComponent = BaseView.extend({
@@ -67,14 +68,32 @@ function($, _, gettext, BaseView, ViewUtils, AddXBlockButton, AddXBlockMenu, Htm
oldOffset = ViewUtils.getScrollOffset(this.$el);
event.preventDefault();
this.closeNewComponent(event);
ViewUtils.runOperationShowingMessage(
gettext('Adding'),
_.bind(this.options.createComponent, this, saveData, $element)
).always(function() {
// Restore the scroll position of the buttons so that the new
// component appears above them.
ViewUtils.setScrollOffset(self.$el, oldOffset);
});
if (saveData.type === 'library_v2') {
var modal = new AddLibraryContent();
modal.showComponentPicker(
this.options.libraryContentPickerUrl,
function(data) {
ViewUtils.runOperationShowingMessage(
gettext('Adding'),
_.bind(this.options.createComponent, this, data, $element),
).always(function() {
// Restore the scroll position of the buttons so that the new
// component appears above them.
ViewUtils.setScrollOffset(self.$el, oldOffset);
});
}.bind(this)
);
} else {
ViewUtils.runOperationShowingMessage(
gettext('Adding'),
_.bind(this.options.createComponent, this, saveData, $element),
).always(function() {
// Restore the scroll position of the buttons so that the new
// component appears above them.
ViewUtils.setScrollOffset(self.$el, oldOffset);
});
}
}
});

View File

@@ -214,7 +214,8 @@ function($, _, Backbone, gettext, BasePage,
var component = new AddXBlockComponent({
el: element,
createComponent: _.bind(self.createComponent, self),
collection: self.options.templates
collection: self.options.templates,
libraryContentPickerUrl: self.options.libraryContentPickerUrl,
});
component.render();
});
@@ -224,7 +225,7 @@ function($, _, Backbone, gettext, BasePage,
},
initializePasteButton() {
if (this.options.canEdit && !self.options.isIframeEmbed) {
if (this.options.canEdit && !this.options.isIframeEmbed) {
// We should have the user's clipboard status.
const data = this.options.clipboardData;
this.refreshPasteButton(data);
@@ -241,7 +242,7 @@ function($, _, Backbone, gettext, BasePage,
refreshPasteButton(data) {
// Do not perform any changes on paste button since they are not
// rendered on Library or LibraryContent pages
if (!this.isLibraryPage && !this.isLibraryContentPage && !self.options.isIframeEmbed) {
if (!this.isLibraryPage && !this.isLibraryContentPage && !this.options.isIframeEmbed) {
// 'data' is the same data returned by the "get clipboard status" API endpoint
// i.e. /api/content-staging/v1/clipboard/
if (this.options.canEdit && data.content) {