Skip to content

Commit

Permalink
MDL-76246 gradereport_user: Make the user search widget a combobox
Browse files Browse the repository at this point in the history
Use <div> instead of <button> because <button> cannot have <div>
children.
  • Loading branch information
rezaies committed Mar 22, 2023
1 parent c4f33ce commit 3db5625
Show file tree
Hide file tree
Showing 20 changed files with 147 additions and 53 deletions.
2 changes: 1 addition & 1 deletion grade/amd/build/searchwidget/basewidget.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion grade/amd/build/searchwidget/basewidget.min.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion grade/amd/build/searchwidget/selectors.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion grade/amd/build/searchwidget/selectors.min.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 20 additions & 3 deletions grade/amd/src/searchwidget/basewidget.js
Expand Up @@ -34,8 +34,9 @@ import Notification from 'core/notification';
* @param {Array} data An array of all the data generated by the callee.
* @param {Function} searchFunc Partially applied function we need to manage search the passed dataset.
* @param {string|null} unsearchableContent The content rendered in a non-searchable area.
* @param {Function} afterSelect Callback executed after an item is selected.
*/
export const init = async(widgetContentContainer, bodyPromise, data, searchFunc, unsearchableContent = null) => {
export const init = async(widgetContentContainer, bodyPromise, data, searchFunc, unsearchableContent = null, afterSelect) => {
bodyPromise.then(async(bodyContent) => {
// Render the body content.
widgetContentContainer.innerHTML = bodyContent;
Expand All @@ -52,7 +53,7 @@ export const init = async(widgetContentContainer, bodyPromise, data, searchFunc,
// Render the search results.
await renderSearchResults(searchResultsContainer, data);

registerListenerEvents(widgetContentContainer, data, searchFunc);
registerListenerEvents(widgetContentContainer, data, searchFunc, afterSelect);

}).catch(Notification.exception);
};
Expand All @@ -64,8 +65,9 @@ export const init = async(widgetContentContainer, bodyPromise, data, searchFunc,
* @param {HTMLElement} widgetContentContainer The selector for the widget container element.
* @param {Array} data An array of all the data generated by the callee.
* @param {Function} searchFunc Partially applied function we need to manage search the passed dataset.
* @param {Function} afterSelect Callback executed after an item is selected.
*/
export const registerListenerEvents = (widgetContentContainer, data, searchFunc) => {
export const registerListenerEvents = (widgetContentContainer, data, searchFunc, afterSelect) => {
const searchResultsContainer = widgetContentContainer.querySelector(Selectors.regions.searchResults);
const searchInput = widgetContentContainer.querySelector(Selectors.actions.search);
// We want to focus on the first known user interable element within the dropdown.
Expand All @@ -80,6 +82,8 @@ export const registerListenerEvents = (widgetContentContainer, data, searchFunc)
} else {
clearSearchButton.classList.add('d-none');
}
// Remove aria-activedescendant when the available options change.
searchInput.removeAttribute('aria-activedescendant');
// Display the search results.
await renderSearchResults(
searchResultsContainer,
Expand All @@ -99,6 +103,9 @@ export const registerListenerEvents = (widgetContentContainer, data, searchFunc)
searchInput.focus();
clearSearchButton.classList.add('d-none');

// Remove aria-activedescendant when the available options change.
searchInput.removeAttribute('aria-activedescendant');

// Display all results.
await renderSearchResults(
searchResultsContainer,
Expand All @@ -109,6 +116,15 @@ export const registerListenerEvents = (widgetContentContainer, data, searchFunc)
)
);
});

const inputElement = document.getElementById(searchInput.dataset.inputElement);
inputElement.addEventListener('change', e => {
const selectedOption = widgetContentContainer.querySelector(Selectors.elements.getSearchWidgetSelectOption(searchInput));

if (selectedOption) {
afterSelect(e.target.value);
}
});
};

/**
Expand All @@ -118,6 +134,7 @@ export const registerListenerEvents = (widgetContentContainer, data, searchFunc)
* @param {HTMLElement} container The DOM node where we'll render the loading placeholder.
*/
export const showLoader = async(container) => {
container.innerHTML = '';
const {html, js} = await Templates.renderForPromise('core_grades/searchwidget/loading', {});
Templates.replaceNodeContents(container, html, js);
};
Expand Down
2 changes: 2 additions & 0 deletions grade/amd/src/searchwidget/selectors.js
Expand Up @@ -33,5 +33,7 @@ export default {
elements: {
getSearchWidgetSelector: searchtype => `.search-widget[data-searchtype="${searchtype}"]`,
getSearchWidgetDropdownSelector: searchtype => `.search-widget[data-searchtype="${searchtype}"] .dropdown-menu`,
getSearchWidgetSelectOption:
searchInput => `#${searchInput.getAttribute('aria-controls')} [role="option"][aria-selected="true"]`,
},
};

0 comments on commit 3db5625

Please sign in to comment.