MDL-86245 core_course: improve activity chooser search
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -6,6 +6,6 @@ define("core_course/local/activitychooser/exporter",["exports","core/str"],(func
|
||||
* @copyright 2025 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
const activityCategories=["administration","assessment","collaboration","communication","content","interactivecontent"];let allStrings=null;loadNecessaryStrings();async function loadNecessaryStrings(){if(null!==allStrings)return allStrings;allStrings={};const stringToLoad=[{key:"all",component:"core"},{key:"yes",component:"core"},{key:"no",component:"core"},{key:"favourites",component:"core"},{key:"recommended",component:"core"},{key:"gradable",component:"core"},{key:"recommended_help",component:"core_course"},...activityCategories.map((key=>({key:"mod_purpose_"+key,component:"core_course"}))),...activityCategories.map((key=>({key:"mod_purpose_"+key+"_help",component:"core_course"})))],loadedStrings=await(0,_str.getStrings)(stringToLoad);return stringToLoad.forEach(((_ref,index)=>{let{key:key}=_ref;allStrings[key]=loadedStrings[index]})),allStrings}return _exports.default=class{getTabData(tabId,filteredModules,tabLabel){let tabHelp=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;const result={tabId:tabId,active:arguments.length>4&&void 0!==arguments[4]&&arguments[4],items:filteredModules,displayed:filteredModules.length>0,tabLabel:tabLabel};return tabHelp&&(result.tabHelp=tabHelp),result}normaliseModulesData(modulesData){if(modulesData instanceof Map)modulesData=Array.from(modulesData.values());else if(!Array.isArray(modulesData))throw new Error("Invalid modules data format. Expected an array or a Map.");return modulesData}async getModChooserTemplateData(modulesData){modulesData=this.normaliseModulesData(modulesData);const allStrings=await loadNecessaryStrings(),favouriteTab=await this.getFavouriteTabData(modulesData),tabs=[{...this.getTabData("all",modulesData,allStrings.all,null,!favouriteTab.displayed),hasSearchResults:!0},favouriteTab,{...this.getTabData("recommended",modulesData.filter((mod=>!0===mod.recommended)),allStrings.recommended,allStrings.recommended_help),separator:!0}];return activityCategories.forEach((category=>{const categoryModules=modulesData.filter((mod=>mod.purpose==category||mod.otherpurpose==category));0!==categoryModules.length&&tabs.push(this.getTabData(category,categoryModules,allStrings["mod_purpose_"+category],allStrings["mod_purpose_"+category+"_help"]))})),{modules:modulesData,tabs:tabs}}async getModuleHelpTemplateData(moduleData){const allStrings=await loadNecessaryStrings(),data={...moduleData,purposes:[]};for(const purposeField of["purpose","otherpurpose"])moduleData[purposeField]&&activityCategories.includes(moduleData[purposeField])&&data.purposes.push({purposename:moduleData[purposeField],purposelabel:allStrings["mod_purpose_".concat(moduleData[purposeField])]});return data.details=[{label:allStrings.gradable,value:moduleData.gradable?allStrings.yes:allStrings.no}],data}async getFavouriteTabData(modulesData){modulesData=this.normaliseModulesData(modulesData);const allStrings=await loadNecessaryStrings(),favouriteModules=modulesData.filter((mod=>!0===mod.favourite));return this.getTabData("favourites",favouriteModules,allStrings.favourites,null,favouriteModules.length>0)}getSearchResultData(resultsModulesData){return{searchresultsnumber:(resultsModulesData=this.normaliseModulesData(resultsModulesData)).length,searchresults:resultsModulesData}}countTabItems(tabData){var _tabData$items$length,_tabData$items;return null!==(_tabData$items$length=null===(_tabData$items=tabData.items)||void 0===_tabData$items?void 0:_tabData$items.length)&&void 0!==_tabData$items$length?_tabData$items$length:0}getFooterData(footerData){return{activeFooter:footerData.customfootertemplate}}},_exports.default}));
|
||||
const activityCategories=["administration","assessment","collaboration","communication","content","interactivecontent"];let allStrings=null;loadNecessaryStrings();async function loadNecessaryStrings(){if(null!==allStrings)return allStrings;allStrings={};const stringToLoad=[{key:"all",component:"core"},{key:"yes",component:"core"},{key:"no",component:"core"},{key:"favourites",component:"core"},{key:"recommended",component:"core"},{key:"gradable",component:"core"},{key:"recommended_help",component:"core_course"},...activityCategories.map((key=>({key:"mod_purpose_"+key,component:"core_course"}))),...activityCategories.map((key=>({key:"mod_purpose_"+key+"_help",component:"core_course"})))],loadedStrings=await(0,_str.getStrings)(stringToLoad);return stringToLoad.forEach(((_ref,index)=>{let{key:key}=_ref;allStrings[key]=loadedStrings[index]})),allStrings}return _exports.default=class{getTabData(tabId,filteredModules,tabLabel){let tabHelp=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;const result={tabId:tabId,active:arguments.length>4&&void 0!==arguments[4]&&arguments[4],items:filteredModules,displayed:filteredModules.length>0,tabLabel:tabLabel};return tabHelp&&(result.tabHelp=tabHelp),result}normaliseModulesData(modulesData){if(modulesData instanceof Map)modulesData=Array.from(modulesData.values());else if(!Array.isArray(modulesData))throw new Error("Invalid modules data format. Expected an array or a Map.");return modulesData}async getModChooserTemplateData(modulesData){modulesData=this.normaliseModulesData(modulesData);const allStrings=await loadNecessaryStrings(),favouriteTab=await this.getFavouriteTabData(modulesData),tabs=[{...this.getTabData("all",modulesData,allStrings.all,null,!favouriteTab.displayed),hasSearchResults:!0},favouriteTab,{...this.getTabData("recommended",modulesData.filter((mod=>!0===mod.recommended)),allStrings.recommended,allStrings.recommended_help),separator:!0}];return activityCategories.forEach((category=>{const categoryModules=modulesData.filter((mod=>mod.purpose==category||mod.otherpurpose==category));0!==categoryModules.length&&tabs.push(this.getTabData(category,categoryModules,allStrings["mod_purpose_"+category],allStrings["mod_purpose_"+category+"_help"]))})),{modules:modulesData,tabs:tabs}}async getModuleHelpTemplateData(moduleData){const allStrings=await loadNecessaryStrings(),data={...moduleData,purposes:[]};for(const purposeField of["purpose","otherpurpose"])moduleData[purposeField]&&activityCategories.includes(moduleData[purposeField])&&data.purposes.push({purposename:moduleData[purposeField],purposelabel:allStrings["mod_purpose_".concat(moduleData[purposeField])]});return data.details=[{label:allStrings.gradable,value:moduleData.gradable?allStrings.yes:allStrings.no}],data}async getFavouriteTabData(modulesData){modulesData=this.normaliseModulesData(modulesData);const allStrings=await loadNecessaryStrings(),favouriteModules=modulesData.filter((mod=>!0===mod.favourite));return this.getTabData("favourites",favouriteModules,allStrings.favourites,null,favouriteModules.length>0)}getSearchResultData(searchQuery,resultsModulesData){return{searchresultsnumber:(resultsModulesData=this.normaliseModulesData(resultsModulesData)).length,searchresults:resultsModulesData,hasresults:resultsModulesData.length>0,searchquery:searchQuery}}countTabItems(tabData){var _tabData$items$length,_tabData$items;return null!==(_tabData$items$length=null===(_tabData$items=tabData.items)||void 0===_tabData$items?void 0:_tabData$items.length)&&void 0!==_tabData$items$length?_tabData$items$length:0}getFooterData(footerData){return{activeFooter:footerData.customfootertemplate}}},_exports.default}));
|
||||
|
||||
//# sourceMappingURL=exporter.min.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -491,7 +491,7 @@ class ActivityChooserDialogue {
|
||||
const searchResultsData = this.searchModules(searchQuery);
|
||||
|
||||
if (searchQuery.length > 0) {
|
||||
await this.dialogueDom.refreshSearchResults(searchResultsData);
|
||||
await this.dialogueDom.refreshSearchResults(searchQuery, searchResultsData);
|
||||
this.dialogueDom.showAllActivitiesTab(true);
|
||||
} else {
|
||||
this.dialogueDom.cleanSearchResults();
|
||||
|
||||
@@ -93,13 +93,14 @@ export default class ChooserDialogueDOM {
|
||||
/**
|
||||
* Show the search results.
|
||||
*
|
||||
* @param {String} searchQuery The search query string.
|
||||
* @param {Object} searchResultsData Data containing the module items that satisfy the search criteria
|
||||
*/
|
||||
async refreshSearchResults(searchResultsData) {
|
||||
async refreshSearchResults(searchQuery, searchResultsData) {
|
||||
const searchResultsContainer = this.modalBody.querySelector(selectors.regions.searchResults);
|
||||
const clearSearchButton = this.modalBody.querySelector(selectors.actions.clearSearch);
|
||||
|
||||
await this.renderSearchResults(searchResultsContainer, searchResultsData);
|
||||
await this.renderSearchResults(searchResultsContainer, searchQuery, searchResultsData);
|
||||
const chooserOptionsContainer = searchResultsContainer.querySelector(selectors.regions.chooserOptions);
|
||||
const firstSearchResultItem = chooserOptionsContainer.querySelector(selectors.regions.chooserOption.container);
|
||||
if (firstSearchResultItem) {
|
||||
@@ -136,10 +137,11 @@ export default class ChooserDialogueDOM {
|
||||
* @private
|
||||
* @method renderSearchResults
|
||||
* @param {HTMLElement} searchResultsContainer The container where the data should be rendered
|
||||
* @param {String} searchQuery The search query string
|
||||
* @param {Object} searchResultsData Data containing the module items that satisfy the search criteria
|
||||
*/
|
||||
async renderSearchResults(searchResultsContainer, searchResultsData) {
|
||||
const templateData = this.exporter.getSearchResultData(searchResultsData);
|
||||
async renderSearchResults(searchResultsContainer, searchQuery, searchResultsData) {
|
||||
const templateData = this.exporter.getSearchResultData(searchQuery, searchResultsData);
|
||||
// Build up the html & js ready to place into the help section.
|
||||
const {html, js} = await Templates.renderForPromise(
|
||||
'core_course/local/activitychooser/search_results',
|
||||
|
||||
@@ -225,14 +225,17 @@ export default class {
|
||||
/**
|
||||
* Get the search result template data.
|
||||
*
|
||||
* @param {String} searchQuery The search query string.
|
||||
* @param {Array|Map} resultsModulesData Modules data to be used in the chooser.
|
||||
* @return {Object} The template data.
|
||||
*/
|
||||
getSearchResultData(resultsModulesData) {
|
||||
getSearchResultData(searchQuery, resultsModulesData) {
|
||||
resultsModulesData = this.normaliseModulesData(resultsModulesData);
|
||||
return {
|
||||
'searchresultsnumber': resultsModulesData.length,
|
||||
'searchresults': resultsModulesData,
|
||||
'hasresults': resultsModulesData.length > 0,
|
||||
'searchquery': searchQuery,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -29,11 +29,19 @@
|
||||
"addoption": "http://addoptionurl.com"
|
||||
},
|
||||
"icon": "<img class='icon' alt='' src='http://urltooptionicon'>"
|
||||
}
|
||||
},
|
||||
"hasresults": true,
|
||||
"searchquery": "search term"
|
||||
}
|
||||
}}
|
||||
<h6>{{#str}} search, core, {{searchresultsnumber}} {{/str}}</h6>
|
||||
<p class="activitychooser_help">{{#str}} resultsfound, core, {{searchresultsnumber}} {{/str}}</p>
|
||||
{{#hasresults}}
|
||||
<h6 class="h5 mb-3 fw-bold">{{#str}} search, core, {{searchresultsnumber}} {{/str}}</h6>
|
||||
<p class="activitychooser_help">{{#str}} resultsfound, core, {{searchresultsnumber}} {{/str}}</p>
|
||||
{{/hasresults}}
|
||||
{{^hasresults}}
|
||||
<h6 class="h5 mb-3 fw-bold">{{#str}} noresultsfor, core, {{searchquery}} {{/str}}</h6>
|
||||
<p class="activitychooser_help">{{#str}} noresultsfor_help, core {{/str}}</p>
|
||||
{{/hasresults}}
|
||||
<div
|
||||
class="optionscontainer mw-100 position-relative"
|
||||
role="menubar"
|
||||
|
||||
@@ -169,7 +169,8 @@ Feature: Display and choose from the available activities in course
|
||||
And I should see "Lesson" in the "Add an activity or resource" "dialogue"
|
||||
# Test non matching search.
|
||||
And I set the field "search" to "Random search query"
|
||||
And I should see "0 results found" in the "Add an activity or resource" "dialogue"
|
||||
And I should see "No results for \"Random search query\"" in the "Add an activity or resource" "dialogue"
|
||||
And I should see "Check your spelling or try different words." in the "Add an activity or resource" "dialogue"
|
||||
|
||||
Scenario: Teacher can return to the default activity chooser state by manually removing the search query
|
||||
Given I open the activity chooser
|
||||
@@ -195,16 +196,16 @@ Feature: Display and choose from the available activities in course
|
||||
|
||||
Scenario: Teacher can instantly remove the search query from the activity search bar by clicking on the clear button
|
||||
Given I open the activity chooser
|
||||
And I set the field "search" to "Search query"
|
||||
And I set the field "search" to "create quizzes"
|
||||
And I should see "results found" in the "Add an activity or resource" "dialogue"
|
||||
When I click on "Clear search input" "button"
|
||||
Then I should not see "Search query"
|
||||
Then I should not see "create quizzes"
|
||||
And ".searchresultscontainer" "css_element" should not be visible
|
||||
And ".optionscontainer" "css_element" should exist
|
||||
|
||||
Scenario: Click on an activity chooser category should cancel the current search
|
||||
Given I open the activity chooser
|
||||
And I set the field "search" to "Search query"
|
||||
And I set the field "search" to "create quizzes"
|
||||
And I should see "results found" in the "Add an activity or resource" "dialogue"
|
||||
And "Clear search input" "button" should be visible
|
||||
When I click on "Resources" "link" in the "Add an activity or resource" "dialogue"
|
||||
|
||||
@@ -1559,6 +1559,7 @@ $string['noneditingteacher'] = 'Non-editing teacher';
|
||||
$string['noneditingteacherdescription'] = 'Non-editing teachers can teach in courses and grade students, but may not alter activities.';
|
||||
$string['nonstandard'] = 'Non-standard';
|
||||
$string['noresultsfor'] = 'No results for "{$a}"';
|
||||
$string['noresultsfor_help'] = 'Check your spelling or try different words.';
|
||||
$string['nopendingcourses'] = 'There are no courses pending approval';
|
||||
$string['nopotentialadmins'] = 'No potential admins';
|
||||
$string['nopotentialcreators'] = 'No potential course creators';
|
||||
|
||||
Reference in New Issue
Block a user