Merge branch 'MDL-85041-500' of https://github.com/junpataleta/moodle into MOODLE_500_STABLE
This commit is contained in:
@@ -1827,6 +1827,7 @@ $string['remoteappuser'] = 'Remote {$a} User';
|
||||
$string['remove'] = 'Remove';
|
||||
$string['removeadmin'] = 'Remove admin';
|
||||
$string['removecreator'] = 'Remove course creator';
|
||||
$string['removed'] = 'Removed {$a}';
|
||||
$string['removestudent'] = 'Remove student';
|
||||
$string['removeteacher'] = 'Remove teacher';
|
||||
$string['rename'] = 'Rename';
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -221,7 +221,7 @@ define([
|
||||
* @param {Element} originalSelect The original select list.
|
||||
* @return {Promise}
|
||||
*/
|
||||
var deselectItem = function(options, state, item, originalSelect) {
|
||||
const deselectItem = async(options, state, item, originalSelect) => {
|
||||
var selectedItemValue = $(item).attr('data-value');
|
||||
|
||||
// Preprend an empty option to the select list to avoid having a default selected option.
|
||||
@@ -239,14 +239,15 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
// Rerender the selection list.
|
||||
return updateSelectionList(options, state, originalSelect)
|
||||
.then(function() {
|
||||
// Notify that the selection changed.
|
||||
notifyChange(originalSelect);
|
||||
|
||||
return;
|
||||
});
|
||||
const selectedItemText = item[0].childNodes[2].textContent?.trim();
|
||||
await announceChanges(state.selectionId, selectedItemText, 'removed');
|
||||
|
||||
// Rerender the selection list.
|
||||
await updateSelectionList(options, state, originalSelect);
|
||||
|
||||
// Notify that the selection changed.
|
||||
notifyChange(originalSelect);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -589,7 +590,7 @@ define([
|
||||
* @param {JQuery} originalSelect The JQuery object matching the hidden select list.
|
||||
* @return {Promise}
|
||||
*/
|
||||
var createItem = function(options, state, originalSelect) {
|
||||
const createItem = async(options, state, originalSelect) => {
|
||||
// Find the element in the DOM.
|
||||
var inputElement = $(document.getElementById(state.inputId));
|
||||
// Get the current text in the input field.
|
||||
@@ -624,23 +625,17 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
return updateSelectionList(options, state, originalSelect)
|
||||
.then(function() {
|
||||
// Notify that the selection changed.
|
||||
notifyChange(originalSelect);
|
||||
// Announce the changes to the assistive technology.
|
||||
await announceChanges(state.selectionId, query.trim(), 'added');
|
||||
|
||||
return;
|
||||
})
|
||||
.then(function() {
|
||||
// Clear the input field.
|
||||
inputElement.val('');
|
||||
await updateSelectionList(options, state, originalSelect);
|
||||
// Notify that the selection changed.
|
||||
notifyChange(originalSelect);
|
||||
|
||||
return;
|
||||
})
|
||||
.then(function() {
|
||||
// Close the suggestions list.
|
||||
return closeSuggestions(state);
|
||||
});
|
||||
// Clear the input field.
|
||||
inputElement.val('');
|
||||
// Close the suggestions list.
|
||||
await closeSuggestions(state);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -651,9 +646,10 @@ define([
|
||||
* @param {Object} options The original options for the autocomplete.
|
||||
* @param {Object} state State variables for the autocomplete.
|
||||
* @param {JQuery} originalSelect The JQuery object matching the hidden select list.
|
||||
* @param {string|null} selectedItem The item to be selected.
|
||||
* @return {Promise}
|
||||
*/
|
||||
var selectCurrentItem = function(options, state, originalSelect) {
|
||||
const selectCurrentItem = async(options, state, originalSelect, selectedItem) => {
|
||||
// Find the elements in the page.
|
||||
var inputElement = $(document.getElementById(state.inputId));
|
||||
var suggestionsElement = $(document.getElementById(state.suggestionsId));
|
||||
@@ -668,32 +664,30 @@ define([
|
||||
originalSelect.children('option').prop('selected', false);
|
||||
}
|
||||
// Look for a match, and toggle the selected property if there is a match.
|
||||
originalSelect.children('option').each(function(index, ele) {
|
||||
originalSelect.children('option').each(function (index, ele) {
|
||||
if ($(ele).attr('value') == selectedItemValue) {
|
||||
$(ele).prop('selected', true);
|
||||
}
|
||||
});
|
||||
|
||||
return updateSelectionList(options, state, originalSelect)
|
||||
.then(function() {
|
||||
// Notify that the selection changed.
|
||||
notifyChange(originalSelect);
|
||||
await announceChanges(state.selectionId, selectedItem, 'added');
|
||||
|
||||
return;
|
||||
})
|
||||
.then(function() {
|
||||
if (options.closeSuggestionsOnSelect) {
|
||||
// Clear the input element.
|
||||
inputElement.val('');
|
||||
// Close the list of suggestions.
|
||||
return closeSuggestions(state);
|
||||
} else {
|
||||
// Focus on the input element so the suggestions does not auto-close.
|
||||
inputElement.focus();
|
||||
// Remove the last selected item from the suggestions list.
|
||||
return updateSuggestions(options, state, inputElement.val(), originalSelect);
|
||||
}
|
||||
});
|
||||
await updateSelectionList(options, state, originalSelect);
|
||||
|
||||
// Notify that the selection changed.
|
||||
notifyChange(originalSelect);
|
||||
|
||||
if (options.closeSuggestionsOnSelect) {
|
||||
// Clear the input element.
|
||||
inputElement.val('');
|
||||
// Close the list of suggestions.
|
||||
await closeSuggestions(state);
|
||||
} else {
|
||||
// Focus on the input element so the suggestions does not auto-close.
|
||||
inputElement.focus();
|
||||
// Remove the last selected item from the suggestions list.
|
||||
await updateSuggestions(options, state, inputElement.val(), originalSelect);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -814,8 +808,9 @@ define([
|
||||
var suggestionsElement = $(document.getElementById(state.suggestionsId));
|
||||
if ((inputElement.attr('aria-expanded') === "true") &&
|
||||
(suggestionsElement.children('[aria-selected=true]').length > 0)) {
|
||||
const selectedItemText = suggestionsElement.children('[aria-selected=true]')[0].textContent.trim();
|
||||
// If the suggestion list has an active item, select it.
|
||||
pendingJsPromise.resolve(selectCurrentItem(options, state, originalSelect));
|
||||
pendingJsPromise.resolve(selectCurrentItem(options, state, originalSelect, selectedItemText));
|
||||
} else if (options.tags) {
|
||||
// If tags are enabled, create a tag.
|
||||
pendingJsPromise.resolve(createItem(options, state, originalSelect));
|
||||
@@ -934,12 +929,13 @@ define([
|
||||
activateItem(current, state)
|
||||
.then(function() {
|
||||
// And select it.
|
||||
return selectCurrentItem(options, state, originalSelect);
|
||||
const selectedItemText = element[0].textContent.trim();
|
||||
return selectCurrentItem(options, state, originalSelect, selectedItemText);
|
||||
})
|
||||
.then(function() {
|
||||
return pendingPromise.resolve();
|
||||
})
|
||||
.catch();
|
||||
.catch(notification.exception);
|
||||
});
|
||||
var selectionElement = $(document.getElementById(state.selectionId));
|
||||
|
||||
@@ -1297,6 +1293,36 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Announces changes to a tag in the autocomplete form.
|
||||
*
|
||||
* Updates the text content of a status element to inform users about the addition or removal
|
||||
* of a tag. This is useful for accessibility purposes, ensuring screen readers can notify users
|
||||
* of changes in the autocomplete component.
|
||||
*
|
||||
* @param {string} selectionId - The ID of the selection element used to locate the announcer element.
|
||||
* @param {string|null|undefined} tagname - The name of the tag that was added or removed.
|
||||
* @param {string} action - The action performed on the tag (e.g., "added" or "removed").
|
||||
*/
|
||||
const announceChanges = async(selectionId, tagname, action) => {
|
||||
if (!tagname) {
|
||||
return;
|
||||
}
|
||||
|
||||
const status = document.getElementById(`${selectionId}-announcer`);
|
||||
if (!status) {
|
||||
return;
|
||||
}
|
||||
|
||||
status.textContent = await str.get_string(action, 'core', tagname);
|
||||
|
||||
// Remove the status message after 4 seconds to prevent screen readers from announcing it.
|
||||
setTimeout(() => {
|
||||
status.textContent = '';
|
||||
}, 4000);
|
||||
|
||||
};
|
||||
|
||||
return {
|
||||
// Public variables and functions.
|
||||
enhanceField: enhanceField,
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
], "noSelectionString": "No selection" }
|
||||
}}
|
||||
<span class="visually-hidden" id="{{selectionId}}-label">{{#str}}selecteditems, form{{/str}}</span>
|
||||
<div id="{{selectionId}}-announcer" aria-live="polite" role="status" class="visually-hidden"></div>
|
||||
<div{{!
|
||||
}} class="form-autocomplete-selection w-100 {{#multiple}}form-autocomplete-multiple{{/multiple}}"{{!
|
||||
}} id="{{selectionId}}"{{!
|
||||
|
||||
@@ -77,7 +77,7 @@ Feature: Use the qbank plugin manager page for bulkmove
|
||||
When I open the autocomplete suggestions list in the ".search-banks" "css_element"
|
||||
Then I should not see "C3 - Question bank 3" in the ".search-banks" "css_element"
|
||||
And I click on "C1 - Question bank 1" item in the autocomplete list
|
||||
Then I should not see "Test questions 1" in the ".search-categories" "css_element"
|
||||
Then I should not see "Test questions 1" in the ".search-categories .form-autocomplete-selection" "css_element"
|
||||
And I open the autocomplete suggestions list in the ".search-categories" "css_element"
|
||||
And "Test questions 2" "autocomplete_suggestions" should exist
|
||||
And "Test questions 3" "autocomplete_suggestions" should not exist
|
||||
|
||||
Reference in New Issue
Block a user