Commit 77192dce by Matjaz Gregoric

Set max-width of drag container to available width.

Measure the available width before rendering the drag container. Set
the drag-container's max-width to the measured available width.
parent aaf90993
...@@ -3,6 +3,18 @@ ...@@ -3,6 +3,18 @@
max-width: 770px; max-width: 770px;
margin: 0; margin: 0;
padding: 0; padding: 0;
position: relative;
}
.xblock--drag-and-drop .resize-detector {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
overflow: hidden;
pointer-events: none;
z-index: -1;
} }
.xblock--drag-and-drop .initial-load-spinner { .xblock--drag-and-drop .initial-load-spinner {
...@@ -64,6 +76,7 @@ ...@@ -64,6 +76,7 @@
/* drag-container holds the .items and the .target image */ /* drag-container holds the .items and the .target image */
.xblock--drag-and-drop .drag-container { .xblock--drag-and-drop .drag-container {
box-sizing: border-box;
width: auto; width: auto;
padding: 1%; padding: 1%;
background-color: #ebf0f2; background-color: #ebf0f2;
...@@ -122,6 +135,8 @@ ...@@ -122,6 +135,8 @@
.xblock--drag-and-drop .drag-container .item-bank .option { .xblock--drag-and-drop .drag-container .item-bank .option {
flex-shrink: 0; flex-shrink: 0;
flex-grow: 0;
max-width: 80%;
} }
} }
......
...@@ -2,6 +2,10 @@ function DragAndDropTemplates(configuration) { ...@@ -2,6 +2,10 @@ function DragAndDropTemplates(configuration) {
"use strict"; "use strict";
var h = virtualDom.h; var h = virtualDom.h;
var isMobileScreen = function() {
return window.matchMedia('screen and (max-width: 480px)').matches;
};
var itemSpinnerTemplate = function(item) { var itemSpinnerTemplate = function(item) {
if (!item.xhr_active) { if (!item.xhr_active) {
return null; return null;
...@@ -33,12 +37,12 @@ function DragAndDropTemplates(configuration) { ...@@ -33,12 +37,12 @@ function DragAndDropTemplates(configuration) {
if (item.widthPercent) { if (item.widthPercent) {
// The item bank container is often wider than the background image, and the // The item bank container is often wider than the background image, and the
// widthPercent is specified relative to the background image so we have to // widthPercent is specified relative to the background image so we have to
// convert it to pixels. But if the browser window / mobile screen is not as // convert it to pixels. But if the browser window is not as wide as the image,
// wide as the image, then the background image will be scaled down and this // then the background image will be scaled down and this pixel value would be too large,
// pixel value would be too large, so we also specify it as a max-width // so we also specify it as a max-width percentage.
// percentage. // On mobile, the image is never scaled down, so we don't specify the max-width.
style.width = (item.widthPercent / 100 * ctx.bg_image_width) + "px"; style.width = (item.widthPercent / 100 * ctx.bg_image_width) + "px";
style.maxWidth = item.widthPercent + "%"; style.maxWidth = isMobileScreen() ? 'none' : item.widthPercent + "%";
} }
return style; return style;
}; };
...@@ -627,9 +631,21 @@ function DragAndDropTemplates(configuration) { ...@@ -627,9 +631,21 @@ function DragAndDropTemplates(configuration) {
} }
}); });
bank_children = bank_children.concat(renderCollection(itemPlaceholderTemplate, items_placed, ctx)); bank_children = bank_children.concat(renderCollection(itemPlaceholderTemplate, items_placed, ctx));
var drag_container_style = {};
var target_img_style = {};
// If drag_container_max_width is null, we are going to render the container width after this render.
// To be able to accurately measure the natural container width, we have to set max-width of the target
// image to 100%, so that it doesn't expand the container.
if (ctx.drag_container_max_width === null) {
target_img_style.maxWidth = '100%';
} else {
drag_container_style.maxWidth = ctx.drag_container_max_width + 'px';
}
return ( return (
h('div.themed-xblock.xblock--drag-and-drop', main_element_properties, [ h('div.themed-xblock.xblock--drag-and-drop', main_element_properties, [
h('object.resize-detector', {
attributes: {type: 'text/html', tabindex: -1, data: 'about:blank'}
}),
problemTitle, problemTitle,
problemProgress, problemProgress,
h('div', [forwardKeyboardHelpButtonTemplate(ctx)]), h('div', [forwardKeyboardHelpButtonTemplate(ctx)]),
...@@ -637,12 +653,16 @@ function DragAndDropTemplates(configuration) { ...@@ -637,12 +653,16 @@ function DragAndDropTemplates(configuration) {
problemHeader, problemHeader,
h('p', {innerHTML: ctx.problem_html}), h('p', {innerHTML: ctx.problem_html}),
]), ]),
h('div.drag-container', {}, [ h('div.drag-container', {style: drag_container_style}, [
h('div.item-bank', item_bank_properties, bank_children), h('div.item-bank', item_bank_properties, bank_children),
h('div.target', {attributes: {'role': 'group', 'arial-label': gettext('Drop Targets')}}, [ h('div.target', {attributes: {'role': 'group', 'arial-label': gettext('Drop Targets')}}, [
itemFeedbackPopupTemplate(ctx), itemFeedbackPopupTemplate(ctx),
h('div.target-img-wrapper', [ h('div.target-img-wrapper', [
h('img.target-img', {src: ctx.target_img_src, alt: ctx.target_img_description}), h('img.target-img', {
src: ctx.target_img_src,
alt: ctx.target_img_description,
style: target_img_style
}),
renderCollection(zoneTemplate, ctx.zones, ctx) renderCollection(zoneTemplate, ctx.zones, ctx)
]), ]),
]), ]),
...@@ -692,7 +712,8 @@ function DragAndDropBlock(runtime, element, configuration) { ...@@ -692,7 +712,8 @@ function DragAndDropBlock(runtime, element, configuration) {
var root = $root[0]; var root = $root[0];
var state = undefined; var state = undefined;
var bgImgNaturalWidth = undefined; // pixel width of the background image (when not scaled) var bgImgNaturalWidth = undefined; // pixel width of the background image (when not scaled)
var containerMaxWidth = null; // measured and set after first render
var __vdom = virtualDom.h(); // blank virtual DOM var __vdom = virtualDom.h(); // blank virtual DOM
// Event string size limit. // Event string size limit.
...@@ -772,11 +793,17 @@ function DragAndDropBlock(runtime, element, configuration) { ...@@ -772,11 +793,17 @@ function DragAndDropBlock(runtime, element, configuration) {
// For the next one, we need to use addEventListener with useCapture 'true' in order // For the next one, we need to use addEventListener with useCapture 'true' in order
// to watch for load events on any child element, since load events do not bubble. // to watch for load events on any child element, since load events do not bubble.
element.addEventListener('load', webkitFix, true); element.addEventListener('load', webkitFix, true);
// Whenever the container div resizes, re-render to take new available width into account.
element.addEventListener('load', bindContainerResize, true);
// Re-render when window size changes.
$(window).on('resize', measureWidthAndRender);
// Remove the spinner and create a blank slate for virtualDom to take over. // Remove the spinner and create a blank slate for virtualDom to take over.
$root.empty(); $root.empty();
applyState(); measureWidthAndRender();
initDraggable(); initDraggable();
initDroppable(); initDroppable();
...@@ -787,6 +814,43 @@ function DragAndDropBlock(runtime, element, configuration) { ...@@ -787,6 +814,43 @@ function DragAndDropBlock(runtime, element, configuration) {
}); });
}; };
// Listens to the 'resize' event of the object element, which is absolutely positioned
// and fit to the edges of the container, so that its size always equals the container size.
// This hack is needed because not all browsers support native 'resize' events on arbitrary
// DOM elements.
var bindContainerResize = function(evt) {
var object = evt.target;
var $object = $(object);
if ($object.is('.resize-detector')) {
var last_width = $object.width();
var last_height = $object.height();
var raf_id = null;
object.contentDocument.defaultView.addEventListener('resize', function() {
cancelAnimationFrame(raf_id);
raf_id = requestAnimationFrame(function() {
var new_width = $object.width();
var new_height = $object.height();
if (last_width !== new_width || last_height !== new_height) {
last_width = new_width;
last_height = new_height;
measureWidthAndRender();
}
});
});
}
};
var measureWidthAndRender = function() {
// First set containerMaxWidth to null to hide the container.
containerMaxWidth = null;
// Render with container hidden to be able to measure max available width.
applyState();
// Mesure available width.
containerMaxWidth = $root.width();
// Re-render now that correct max-width is known.
applyState();
};
var runOnKey = function(evt, key, handler) { var runOnKey = function(evt, key, handler) {
if (evt.which === key) { if (evt.which === key) {
handler(evt); handler(evt);
...@@ -1058,13 +1122,13 @@ function DragAndDropBlock(runtime, element, configuration) { ...@@ -1058,13 +1122,13 @@ function DragAndDropBlock(runtime, element, configuration) {
state.screen_reader_messages = paragraphs.join(''); state.screen_reader_messages = paragraphs.join('');
// Remove the text on next redraw. This will make screen readers read the message again, // Remove the text after a short time. This will make screen readers read the message again,
// next time the user performs an action, even if next feedback message did not change from // next time the user performs an action, even if next feedback message did not change from
// last attempt (for example: if user drops the same item on two wrong zones one after another, // last attempt (for example: if user drops the same item on two wrong zones one after another,
// the negative feedback should be read out twice, not only on first drop). // the negative feedback should be read out twice, not only on first drop).
sr_clear_timeout = setTimeout(function() { sr_clear_timeout = setTimeout(function() {
state.screen_reader_messages = ''; state.screen_reader_messages = '';
}, 0); }, 250);
}; };
var publishEvent = function(data) { var publishEvent = function(data) {
...@@ -1731,6 +1795,8 @@ function DragAndDropBlock(runtime, element, configuration) { ...@@ -1731,6 +1795,8 @@ function DragAndDropBlock(runtime, element, configuration) {
configuration.mode === DragAndDropBlock.ASSESSMENT_MODE; configuration.mode === DragAndDropBlock.ASSESSMENT_MODE;
var context = { var context = {
hide_drag_container: containerMaxWidth === null,
drag_container_max_width: containerMaxWidth,
// configuration - parts that never change: // configuration - parts that never change:
bg_image_width: bgImgNaturalWidth, // Not stored in configuration since it's unknown on the server side bg_image_width: bgImgNaturalWidth, // Not stored in configuration since it's unknown on the server side
title_html: configuration.title, title_html: configuration.title,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment