mirror of
https://github.com/moodle/moodle.git
synced 2025-08-09 10:56: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
11 changed files with 65 additions and 19 deletions
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;
|
||||
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 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…
Add table
Add a link
Reference in a new issue