From 8c26445d8ded1bd709393e2052a1a44db5163623 Mon Sep 17 00:00:00 2001 From: Jun Pataleta Date: Mon, 19 Feb 2024 12:07:43 +0800 Subject: [PATCH] MDL-78370 block_myoverview: Conditionally show "All" paging option To minimise performance issues when displaying courses in Summary view, we need to conditionally show the "All" paging option. This commit will prevent the "All" paging option to be shown if there are more than 100 courses to be shown. --- blocks/myoverview/amd/build/view.min.js | 2 +- blocks/myoverview/amd/build/view.min.js.map | 2 +- blocks/myoverview/amd/src/view.js | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/blocks/myoverview/amd/build/view.min.js b/blocks/myoverview/amd/build/view.min.js index 347911a6808..af66365f27a 100644 --- a/blocks/myoverview/amd/build/view.min.js +++ b/blocks/myoverview/amd/build/view.min.js @@ -4,6 +4,6 @@ define("block_myoverview/view",["exports","jquery","block_myoverview/repository" * * @copyright 2018 Bas Brands * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.reset=_exports.init=_exports.clearSearch=void 0,_jquery=_interopRequireDefault(_jquery),Repository=_interopRequireWildcard(Repository),PagedContentFactory=_interopRequireWildcard(PagedContentFactory),PubSub=_interopRequireWildcard(PubSub),CustomEvents=_interopRequireWildcard(CustomEvents),Notification=_interopRequireWildcard(Notification),Templates=_interopRequireWildcard(Templates),CourseEvents=_interopRequireWildcard(CourseEvents),_selectors=_interopRequireDefault(_selectors),PagedContentEvents=_interopRequireWildcard(PagedContentEvents),Aria=_interopRequireWildcard(Aria);const TEMPLATES_COURSES_CARDS="block_myoverview/view-cards",TEMPLATES_COURSES_LIST="block_myoverview/view-list",TEMPLATES_COURSES_SUMMARY="block_myoverview/view-summary",TEMPLATES_NOCOURSES="core_course/no-courses",GROUPINGS_GROUPING_ALLINCLUDINGHIDDEN="allincludinghidden",NUMCOURSES_PERPAGE=[12,24,48,96,0];let loadedPages=[],courseOffset=0,lastPage=0,lastLimit=0,namespace=null,summaryDisplayLoaded=!1;const getFilterValues=root=>{const courseRegion=root.find(_selectors.default.courseView.region);return{display:courseRegion.attr("data-display"),grouping:courseRegion.attr("data-grouping"),sort:courseRegion.attr("data-sort"),displaycategories:courseRegion.attr("data-displaycategories"),customfieldname:courseRegion.attr("data-customfieldname"),customfieldvalue:courseRegion.attr("data-customfieldvalue")}},DEFAULT_PAGED_CONTENT_CONFIG={ignoreControlWhileLoading:!0,controlPlacementBottom:!0,persistentLimitKey:"block_myoverview_user_paging_preference"},getFavouriteIconContainer=(root,courseId)=>root.find(_selectors.default.FAVOURITE_ICON+'[data-course-id="'+courseId+'"]'),getPagedContentContainer=(root,index)=>root.find('[data-region="paged-content-page"][data-page="'+index+'"]'),getCourseId=root=>root.attr("data-course-id"),getAddFavouriteMenuItem=(root,courseId)=>root.find('[data-action="add-favourite"][data-course-id="'+courseId+'"]'),getRemoveFavouriteMenuItem=(root,courseId)=>root.find('[data-action="remove-favourite"][data-course-id="'+courseId+'"]'),addToFavourites=(root,courseId)=>{const removeAction=getRemoveFavouriteMenuItem(root,courseId),addAction=getAddFavouriteMenuItem(root,courseId);setCourseFavouriteState(courseId,!0).then((success=>{success?(PubSub.publish(CourseEvents.favourited,courseId),removeAction.removeClass("hidden"),addAction.addClass("hidden"),((root,courseId)=>{const iconContainer=getFavouriteIconContainer(root,courseId),isFavouriteIcon=iconContainer.find(_selectors.default.ICON_IS_FAVOURITE);isFavouriteIcon.removeClass("hidden"),Aria.unhide(isFavouriteIcon);const notFavourteIcon=iconContainer.find(_selectors.default.ICON_NOT_FAVOURITE);notFavourteIcon.addClass("hidden"),Aria.hide(notFavourteIcon)})(root,courseId)):Notification.alert("Starring course failed","Could not change favourite state")})).catch(Notification.exception)},removeFromFavourites=(root,courseId)=>{const removeAction=getRemoveFavouriteMenuItem(root,courseId),addAction=getAddFavouriteMenuItem(root,courseId);setCourseFavouriteState(courseId,!1).then((success=>{success?(PubSub.publish(CourseEvents.unfavorited,courseId),removeAction.addClass("hidden"),addAction.removeClass("hidden"),((root,courseId)=>{const iconContainer=getFavouriteIconContainer(root,courseId),isFavouriteIcon=iconContainer.find(_selectors.default.ICON_IS_FAVOURITE);isFavouriteIcon.addClass("hidden"),Aria.hide(isFavouriteIcon);const notFavourteIcon=iconContainer.find(_selectors.default.ICON_NOT_FAVOURITE);notFavourteIcon.removeClass("hidden"),Aria.unhide(notFavourteIcon)})(root,courseId)):Notification.alert("Starring course failed","Could not change favourite state")})).catch(Notification.exception)},getHideCourseMenuItem=(root,courseId)=>root.find('[data-action="hide-course"][data-course-id="'+courseId+'"]'),getShowCourseMenuItem=(root,courseId)=>root.find('[data-action="show-course"][data-course-id="'+courseId+'"]'),setCourseHiddenState=(courseId,status)=>(!1===status&&(status=null),(0,_repository2.setUserPreference)("block_myoverview_hidden_course_".concat(courseId),status).catch(Notification.exception)),hideElement=(root,id)=>{const pagingBar=root.find('[data-region="paging-bar"]'),jumpto=parseInt(pagingBar.attr("data-active-page-number"));let reducedCourse=loadedPages[jumpto].courses.reduce(((accumulator,current)=>(+id!=+current.id&&accumulator.push(current),accumulator)),[]);if(void 0!==loadedPages[jumpto+1]){const newElement=loadedPages[jumpto+1].courses.slice(0,1);loadedPages.forEach(((courseList,index)=>{if(index>jumpto){let popElement=[];void 0!==loadedPages[index+1]&&(popElement=loadedPages[index+1].courses.slice(0,1)),loadedPages[index].courses=[...loadedPages[index].courses.slice(1),...popElement]}})),reducedCourse=[...reducedCourse,...newElement]}if(lastPage===jumpto+1&&0===loadedPages[jumpto+1].courses.length){const pagedContentContainer=root.find('[data-region="paged-content-container"]');PagedContentFactory.resetLastPageNumber((0,_jquery.default)(pagedContentContainer).attr("id"),jumpto)}loadedPages[jumpto].courses=reducedCourse,courseOffset--;const pagedContentPage=getPagedContentContainer(root,jumpto);renderCourses(root,loadedPages[jumpto]).then(((html,js)=>Templates.replaceNodeContents(pagedContentPage,html,js))).catch(Notification.exception),loadedPages.forEach(((courseList,index)=>{if(index>jumpto){getPagedContentContainer(root,index).remove()}}))},setCourseFavouriteState=(courseId,status)=>Repository.setFavouriteCourses({courses:[{id:courseId,favourite:status}]}).then((result=>0===result.warnings.length&&(loadedPages.forEach((courseList=>{courseList.courses.forEach(((course,index)=>{course.id==courseId&&(courseList.courses[index].isfavourite=status)}))})),!0))).catch(Notification.exception),noCoursesRender=root=>{const nocoursesimg=root.find(_selectors.default.courseView.region).attr("data-nocoursesimg"),newcourseurl=root.find(_selectors.default.courseView.region).attr("data-newcourseurl");return Templates.render(TEMPLATES_NOCOURSES,{nocoursesimg:nocoursesimg,newcourseurl:newcourseurl})},renderCourses=(root,coursesData)=>{const filters=getFilterValues(root);let currentTemplate="";return currentTemplate="card"===filters.display?TEMPLATES_COURSES_CARDS:"list"===filters.display?TEMPLATES_COURSES_LIST:TEMPLATES_COURSES_SUMMARY,coursesData?(!1===Array.isArray(coursesData.courses)&&(coursesData.courses=Object.values(coursesData.courses)),coursesData.courses=coursesData.courses.map((course=>(course.showcoursecategory="on"===filters.displaycategories,course))),coursesData.courses.length?Templates.render(currentTemplate,{courses:coursesData.courses}):noCoursesRender(root)):noCoursesRender(root)},registerPagedEventHandlers=(root,namespace)=>{const event=namespace+PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT;PubSub.subscribe(event,(root=>limit=>root.find(_selectors.default.courseView.region).attr("data-paging",limit))(root))},itemsPerPageFunc=(pagingLimit,root)=>{let itemsPerPage=NUMCOURSES_PERPAGE.map((value=>{let active=!1;return value===pagingLimit&&(active=!0),{value:value,active:active}}));const totalCourseCount=parseInt(root.find(_selectors.default.courseView.region).attr("data-totalcoursecount"),10);return itemsPerPage.filter((pagingOption=>pagingOption.value4&&void 0!==arguments[4]?arguments[4]:null,courses=coursesData.courses?coursesData.courses:coursesData,nextPageStart=0,pageCourses=[];if(void 0!==loadedPages[currentPage]){pageCourses=loadedPages[currentPage].courses;const currentPageLength=pageCourses.length;currentPageLength0?courses.slice(0,pageData.limit):courses;loadedPages[currentPage]={courses:pageCourses};const remainingCourses=!1!==nextPageStart?courses.slice(nextPageStart,courses.length):[];remainingCourses.length&&(loadedPages[currentPage+1]={courses:remainingCourses}),loadedPages[currentPage].courses.length{courseOffset=0,loadedPages=[],lastPage=0,lastLimit=0},standardFunctionalityCurry=()=>(resetGlobals(),(filters,currentPage,pageData,actions,root,promises,limit)=>{const pagePromise=((filters,limit)=>{const params={offset:courseOffset,limit:limit,classification:filters.grouping,sort:filters.sort,customfieldname:filters.customfieldname,customfieldvalue:filters.customfieldvalue};return"summary"===filters.display?(params.requiredfields=Repository.SUMMARY_REQUIRED_FIELDS,summaryDisplayLoaded=!0):params.requiredfields=Repository.CARDLIST_REQUIRED_FIELDS,Repository.getEnrolledCoursesByTimeline(params)})(filters,limit).then((coursesData=>(pageBuilder(coursesData,currentPage,pageData,actions),renderCourses(root,loadedPages[currentPage])))).catch(Notification.exception);promises.push(pagePromise)}),searchFunctionalityCurry=()=>(resetGlobals(),(filters,currentPage,pageData,actions,root,promises,limit,inputValue)=>{const searchingPromise=((filters,limit,searchValue)=>{const params={offset:courseOffset,limit:limit,classification:"search",sort:filters.sort,customfieldname:filters.customfieldname,customfieldvalue:filters.customfieldvalue,searchvalue:searchValue};return"summary"===filters.display?(params.requiredfields=Repository.SUMMARY_REQUIRED_FIELDS,summaryDisplayLoaded=!0):(params.requiredfields=Repository.CARDLIST_REQUIRED_FIELDS,summaryDisplayLoaded=!1),Repository.getEnrolledCoursesByTimeline(params)})(filters,limit,inputValue).then((coursesData=>(pageBuilder(coursesData,currentPage,pageData,actions),renderCourses(root,loadedPages[currentPage])))).catch(Notification.exception);promises.push(searchingPromise)}),initializePagedContent=function(root,promiseFunction){let inputValue=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const pagingLimit=parseInt(root.find(_selectors.default.courseView.region).attr("data-paging"),10);let itemsPerPage=itemsPerPageFunc(pagingLimit,root);const filters=getFilterValues(root),config={...DEFAULT_PAGED_CONTENT_CONFIG};config.eventNamespace=namespace;const pagedContentPromise=PagedContentFactory.createWithLimit(itemsPerPage,((pagesData,actions)=>{let promises=[];return pagesData.forEach((pageData=>{const currentPage=pageData.pageNumber;let limit=pageData.limit>0?pageData.limit:0;if(+lastLimit!=+limit&&(loadedPages=[],courseOffset=0,lastPage=0),lastPage===currentPage)return actions.allItemsLoaded(lastPage),void promises.push(renderCourses(root,loadedPages[currentPage]));lastLimit=limit,void 0===loadedPages[currentPage+1]&&void 0===loadedPages[currentPage]&&(limit*=2),promiseFunction(filters,currentPage,pageData,actions,root,promises,limit,inputValue)})),promises}),config);pagedContentPromise.then(((html,js)=>(registerPagedEventHandlers(root,namespace),Templates.replaceNodeContents(root.find(_selectors.default.courseView.region),html,js)))).catch(Notification.exception)},registerEventListeners=(root,page)=>{CustomEvents.define(root,[CustomEvents.events.activate]),root.on(CustomEvents.events.activate,_selectors.default.ACTION_ADD_FAVOURITE,((e,data)=>{const favourite=(0,_jquery.default)(e.target).closest(_selectors.default.ACTION_ADD_FAVOURITE),courseId=getCourseId(favourite);addToFavourites(root,courseId),data.originalEvent.preventDefault()})),root.on(CustomEvents.events.activate,_selectors.default.ACTION_REMOVE_FAVOURITE,((e,data)=>{const favourite=(0,_jquery.default)(e.target).closest(_selectors.default.ACTION_REMOVE_FAVOURITE),courseId=getCourseId(favourite);removeFromFavourites(root,courseId),data.originalEvent.preventDefault()})),root.on(CustomEvents.events.activate,_selectors.default.FAVOURITE_ICON,((e,data)=>{data.originalEvent.preventDefault()})),root.on(CustomEvents.events.activate,_selectors.default.ACTION_HIDE_COURSE,((e,data)=>{const target=(0,_jquery.default)(e.target).closest(_selectors.default.ACTION_HIDE_COURSE),courseId=getCourseId(target);((root,courseId)=>{const hideAction=getHideCourseMenuItem(root,courseId),showAction=getShowCourseMenuItem(root,courseId),filters=getFilterValues(root);setCourseHiddenState(courseId,!0),filters.grouping!==GROUPINGS_GROUPING_ALLINCLUDINGHIDDEN&&hideElement(root,courseId),hideAction.addClass("hidden"),showAction.removeClass("hidden")})(root,courseId),data.originalEvent.preventDefault()})),root.on(CustomEvents.events.activate,_selectors.default.ACTION_SHOW_COURSE,((e,data)=>{const target=(0,_jquery.default)(e.target).closest(_selectors.default.ACTION_SHOW_COURSE),courseId=getCourseId(target);((root,courseId)=>{const hideAction=getHideCourseMenuItem(root,courseId),showAction=getShowCourseMenuItem(root,courseId),filters=getFilterValues(root);setCourseHiddenState(courseId,null),filters.grouping!==GROUPINGS_GROUPING_ALLINCLUDINGHIDDEN&&hideElement(root,courseId),hideAction.removeClass("hidden"),showAction.addClass("hidden")})(root,courseId),data.originalEvent.preventDefault()}));const input=page.querySelector(_selectors.default.region.searchInput),clearIcon=page.querySelector(_selectors.default.region.clearIcon);clearIcon.addEventListener("click",(()=>{input.value="",input.focus(),clearSearch(clearIcon,root)})),input.addEventListener("input",(0,_utils.debounce)((()=>{""===input.value?clearSearch(clearIcon,root):(activeSearch(clearIcon),initializePagedContent(root,searchFunctionalityCurry(),input.value.trim()))}),1e3))},clearSearch=(clearIcon,root)=>{clearIcon.classList.add("d-none"),init(root)};_exports.clearSearch=clearSearch;const activeSearch=clearIcon=>{clearIcon.classList.remove("d-none")},init=root=>{if(root=(0,_jquery.default)(root),loadedPages=[],lastPage=0,courseOffset=0,!root.attr("data-init")){const page=document.querySelector(_selectors.default.region.selectBlock);registerEventListeners(root,page),namespace="block_myoverview_"+root.attr("id")+"_"+Math.random(),root.attr("data-init",!0)}initializePagedContent(root,standardFunctionalityCurry())};_exports.init=init;_exports.reset=root=>{if(loadedPages.length>0){if("summary"!==getFilterValues(root).display||summaryDisplayLoaded)loadedPages.forEach(((courseList,index)=>{let pagedContentPage=getPagedContentContainer(root,index);renderCourses(root,courseList).then(((html,js)=>Templates.replaceNodeContents(pagedContentPage,html,js))).catch(Notification.exception)}));else{const input=document.querySelector(_selectors.default.region.selectBlock).querySelector(_selectors.default.region.searchInput);""!==input.value?initializePagedContent(root,searchFunctionalityCurry(),input.value.trim()):initializePagedContent(root,standardFunctionalityCurry())}}else init(root)}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.reset=_exports.init=_exports.clearSearch=void 0,_jquery=_interopRequireDefault(_jquery),Repository=_interopRequireWildcard(Repository),PagedContentFactory=_interopRequireWildcard(PagedContentFactory),PubSub=_interopRequireWildcard(PubSub),CustomEvents=_interopRequireWildcard(CustomEvents),Notification=_interopRequireWildcard(Notification),Templates=_interopRequireWildcard(Templates),CourseEvents=_interopRequireWildcard(CourseEvents),_selectors=_interopRequireDefault(_selectors),PagedContentEvents=_interopRequireWildcard(PagedContentEvents),Aria=_interopRequireWildcard(Aria);const TEMPLATES_COURSES_CARDS="block_myoverview/view-cards",TEMPLATES_COURSES_LIST="block_myoverview/view-list",TEMPLATES_COURSES_SUMMARY="block_myoverview/view-summary",TEMPLATES_NOCOURSES="core_course/no-courses",GROUPINGS_GROUPING_ALLINCLUDINGHIDDEN="allincludinghidden",NUMCOURSES_PERPAGE=[12,24,48,96,0];let loadedPages=[],courseOffset=0,lastPage=0,lastLimit=0,namespace=null,summaryDisplayLoaded=!1;const getFilterValues=root=>{const courseRegion=root.find(_selectors.default.courseView.region);return{display:courseRegion.attr("data-display"),grouping:courseRegion.attr("data-grouping"),sort:courseRegion.attr("data-sort"),displaycategories:courseRegion.attr("data-displaycategories"),customfieldname:courseRegion.attr("data-customfieldname"),customfieldvalue:courseRegion.attr("data-customfieldvalue")}},DEFAULT_PAGED_CONTENT_CONFIG={ignoreControlWhileLoading:!0,controlPlacementBottom:!0,persistentLimitKey:"block_myoverview_user_paging_preference"},getFavouriteIconContainer=(root,courseId)=>root.find(_selectors.default.FAVOURITE_ICON+'[data-course-id="'+courseId+'"]'),getPagedContentContainer=(root,index)=>root.find('[data-region="paged-content-page"][data-page="'+index+'"]'),getCourseId=root=>root.attr("data-course-id"),getAddFavouriteMenuItem=(root,courseId)=>root.find('[data-action="add-favourite"][data-course-id="'+courseId+'"]'),getRemoveFavouriteMenuItem=(root,courseId)=>root.find('[data-action="remove-favourite"][data-course-id="'+courseId+'"]'),addToFavourites=(root,courseId)=>{const removeAction=getRemoveFavouriteMenuItem(root,courseId),addAction=getAddFavouriteMenuItem(root,courseId);setCourseFavouriteState(courseId,!0).then((success=>{success?(PubSub.publish(CourseEvents.favourited,courseId),removeAction.removeClass("hidden"),addAction.addClass("hidden"),((root,courseId)=>{const iconContainer=getFavouriteIconContainer(root,courseId),isFavouriteIcon=iconContainer.find(_selectors.default.ICON_IS_FAVOURITE);isFavouriteIcon.removeClass("hidden"),Aria.unhide(isFavouriteIcon);const notFavourteIcon=iconContainer.find(_selectors.default.ICON_NOT_FAVOURITE);notFavourteIcon.addClass("hidden"),Aria.hide(notFavourteIcon)})(root,courseId)):Notification.alert("Starring course failed","Could not change favourite state")})).catch(Notification.exception)},removeFromFavourites=(root,courseId)=>{const removeAction=getRemoveFavouriteMenuItem(root,courseId),addAction=getAddFavouriteMenuItem(root,courseId);setCourseFavouriteState(courseId,!1).then((success=>{success?(PubSub.publish(CourseEvents.unfavorited,courseId),removeAction.addClass("hidden"),addAction.removeClass("hidden"),((root,courseId)=>{const iconContainer=getFavouriteIconContainer(root,courseId),isFavouriteIcon=iconContainer.find(_selectors.default.ICON_IS_FAVOURITE);isFavouriteIcon.addClass("hidden"),Aria.hide(isFavouriteIcon);const notFavourteIcon=iconContainer.find(_selectors.default.ICON_NOT_FAVOURITE);notFavourteIcon.removeClass("hidden"),Aria.unhide(notFavourteIcon)})(root,courseId)):Notification.alert("Starring course failed","Could not change favourite state")})).catch(Notification.exception)},getHideCourseMenuItem=(root,courseId)=>root.find('[data-action="hide-course"][data-course-id="'+courseId+'"]'),getShowCourseMenuItem=(root,courseId)=>root.find('[data-action="show-course"][data-course-id="'+courseId+'"]'),setCourseHiddenState=(courseId,status)=>(!1===status&&(status=null),(0,_repository2.setUserPreference)("block_myoverview_hidden_course_".concat(courseId),status).catch(Notification.exception)),hideElement=(root,id)=>{const pagingBar=root.find('[data-region="paging-bar"]'),jumpto=parseInt(pagingBar.attr("data-active-page-number"));let reducedCourse=loadedPages[jumpto].courses.reduce(((accumulator,current)=>(+id!=+current.id&&accumulator.push(current),accumulator)),[]);if(void 0!==loadedPages[jumpto+1]){const newElement=loadedPages[jumpto+1].courses.slice(0,1);loadedPages.forEach(((courseList,index)=>{if(index>jumpto){let popElement=[];void 0!==loadedPages[index+1]&&(popElement=loadedPages[index+1].courses.slice(0,1)),loadedPages[index].courses=[...loadedPages[index].courses.slice(1),...popElement]}})),reducedCourse=[...reducedCourse,...newElement]}if(lastPage===jumpto+1&&0===loadedPages[jumpto+1].courses.length){const pagedContentContainer=root.find('[data-region="paged-content-container"]');PagedContentFactory.resetLastPageNumber((0,_jquery.default)(pagedContentContainer).attr("id"),jumpto)}loadedPages[jumpto].courses=reducedCourse,courseOffset--;const pagedContentPage=getPagedContentContainer(root,jumpto);renderCourses(root,loadedPages[jumpto]).then(((html,js)=>Templates.replaceNodeContents(pagedContentPage,html,js))).catch(Notification.exception),loadedPages.forEach(((courseList,index)=>{if(index>jumpto){getPagedContentContainer(root,index).remove()}}))},setCourseFavouriteState=(courseId,status)=>Repository.setFavouriteCourses({courses:[{id:courseId,favourite:status}]}).then((result=>0===result.warnings.length&&(loadedPages.forEach((courseList=>{courseList.courses.forEach(((course,index)=>{course.id==courseId&&(courseList.courses[index].isfavourite=status)}))})),!0))).catch(Notification.exception),noCoursesRender=root=>{const nocoursesimg=root.find(_selectors.default.courseView.region).attr("data-nocoursesimg"),newcourseurl=root.find(_selectors.default.courseView.region).attr("data-newcourseurl");return Templates.render(TEMPLATES_NOCOURSES,{nocoursesimg:nocoursesimg,newcourseurl:newcourseurl})},renderCourses=(root,coursesData)=>{const filters=getFilterValues(root);let currentTemplate="";return currentTemplate="card"===filters.display?TEMPLATES_COURSES_CARDS:"list"===filters.display?TEMPLATES_COURSES_LIST:TEMPLATES_COURSES_SUMMARY,coursesData?(!1===Array.isArray(coursesData.courses)&&(coursesData.courses=Object.values(coursesData.courses)),coursesData.courses=coursesData.courses.map((course=>(course.showcoursecategory="on"===filters.displaycategories,course))),coursesData.courses.length?Templates.render(currentTemplate,{courses:coursesData.courses}):noCoursesRender(root)):noCoursesRender(root)},registerPagedEventHandlers=(root,namespace)=>{const event=namespace+PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT;PubSub.subscribe(event,(root=>limit=>root.find(_selectors.default.courseView.region).attr("data-paging",limit))(root))},itemsPerPageFunc=(pagingLimit,root)=>{let itemsPerPage=NUMCOURSES_PERPAGE.map((value=>{let active=!1;return value===pagingLimit&&(active=!0),{value:value,active:active}}));const totalCourseCount=parseInt(root.find(_selectors.default.courseView.region).attr("data-totalcoursecount"),10);return itemsPerPage.filter((pagingOption=>!(0===pagingOption.value&&totalCourseCount>100)&&pagingOption.value4&&void 0!==arguments[4]?arguments[4]:null,courses=coursesData.courses?coursesData.courses:coursesData,nextPageStart=0,pageCourses=[];if(void 0!==loadedPages[currentPage]){pageCourses=loadedPages[currentPage].courses;const currentPageLength=pageCourses.length;currentPageLength0?courses.slice(0,pageData.limit):courses;loadedPages[currentPage]={courses:pageCourses};const remainingCourses=!1!==nextPageStart?courses.slice(nextPageStart,courses.length):[];remainingCourses.length&&(loadedPages[currentPage+1]={courses:remainingCourses}),loadedPages[currentPage].courses.length{courseOffset=0,loadedPages=[],lastPage=0,lastLimit=0},standardFunctionalityCurry=()=>(resetGlobals(),(filters,currentPage,pageData,actions,root,promises,limit)=>{const pagePromise=((filters,limit)=>{const params={offset:courseOffset,limit:limit,classification:filters.grouping,sort:filters.sort,customfieldname:filters.customfieldname,customfieldvalue:filters.customfieldvalue};return"summary"===filters.display?(params.requiredfields=Repository.SUMMARY_REQUIRED_FIELDS,summaryDisplayLoaded=!0):params.requiredfields=Repository.CARDLIST_REQUIRED_FIELDS,Repository.getEnrolledCoursesByTimeline(params)})(filters,limit).then((coursesData=>(pageBuilder(coursesData,currentPage,pageData,actions),renderCourses(root,loadedPages[currentPage])))).catch(Notification.exception);promises.push(pagePromise)}),searchFunctionalityCurry=()=>(resetGlobals(),(filters,currentPage,pageData,actions,root,promises,limit,inputValue)=>{const searchingPromise=((filters,limit,searchValue)=>{const params={offset:courseOffset,limit:limit,classification:"search",sort:filters.sort,customfieldname:filters.customfieldname,customfieldvalue:filters.customfieldvalue,searchvalue:searchValue};return"summary"===filters.display?(params.requiredfields=Repository.SUMMARY_REQUIRED_FIELDS,summaryDisplayLoaded=!0):(params.requiredfields=Repository.CARDLIST_REQUIRED_FIELDS,summaryDisplayLoaded=!1),Repository.getEnrolledCoursesByTimeline(params)})(filters,limit,inputValue).then((coursesData=>(pageBuilder(coursesData,currentPage,pageData,actions),renderCourses(root,loadedPages[currentPage])))).catch(Notification.exception);promises.push(searchingPromise)}),initializePagedContent=function(root,promiseFunction){let inputValue=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const pagingLimit=parseInt(root.find(_selectors.default.courseView.region).attr("data-paging"),10);let itemsPerPage=itemsPerPageFunc(pagingLimit,root);const filters=getFilterValues(root),config={...DEFAULT_PAGED_CONTENT_CONFIG};config.eventNamespace=namespace;const pagedContentPromise=PagedContentFactory.createWithLimit(itemsPerPage,((pagesData,actions)=>{let promises=[];return pagesData.forEach((pageData=>{const currentPage=pageData.pageNumber;let limit=pageData.limit>0?pageData.limit:0;if(+lastLimit!=+limit&&(loadedPages=[],courseOffset=0,lastPage=0),lastPage===currentPage)return actions.allItemsLoaded(lastPage),void promises.push(renderCourses(root,loadedPages[currentPage]));lastLimit=limit,void 0===loadedPages[currentPage+1]&&void 0===loadedPages[currentPage]&&(limit*=2),promiseFunction(filters,currentPage,pageData,actions,root,promises,limit,inputValue)})),promises}),config);pagedContentPromise.then(((html,js)=>(registerPagedEventHandlers(root,namespace),Templates.replaceNodeContents(root.find(_selectors.default.courseView.region),html,js)))).catch(Notification.exception)},registerEventListeners=(root,page)=>{CustomEvents.define(root,[CustomEvents.events.activate]),root.on(CustomEvents.events.activate,_selectors.default.ACTION_ADD_FAVOURITE,((e,data)=>{const favourite=(0,_jquery.default)(e.target).closest(_selectors.default.ACTION_ADD_FAVOURITE),courseId=getCourseId(favourite);addToFavourites(root,courseId),data.originalEvent.preventDefault()})),root.on(CustomEvents.events.activate,_selectors.default.ACTION_REMOVE_FAVOURITE,((e,data)=>{const favourite=(0,_jquery.default)(e.target).closest(_selectors.default.ACTION_REMOVE_FAVOURITE),courseId=getCourseId(favourite);removeFromFavourites(root,courseId),data.originalEvent.preventDefault()})),root.on(CustomEvents.events.activate,_selectors.default.FAVOURITE_ICON,((e,data)=>{data.originalEvent.preventDefault()})),root.on(CustomEvents.events.activate,_selectors.default.ACTION_HIDE_COURSE,((e,data)=>{const target=(0,_jquery.default)(e.target).closest(_selectors.default.ACTION_HIDE_COURSE),courseId=getCourseId(target);((root,courseId)=>{const hideAction=getHideCourseMenuItem(root,courseId),showAction=getShowCourseMenuItem(root,courseId),filters=getFilterValues(root);setCourseHiddenState(courseId,!0),filters.grouping!==GROUPINGS_GROUPING_ALLINCLUDINGHIDDEN&&hideElement(root,courseId),hideAction.addClass("hidden"),showAction.removeClass("hidden")})(root,courseId),data.originalEvent.preventDefault()})),root.on(CustomEvents.events.activate,_selectors.default.ACTION_SHOW_COURSE,((e,data)=>{const target=(0,_jquery.default)(e.target).closest(_selectors.default.ACTION_SHOW_COURSE),courseId=getCourseId(target);((root,courseId)=>{const hideAction=getHideCourseMenuItem(root,courseId),showAction=getShowCourseMenuItem(root,courseId),filters=getFilterValues(root);setCourseHiddenState(courseId,null),filters.grouping!==GROUPINGS_GROUPING_ALLINCLUDINGHIDDEN&&hideElement(root,courseId),hideAction.removeClass("hidden"),showAction.addClass("hidden")})(root,courseId),data.originalEvent.preventDefault()}));const input=page.querySelector(_selectors.default.region.searchInput),clearIcon=page.querySelector(_selectors.default.region.clearIcon);clearIcon.addEventListener("click",(()=>{input.value="",input.focus(),clearSearch(clearIcon,root)})),input.addEventListener("input",(0,_utils.debounce)((()=>{""===input.value?clearSearch(clearIcon,root):(activeSearch(clearIcon),initializePagedContent(root,searchFunctionalityCurry(),input.value.trim()))}),1e3))},clearSearch=(clearIcon,root)=>{clearIcon.classList.add("d-none"),init(root)};_exports.clearSearch=clearSearch;const activeSearch=clearIcon=>{clearIcon.classList.remove("d-none")},init=root=>{if(root=(0,_jquery.default)(root),loadedPages=[],lastPage=0,courseOffset=0,!root.attr("data-init")){const page=document.querySelector(_selectors.default.region.selectBlock);registerEventListeners(root,page),namespace="block_myoverview_"+root.attr("id")+"_"+Math.random(),root.attr("data-init",!0)}initializePagedContent(root,standardFunctionalityCurry())};_exports.init=init;_exports.reset=root=>{if(loadedPages.length>0){if("summary"!==getFilterValues(root).display||summaryDisplayLoaded)loadedPages.forEach(((courseList,index)=>{let pagedContentPage=getPagedContentContainer(root,index);renderCourses(root,courseList).then(((html,js)=>Templates.replaceNodeContents(pagedContentPage,html,js))).catch(Notification.exception)}));else{const input=document.querySelector(_selectors.default.region.selectBlock).querySelector(_selectors.default.region.searchInput);""!==input.value?initializePagedContent(root,searchFunctionalityCurry(),input.value.trim()):initializePagedContent(root,standardFunctionalityCurry())}}else init(root)}})); //# sourceMappingURL=view.min.js.map \ No newline at end of file diff --git a/blocks/myoverview/amd/build/view.min.js.map b/blocks/myoverview/amd/build/view.min.js.map index 3031516e38d..d9cffc5deac 100644 --- a/blocks/myoverview/amd/build/view.min.js.map +++ b/blocks/myoverview/amd/build/view.min.js.map @@ -1 +1 @@ -{"version":3,"file":"view.min.js","sources":["../src/view.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Manage the courses view for the overview block.\n *\n * @copyright 2018 Bas Brands \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport * as Repository from 'block_myoverview/repository';\nimport * as PagedContentFactory from 'core/paged_content_factory';\nimport * as PubSub from 'core/pubsub';\nimport * as CustomEvents from 'core/custom_interaction_events';\nimport * as Notification from 'core/notification';\nimport * as Templates from 'core/templates';\nimport * as CourseEvents from 'core_course/events';\nimport SELECTORS from 'block_myoverview/selectors';\nimport * as PagedContentEvents from 'core/paged_content_events';\nimport * as Aria from 'core/aria';\nimport {debounce} from 'core/utils';\nimport {setUserPreference} from 'core_user/repository';\n\nconst TEMPLATES = {\n COURSES_CARDS: 'block_myoverview/view-cards',\n COURSES_LIST: 'block_myoverview/view-list',\n COURSES_SUMMARY: 'block_myoverview/view-summary',\n NOCOURSES: 'core_course/no-courses'\n};\n\nconst GROUPINGS = {\n GROUPING_ALLINCLUDINGHIDDEN: 'allincludinghidden',\n GROUPING_ALL: 'all',\n GROUPING_INPROGRESS: 'inprogress',\n GROUPING_FUTURE: 'future',\n GROUPING_PAST: 'past',\n GROUPING_FAVOURITES: 'favourites',\n GROUPING_HIDDEN: 'hidden'\n};\n\nconst NUMCOURSES_PERPAGE = [12, 24, 48, 96, 0];\n\nlet loadedPages = [];\n\nlet courseOffset = 0;\n\nlet lastPage = 0;\n\nlet lastLimit = 0;\n\nlet namespace = null;\n\n/**\n * Whether the summary display has been loaded.\n *\n * If true, this means that courses have been loaded with the summary text.\n * Otherwise, switching to the summary display mode will require course data to be fetched with the summary text.\n *\n * @type {boolean}\n */\nlet summaryDisplayLoaded = false;\n\n/**\n * Get filter values from DOM.\n *\n * @param {object} root The root element for the courses view.\n * @return {filters} Set filters.\n */\nconst getFilterValues = root => {\n const courseRegion = root.find(SELECTORS.courseView.region);\n return {\n display: courseRegion.attr('data-display'),\n grouping: courseRegion.attr('data-grouping'),\n sort: courseRegion.attr('data-sort'),\n displaycategories: courseRegion.attr('data-displaycategories'),\n customfieldname: courseRegion.attr('data-customfieldname'),\n customfieldvalue: courseRegion.attr('data-customfieldvalue'),\n };\n};\n\n// We want the paged content controls below the paged content area.\n// and the controls should be ignored while data is loading.\nconst DEFAULT_PAGED_CONTENT_CONFIG = {\n ignoreControlWhileLoading: true,\n controlPlacementBottom: true,\n persistentLimitKey: 'block_myoverview_user_paging_preference'\n};\n\n/**\n * Get enrolled courses from backend.\n *\n * @param {object} filters The filters for this view.\n * @param {int} limit The number of courses to show.\n * @return {promise} Resolved with an array of courses.\n */\nconst getMyCourses = (filters, limit) => {\n const params = {\n offset: courseOffset,\n limit: limit,\n classification: filters.grouping,\n sort: filters.sort,\n customfieldname: filters.customfieldname,\n customfieldvalue: filters.customfieldvalue,\n };\n if (filters.display === 'summary') {\n params.requiredfields = Repository.SUMMARY_REQUIRED_FIELDS;\n summaryDisplayLoaded = true;\n } else {\n params.requiredfields = Repository.CARDLIST_REQUIRED_FIELDS;\n }\n return Repository.getEnrolledCoursesByTimeline(params);\n};\n\n/**\n * Search for enrolled courses from backend.\n *\n * @param {object} filters The filters for this view.\n * @param {int} limit The number of courses to show.\n * @param {string} searchValue What does the user want to search within their courses.\n * @return {promise} Resolved with an array of courses.\n */\nconst getSearchMyCourses = (filters, limit, searchValue) => {\n const params = {\n offset: courseOffset,\n limit: limit,\n classification: 'search',\n sort: filters.sort,\n customfieldname: filters.customfieldname,\n customfieldvalue: filters.customfieldvalue,\n searchvalue: searchValue,\n };\n if (filters.display === 'summary') {\n params.requiredfields = Repository.SUMMARY_REQUIRED_FIELDS;\n summaryDisplayLoaded = true;\n } else {\n params.requiredfields = Repository.CARDLIST_REQUIRED_FIELDS;\n summaryDisplayLoaded = false;\n }\n return Repository.getEnrolledCoursesByTimeline(params);\n};\n\n/**\n * Get the container element for the favourite icon.\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n * @return {Object} The favourite icon container\n */\nconst getFavouriteIconContainer = (root, courseId) => {\n return root.find(SELECTORS.FAVOURITE_ICON + '[data-course-id=\"' + courseId + '\"]');\n};\n\n/**\n * Get the paged content container element.\n *\n * @param {Object} root The course overview container\n * @param {Number} index Rendered page index.\n * @return {Object} The rendered paged container.\n */\nconst getPagedContentContainer = (root, index) => {\n return root.find('[data-region=\"paged-content-page\"][data-page=\"' + index + '\"]');\n};\n\n/**\n * Get the course id from a favourite element.\n *\n * @param {Object} root The favourite icon container element.\n * @return {Number} Course id.\n */\nconst getCourseId = root => {\n return root.attr('data-course-id');\n};\n\n/**\n * Hide the favourite icon.\n *\n * @param {Object} root The favourite icon container element.\n * @param {Number} courseId Course id number.\n */\nconst hideFavouriteIcon = (root, courseId) => {\n const iconContainer = getFavouriteIconContainer(root, courseId);\n\n const isFavouriteIcon = iconContainer.find(SELECTORS.ICON_IS_FAVOURITE);\n isFavouriteIcon.addClass('hidden');\n Aria.hide(isFavouriteIcon);\n\n const notFavourteIcon = iconContainer.find(SELECTORS.ICON_NOT_FAVOURITE);\n notFavourteIcon.removeClass('hidden');\n Aria.unhide(notFavourteIcon);\n};\n\n/**\n * Show the favourite icon.\n *\n * @param {Object} root The course overview container.\n * @param {Number} courseId Course id number.\n */\nconst showFavouriteIcon = (root, courseId) => {\n const iconContainer = getFavouriteIconContainer(root, courseId);\n\n const isFavouriteIcon = iconContainer.find(SELECTORS.ICON_IS_FAVOURITE);\n isFavouriteIcon.removeClass('hidden');\n Aria.unhide(isFavouriteIcon);\n\n const notFavourteIcon = iconContainer.find(SELECTORS.ICON_NOT_FAVOURITE);\n notFavourteIcon.addClass('hidden');\n Aria.hide(notFavourteIcon);\n};\n\n/**\n * Get the action menu item\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The add to favourite menu item.\n */\nconst getAddFavouriteMenuItem = (root, courseId) => {\n return root.find('[data-action=\"add-favourite\"][data-course-id=\"' + courseId + '\"]');\n};\n\n/**\n * Get the action menu item\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The remove from favourites menu item.\n */\nconst getRemoveFavouriteMenuItem = (root, courseId) => {\n return root.find('[data-action=\"remove-favourite\"][data-course-id=\"' + courseId + '\"]');\n};\n\n/**\n * Add course to favourites\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n */\nconst addToFavourites = (root, courseId) => {\n const removeAction = getRemoveFavouriteMenuItem(root, courseId);\n const addAction = getAddFavouriteMenuItem(root, courseId);\n\n setCourseFavouriteState(courseId, true).then(success => {\n if (success) {\n PubSub.publish(CourseEvents.favourited, courseId);\n removeAction.removeClass('hidden');\n addAction.addClass('hidden');\n showFavouriteIcon(root, courseId);\n } else {\n Notification.alert('Starring course failed', 'Could not change favourite state');\n }\n return;\n }).catch(Notification.exception);\n};\n\n/**\n * Remove course from favourites\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n */\nconst removeFromFavourites = (root, courseId) => {\n const removeAction = getRemoveFavouriteMenuItem(root, courseId);\n const addAction = getAddFavouriteMenuItem(root, courseId);\n\n setCourseFavouriteState(courseId, false).then(success => {\n if (success) {\n PubSub.publish(CourseEvents.unfavorited, courseId);\n removeAction.addClass('hidden');\n addAction.removeClass('hidden');\n hideFavouriteIcon(root, courseId);\n } else {\n Notification.alert('Starring course failed', 'Could not change favourite state');\n }\n return;\n }).catch(Notification.exception);\n};\n\n/**\n * Get the action menu item\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The hide course menu item.\n */\nconst getHideCourseMenuItem = (root, courseId) => {\n return root.find('[data-action=\"hide-course\"][data-course-id=\"' + courseId + '\"]');\n};\n\n/**\n * Get the action menu item\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The show course menu item.\n */\nconst getShowCourseMenuItem = (root, courseId) => {\n return root.find('[data-action=\"show-course\"][data-course-id=\"' + courseId + '\"]');\n};\n\n/**\n * Hide course\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n */\nconst hideCourse = (root, courseId) => {\n const hideAction = getHideCourseMenuItem(root, courseId);\n const showAction = getShowCourseMenuItem(root, courseId);\n const filters = getFilterValues(root);\n\n setCourseHiddenState(courseId, true);\n\n // Remove the course from this view as it is now hidden and thus not covered by this view anymore.\n // Do only if we are not in \"All (including archived)\" view mode where really all courses are shown.\n if (filters.grouping !== GROUPINGS.GROUPING_ALLINCLUDINGHIDDEN) {\n hideElement(root, courseId);\n }\n\n hideAction.addClass('hidden');\n showAction.removeClass('hidden');\n};\n\n/**\n * Show course\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n */\nconst showCourse = (root, courseId) => {\n const hideAction = getHideCourseMenuItem(root, courseId);\n const showAction = getShowCourseMenuItem(root, courseId);\n const filters = getFilterValues(root);\n\n setCourseHiddenState(courseId, null);\n\n // Remove the course from this view as it is now shown again and thus not covered by this view anymore.\n // Do only if we are not in \"All (including archived)\" view mode where really all courses are shown.\n if (filters.grouping !== GROUPINGS.GROUPING_ALLINCLUDINGHIDDEN) {\n hideElement(root, courseId);\n }\n\n hideAction.removeClass('hidden');\n showAction.addClass('hidden');\n};\n\n/**\n * Set the courses hidden status and push to repository\n *\n * @param {Number} courseId Course id to favourite.\n * @param {Boolean} status new hidden status.\n * @return {Promise} Repository promise.\n */\nconst setCourseHiddenState = (courseId, status) => {\n\n // If the given status is not hidden, the preference has to be deleted with a null value.\n if (status === false) {\n status = null;\n }\n\n return setUserPreference(`block_myoverview_hidden_course_${courseId}`, status)\n .catch(Notification.exception);\n};\n\n/**\n * Reset the loadedPages dataset to take into account the hidden element\n *\n * @param {Object} root The course overview container\n * @param {Number} id The course id number\n */\nconst hideElement = (root, id) => {\n const pagingBar = root.find('[data-region=\"paging-bar\"]');\n const jumpto = parseInt(pagingBar.attr('data-active-page-number'));\n\n // Get a reduced dataset for the current page.\n const courseList = loadedPages[jumpto];\n let reducedCourse = courseList.courses.reduce((accumulator, current) => {\n if (+id !== +current.id) {\n accumulator.push(current);\n }\n return accumulator;\n }, []);\n\n // Get the next page's data if loaded and pop the first element from it.\n if (typeof (loadedPages[jumpto + 1]) !== 'undefined') {\n const newElement = loadedPages[jumpto + 1].courses.slice(0, 1);\n\n // Adjust the dataset for the reset of the pages that are loaded.\n loadedPages.forEach((courseList, index) => {\n if (index > jumpto) {\n let popElement = [];\n if (typeof (loadedPages[index + 1]) !== 'undefined') {\n popElement = loadedPages[index + 1].courses.slice(0, 1);\n }\n loadedPages[index].courses = [...loadedPages[index].courses.slice(1), ...popElement];\n }\n });\n\n reducedCourse = [...reducedCourse, ...newElement];\n }\n\n // Check if the next page is the last page and if it still has data associated to it.\n if (lastPage === jumpto + 1 && loadedPages[jumpto + 1].courses.length === 0) {\n const pagedContentContainer = root.find('[data-region=\"paged-content-container\"]');\n PagedContentFactory.resetLastPageNumber($(pagedContentContainer).attr('id'), jumpto);\n }\n\n loadedPages[jumpto].courses = reducedCourse;\n\n // Reduce the course offset.\n courseOffset--;\n\n // Render the paged content for the current.\n const pagedContentPage = getPagedContentContainer(root, jumpto);\n renderCourses(root, loadedPages[jumpto]).then((html, js) => {\n return Templates.replaceNodeContents(pagedContentPage, html, js);\n }).catch(Notification.exception);\n\n // Delete subsequent pages in order to trigger the callback.\n loadedPages.forEach((courseList, index) => {\n if (index > jumpto) {\n const page = getPagedContentContainer(root, index);\n page.remove();\n }\n });\n};\n\n/**\n * Set the courses favourite status and push to repository\n *\n * @param {Number} courseId Course id to favourite.\n * @param {boolean} status new favourite status.\n * @return {Promise} Repository promise.\n */\nconst setCourseFavouriteState = (courseId, status) => {\n\n return Repository.setFavouriteCourses({\n courses: [\n {\n 'id': courseId,\n 'favourite': status\n }\n ]\n }).then(result => {\n if (result.warnings.length === 0) {\n loadedPages.forEach(courseList => {\n courseList.courses.forEach((course, index) => {\n if (course.id == courseId) {\n courseList.courses[index].isfavourite = status;\n }\n });\n });\n return true;\n } else {\n return false;\n }\n }).catch(Notification.exception);\n};\n\n/**\n * Given there are no courses to render provide the rendered template.\n *\n * @param {object} root The root element for the courses view.\n * @return {promise} jQuery promise resolved after rendering is complete.\n */\nconst noCoursesRender = root => {\n const nocoursesimg = root.find(SELECTORS.courseView.region).attr('data-nocoursesimg');\n const newcourseurl = root.find(SELECTORS.courseView.region).attr('data-newcourseurl');\n return Templates.render(TEMPLATES.NOCOURSES, {\n nocoursesimg: nocoursesimg,\n newcourseurl: newcourseurl\n });\n};\n\n/**\n * Render the dashboard courses.\n *\n * @param {object} root The root element for the courses view.\n * @param {array} coursesData containing array of returned courses.\n * @return {promise} jQuery promise resolved after rendering is complete.\n */\nconst renderCourses = (root, coursesData) => {\n\n const filters = getFilterValues(root);\n\n let currentTemplate = '';\n if (filters.display === 'card') {\n currentTemplate = TEMPLATES.COURSES_CARDS;\n } else if (filters.display === 'list') {\n currentTemplate = TEMPLATES.COURSES_LIST;\n } else {\n currentTemplate = TEMPLATES.COURSES_SUMMARY;\n }\n\n if (!coursesData) {\n return noCoursesRender(root);\n } else {\n // Sometimes we get weird objects coming after a failed search, cast to ensure typing functions.\n if (Array.isArray(coursesData.courses) === false) {\n coursesData.courses = Object.values(coursesData.courses);\n }\n // Whether the course category should be displayed in the course item.\n coursesData.courses = coursesData.courses.map(course => {\n course.showcoursecategory = filters.displaycategories === 'on';\n return course;\n });\n if (coursesData.courses.length) {\n return Templates.render(currentTemplate, {\n courses: coursesData.courses,\n });\n } else {\n return noCoursesRender(root);\n }\n }\n};\n\n/**\n * Return the callback to be passed to the subscribe event\n *\n * @param {object} root The root element for the courses view\n * @return {function} Partially applied function that'll execute when passed a limit\n */\nconst setLimit = root => {\n // @param {Number} limit The paged limit that is passed through the event.\n return limit => root.find(SELECTORS.courseView.region).attr('data-paging', limit);\n};\n\n/**\n * Intialise the paged list and cards views on page load.\n * Returns an array of paged contents that we would like to handle here\n *\n * @param {object} root The root element for the courses view\n * @param {string} namespace The namespace for all the events attached\n */\nconst registerPagedEventHandlers = (root, namespace) => {\n const event = namespace + PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT;\n PubSub.subscribe(event, setLimit(root));\n};\n\n/**\n * Figure out how many items are going to be allowed to be rendered in the block.\n *\n * @param {Number} pagingLimit How many courses to display\n * @param {Object} root The course overview container\n * @return {Number[]} How many courses will be rendered\n */\nconst itemsPerPageFunc = (pagingLimit, root) => {\n let itemsPerPage = NUMCOURSES_PERPAGE.map(value => {\n let active = false;\n if (value === pagingLimit) {\n active = true;\n }\n\n return {\n value: value,\n active: active\n };\n });\n\n // Filter out all pagination options which are too large for the amount of courses user is enrolled in.\n const totalCourseCount = parseInt(root.find(SELECTORS.courseView.region).attr('data-totalcoursecount'), 10);\n return itemsPerPage.filter(pagingOption => {\n return pagingOption.value < totalCourseCount || pagingOption.value === 0;\n });\n};\n\n/**\n * Mutates and controls the loadedPages array and handles the bootstrapping.\n *\n * @param {Array|Object} coursesData Array of all of the courses to start building the page from\n * @param {Number} currentPage What page are we currently on?\n * @param {Object} pageData Any current page information\n * @param {Object} actions Paged content helper\n * @param {null|boolean} activeSearch Are we currently actively searching and building up search results?\n */\nconst pageBuilder = (coursesData, currentPage, pageData, actions, activeSearch = null) => {\n // If the courseData comes in an object then get the value otherwise it is a pure array.\n let courses = coursesData.courses ? coursesData.courses : coursesData;\n let nextPageStart = 0;\n let pageCourses = [];\n\n // If current page's data is loaded make sure we max it to page limit.\n if (typeof (loadedPages[currentPage]) !== 'undefined') {\n pageCourses = loadedPages[currentPage].courses;\n const currentPageLength = pageCourses.length;\n if (currentPageLength < pageData.limit) {\n nextPageStart = pageData.limit - currentPageLength;\n pageCourses = {...loadedPages[currentPage].courses, ...courses.slice(0, nextPageStart)};\n }\n } else {\n // When the page limit is zero, there is only one page of courses, no start for next page.\n nextPageStart = pageData.limit || false;\n pageCourses = (pageData.limit > 0) ? courses.slice(0, pageData.limit) : courses;\n }\n\n // Finished setting up the current page.\n loadedPages[currentPage] = {\n courses: pageCourses\n };\n\n // Set up the next page (if there is more than one page).\n const remainingCourses = nextPageStart !== false ? courses.slice(nextPageStart, courses.length) : [];\n if (remainingCourses.length) {\n loadedPages[currentPage + 1] = {\n courses: remainingCourses\n };\n }\n\n // Set the last page to either the current or next page.\n if (loadedPages[currentPage].courses.length < pageData.limit || !remainingCourses.length) {\n lastPage = currentPage;\n if (activeSearch === null) {\n actions.allItemsLoaded(currentPage);\n }\n } else if (typeof (loadedPages[currentPage + 1]) !== 'undefined'\n && loadedPages[currentPage + 1].courses.length < pageData.limit) {\n lastPage = currentPage + 1;\n }\n\n courseOffset = coursesData.nextoffset;\n};\n\n/**\n * In cases when switching between regular rendering and search rendering we need to reset some variables.\n */\nconst resetGlobals = () => {\n courseOffset = 0;\n loadedPages = [];\n lastPage = 0;\n lastLimit = 0;\n};\n\n/**\n * The default functionality of fetching paginated courses without special handling.\n *\n * @return {function(Object, Object, Object, Object, Object, Promise, Number): void}\n */\nconst standardFunctionalityCurry = () => {\n resetGlobals();\n return (filters, currentPage, pageData, actions, root, promises, limit) => {\n const pagePromise = getMyCourses(\n filters,\n limit\n ).then(coursesData => {\n pageBuilder(coursesData, currentPage, pageData, actions);\n return renderCourses(root, loadedPages[currentPage]);\n }).catch(Notification.exception);\n\n promises.push(pagePromise);\n };\n};\n\n/**\n * Initialize the searching functionality so we can call it when required.\n *\n * @return {function(Object, Number, Object, Object, Object, Promise, Number, String): void}\n */\nconst searchFunctionalityCurry = () => {\n resetGlobals();\n return (filters, currentPage, pageData, actions, root, promises, limit, inputValue) => {\n const searchingPromise = getSearchMyCourses(\n filters,\n limit,\n inputValue\n ).then(coursesData => {\n pageBuilder(coursesData, currentPage, pageData, actions);\n return renderCourses(root, loadedPages[currentPage]);\n }).catch(Notification.exception);\n\n promises.push(searchingPromise);\n };\n};\n\n/**\n * Initialise the courses list and cards views on page load.\n *\n * @param {object} root The root element for the courses view.\n * @param {function} promiseFunction How do we fetch the courses and what do we do with them?\n * @param {null | string} inputValue What to search for\n */\nconst initializePagedContent = (root, promiseFunction, inputValue = null) => {\n const pagingLimit = parseInt(root.find(SELECTORS.courseView.region).attr('data-paging'), 10);\n let itemsPerPage = itemsPerPageFunc(pagingLimit, root);\n\n const filters = getFilterValues(root);\n const config = {...{}, ...DEFAULT_PAGED_CONTENT_CONFIG};\n config.eventNamespace = namespace;\n\n const pagedContentPromise = PagedContentFactory.createWithLimit(\n itemsPerPage,\n (pagesData, actions) => {\n let promises = [];\n pagesData.forEach(pageData => {\n const currentPage = pageData.pageNumber;\n let limit = (pageData.limit > 0) ? pageData.limit : 0;\n\n // Reset local variables if limits have changed.\n if (+lastLimit !== +limit) {\n loadedPages = [];\n courseOffset = 0;\n lastPage = 0;\n }\n\n if (lastPage === currentPage) {\n // If we are on the last page and have it's data then load it from cache.\n actions.allItemsLoaded(lastPage);\n promises.push(renderCourses(root, loadedPages[currentPage]));\n return;\n }\n\n lastLimit = limit;\n\n // Get 2 pages worth of data as we will need it for the hidden functionality.\n if (typeof (loadedPages[currentPage + 1]) === 'undefined') {\n if (typeof (loadedPages[currentPage]) === 'undefined') {\n limit *= 2;\n }\n }\n\n // Call the curried function that'll handle the course promise and any manipulation of it.\n promiseFunction(filters, currentPage, pageData, actions, root, promises, limit, inputValue);\n });\n return promises;\n },\n config\n );\n\n pagedContentPromise.then((html, js) => {\n registerPagedEventHandlers(root, namespace);\n return Templates.replaceNodeContents(root.find(SELECTORS.courseView.region), html, js);\n }).catch(Notification.exception);\n};\n\n/**\n * Listen to, and handle events for the myoverview block.\n *\n * @param {Object} root The myoverview block container element.\n * @param {HTMLElement} page The whole HTMLElement for our block.\n */\nconst registerEventListeners = (root, page) => {\n\n CustomEvents.define(root, [\n CustomEvents.events.activate\n ]);\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_ADD_FAVOURITE, (e, data) => {\n const favourite = $(e.target).closest(SELECTORS.ACTION_ADD_FAVOURITE);\n const courseId = getCourseId(favourite);\n addToFavourites(root, courseId);\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_REMOVE_FAVOURITE, (e, data) => {\n const favourite = $(e.target).closest(SELECTORS.ACTION_REMOVE_FAVOURITE);\n const courseId = getCourseId(favourite);\n removeFromFavourites(root, courseId);\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.FAVOURITE_ICON, (e, data) => {\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_HIDE_COURSE, (e, data) => {\n const target = $(e.target).closest(SELECTORS.ACTION_HIDE_COURSE);\n const courseId = getCourseId(target);\n hideCourse(root, courseId);\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_SHOW_COURSE, (e, data) => {\n const target = $(e.target).closest(SELECTORS.ACTION_SHOW_COURSE);\n const courseId = getCourseId(target);\n showCourse(root, courseId);\n data.originalEvent.preventDefault();\n });\n\n // Searching functionality event handlers.\n const input = page.querySelector(SELECTORS.region.searchInput);\n const clearIcon = page.querySelector(SELECTORS.region.clearIcon);\n\n clearIcon.addEventListener('click', () => {\n input.value = '';\n input.focus();\n clearSearch(clearIcon, root);\n });\n\n input.addEventListener('input', debounce(() => {\n if (input.value === '') {\n clearSearch(clearIcon, root);\n } else {\n activeSearch(clearIcon);\n initializePagedContent(root, searchFunctionalityCurry(), input.value.trim());\n }\n }, 1000));\n};\n\n/**\n * Reset the search icon and trigger the init for the block.\n *\n * @param {HTMLElement} clearIcon Our closing icon to manipulate.\n * @param {Object} root The myoverview block container element.\n */\nexport const clearSearch = (clearIcon, root) => {\n clearIcon.classList.add('d-none');\n init(root);\n};\n\n/**\n * Change the searching icon to its' active state.\n *\n * @param {HTMLElement} clearIcon Our closing icon to manipulate.\n */\nconst activeSearch = (clearIcon) => {\n clearIcon.classList.remove('d-none');\n};\n\n/**\n * Intialise the courses list and cards views on page load.\n *\n * @param {object} root The root element for the courses view.\n */\nexport const init = root => {\n root = $(root);\n loadedPages = [];\n lastPage = 0;\n courseOffset = 0;\n\n if (!root.attr('data-init')) {\n const page = document.querySelector(SELECTORS.region.selectBlock);\n registerEventListeners(root, page);\n namespace = \"block_myoverview_\" + root.attr('id') + \"_\" + Math.random();\n root.attr('data-init', true);\n }\n\n initializePagedContent(root, standardFunctionalityCurry());\n};\n\n/**\n * Reset the courses views to their original\n * state on first page load.courseOffset\n *\n * This is called when configuration has changed for the event lists\n * to cause them to reload their data.\n *\n * @param {Object} root The root element for the timeline view.\n */\nexport const reset = root => {\n if (loadedPages.length > 0) {\n const filters = getFilterValues(root);\n // If the display mode is changed to 'summary' but the summary display has not been loaded yet,\n // we need to re-fetch the courses to include the course summary text.\n if (filters.display === 'summary' && !summaryDisplayLoaded) {\n const page = document.querySelector(SELECTORS.region.selectBlock);\n const input = page.querySelector(SELECTORS.region.searchInput);\n if (input.value !== '') {\n initializePagedContent(root, searchFunctionalityCurry(), input.value.trim());\n } else {\n initializePagedContent(root, standardFunctionalityCurry());\n }\n } else {\n loadedPages.forEach((courseList, index) => {\n let pagedContentPage = getPagedContentContainer(root, index);\n renderCourses(root, courseList).then((html, js) => {\n return Templates.replaceNodeContents(pagedContentPage, html, js);\n }).catch(Notification.exception);\n });\n }\n } else {\n init(root);\n }\n};\n"],"names":["TEMPLATES","GROUPINGS","NUMCOURSES_PERPAGE","loadedPages","courseOffset","lastPage","lastLimit","namespace","summaryDisplayLoaded","getFilterValues","root","courseRegion","find","SELECTORS","courseView","region","display","attr","grouping","sort","displaycategories","customfieldname","customfieldvalue","DEFAULT_PAGED_CONTENT_CONFIG","ignoreControlWhileLoading","controlPlacementBottom","persistentLimitKey","getFavouriteIconContainer","courseId","FAVOURITE_ICON","getPagedContentContainer","index","getCourseId","getAddFavouriteMenuItem","getRemoveFavouriteMenuItem","addToFavourites","removeAction","addAction","setCourseFavouriteState","then","success","PubSub","publish","CourseEvents","favourited","removeClass","addClass","iconContainer","isFavouriteIcon","ICON_IS_FAVOURITE","Aria","unhide","notFavourteIcon","ICON_NOT_FAVOURITE","hide","showFavouriteIcon","Notification","alert","catch","exception","removeFromFavourites","unfavorited","hideFavouriteIcon","getHideCourseMenuItem","getShowCourseMenuItem","setCourseHiddenState","status","hideElement","id","pagingBar","jumpto","parseInt","reducedCourse","courses","reduce","accumulator","current","push","newElement","slice","forEach","courseList","popElement","length","pagedContentContainer","PagedContentFactory","resetLastPageNumber","pagedContentPage","renderCourses","html","js","Templates","replaceNodeContents","remove","Repository","setFavouriteCourses","result","warnings","course","isfavourite","noCoursesRender","nocoursesimg","newcourseurl","render","coursesData","filters","currentTemplate","Array","isArray","Object","values","map","showcoursecategory","registerPagedEventHandlers","event","PagedContentEvents","SET_ITEMS_PER_PAGE_LIMIT","subscribe","limit","setLimit","itemsPerPageFunc","pagingLimit","itemsPerPage","value","active","totalCourseCount","filter","pagingOption","pageBuilder","currentPage","pageData","actions","activeSearch","nextPageStart","pageCourses","currentPageLength","remainingCourses","allItemsLoaded","nextoffset","resetGlobals","standardFunctionalityCurry","promises","pagePromise","params","offset","classification","requiredfields","SUMMARY_REQUIRED_FIELDS","CARDLIST_REQUIRED_FIELDS","getEnrolledCoursesByTimeline","getMyCourses","searchFunctionalityCurry","inputValue","searchingPromise","searchValue","searchvalue","getSearchMyCourses","initializePagedContent","promiseFunction","config","eventNamespace","pagedContentPromise","createWithLimit","pagesData","pageNumber","registerEventListeners","page","CustomEvents","define","events","activate","on","ACTION_ADD_FAVOURITE","e","data","favourite","target","closest","originalEvent","preventDefault","ACTION_REMOVE_FAVOURITE","ACTION_HIDE_COURSE","hideAction","showAction","hideCourse","ACTION_SHOW_COURSE","showCourse","input","querySelector","searchInput","clearIcon","addEventListener","focus","clearSearch","trim","classList","add","init","document","selectBlock","Math","random"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"view.min.js","sources":["../src/view.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Manage the courses view for the overview block.\n *\n * @copyright 2018 Bas Brands \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport * as Repository from 'block_myoverview/repository';\nimport * as PagedContentFactory from 'core/paged_content_factory';\nimport * as PubSub from 'core/pubsub';\nimport * as CustomEvents from 'core/custom_interaction_events';\nimport * as Notification from 'core/notification';\nimport * as Templates from 'core/templates';\nimport * as CourseEvents from 'core_course/events';\nimport SELECTORS from 'block_myoverview/selectors';\nimport * as PagedContentEvents from 'core/paged_content_events';\nimport * as Aria from 'core/aria';\nimport {debounce} from 'core/utils';\nimport {setUserPreference} from 'core_user/repository';\n\nconst TEMPLATES = {\n COURSES_CARDS: 'block_myoverview/view-cards',\n COURSES_LIST: 'block_myoverview/view-list',\n COURSES_SUMMARY: 'block_myoverview/view-summary',\n NOCOURSES: 'core_course/no-courses'\n};\n\nconst GROUPINGS = {\n GROUPING_ALLINCLUDINGHIDDEN: 'allincludinghidden',\n GROUPING_ALL: 'all',\n GROUPING_INPROGRESS: 'inprogress',\n GROUPING_FUTURE: 'future',\n GROUPING_PAST: 'past',\n GROUPING_FAVOURITES: 'favourites',\n GROUPING_HIDDEN: 'hidden'\n};\n\nconst NUMCOURSES_PERPAGE = [12, 24, 48, 96, 0];\n\nlet loadedPages = [];\n\nlet courseOffset = 0;\n\nlet lastPage = 0;\n\nlet lastLimit = 0;\n\nlet namespace = null;\n\n/**\n * Whether the summary display has been loaded.\n *\n * If true, this means that courses have been loaded with the summary text.\n * Otherwise, switching to the summary display mode will require course data to be fetched with the summary text.\n *\n * @type {boolean}\n */\nlet summaryDisplayLoaded = false;\n\n/**\n * Get filter values from DOM.\n *\n * @param {object} root The root element for the courses view.\n * @return {filters} Set filters.\n */\nconst getFilterValues = root => {\n const courseRegion = root.find(SELECTORS.courseView.region);\n return {\n display: courseRegion.attr('data-display'),\n grouping: courseRegion.attr('data-grouping'),\n sort: courseRegion.attr('data-sort'),\n displaycategories: courseRegion.attr('data-displaycategories'),\n customfieldname: courseRegion.attr('data-customfieldname'),\n customfieldvalue: courseRegion.attr('data-customfieldvalue'),\n };\n};\n\n// We want the paged content controls below the paged content area.\n// and the controls should be ignored while data is loading.\nconst DEFAULT_PAGED_CONTENT_CONFIG = {\n ignoreControlWhileLoading: true,\n controlPlacementBottom: true,\n persistentLimitKey: 'block_myoverview_user_paging_preference'\n};\n\n/**\n * Get enrolled courses from backend.\n *\n * @param {object} filters The filters for this view.\n * @param {int} limit The number of courses to show.\n * @return {promise} Resolved with an array of courses.\n */\nconst getMyCourses = (filters, limit) => {\n const params = {\n offset: courseOffset,\n limit: limit,\n classification: filters.grouping,\n sort: filters.sort,\n customfieldname: filters.customfieldname,\n customfieldvalue: filters.customfieldvalue,\n };\n if (filters.display === 'summary') {\n params.requiredfields = Repository.SUMMARY_REQUIRED_FIELDS;\n summaryDisplayLoaded = true;\n } else {\n params.requiredfields = Repository.CARDLIST_REQUIRED_FIELDS;\n }\n return Repository.getEnrolledCoursesByTimeline(params);\n};\n\n/**\n * Search for enrolled courses from backend.\n *\n * @param {object} filters The filters for this view.\n * @param {int} limit The number of courses to show.\n * @param {string} searchValue What does the user want to search within their courses.\n * @return {promise} Resolved with an array of courses.\n */\nconst getSearchMyCourses = (filters, limit, searchValue) => {\n const params = {\n offset: courseOffset,\n limit: limit,\n classification: 'search',\n sort: filters.sort,\n customfieldname: filters.customfieldname,\n customfieldvalue: filters.customfieldvalue,\n searchvalue: searchValue,\n };\n if (filters.display === 'summary') {\n params.requiredfields = Repository.SUMMARY_REQUIRED_FIELDS;\n summaryDisplayLoaded = true;\n } else {\n params.requiredfields = Repository.CARDLIST_REQUIRED_FIELDS;\n summaryDisplayLoaded = false;\n }\n return Repository.getEnrolledCoursesByTimeline(params);\n};\n\n/**\n * Get the container element for the favourite icon.\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n * @return {Object} The favourite icon container\n */\nconst getFavouriteIconContainer = (root, courseId) => {\n return root.find(SELECTORS.FAVOURITE_ICON + '[data-course-id=\"' + courseId + '\"]');\n};\n\n/**\n * Get the paged content container element.\n *\n * @param {Object} root The course overview container\n * @param {Number} index Rendered page index.\n * @return {Object} The rendered paged container.\n */\nconst getPagedContentContainer = (root, index) => {\n return root.find('[data-region=\"paged-content-page\"][data-page=\"' + index + '\"]');\n};\n\n/**\n * Get the course id from a favourite element.\n *\n * @param {Object} root The favourite icon container element.\n * @return {Number} Course id.\n */\nconst getCourseId = root => {\n return root.attr('data-course-id');\n};\n\n/**\n * Hide the favourite icon.\n *\n * @param {Object} root The favourite icon container element.\n * @param {Number} courseId Course id number.\n */\nconst hideFavouriteIcon = (root, courseId) => {\n const iconContainer = getFavouriteIconContainer(root, courseId);\n\n const isFavouriteIcon = iconContainer.find(SELECTORS.ICON_IS_FAVOURITE);\n isFavouriteIcon.addClass('hidden');\n Aria.hide(isFavouriteIcon);\n\n const notFavourteIcon = iconContainer.find(SELECTORS.ICON_NOT_FAVOURITE);\n notFavourteIcon.removeClass('hidden');\n Aria.unhide(notFavourteIcon);\n};\n\n/**\n * Show the favourite icon.\n *\n * @param {Object} root The course overview container.\n * @param {Number} courseId Course id number.\n */\nconst showFavouriteIcon = (root, courseId) => {\n const iconContainer = getFavouriteIconContainer(root, courseId);\n\n const isFavouriteIcon = iconContainer.find(SELECTORS.ICON_IS_FAVOURITE);\n isFavouriteIcon.removeClass('hidden');\n Aria.unhide(isFavouriteIcon);\n\n const notFavourteIcon = iconContainer.find(SELECTORS.ICON_NOT_FAVOURITE);\n notFavourteIcon.addClass('hidden');\n Aria.hide(notFavourteIcon);\n};\n\n/**\n * Get the action menu item\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The add to favourite menu item.\n */\nconst getAddFavouriteMenuItem = (root, courseId) => {\n return root.find('[data-action=\"add-favourite\"][data-course-id=\"' + courseId + '\"]');\n};\n\n/**\n * Get the action menu item\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The remove from favourites menu item.\n */\nconst getRemoveFavouriteMenuItem = (root, courseId) => {\n return root.find('[data-action=\"remove-favourite\"][data-course-id=\"' + courseId + '\"]');\n};\n\n/**\n * Add course to favourites\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n */\nconst addToFavourites = (root, courseId) => {\n const removeAction = getRemoveFavouriteMenuItem(root, courseId);\n const addAction = getAddFavouriteMenuItem(root, courseId);\n\n setCourseFavouriteState(courseId, true).then(success => {\n if (success) {\n PubSub.publish(CourseEvents.favourited, courseId);\n removeAction.removeClass('hidden');\n addAction.addClass('hidden');\n showFavouriteIcon(root, courseId);\n } else {\n Notification.alert('Starring course failed', 'Could not change favourite state');\n }\n return;\n }).catch(Notification.exception);\n};\n\n/**\n * Remove course from favourites\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n */\nconst removeFromFavourites = (root, courseId) => {\n const removeAction = getRemoveFavouriteMenuItem(root, courseId);\n const addAction = getAddFavouriteMenuItem(root, courseId);\n\n setCourseFavouriteState(courseId, false).then(success => {\n if (success) {\n PubSub.publish(CourseEvents.unfavorited, courseId);\n removeAction.addClass('hidden');\n addAction.removeClass('hidden');\n hideFavouriteIcon(root, courseId);\n } else {\n Notification.alert('Starring course failed', 'Could not change favourite state');\n }\n return;\n }).catch(Notification.exception);\n};\n\n/**\n * Get the action menu item\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The hide course menu item.\n */\nconst getHideCourseMenuItem = (root, courseId) => {\n return root.find('[data-action=\"hide-course\"][data-course-id=\"' + courseId + '\"]');\n};\n\n/**\n * Get the action menu item\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The show course menu item.\n */\nconst getShowCourseMenuItem = (root, courseId) => {\n return root.find('[data-action=\"show-course\"][data-course-id=\"' + courseId + '\"]');\n};\n\n/**\n * Hide course\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n */\nconst hideCourse = (root, courseId) => {\n const hideAction = getHideCourseMenuItem(root, courseId);\n const showAction = getShowCourseMenuItem(root, courseId);\n const filters = getFilterValues(root);\n\n setCourseHiddenState(courseId, true);\n\n // Remove the course from this view as it is now hidden and thus not covered by this view anymore.\n // Do only if we are not in \"All (including archived)\" view mode where really all courses are shown.\n if (filters.grouping !== GROUPINGS.GROUPING_ALLINCLUDINGHIDDEN) {\n hideElement(root, courseId);\n }\n\n hideAction.addClass('hidden');\n showAction.removeClass('hidden');\n};\n\n/**\n * Show course\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n */\nconst showCourse = (root, courseId) => {\n const hideAction = getHideCourseMenuItem(root, courseId);\n const showAction = getShowCourseMenuItem(root, courseId);\n const filters = getFilterValues(root);\n\n setCourseHiddenState(courseId, null);\n\n // Remove the course from this view as it is now shown again and thus not covered by this view anymore.\n // Do only if we are not in \"All (including archived)\" view mode where really all courses are shown.\n if (filters.grouping !== GROUPINGS.GROUPING_ALLINCLUDINGHIDDEN) {\n hideElement(root, courseId);\n }\n\n hideAction.removeClass('hidden');\n showAction.addClass('hidden');\n};\n\n/**\n * Set the courses hidden status and push to repository\n *\n * @param {Number} courseId Course id to favourite.\n * @param {Boolean} status new hidden status.\n * @return {Promise} Repository promise.\n */\nconst setCourseHiddenState = (courseId, status) => {\n\n // If the given status is not hidden, the preference has to be deleted with a null value.\n if (status === false) {\n status = null;\n }\n\n return setUserPreference(`block_myoverview_hidden_course_${courseId}`, status)\n .catch(Notification.exception);\n};\n\n/**\n * Reset the loadedPages dataset to take into account the hidden element\n *\n * @param {Object} root The course overview container\n * @param {Number} id The course id number\n */\nconst hideElement = (root, id) => {\n const pagingBar = root.find('[data-region=\"paging-bar\"]');\n const jumpto = parseInt(pagingBar.attr('data-active-page-number'));\n\n // Get a reduced dataset for the current page.\n const courseList = loadedPages[jumpto];\n let reducedCourse = courseList.courses.reduce((accumulator, current) => {\n if (+id !== +current.id) {\n accumulator.push(current);\n }\n return accumulator;\n }, []);\n\n // Get the next page's data if loaded and pop the first element from it.\n if (typeof (loadedPages[jumpto + 1]) !== 'undefined') {\n const newElement = loadedPages[jumpto + 1].courses.slice(0, 1);\n\n // Adjust the dataset for the reset of the pages that are loaded.\n loadedPages.forEach((courseList, index) => {\n if (index > jumpto) {\n let popElement = [];\n if (typeof (loadedPages[index + 1]) !== 'undefined') {\n popElement = loadedPages[index + 1].courses.slice(0, 1);\n }\n loadedPages[index].courses = [...loadedPages[index].courses.slice(1), ...popElement];\n }\n });\n\n reducedCourse = [...reducedCourse, ...newElement];\n }\n\n // Check if the next page is the last page and if it still has data associated to it.\n if (lastPage === jumpto + 1 && loadedPages[jumpto + 1].courses.length === 0) {\n const pagedContentContainer = root.find('[data-region=\"paged-content-container\"]');\n PagedContentFactory.resetLastPageNumber($(pagedContentContainer).attr('id'), jumpto);\n }\n\n loadedPages[jumpto].courses = reducedCourse;\n\n // Reduce the course offset.\n courseOffset--;\n\n // Render the paged content for the current.\n const pagedContentPage = getPagedContentContainer(root, jumpto);\n renderCourses(root, loadedPages[jumpto]).then((html, js) => {\n return Templates.replaceNodeContents(pagedContentPage, html, js);\n }).catch(Notification.exception);\n\n // Delete subsequent pages in order to trigger the callback.\n loadedPages.forEach((courseList, index) => {\n if (index > jumpto) {\n const page = getPagedContentContainer(root, index);\n page.remove();\n }\n });\n};\n\n/**\n * Set the courses favourite status and push to repository\n *\n * @param {Number} courseId Course id to favourite.\n * @param {boolean} status new favourite status.\n * @return {Promise} Repository promise.\n */\nconst setCourseFavouriteState = (courseId, status) => {\n\n return Repository.setFavouriteCourses({\n courses: [\n {\n 'id': courseId,\n 'favourite': status\n }\n ]\n }).then(result => {\n if (result.warnings.length === 0) {\n loadedPages.forEach(courseList => {\n courseList.courses.forEach((course, index) => {\n if (course.id == courseId) {\n courseList.courses[index].isfavourite = status;\n }\n });\n });\n return true;\n } else {\n return false;\n }\n }).catch(Notification.exception);\n};\n\n/**\n * Given there are no courses to render provide the rendered template.\n *\n * @param {object} root The root element for the courses view.\n * @return {promise} jQuery promise resolved after rendering is complete.\n */\nconst noCoursesRender = root => {\n const nocoursesimg = root.find(SELECTORS.courseView.region).attr('data-nocoursesimg');\n const newcourseurl = root.find(SELECTORS.courseView.region).attr('data-newcourseurl');\n return Templates.render(TEMPLATES.NOCOURSES, {\n nocoursesimg: nocoursesimg,\n newcourseurl: newcourseurl\n });\n};\n\n/**\n * Render the dashboard courses.\n *\n * @param {object} root The root element for the courses view.\n * @param {array} coursesData containing array of returned courses.\n * @return {promise} jQuery promise resolved after rendering is complete.\n */\nconst renderCourses = (root, coursesData) => {\n\n const filters = getFilterValues(root);\n\n let currentTemplate = '';\n if (filters.display === 'card') {\n currentTemplate = TEMPLATES.COURSES_CARDS;\n } else if (filters.display === 'list') {\n currentTemplate = TEMPLATES.COURSES_LIST;\n } else {\n currentTemplate = TEMPLATES.COURSES_SUMMARY;\n }\n\n if (!coursesData) {\n return noCoursesRender(root);\n } else {\n // Sometimes we get weird objects coming after a failed search, cast to ensure typing functions.\n if (Array.isArray(coursesData.courses) === false) {\n coursesData.courses = Object.values(coursesData.courses);\n }\n // Whether the course category should be displayed in the course item.\n coursesData.courses = coursesData.courses.map(course => {\n course.showcoursecategory = filters.displaycategories === 'on';\n return course;\n });\n if (coursesData.courses.length) {\n return Templates.render(currentTemplate, {\n courses: coursesData.courses,\n });\n } else {\n return noCoursesRender(root);\n }\n }\n};\n\n/**\n * Return the callback to be passed to the subscribe event\n *\n * @param {object} root The root element for the courses view\n * @return {function} Partially applied function that'll execute when passed a limit\n */\nconst setLimit = root => {\n // @param {Number} limit The paged limit that is passed through the event.\n return limit => root.find(SELECTORS.courseView.region).attr('data-paging', limit);\n};\n\n/**\n * Intialise the paged list and cards views on page load.\n * Returns an array of paged contents that we would like to handle here\n *\n * @param {object} root The root element for the courses view\n * @param {string} namespace The namespace for all the events attached\n */\nconst registerPagedEventHandlers = (root, namespace) => {\n const event = namespace + PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT;\n PubSub.subscribe(event, setLimit(root));\n};\n\n/**\n * Figure out how many items are going to be allowed to be rendered in the block.\n *\n * @param {Number} pagingLimit How many courses to display\n * @param {Object} root The course overview container\n * @return {Number[]} How many courses will be rendered\n */\nconst itemsPerPageFunc = (pagingLimit, root) => {\n let itemsPerPage = NUMCOURSES_PERPAGE.map(value => {\n let active = false;\n if (value === pagingLimit) {\n active = true;\n }\n\n return {\n value: value,\n active: active\n };\n });\n\n // Filter out all pagination options which are too large for the amount of courses user is enrolled in.\n const totalCourseCount = parseInt(root.find(SELECTORS.courseView.region).attr('data-totalcoursecount'), 10);\n return itemsPerPage.filter(pagingOption => {\n if (pagingOption.value === 0 && totalCourseCount > 100) {\n // To minimise performance issues, do not show the \"All\" option if the user is enrolled in more than 100 courses.\n return false;\n }\n return pagingOption.value < totalCourseCount;\n });\n};\n\n/**\n * Mutates and controls the loadedPages array and handles the bootstrapping.\n *\n * @param {Array|Object} coursesData Array of all of the courses to start building the page from\n * @param {Number} currentPage What page are we currently on?\n * @param {Object} pageData Any current page information\n * @param {Object} actions Paged content helper\n * @param {null|boolean} activeSearch Are we currently actively searching and building up search results?\n */\nconst pageBuilder = (coursesData, currentPage, pageData, actions, activeSearch = null) => {\n // If the courseData comes in an object then get the value otherwise it is a pure array.\n let courses = coursesData.courses ? coursesData.courses : coursesData;\n let nextPageStart = 0;\n let pageCourses = [];\n\n // If current page's data is loaded make sure we max it to page limit.\n if (typeof (loadedPages[currentPage]) !== 'undefined') {\n pageCourses = loadedPages[currentPage].courses;\n const currentPageLength = pageCourses.length;\n if (currentPageLength < pageData.limit) {\n nextPageStart = pageData.limit - currentPageLength;\n pageCourses = {...loadedPages[currentPage].courses, ...courses.slice(0, nextPageStart)};\n }\n } else {\n // When the page limit is zero, there is only one page of courses, no start for next page.\n nextPageStart = pageData.limit || false;\n pageCourses = (pageData.limit > 0) ? courses.slice(0, pageData.limit) : courses;\n }\n\n // Finished setting up the current page.\n loadedPages[currentPage] = {\n courses: pageCourses\n };\n\n // Set up the next page (if there is more than one page).\n const remainingCourses = nextPageStart !== false ? courses.slice(nextPageStart, courses.length) : [];\n if (remainingCourses.length) {\n loadedPages[currentPage + 1] = {\n courses: remainingCourses\n };\n }\n\n // Set the last page to either the current or next page.\n if (loadedPages[currentPage].courses.length < pageData.limit || !remainingCourses.length) {\n lastPage = currentPage;\n if (activeSearch === null) {\n actions.allItemsLoaded(currentPage);\n }\n } else if (typeof (loadedPages[currentPage + 1]) !== 'undefined'\n && loadedPages[currentPage + 1].courses.length < pageData.limit) {\n lastPage = currentPage + 1;\n }\n\n courseOffset = coursesData.nextoffset;\n};\n\n/**\n * In cases when switching between regular rendering and search rendering we need to reset some variables.\n */\nconst resetGlobals = () => {\n courseOffset = 0;\n loadedPages = [];\n lastPage = 0;\n lastLimit = 0;\n};\n\n/**\n * The default functionality of fetching paginated courses without special handling.\n *\n * @return {function(Object, Object, Object, Object, Object, Promise, Number): void}\n */\nconst standardFunctionalityCurry = () => {\n resetGlobals();\n return (filters, currentPage, pageData, actions, root, promises, limit) => {\n const pagePromise = getMyCourses(\n filters,\n limit\n ).then(coursesData => {\n pageBuilder(coursesData, currentPage, pageData, actions);\n return renderCourses(root, loadedPages[currentPage]);\n }).catch(Notification.exception);\n\n promises.push(pagePromise);\n };\n};\n\n/**\n * Initialize the searching functionality so we can call it when required.\n *\n * @return {function(Object, Number, Object, Object, Object, Promise, Number, String): void}\n */\nconst searchFunctionalityCurry = () => {\n resetGlobals();\n return (filters, currentPage, pageData, actions, root, promises, limit, inputValue) => {\n const searchingPromise = getSearchMyCourses(\n filters,\n limit,\n inputValue\n ).then(coursesData => {\n pageBuilder(coursesData, currentPage, pageData, actions);\n return renderCourses(root, loadedPages[currentPage]);\n }).catch(Notification.exception);\n\n promises.push(searchingPromise);\n };\n};\n\n/**\n * Initialise the courses list and cards views on page load.\n *\n * @param {object} root The root element for the courses view.\n * @param {function} promiseFunction How do we fetch the courses and what do we do with them?\n * @param {null | string} inputValue What to search for\n */\nconst initializePagedContent = (root, promiseFunction, inputValue = null) => {\n const pagingLimit = parseInt(root.find(SELECTORS.courseView.region).attr('data-paging'), 10);\n let itemsPerPage = itemsPerPageFunc(pagingLimit, root);\n\n const filters = getFilterValues(root);\n const config = {...{}, ...DEFAULT_PAGED_CONTENT_CONFIG};\n config.eventNamespace = namespace;\n\n const pagedContentPromise = PagedContentFactory.createWithLimit(\n itemsPerPage,\n (pagesData, actions) => {\n let promises = [];\n pagesData.forEach(pageData => {\n const currentPage = pageData.pageNumber;\n let limit = (pageData.limit > 0) ? pageData.limit : 0;\n\n // Reset local variables if limits have changed.\n if (+lastLimit !== +limit) {\n loadedPages = [];\n courseOffset = 0;\n lastPage = 0;\n }\n\n if (lastPage === currentPage) {\n // If we are on the last page and have it's data then load it from cache.\n actions.allItemsLoaded(lastPage);\n promises.push(renderCourses(root, loadedPages[currentPage]));\n return;\n }\n\n lastLimit = limit;\n\n // Get 2 pages worth of data as we will need it for the hidden functionality.\n if (typeof (loadedPages[currentPage + 1]) === 'undefined') {\n if (typeof (loadedPages[currentPage]) === 'undefined') {\n limit *= 2;\n }\n }\n\n // Call the curried function that'll handle the course promise and any manipulation of it.\n promiseFunction(filters, currentPage, pageData, actions, root, promises, limit, inputValue);\n });\n return promises;\n },\n config\n );\n\n pagedContentPromise.then((html, js) => {\n registerPagedEventHandlers(root, namespace);\n return Templates.replaceNodeContents(root.find(SELECTORS.courseView.region), html, js);\n }).catch(Notification.exception);\n};\n\n/**\n * Listen to, and handle events for the myoverview block.\n *\n * @param {Object} root The myoverview block container element.\n * @param {HTMLElement} page The whole HTMLElement for our block.\n */\nconst registerEventListeners = (root, page) => {\n\n CustomEvents.define(root, [\n CustomEvents.events.activate\n ]);\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_ADD_FAVOURITE, (e, data) => {\n const favourite = $(e.target).closest(SELECTORS.ACTION_ADD_FAVOURITE);\n const courseId = getCourseId(favourite);\n addToFavourites(root, courseId);\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_REMOVE_FAVOURITE, (e, data) => {\n const favourite = $(e.target).closest(SELECTORS.ACTION_REMOVE_FAVOURITE);\n const courseId = getCourseId(favourite);\n removeFromFavourites(root, courseId);\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.FAVOURITE_ICON, (e, data) => {\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_HIDE_COURSE, (e, data) => {\n const target = $(e.target).closest(SELECTORS.ACTION_HIDE_COURSE);\n const courseId = getCourseId(target);\n hideCourse(root, courseId);\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_SHOW_COURSE, (e, data) => {\n const target = $(e.target).closest(SELECTORS.ACTION_SHOW_COURSE);\n const courseId = getCourseId(target);\n showCourse(root, courseId);\n data.originalEvent.preventDefault();\n });\n\n // Searching functionality event handlers.\n const input = page.querySelector(SELECTORS.region.searchInput);\n const clearIcon = page.querySelector(SELECTORS.region.clearIcon);\n\n clearIcon.addEventListener('click', () => {\n input.value = '';\n input.focus();\n clearSearch(clearIcon, root);\n });\n\n input.addEventListener('input', debounce(() => {\n if (input.value === '') {\n clearSearch(clearIcon, root);\n } else {\n activeSearch(clearIcon);\n initializePagedContent(root, searchFunctionalityCurry(), input.value.trim());\n }\n }, 1000));\n};\n\n/**\n * Reset the search icon and trigger the init for the block.\n *\n * @param {HTMLElement} clearIcon Our closing icon to manipulate.\n * @param {Object} root The myoverview block container element.\n */\nexport const clearSearch = (clearIcon, root) => {\n clearIcon.classList.add('d-none');\n init(root);\n};\n\n/**\n * Change the searching icon to its' active state.\n *\n * @param {HTMLElement} clearIcon Our closing icon to manipulate.\n */\nconst activeSearch = (clearIcon) => {\n clearIcon.classList.remove('d-none');\n};\n\n/**\n * Intialise the courses list and cards views on page load.\n *\n * @param {object} root The root element for the courses view.\n */\nexport const init = root => {\n root = $(root);\n loadedPages = [];\n lastPage = 0;\n courseOffset = 0;\n\n if (!root.attr('data-init')) {\n const page = document.querySelector(SELECTORS.region.selectBlock);\n registerEventListeners(root, page);\n namespace = \"block_myoverview_\" + root.attr('id') + \"_\" + Math.random();\n root.attr('data-init', true);\n }\n\n initializePagedContent(root, standardFunctionalityCurry());\n};\n\n/**\n * Reset the courses views to their original\n * state on first page load.courseOffset\n *\n * This is called when configuration has changed for the event lists\n * to cause them to reload their data.\n *\n * @param {Object} root The root element for the timeline view.\n */\nexport const reset = root => {\n if (loadedPages.length > 0) {\n const filters = getFilterValues(root);\n // If the display mode is changed to 'summary' but the summary display has not been loaded yet,\n // we need to re-fetch the courses to include the course summary text.\n if (filters.display === 'summary' && !summaryDisplayLoaded) {\n const page = document.querySelector(SELECTORS.region.selectBlock);\n const input = page.querySelector(SELECTORS.region.searchInput);\n if (input.value !== '') {\n initializePagedContent(root, searchFunctionalityCurry(), input.value.trim());\n } else {\n initializePagedContent(root, standardFunctionalityCurry());\n }\n } else {\n loadedPages.forEach((courseList, index) => {\n let pagedContentPage = getPagedContentContainer(root, index);\n renderCourses(root, courseList).then((html, js) => {\n return Templates.replaceNodeContents(pagedContentPage, html, js);\n }).catch(Notification.exception);\n });\n }\n } else {\n init(root);\n }\n};\n"],"names":["TEMPLATES","GROUPINGS","NUMCOURSES_PERPAGE","loadedPages","courseOffset","lastPage","lastLimit","namespace","summaryDisplayLoaded","getFilterValues","root","courseRegion","find","SELECTORS","courseView","region","display","attr","grouping","sort","displaycategories","customfieldname","customfieldvalue","DEFAULT_PAGED_CONTENT_CONFIG","ignoreControlWhileLoading","controlPlacementBottom","persistentLimitKey","getFavouriteIconContainer","courseId","FAVOURITE_ICON","getPagedContentContainer","index","getCourseId","getAddFavouriteMenuItem","getRemoveFavouriteMenuItem","addToFavourites","removeAction","addAction","setCourseFavouriteState","then","success","PubSub","publish","CourseEvents","favourited","removeClass","addClass","iconContainer","isFavouriteIcon","ICON_IS_FAVOURITE","Aria","unhide","notFavourteIcon","ICON_NOT_FAVOURITE","hide","showFavouriteIcon","Notification","alert","catch","exception","removeFromFavourites","unfavorited","hideFavouriteIcon","getHideCourseMenuItem","getShowCourseMenuItem","setCourseHiddenState","status","hideElement","id","pagingBar","jumpto","parseInt","reducedCourse","courses","reduce","accumulator","current","push","newElement","slice","forEach","courseList","popElement","length","pagedContentContainer","PagedContentFactory","resetLastPageNumber","pagedContentPage","renderCourses","html","js","Templates","replaceNodeContents","remove","Repository","setFavouriteCourses","result","warnings","course","isfavourite","noCoursesRender","nocoursesimg","newcourseurl","render","coursesData","filters","currentTemplate","Array","isArray","Object","values","map","showcoursecategory","registerPagedEventHandlers","event","PagedContentEvents","SET_ITEMS_PER_PAGE_LIMIT","subscribe","limit","setLimit","itemsPerPageFunc","pagingLimit","itemsPerPage","value","active","totalCourseCount","filter","pagingOption","pageBuilder","currentPage","pageData","actions","activeSearch","nextPageStart","pageCourses","currentPageLength","remainingCourses","allItemsLoaded","nextoffset","resetGlobals","standardFunctionalityCurry","promises","pagePromise","params","offset","classification","requiredfields","SUMMARY_REQUIRED_FIELDS","CARDLIST_REQUIRED_FIELDS","getEnrolledCoursesByTimeline","getMyCourses","searchFunctionalityCurry","inputValue","searchingPromise","searchValue","searchvalue","getSearchMyCourses","initializePagedContent","promiseFunction","config","eventNamespace","pagedContentPromise","createWithLimit","pagesData","pageNumber","registerEventListeners","page","CustomEvents","define","events","activate","on","ACTION_ADD_FAVOURITE","e","data","favourite","target","closest","originalEvent","preventDefault","ACTION_REMOVE_FAVOURITE","ACTION_HIDE_COURSE","hideAction","showAction","hideCourse","ACTION_SHOW_COURSE","showCourse","input","querySelector","searchInput","clearIcon","addEventListener","focus","clearSearch","trim","classList","add","init","document","selectBlock","Math","random"],"mappings":"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"} \ No newline at end of file diff --git a/blocks/myoverview/amd/src/view.js b/blocks/myoverview/amd/src/view.js index 08cdbb6abb2..a6e7dfc0e14 100644 --- a/blocks/myoverview/amd/src/view.js +++ b/blocks/myoverview/amd/src/view.js @@ -572,7 +572,11 @@ const itemsPerPageFunc = (pagingLimit, root) => { // Filter out all pagination options which are too large for the amount of courses user is enrolled in. const totalCourseCount = parseInt(root.find(SELECTORS.courseView.region).attr('data-totalcoursecount'), 10); return itemsPerPage.filter(pagingOption => { - return pagingOption.value < totalCourseCount || pagingOption.value === 0; + if (pagingOption.value === 0 && totalCourseCount > 100) { + // To minimise performance issues, do not show the "All" option if the user is enrolled in more than 100 courses. + return false; + } + return pagingOption.value < totalCourseCount; }); };