mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
MDL-74054 questions: Fix question bank header widths
Chrome ignores min-width on table headers with table-layout:fixed, meaning that question bank headers could be resized so that the controls were overlapping, and could be too narrow by default. This removes min-width: min-content in the headers and instead uses Javascript to calculate a constrain a min width based on the content of the headers.
This commit is contained in:
parent
216060b637
commit
0ac2936c11
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -48,6 +48,9 @@ let currentHeader;
|
||||
/** Current mouse x postion, to track mouse event on a table header */
|
||||
let currentX;
|
||||
|
||||
/** Minimum size for the column currently being resized. */
|
||||
let currentMin;
|
||||
|
||||
/**
|
||||
* Flag to temporarily prevent move and resize handles from being shown or hidden.
|
||||
*
|
||||
@ -129,6 +132,21 @@ const serialiseColumnSizes = (uiRoot) => {
|
||||
return JSON.stringify(columnSizes);
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the minimum width for a header, based on the width of its contents.
|
||||
*
|
||||
* This is to simulate `min-width: min-content;`, which doesn't work on Chrome because
|
||||
* min-width is ignored width `table-layout: fixed;`.
|
||||
*
|
||||
* @param {Element} header The table header
|
||||
* @return {Number} The minimum width in pixels
|
||||
*/
|
||||
const getMinWidth = (header) => {
|
||||
const contents = Array.from(header.querySelector('.header-text').children);
|
||||
const contentWidth = contents.reduce((width, contentElement) => width + contentElement.getBoundingClientRect().width, 0);
|
||||
return Math.ceil(contentWidth);
|
||||
};
|
||||
|
||||
/**
|
||||
* Render resize handles in each container.
|
||||
*
|
||||
@ -141,6 +159,11 @@ const setUpResizeHandles = (uiRoot) => {
|
||||
const resizeActions = uiRoot.querySelectorAll(SELECTORS.resizeAction);
|
||||
resizeActions.forEach(resizeAction => {
|
||||
const headerContainer = resizeAction.closest(SELECTORS.headerContainer);
|
||||
const header = resizeAction.closest(actions.SELECTORS.sortableColumn);
|
||||
const minWidth = getMinWidth(header);
|
||||
if (header.offsetWidth < minWidth) {
|
||||
header.style.width = minWidth + 'px';
|
||||
}
|
||||
const handleContainer = headerContainer.querySelector(SELECTORS.handleContainer);
|
||||
const context = {
|
||||
action: "resize",
|
||||
@ -170,6 +193,7 @@ const setUpResizeHandles = (uiRoot) => {
|
||||
currentX = e.pageX;
|
||||
// Find the header.
|
||||
currentHeader = e.target.closest(actions.SELECTORS.sortableColumn);
|
||||
currentMin = getMinWidth(currentHeader);
|
||||
moveTracker = false;
|
||||
suspendShowHideHandles = true;
|
||||
});
|
||||
@ -187,7 +211,9 @@ const setUpResizeHandles = (uiRoot) => {
|
||||
const offset = e.pageX - currentX;
|
||||
currentX = e.pageX;
|
||||
const newWidth = currentHeader.offsetWidth + offset;
|
||||
currentHeader.style.width = newWidth + 'px';
|
||||
if (newWidth >= currentMin) {
|
||||
currentHeader.style.width = newWidth + 'px';
|
||||
}
|
||||
moveTracker = true;
|
||||
});
|
||||
|
||||
@ -203,6 +229,7 @@ const setUpResizeHandles = (uiRoot) => {
|
||||
// If the mouse didn't move, display a modal to change the size using a form.
|
||||
showResizeModal(currentHeader, uiRoot);
|
||||
}
|
||||
currentMin = null;
|
||||
currentHeader = null;
|
||||
currentResizeHandle = null;
|
||||
currentX = 0;
|
||||
@ -238,10 +265,11 @@ const setUpResizeActions = uiRoot => {
|
||||
*/
|
||||
const showResizeModal = async(currentHeader, uiRoot) => {
|
||||
const initialWidth = currentHeader.offsetWidth;
|
||||
const minWidth = getMinWidth(currentHeader);
|
||||
|
||||
const modal = await ModalSaveCancel.create({
|
||||
title: getString('resizecolumn', 'qbank_columnsortorder', currentHeader.textContent),
|
||||
body: Templates.render('qbank_columnsortorder/resize_modal', {}),
|
||||
body: Templates.render('qbank_columnsortorder/resize_modal', {width: initialWidth, min: minWidth}),
|
||||
show: true,
|
||||
});
|
||||
const root = modal.getRoot();
|
||||
@ -254,11 +282,14 @@ const showResizeModal = async(currentHeader, uiRoot) => {
|
||||
|
||||
const body = await modal.bodyPromise;
|
||||
const input = body.get(0).querySelector('input');
|
||||
input.value = initialWidth;
|
||||
|
||||
input.addEventListener('change', e => {
|
||||
const newWidth = e.target.value;
|
||||
currentHeader.style.width = `${newWidth}px`;
|
||||
const valid = e.target.checkValidity();
|
||||
e.target.closest('.has-validation').classList.add('was-validated');
|
||||
if (valid) {
|
||||
const newWidth = e.target.value;
|
||||
currentHeader.style.width = `${newWidth}px`;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -35,9 +35,14 @@ use templatable;
|
||||
*/
|
||||
class column_sort_ui implements renderable, templatable {
|
||||
/**
|
||||
* @var int The minimum custom width for a column.
|
||||
* The minimum custom width for a column.
|
||||
*
|
||||
* This is based on the minimum possible width of the smallest core column (question type).
|
||||
* When viewed, the width will be resized to the minimum width of the column header, if too small.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const MIN_COLUMN_WIDTH = 10;
|
||||
const MIN_COLUMN_WIDTH = 30;
|
||||
|
||||
public function export_for_template(\renderer_base $output): array {
|
||||
$columnmanager = new column_manager(true);
|
||||
|
@ -27,7 +27,7 @@ $string['addcolumn'] = 'Add column \'{$a}\'';
|
||||
$string['addcolumns'] = 'Add columns';
|
||||
$string['auto'] = 'Auto';
|
||||
$string['columnwidth'] = 'Column width (pixels)';
|
||||
$string['invalidwidth'] = 'Width must be at least 10.';
|
||||
$string['invalidwidth'] = 'Width must be at least {$a}.';
|
||||
$string['movecolumn'] = 'Move column \'{$a}\'';
|
||||
$string['pluginname'] = 'Column sort order';
|
||||
$string['privacy:metadata:preference:enabledcol'] = 'The plugin saves user preference of column orders.';
|
||||
|
@ -149,7 +149,7 @@
|
||||
{{#str}}save{{/str}}
|
||||
</button>
|
||||
<div class="invalid-feedback">
|
||||
{{#str}}invalidwidth, qbank_columnsortorder{{/str}}
|
||||
{{#str}}invalidwidth, qbank_columnsortorder, {{minwidth}}{{/str}}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
@ -23,7 +23,11 @@
|
||||
{
|
||||
}
|
||||
}}
|
||||
<label>
|
||||
{{#str}}columnwidth, qbank_columnsortorder{{/str}}
|
||||
<input name="columnwidth" type="number" value="">
|
||||
</label>
|
||||
<form class="has-validation">
|
||||
<label for="columnwidth">{{#str}}columnwidth, qbank_columnsortorder{{/str}}</label>
|
||||
<input class="form-control" id="columnwidth" type="number" value="{{width}}" min="{{min}}">
|
||||
<div class="invalid-feedback">
|
||||
{{#str}}invalidwidth, qbank_columnsortorder, {{min}}{{/str}}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
@ -97,6 +97,6 @@ class checkbox_column extends column_base {
|
||||
}
|
||||
|
||||
public function get_default_width(): int {
|
||||
return 25;
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
|
@ -189,7 +189,6 @@ table.question-bank-table {
|
||||
|
||||
.header {
|
||||
text-align: left;
|
||||
min-width: min-content;
|
||||
|
||||
&.sortable-list-current-position {
|
||||
background-color: lighten($primary, 40%);
|
||||
@ -206,6 +205,9 @@ table.question-bank-table {
|
||||
.dropdown-toggle::after {
|
||||
margin-left: 0;
|
||||
}
|
||||
&.checkbox .form-check {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32054,7 +32054,6 @@ table.question-bank-table label {
|
||||
}
|
||||
table.question-bank-table .header {
|
||||
text-align: left;
|
||||
min-width: min-content;
|
||||
}
|
||||
table.question-bank-table .header.sortable-list-current-position {
|
||||
background-color: #a2cff8;
|
||||
@ -32069,6 +32068,9 @@ table.question-bank-table .header .header-text > div {
|
||||
table.question-bank-table .header .dropdown-toggle::after {
|
||||
margin-left: 0;
|
||||
}
|
||||
table.question-bank-table .header.checkbox .form-check {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
#page-mod-quiz-edit div.questionbankwindow div.header {
|
||||
margin: 0;
|
||||
|
@ -32054,7 +32054,6 @@ table.question-bank-table label {
|
||||
}
|
||||
table.question-bank-table .header {
|
||||
text-align: left;
|
||||
min-width: min-content;
|
||||
}
|
||||
table.question-bank-table .header.sortable-list-current-position {
|
||||
background-color: #a2cff8;
|
||||
@ -32069,6 +32068,9 @@ table.question-bank-table .header .header-text > div {
|
||||
table.question-bank-table .header .dropdown-toggle::after {
|
||||
margin-left: 0;
|
||||
}
|
||||
table.question-bank-table .header.checkbox .form-check {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
#page-mod-quiz-edit div.questionbankwindow div.header {
|
||||
margin: 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user