Skip to content

Commit

Permalink
feat: [FC-0070] add events and style for rendering Split xblock in ch…
Browse files Browse the repository at this point in the history
…romeless template
  • Loading branch information
ihor-romaniuk committed Feb 26, 2025
1 parent 2798f28 commit 01329d3
Show file tree
Hide file tree
Showing 13 changed files with 370 additions and 132 deletions.
6 changes: 6 additions & 0 deletions cms/static/images/advanced-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions cms/static/images/drag-and-drop-v2-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions cms/static/images/itembank-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions cms/static/images/library-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions cms/static/images/library_v2-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions cms/static/images/openassessment-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions cms/static/images/problem-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions cms/static/images/text-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions cms/static/images/video-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 28 additions & 1 deletion cms/static/js/views/components/add_xblock.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,37 @@ function($, _, gettext, BaseView, ViewUtils, AddXBlockButton, AddXBlockMenu, Add
},

showComponentTemplates: function(event) {
var type;
var type, parentLocator, model;
event.preventDefault();
event.stopPropagation();

type = $(event.currentTarget).data('type');
parentLocator = $(event.currentTarget).closest('.xblock[data-usage-id]').data('usage-id');
model = this.collection.models.find(function(item) { return item.type === type; }) || {};

try {
if (this.options.isIframeEmbed) {
window.parent.postMessage(
{
type: 'showComponentTemplates',
payload: {
type: type,
parentLocator: parentLocator,
model: {
type: model.type,
display_name: model.display_name,
templates: model.templates,
support_legend: model.support_legend,
},
}
}, document.referrer
);
}
return true;
} catch (e) {
console.error(e);
}

this.$('.new-component').slideUp(250);
this.$('.new-component-' + type).slideDown(250);
this.$('.new-component-' + type + ' div').focus();
Expand Down
182 changes: 89 additions & 93 deletions cms/static/js/views/pages/container.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,17 @@ function($, _, Backbone, gettext, BasePage,
this.listenTo(Backbone, 'move:onXBlockMoved', this.onXBlockMoved);
},

postMessageToParent: function(body, callbackFn = null) {
try {
window.parent.postMessage(body, document.referrer);
if (callbackFn) {
callbackFn();
}
} catch (e) {
console.error('Failed to post message:', e);
}
},

getViewParameters: function() {
return {
el: this.$('.wrapper-xblock'),
Expand Down Expand Up @@ -237,18 +248,14 @@ function($, _, Backbone, gettext, BasePage,
const scrollOffset = scrollOffsetString ? parseInt(scrollOffsetString, 10) : 0;

if (scrollOffset) {
try {
window.parent.postMessage(
{
type: 'scrollToXBlock',
message: 'Scroll to XBlock',
payload: { scrollOffset }
}, document.referrer
);
localStorage.removeItem('modalEditLastYPosition');
} catch (e) {
console.error(e);
}
self.postMessageToParent(
{
type: 'scrollToXBlock',
message: 'Scroll to XBlock',
payload: { scrollOffset }
},
() => localStorage.removeItem('modalEditLastYPosition')
);
}
}
},
Expand All @@ -272,13 +279,15 @@ function($, _, Backbone, gettext, BasePage,

renderAddXBlockComponents: function() {
var self = this;
if (self.options.canEdit && !self.options.isIframeEmbed) {
var isSplitTest = self.model.attributes.category === 'split_test';
if (self.options.canEdit && (!self.options.isIframeEmbed || isSplitTest)) {
this.$('.add-xblock-component').each(function(index, element) {
var component = new AddXBlockComponent({
el: element,
createComponent: _.bind(self.createComponent, self),
collection: self.options.templates,
libraryContentPickerUrl: self.options.libraryContentPickerUrl,
isIframeEmbed: self.options.isIframeEmbed,
});
component.render();
});
Expand All @@ -288,7 +297,8 @@ function($, _, Backbone, gettext, BasePage,
},

initializePasteButton() {
if (this.options.canEdit && !this.options.isIframeEmbed) {
var isSplitTest = this.model.attributes.category === 'split_test';
if (this.options.canEdit && (!this.options.isIframeEmbed || isSplitTest)) {
// We should have the user's clipboard status.
const data = this.options.clipboardData;
this.refreshPasteButton(data);
Expand All @@ -305,7 +315,8 @@ 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 && !this.options.isIframeEmbed) {
var isSplitTest = this.model.attributes.category === 'split_test';
if (!this.isLibraryPage && !this.isLibraryContentPage && (!this.options.isIframeEmbed || isSplitTest)) {
// '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) {
Expand Down Expand Up @@ -340,17 +351,11 @@ function($, _, Backbone, gettext, BasePage,
/** The user has clicked on the "Paste Component button" */
pasteComponent(event) {
event.preventDefault();
try {
if (this.options.isIframeEmbed) {
window.parent.postMessage(
{
type: 'pasteComponent',
payload: {}
}, document.referrer
);
}
} catch (e) {
console.error(e);
if (this.options.isIframeEmbed) {
this.postMessageToParent({
type: 'pasteComponent',
payload: {},
});
}
// Get the ID of the container (usually a unit/vertical) that we're pasting into:
const parentElement = this.findXBlockElement(event.target);
Expand All @@ -375,6 +380,13 @@ function($, _, Backbone, gettext, BasePage,
placeholderElement.remove();
});
}).done((data) => {
if (this.options.isIframeEmbed) {
this.postMessageToParent({
type: 'hideProcessingNotification',
message: 'Hide processing notification',
payload: {},
});
}
const {
conflicting_files: conflictingFiles,
error_files: errorFiles,
Expand Down Expand Up @@ -646,17 +658,11 @@ function($, _, Backbone, gettext, BasePage,
subMenu.classList.toggle('is-shown');

if (!subMenu.classList.contains('is-shown') && this.options.isIframeEmbed) {
try {
window.parent.postMessage(
{
type: 'toggleCourseXBlockDropdown',
message: 'Adjust the height of the dropdown menu',
payload: { courseXBlockDropdownHeight: 0 }
}, document.referrer
);
} catch (error) {
console.error(error);
}
this.postMessageToParent({
type: 'toggleCourseXBlockDropdown',
message: 'Adjust the height of the dropdown menu',
payload: { courseXBlockDropdownHeight: 0 }
});
}

// Calculate the viewport height and the dropdown menu height.
Expand All @@ -668,33 +674,21 @@ function($, _, Backbone, gettext, BasePage,

if (courseUnitXBlockIframeHeight < courseXBlockDropdownHeight) {
// If the dropdown menu is taller than the iframe, adjust the height of the dropdown menu.
try {
window.parent.postMessage(
{
type: 'toggleCourseXBlockDropdown',
message: 'Adjust the height of the dropdown menu',
payload: { courseXBlockDropdownHeight },
}, document.referrer
);
} catch (error) {
console.error(error);
}
this.postMessageToParent({
type: 'toggleCourseXBlockDropdown',
message: 'Adjust the height of the dropdown menu',
payload: { courseXBlockDropdownHeight },
});
} else if ((courseXBlockDropdownHeight + clickYPosition) > courseUnitXBlockIframeHeight) {
if (courseXBlockDropdownHeight > courseUnitXBlockIframeHeight / 2) {
// If the dropdown menu is taller than half the iframe, send a message to adjust its height.
try {
window.parent.postMessage(
{
type: 'toggleCourseXBlockDropdown',
message: 'Adjust the height of the dropdown menu',
payload: {
courseXBlockDropdownHeight: courseXBlockDropdownHeight / 2,
},
}, document.referrer
);
} catch (error) {
console.error(error);
}
this.postMessageToParent({
type: 'toggleCourseXBlockDropdown',
message: 'Adjust the height of the dropdown menu',
payload: {
courseXBlockDropdownHeight: courseXBlockDropdownHeight / 2,
},
});
} else {
// Move the dropdown menu upward to prevent it from overflowing out of the viewport.
if (this.options.isIframeEmbed) {
Expand All @@ -719,17 +713,11 @@ function($, _, Backbone, gettext, BasePage,
},

openManageTags: function(event) {
try {
if (this.options.isIframeEmbed) {
window.parent.postMessage(
{
type: 'openManageTags',
payload: {}
}, document.referrer
);
}
} catch (e) {
console.error(e);
if (this.options.isIframeEmbed) {
this.postMessageToParent({
type: 'openManageTags',
payload: {},
});
}
const taxonomyTagsWidgetUrl = this.model.get('taxonomy_tags_widget_url');
const contentId = this.findXBlockElement(event.target).data('locator');
Expand Down Expand Up @@ -909,15 +897,13 @@ function($, _, Backbone, gettext, BasePage,
this.deleteComponent(this.findXBlockElement(event.target));
},

createPlaceholderElement: function() {
return $('<div/>', {class: 'studio-xblock-wrapper'});
},

createComponent: function(template, target, iframeMessageData) {
// A placeholder element is created in the correct location for the new xblock
// and then onNewXBlock will replace it with a rendering of the xblock. Note that
// for xblocks that can't be replaced inline, the entire parent will be refreshed.
var parentElement = this.findXBlockElement(target),
self = this,
isSplitTest = this.model.attributes.category === 'split_test',
parentLocator = parentElement.data('locator'),
buttonPanel = target?.closest('.add-xblock-component'),
listPanel = buttonPanel?.prev(),
Expand All @@ -929,7 +915,7 @@ function($, _, Backbone, gettext, BasePage,
placeholderElement,
$container;

if (this.options.isIframeEmbed) {
if (this.options.isIframeEmbed && !isSplitTest) {
$container = $('ol.reorderable-container.ui-sortable');
scrollOffset = 0;
} else {
Expand All @@ -939,14 +925,31 @@ function($, _, Backbone, gettext, BasePage,

placeholderElement = $placeholderEl.appendTo($container);

if (this.options.isIframeEmbed) {
if (iframeMessageData.payload.data && iframeMessageData.type === 'addXBlock') {
return this.onNewXBlock(placeholderElement, scrollOffset, false, iframeMessageData.payload.data);
}
if (this.options.isIframeEmbed && !isSplitTest) {
if (iframeMessageData.payload.data && iframeMessageData.type === 'addXBlock') {
return this.onNewXBlock(placeholderElement, scrollOffset, false, iframeMessageData.payload.data);
}
}

if (this.options.isIframeEmbed && isSplitTest) {
this.postMessageToParent({
type: 'addNewComponent',
message: 'Add new XBlock',
payload: {},
});
}

return $.postJSON(this.getURLRoot() + '/', requestData,
_.bind(this.onNewXBlock, this, placeholderElement, scrollOffset, false))
.success(function () {
if (self.options.isIframeEmbed && isSplitTest) {
self.postMessageToParent({
type: 'hideProcessingNotification',
message: 'Hide processing notification',
payload: {}
});
}
})
.fail(function() {
// Remove the placeholder if the update failed
placeholderElement.remove();
Expand All @@ -966,17 +969,11 @@ function($, _, Backbone, gettext, BasePage,
placeholderElement = $placeholderEl.insertAfter(xblockElement);

if (this.options.isIframeEmbed) {
try {
window.parent.postMessage(
{
type: 'scrollToXBlock',
message: 'Scroll to XBlock',
payload: { scrollOffset: xblockElement.height() }
}, document.referrer
);
} catch (e) {
console.error(e);
}
this.postMessageToParent({
type: 'scrollToXBlock',
message: 'Scroll to XBlock',
payload: { scrollOffset: xblockElement.height() }
});

const messageHandler = ({ data }) => {
if (data && data.type === 'completeXBlockDuplicating') {
Expand Down Expand Up @@ -1028,7 +1025,6 @@ function($, _, Backbone, gettext, BasePage,
getSelectedLibraryComponents: function() {
var self = this;
var locator = this.$el.find('.studio-xblock-wrapper').data('locator');
console.log(ModuleUtils);
$.getJSON(
ModuleUtils.getUpdateUrl(locator) + '/handler/get_block_ids',
function(data) {
Expand Down
Loading

0 comments on commit 01329d3

Please sign in to comment.