feat: add full screen modal option to base_modal (#38001)

Adds a "Fullscreen" button to the iframe editors for advanced XBlocks
This commit is contained in:
Rômulo Penido
2026-02-27 13:12:04 -03:00
committed by GitHub
parent e1757ebd1e
commit 85e81b32e4
5 changed files with 107 additions and 6 deletions

View File

@@ -21,6 +21,7 @@
* primaryActionButtonType: A string to be used as type for primary action button.
* primaryActionButtonTitle: A string to be used as title for primary action button.
* showEditorModeButtons: Whether to show editor mode button in the modal header.
* showFullscreenButton: Whether to show fullscreen button in the modal header.
*/
define(['jquery', 'underscore', 'gettext', 'js/views/baseview'],
function($, _, gettext, BaseView) {
@@ -43,7 +44,8 @@ define(['jquery', 'underscore', 'gettext', 'js/views/baseview'],
addPrimaryActionButton: false,
primaryActionButtonType: 'save',
primaryActionButtonTitle: gettext('Save'),
showEditorModeButtons: true
showEditorModeButtons: true,
showFullscreenButton: false,
}),
initialize: function() {
@@ -71,7 +73,8 @@ define(['jquery', 'underscore', 'gettext', 'js/views/baseview'],
title: this.getTitle(),
modalSRTitle: this.options.modalSRTitle,
showEditorModeButtons: this.options.showEditorModeButtons,
viewSpecificClasses: this.options.viewSpecificClasses
viewSpecificClasses: this.options.viewSpecificClasses,
showFullscreenButton: this.options.showFullscreenButton,
}));
this.addActionButtons();
this.renderContents();
@@ -83,9 +86,14 @@ define(['jquery', 'underscore', 'gettext', 'js/views/baseview'],
},
renderContents: function() {
var contentHtml = this.getContentHtml();
const contentHtml = this.getContentHtml();
// xss-lint: disable=javascript-jquery-html
this.$('.modal-content').html(contentHtml);
const fullscreenButton = this.$('.fullscreen-button');
if (fullscreenButton.length) {
fullscreenButton.bind('click', this.toggleFullscreen.bind(this));
}
},
/**
@@ -106,6 +114,7 @@ define(['jquery', 'underscore', 'gettext', 'js/views/baseview'],
// after showing and resizing, send focus
this.$el.find(this.options.modalWindowClass).focus();
}
},
hide: function() {
@@ -120,6 +129,10 @@ define(['jquery', 'underscore', 'gettext', 'js/views/baseview'],
} catch (e) {
console.error(e);
}
const fullscreenButton = this.$('.fullscreen-button');
if (fullscreenButton.length) {
fullscreenButton.unbind('click');
}
// Completely remove the modal from the DOM
this.undelegateEvents();
@@ -195,11 +208,25 @@ define(['jquery', 'underscore', 'gettext', 'js/views/baseview'],
this.getActionBar().find('.action-' + type).prop('disabled', true).addClass('is-disabled');
},
toggleFullscreen: function() {
this.$('.fullscreen-button .icon').toggleClass('fa-expand fa-compress');
this.$('.modal-editor').toggleClass(`modal-${this.options.modalSize} modal-fullscreen`);
this.resize();
},
resize: function() {
var top, left, modalWindow, modalWidth, modalHeight,
availableWidth, availableHeight, maxWidth, maxHeight;
modalWindow = this.$el.find(this.options.modalWindowClass);
if (modalWindow.hasClass('modal-fullscreen')) {
// Remove previously set width and height from the modal window
modalWindow.css({
top: '',
left: '',
});
return;
}
availableWidth = $(window).width();
availableHeight = $(window).height();
maxWidth = availableWidth * 0.98;

View File

@@ -21,7 +21,8 @@ function($, _, Backbone, gettext, BaseModal, ViewUtils, XBlockViewUtils, XBlockE
viewSpecificClasses: 'modal-editor confirm',
// Translators: "title" is the name of the current component being edited.
titleFormat: gettext('Editing: {title}'),
addPrimaryActionButton: true
addPrimaryActionButton: true,
showFullscreenButton: true,
}),
initialize: function() {
@@ -127,6 +128,7 @@ function($, _, Backbone, gettext, BaseModal, ViewUtils, XBlockViewUtils, XBlockE
} else {
this.$('.modal-window-title').text(title);
}
this.getXBlockUpstreamLink();
// If the xblock is not using custom buttons then choose which buttons to show
@@ -292,8 +294,7 @@ function($, _, Backbone, gettext, BaseModal, ViewUtils, XBlockViewUtils, XBlockE
$input.focus().select();
$(event.target).remove();
return true;
}
},
});
return EditXBlockModal;

View File

@@ -452,12 +452,31 @@ body,
line-height: 28px;
}
.fullscreen-button {
color: $primary-base;
height: 44px;
width: 44px;
border-radius: 22px;
&:hover {
border-color: $primary-base;
}
&:focus {
border-color: $primary-base;
}
}
.xblock-actions {
border-top: 1px solid $border-color;
background-color: $white;
display: flex;
justify-content: flex-end;
ul {
margin-left: auto;
}
.action-button {
background-color: $transparent;
border: 1px solid $transparent;

View File

@@ -308,6 +308,14 @@
bottom: 30px;
}
}
.fullscreen-button {
height: 44px;
width: 44px;
position: absolute;
right: 30px;
z-index: 10;
}
}
@@ -391,6 +399,48 @@
}
}
// fullscreen modals - component editors
.modal-fullscreen {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
// Set the components to flex so that they can grow
div,
form {
display: flex;
flex-direction: column;
flex-grow: 1;
// Set the header to not grow
header,
&.modal-header {
flex-grow: 0;
}
}
ul {
flex-grow: 1;
// Reset the divs inside the ul to preserve previous styling
div,
form {
display: unset;
flex-direction: unset;
flex-grow: unset;
}
}
&.modal-editor {
.modal-content {
padding: 0px;
}
}
}
// specific modal overrides

View File

@@ -3,6 +3,9 @@
role="dialog">
<div class="modal-window-overlay"></div>
<div class="modal-window <%- viewSpecificClasses %> modal-<%- size %> modal-type-<%- type %>" tabindex="-1" aria-labelledby="modal-window-title">
<% if (showFullscreenButton) { %>
<button class="btn-default fullscreen-button" aria-label="<%- gettext("Toggle Fullscreen") %>"><span class="icon fa fa-expand"></span></button>
<% } %>
<div class="<%- name %>-modal">
<% if (title || modalSRTitle || showEditorModeButtons) { %>
<div class="modal-header">
@@ -29,3 +32,4 @@
</div>
</div>
</div>