From c0add7c713c28b08e6247d61e9c5fb1b37b635dd Mon Sep 17 00:00:00 2001 From: Tom Dickman Date: Wed, 3 Jul 2019 13:47:56 +1000 Subject: [PATCH] MDL-64860 block_myoverview: added additional pagination options Added additional pagination options based on the amount of courses the user is enrolled in. This will allow the user to display all courses on one page if they wish, and scale based on their total courses up to pages of 96 courses, now defaults to `All` if they have less than 12 courses and hides the dropdown menu as there is only one choice. --- blocks/myoverview/amd/build/view.min.js | 2 +- blocks/myoverview/amd/build/view.min.js.map | 2 +- blocks/myoverview/amd/src/view.js | 35 +++++++++++-------- blocks/myoverview/classes/output/main.php | 10 +++++- blocks/myoverview/lib.php | 6 +++- .../templates/courses-view.mustache | 1 + ...k_myoverview_pagelimit_persistence.feature | 18 +++++----- blocks/myoverview/version.php | 2 +- lib/amd/build/paged_content_factory.min.js | 2 +- .../build/paged_content_factory.min.js.map | 2 +- lib/amd/src/paged_content_factory.js | 3 +- .../paged_content_paging_bar.mustache | 6 ++-- 12 files changed, 54 insertions(+), 35 deletions(-) diff --git a/blocks/myoverview/amd/build/view.min.js b/blocks/myoverview/amd/build/view.min.js index 57e14e5e734..f58ff473050 100644 --- a/blocks/myoverview/amd/build/view.min.js +++ b/blocks/myoverview/amd/build/view.min.js @@ -1,2 +1,2 @@ -define ("block_myoverview/view",["jquery","block_myoverview/repository","core/paged_content_factory","core/pubsub","core/custom_interaction_events","core/notification","core/templates","core_course/events","block_myoverview/selectors","core/paged_content_events"],function(a,b,c,d,e,f,g,h,i,j){var k={COURSE_REGION:"[data-region=\"course-view-content\"]",ACTION_HIDE_COURSE:"[data-action=\"hide-course\"]",ACTION_SHOW_COURSE:"[data-action=\"show-course\"]",ACTION_ADD_FAVOURITE:"[data-action=\"add-favourite\"]",ACTION_REMOVE_FAVOURITE:"[data-action=\"remove-favourite\"]",FAVOURITE_ICON:"[data-region=\"favourite-icon\"]",ICON_IS_FAVOURITE:"[data-region=\"is-favourite\"]",ICON_NOT_FAVOURITE:"[data-region=\"not-favourite\"]",PAGED_CONTENT_CONTAINER:"[data-region=\"page-container\"]"},l={COURSES_CARDS:"block_myoverview/view-cards",COURSES_LIST:"block_myoverview/view-list",COURSES_SUMMARY:"block_myoverview/view-summary",NOCOURSES:"core_course/no-courses"},m=[12,24,48],n=[],o=0,p=0,q=0,r=null,s=function(a){var b=a.find(i.courseView.region);return{display:b.attr("data-display"),grouping:b.attr("data-grouping"),sort:b.attr("data-sort"),displaycategories:b.attr("data-displaycategories")}},t={ignoreControlWhileLoading:!0,controlPlacementBottom:!0,persistentLimitKey:"block_myoverview_user_paging_preference"},u=function(a,c){return b.getEnrolledCoursesByTimeline({offset:o,limit:c,classification:a.grouping,sort:a.sort})},v=function(a,b){return a.find(k.FAVOURITE_ICON+"[data-course-id=\""+b+"\"]")},w=function(a,b){return a.find("[data-region=\"paged-content-page\"][data-page=\""+b+"\"]")},x=function(a){return a.attr("data-course-id")},y=function(a,b){var c=v(a,b),d=c.find(k.ICON_IS_FAVOURITE);d.addClass("hidden");d.attr("aria-hidden",!0);var e=c.find(k.ICON_NOT_FAVOURITE);e.removeClass("hidden");e.attr("aria-hidden",!1)},z=function(a,b){var c=v(a,b),d=c.find(k.ICON_IS_FAVOURITE);d.removeClass("hidden");d.attr("aria-hidden",!1);var e=c.find(k.ICON_NOT_FAVOURITE);e.addClass("hidden");e.attr("aria-hidden",!0)},A=function(a,b){return a.find("[data-action=\"add-favourite\"][data-course-id=\""+b+"\"]")},B=function(a,b){return a.find("[data-action=\"remove-favourite\"][data-course-id=\""+b+"\"]")},C=function(a,b){var c=B(a,b),e=A(a,b);F(b,!0).then(function(g){if(g){d.publish(h.favourited,b);c.removeClass("hidden");e.addClass("hidden");z(a,b)}else{f.alert("Starring course failed","Could not change favourite state")}}).catch(f.exception)},D=function(a,b){var c=B(a,b),e=A(a,b);F(b,!1).then(function(g){if(g){d.publish(h.unfavorited,b);c.addClass("hidden");e.removeClass("hidden");y(a,b)}else{f.alert("Starring course failed","Could not change favourite state")}}).catch(f.exception)},E=function(b,d){var e=x(d),h=b.find("[data-region=\"paging-bar\"]"),i=parseInt(h.attr("data-active-page-number")),j=n[i],k=j.courses.reduce(function(a,b){if(e!=b.id){a.push(b)}return a},[]);if(n[i+1]!=void 0){var l=n[i+1].courses.slice(0,1);n.forEach(function(b,c){if(c>i){var d=[];if(n[c+1]!=void 0){d=n[c+1].courses.slice(0,1)}n[c].courses=a.merge(n[c].courses.slice(1),d)}});k=a.merge(k,l)}if(p==i+1&&0==n[i+1].courses.length){var m=b.find("[data-region=\"paged-content-container\"]");c.resetLastPageNumber(a(m).attr("id"),i)}n[i].courses=k;o--;var q=w(b,i);G(b,n[i]).then(function(a,b){return g.replaceNodeContents(q,a,b)}).catch(f.exception);n.forEach(function(a,c){if(c>i){var d=w(b,c);d.remove()}})},F=function(a,c){return b.setFavouriteCourses({courses:[{id:a,favourite:c}]}).then(function(b){if(0==b.warnings.length){n.forEach(function(b){b.courses.forEach(function(d,e){if(d.id==a){b.courses[e].isfavourite=c}})});return!0}else{return!1}}).catch(f.exception)},G=function(a,b){var c=s(a),d="";if("card"==c.display){d=l.COURSES_CARDS}else if("list"==c.display){d=l.COURSES_LIST}else{d=l.COURSES_SUMMARY}if("on"!=c.displaycategories){b.courses=b.courses.map(function(a){delete a.coursecategory;return a})}if(b.courses.length){return g.render(d,{courses:b.courses})}else{var e=a.find(i.courseView.region).attr("data-nocoursesimg");return g.render(l.NOCOURSES,{nocoursesimg:e})}},H=function(a){this.find(i.courseView.region).attr("data-paging",a)},I=function(a,b){var c=b+j.SET_ITEMS_PER_PAGE_LIMIT;d.subscribe(c,H.bind(a))},J=function(b){r="block_myoverview_"+b.attr("id")+"_"+Math.random();var d=m,e=parseInt(b.find(i.courseView.region).attr("data-paging"),10);if(e){d=m.map(function(a){var b=!1;if(a==e){b=!0}return{value:a,active:b}})}var h=s(b),j=a.extend({},t);j.eventNamespace=r;var k=c.createWithLimit(d,function(c,d){var e=[];c.forEach(function(c){var g=c.pageNumber,i=c.limit;if(q!=i){n=[];o=0;p=0}if(p==g){d.allItemsLoaded(p);e.push(G(b,n[g]));return}q=i;if(n[g+1]==void 0){if(n[g]==void 0){i*=2}}var j=u(h,i).then(function(e){var f=e.courses,h=0,i=[];if(n[g]!=void 0){i=n[g].courses;var j=i.length;if(ji){var d=[];if(n[c+1]!=void 0){d=n[c+1].courses.slice(0,1)}n[c].courses=a.merge(n[c].courses.slice(1),d)}});k=a.merge(k,l)}if(p==i+1&&0==n[i+1].courses.length){var m=b.find("[data-region=\"paged-content-container\"]");c.resetLastPageNumber(a(m).attr("id"),i)}n[i].courses=k;o--;var q=w(b,i);G(b,n[i]).then(function(a,b){return g.replaceNodeContents(q,a,b)}).catch(f.exception);n.forEach(function(a,c){if(c>i){var d=w(b,c);d.remove()}})},F=function(a,c){return b.setFavouriteCourses({courses:[{id:a,favourite:c}]}).then(function(b){if(0==b.warnings.length){n.forEach(function(b){b.courses.forEach(function(d,e){if(d.id==a){b.courses[e].isfavourite=c}})});return!0}else{return!1}}).catch(f.exception)},G=function(a,b){var c=s(a),d="";if("card"==c.display){d=l.COURSES_CARDS}else if("list"==c.display){d=l.COURSES_LIST}else{d=l.COURSES_SUMMARY}if("on"!=c.displaycategories){b.courses=b.courses.map(function(a){delete a.coursecategory;return a})}if(b.courses.length){return g.render(d,{courses:b.courses})}else{var e=a.find(i.courseView.region).attr("data-nocoursesimg");return g.render(l.NOCOURSES,{nocoursesimg:e})}},H=function(a){this.find(i.courseView.region).attr("data-paging",a)},I=function(a,b){var c=b+j.SET_ITEMS_PER_PAGE_LIMIT;d.subscribe(c,H.bind(a))},J=function(b){r="block_myoverview_"+b.attr("id")+"_"+Math.random();var d=parseInt(b.find(i.courseView.region).attr("data-paging"),10),e=m.map(function(a){var b=!1;if(a==d){b=!0}return{value:a,active:b}}),h=parseInt(b.find(i.courseView.region).attr("data-totalcoursecount"),10);if(h){e=e.filter(function(a){return a.value.\n\n/**\n * Manage the courses view for the overview block.\n *\n * @package block_myoverview\n * @copyright 2018 Bas Brands \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(\n[\n 'jquery',\n 'block_myoverview/repository',\n 'core/paged_content_factory',\n 'core/pubsub',\n 'core/custom_interaction_events',\n 'core/notification',\n 'core/templates',\n 'core_course/events',\n 'block_myoverview/selectors',\n 'core/paged_content_events',\n],\nfunction(\n $,\n Repository,\n PagedContentFactory,\n PubSub,\n CustomEvents,\n Notification,\n Templates,\n CourseEvents,\n Selectors,\n PagedContentEvents\n) {\n\n var SELECTORS = {\n COURSE_REGION: '[data-region=\"course-view-content\"]',\n ACTION_HIDE_COURSE: '[data-action=\"hide-course\"]',\n ACTION_SHOW_COURSE: '[data-action=\"show-course\"]',\n ACTION_ADD_FAVOURITE: '[data-action=\"add-favourite\"]',\n ACTION_REMOVE_FAVOURITE: '[data-action=\"remove-favourite\"]',\n FAVOURITE_ICON: '[data-region=\"favourite-icon\"]',\n ICON_IS_FAVOURITE: '[data-region=\"is-favourite\"]',\n ICON_NOT_FAVOURITE: '[data-region=\"not-favourite\"]',\n PAGED_CONTENT_CONTAINER: '[data-region=\"page-container\"]'\n\n };\n\n var 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\n var NUMCOURSES_PERPAGE = [12, 24, 48];\n\n var loadedPages = [];\n\n var courseOffset = 0;\n\n var lastPage = 0;\n\n var lastLimit = 0;\n\n var namespace = null;\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 */\n var getFilterValues = function(root) {\n var 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 };\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.\n var 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 */\n var getMyCourses = function(filters, limit) {\n\n return Repository.getEnrolledCoursesByTimeline({\n offset: courseOffset,\n limit: limit,\n classification: filters.grouping,\n sort: filters.sort\n });\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 */\n var getFavouriteIconContainer = function(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 */\n var getPagedContentContainer = function(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 */\n var getCourseId = function(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 */\n var hideFavouriteIcon = function(root, courseId) {\n var iconContainer = getFavouriteIconContainer(root, courseId);\n var isFavouriteIcon = iconContainer.find(SELECTORS.ICON_IS_FAVOURITE);\n isFavouriteIcon.addClass('hidden');\n isFavouriteIcon.attr('aria-hidden', true);\n var notFavourteIcon = iconContainer.find(SELECTORS.ICON_NOT_FAVOURITE);\n notFavourteIcon.removeClass('hidden');\n notFavourteIcon.attr('aria-hidden', false);\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 */\n var showFavouriteIcon = function(root, courseId) {\n var iconContainer = getFavouriteIconContainer(root, courseId);\n var isFavouriteIcon = iconContainer.find(SELECTORS.ICON_IS_FAVOURITE);\n isFavouriteIcon.removeClass('hidden');\n isFavouriteIcon.attr('aria-hidden', false);\n var notFavourteIcon = iconContainer.find(SELECTORS.ICON_NOT_FAVOURITE);\n notFavourteIcon.addClass('hidden');\n notFavourteIcon.attr('aria-hidden', true);\n };\n\n /**\n * Get the action menu item\n *\n * @param {Object} root root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The add to favourite menu item.\n */\n var getAddFavouriteMenuItem = function(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 root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The remove from favourites menu item.\n */\n var getRemoveFavouriteMenuItem = function(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 */\n var addToFavourites = function(root, courseId) {\n var removeAction = getRemoveFavouriteMenuItem(root, courseId);\n var addAction = getAddFavouriteMenuItem(root, courseId);\n\n setCourseFavouriteState(courseId, true).then(function(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 */\n var removeFromFavourites = function(root, courseId) {\n var removeAction = getRemoveFavouriteMenuItem(root, courseId);\n var addAction = getAddFavouriteMenuItem(root, courseId);\n\n setCourseFavouriteState(courseId, false).then(function(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 * Reset the loadedPages dataset to take into account the hidden element\n *\n * @param {Object} root The course overview container\n * @param {Object} target The course that you want to hide\n */\n var hideElement = function(root, target) {\n var id = getCourseId(target);\n\n var pagingBar = root.find('[data-region=\"paging-bar\"]');\n var jumpto = parseInt(pagingBar.attr('data-active-page-number'));\n\n // Get a reduced dataset for the current page.\n var courseList = loadedPages[jumpto];\n var reducedCourse = courseList.courses.reduce(function(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 (loadedPages[jumpto + 1] != undefined) {\n var 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(function(courseList, index) {\n if (index > jumpto) {\n var popElement = [];\n if (loadedPages[index + 1] != undefined) {\n popElement = loadedPages[index + 1].courses.slice(0, 1);\n }\n\n loadedPages[index].courses = $.merge(loadedPages[index].courses.slice(1), popElement);\n }\n });\n\n\n reducedCourse = $.merge(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 var 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 var pagedContentPage = getPagedContentContainer(root, jumpto);\n renderCourses(root, loadedPages[jumpto]).then(function(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(function(courseList, index) {\n if (index > jumpto) {\n var 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 {Bool} status new favourite status.\n * @return {Promise} Repository promise.\n */\n var setCourseFavouriteState = function(courseId, status) {\n\n return Repository.setFavouriteCourses({\n courses: [\n {\n 'id': courseId,\n 'favourite': status\n }\n ]\n }).then(function(result) {\n if (result.warnings.length == 0) {\n loadedPages.forEach(function(courseList) {\n courseList.courses.forEach(function(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 * 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 */\n var renderCourses = function(root, coursesData) {\n\n var filters = getFilterValues(root);\n\n var 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 // Delete the course category if it is not to be displayed\n if (filters.displaycategories != 'on') {\n coursesData.courses = coursesData.courses.map(function(course) {\n delete course.coursecategory;\n return course;\n });\n }\n\n if (coursesData.courses.length) {\n return Templates.render(currentTemplate, {\n courses: coursesData.courses,\n });\n } else {\n var nocoursesimg = root.find(Selectors.courseView.region).attr('data-nocoursesimg');\n return Templates.render(TEMPLATES.NOCOURSES, {\n nocoursesimg: nocoursesimg\n });\n }\n };\n\n /**\n * Return the callback to be passed to the subscribe event\n *\n * @param {Number} limit The paged limit that is passed through the event\n */\n var setLimit = function(limit) {\n this.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 */\n var registerPagedEventHandlers = function(root, namespace) {\n var event = namespace + PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT;\n PubSub.subscribe(event, setLimit.bind(root));\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 * @param {object} content The content element for the courses view.\n */\n var initializePagedContent = function(root) {\n namespace = \"block_myoverview_\" + root.attr('id') + \"_\" + Math.random();\n\n var itemsPerPage = NUMCOURSES_PERPAGE;\n var pagingLimit = parseInt(root.find(Selectors.courseView.region).attr('data-paging'), 10);\n if (pagingLimit) {\n itemsPerPage = NUMCOURSES_PERPAGE.map(function(value) {\n var active = false;\n if (value == pagingLimit) {\n active = true;\n }\n\n return {\n value: value,\n active: active\n };\n });\n }\n\n var filters = getFilterValues(root);\n var config = $.extend({}, DEFAULT_PAGED_CONTENT_CONFIG);\n config.eventNamespace = namespace;\n\n var pagedContentPromise = PagedContentFactory.createWithLimit(\n itemsPerPage,\n function(pagesData, actions) {\n var promises = [];\n\n pagesData.forEach(function(pageData) {\n var currentPage = pageData.pageNumber;\n var limit = pageData.limit;\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 (loadedPages[currentPage + 1] == undefined) {\n if (loadedPages[currentPage] == undefined) {\n limit *= 2;\n }\n }\n\n var pagePromise = getMyCourses(\n filters,\n limit\n ).then(function(coursesData) {\n var courses = coursesData.courses;\n var nextPageStart = 0;\n var pageCourses = [];\n\n // If current page's data is loaded make sure we max it to page limit\n if (loadedPages[currentPage] != undefined) {\n pageCourses = loadedPages[currentPage].courses;\n var currentPageLength = pageCourses.length;\n if (currentPageLength < pageData.limit) {\n nextPageStart = pageData.limit - currentPageLength;\n pageCourses = $.merge(loadedPages[currentPage].courses, courses.slice(0, nextPageStart));\n }\n } else {\n nextPageStart = pageData.limit;\n pageCourses = courses.slice(0, pageData.limit);\n }\n\n // Finished setting up the current page\n loadedPages[currentPage] = {\n courses: pageCourses\n };\n\n // Set up the next page\n var remainingCourses = 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 actions.allItemsLoaded(currentPage);\n } else if (loadedPages[currentPage + 1] != undefined\n && loadedPages[currentPage + 1].courses.length < pageData.limit) {\n lastPage = currentPage + 1;\n }\n\n courseOffset = coursesData.nextoffset;\n return renderCourses(root, loadedPages[currentPage]);\n })\n .catch(Notification.exception);\n\n promises.push(pagePromise);\n });\n\n return promises;\n },\n config\n );\n\n pagedContentPromise.then(function(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 */\n var registerEventListeners = function(root) {\n CustomEvents.define(root, [\n CustomEvents.events.activate\n ]);\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_ADD_FAVOURITE, function(e, data) {\n var favourite = $(e.target).closest(SELECTORS.ACTION_ADD_FAVOURITE);\n var courseId = getCourseId(favourite);\n addToFavourites(root, courseId);\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_REMOVE_FAVOURITE, function(e, data) {\n var favourite = $(e.target).closest(SELECTORS.ACTION_REMOVE_FAVOURITE);\n var courseId = getCourseId(favourite);\n removeFromFavourites(root, courseId);\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.FAVOURITE_ICON, function(e, data) {\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_HIDE_COURSE, function(e, data) {\n var target = $(e.target).closest(SELECTORS.ACTION_HIDE_COURSE);\n var id = getCourseId(target);\n\n var request = {\n preferences: [\n {\n type: 'block_myoverview_hidden_course_' + id,\n value: true\n }\n ]\n };\n Repository.updateUserPreferences(request);\n\n hideElement(root, target);\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_SHOW_COURSE, function(e, data) {\n var target = $(e.target).closest(SELECTORS.ACTION_SHOW_COURSE);\n var id = getCourseId(target);\n\n var request = {\n preferences: [\n {\n type: 'block_myoverview_hidden_course_' + id,\n value: null\n }\n ]\n };\n\n Repository.updateUserPreferences(request);\n\n hideElement(root, target);\n data.originalEvent.preventDefault();\n });\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 */\n var init = function(root) {\n root = $(root);\n loadedPages = [];\n lastPage = 0;\n courseOffset = 0;\n\n initializePagedContent(root);\n\n if (!root.attr('data-init')) {\n registerEventListeners(root);\n root.attr('data-init', true);\n }\n };\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 */\n var reset = function(root) {\n if (loadedPages.length > 0) {\n loadedPages.forEach(function(courseList, index) {\n var pagedContentPage = getPagedContentContainer(root, index);\n renderCourses(root, courseList).then(function(html, js) {\n return Templates.replaceNodeContents(pagedContentPage, html, js);\n }).catch(Notification.exception);\n });\n } else {\n init(root);\n }\n };\n\n return {\n init: init,\n reset: reset\n };\n});\n"],"file":"view.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/view.js"],"names":["define","$","Repository","PagedContentFactory","PubSub","CustomEvents","Notification","Templates","CourseEvents","Selectors","PagedContentEvents","SELECTORS","COURSE_REGION","ACTION_HIDE_COURSE","ACTION_SHOW_COURSE","ACTION_ADD_FAVOURITE","ACTION_REMOVE_FAVOURITE","FAVOURITE_ICON","ICON_IS_FAVOURITE","ICON_NOT_FAVOURITE","PAGED_CONTENT_CONTAINER","TEMPLATES","COURSES_CARDS","COURSES_LIST","COURSES_SUMMARY","NOCOURSES","NUMCOURSES_PERPAGE","loadedPages","courseOffset","lastPage","lastLimit","namespace","getFilterValues","root","courseRegion","find","courseView","region","display","attr","grouping","sort","displaycategories","DEFAULT_PAGED_CONTENT_CONFIG","ignoreControlWhileLoading","controlPlacementBottom","persistentLimitKey","getMyCourses","filters","limit","getEnrolledCoursesByTimeline","offset","classification","getFavouriteIconContainer","courseId","getPagedContentContainer","index","getCourseId","hideFavouriteIcon","iconContainer","isFavouriteIcon","addClass","notFavourteIcon","removeClass","showFavouriteIcon","getAddFavouriteMenuItem","getRemoveFavouriteMenuItem","addToFavourites","removeAction","addAction","setCourseFavouriteState","then","success","publish","favourited","alert","catch","exception","removeFromFavourites","unfavorited","hideElement","target","id","pagingBar","jumpto","parseInt","courseList","reducedCourse","courses","reduce","accumulator","current","push","newElement","slice","forEach","popElement","merge","length","pagedContentContainer","resetLastPageNumber","pagedContentPage","renderCourses","html","js","replaceNodeContents","page","remove","status","setFavouriteCourses","result","warnings","course","isfavourite","coursesData","currentTemplate","map","coursecategory","render","nocoursesimg","setLimit","registerPagedEventHandlers","event","SET_ITEMS_PER_PAGE_LIMIT","subscribe","bind","initializePagedContent","Math","random","pagingLimit","itemsPerPage","value","active","totalCourseCount","filter","pagingOption","config","extend","eventNamespace","pagedContentPromise","createWithLimit","pagesData","actions","promises","pageData","currentPage","pageNumber","allItemsLoaded","pagePromise","nextPageStart","pageCourses","currentPageLength","remainingCourses","nextoffset","registerEventListeners","events","activate","on","e","data","favourite","closest","originalEvent","preventDefault","updateUserPreferences","preferences","type","init","reset"],"mappings":"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","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 * @package block_myoverview\n * @copyright 2018 Bas Brands \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(\n[\n 'jquery',\n 'block_myoverview/repository',\n 'core/paged_content_factory',\n 'core/pubsub',\n 'core/custom_interaction_events',\n 'core/notification',\n 'core/templates',\n 'core_course/events',\n 'block_myoverview/selectors',\n 'core/paged_content_events',\n],\nfunction(\n $,\n Repository,\n PagedContentFactory,\n PubSub,\n CustomEvents,\n Notification,\n Templates,\n CourseEvents,\n Selectors,\n PagedContentEvents\n) {\n\n var SELECTORS = {\n COURSE_REGION: '[data-region=\"course-view-content\"]',\n ACTION_HIDE_COURSE: '[data-action=\"hide-course\"]',\n ACTION_SHOW_COURSE: '[data-action=\"show-course\"]',\n ACTION_ADD_FAVOURITE: '[data-action=\"add-favourite\"]',\n ACTION_REMOVE_FAVOURITE: '[data-action=\"remove-favourite\"]',\n FAVOURITE_ICON: '[data-region=\"favourite-icon\"]',\n ICON_IS_FAVOURITE: '[data-region=\"is-favourite\"]',\n ICON_NOT_FAVOURITE: '[data-region=\"not-favourite\"]',\n PAGED_CONTENT_CONTAINER: '[data-region=\"page-container\"]'\n\n };\n\n var 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\n var NUMCOURSES_PERPAGE = [12, 24, 48, 96, 0];\n\n var loadedPages = [];\n\n var courseOffset = 0;\n\n var lastPage = 0;\n\n var lastLimit = 0;\n\n var namespace = null;\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 */\n var getFilterValues = function(root) {\n var 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 };\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.\n var 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 */\n var getMyCourses = function(filters, limit) {\n\n return Repository.getEnrolledCoursesByTimeline({\n offset: courseOffset,\n limit: limit,\n classification: filters.grouping,\n sort: filters.sort\n });\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 */\n var getFavouriteIconContainer = function(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 */\n var getPagedContentContainer = function(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 */\n var getCourseId = function(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 */\n var hideFavouriteIcon = function(root, courseId) {\n var iconContainer = getFavouriteIconContainer(root, courseId);\n var isFavouriteIcon = iconContainer.find(SELECTORS.ICON_IS_FAVOURITE);\n isFavouriteIcon.addClass('hidden');\n isFavouriteIcon.attr('aria-hidden', true);\n var notFavourteIcon = iconContainer.find(SELECTORS.ICON_NOT_FAVOURITE);\n notFavourteIcon.removeClass('hidden');\n notFavourteIcon.attr('aria-hidden', false);\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 */\n var showFavouriteIcon = function(root, courseId) {\n var iconContainer = getFavouriteIconContainer(root, courseId);\n var isFavouriteIcon = iconContainer.find(SELECTORS.ICON_IS_FAVOURITE);\n isFavouriteIcon.removeClass('hidden');\n isFavouriteIcon.attr('aria-hidden', false);\n var notFavourteIcon = iconContainer.find(SELECTORS.ICON_NOT_FAVOURITE);\n notFavourteIcon.addClass('hidden');\n notFavourteIcon.attr('aria-hidden', true);\n };\n\n /**\n * Get the action menu item\n *\n * @param {Object} root root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The add to favourite menu item.\n */\n var getAddFavouriteMenuItem = function(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 root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The remove from favourites menu item.\n */\n var getRemoveFavouriteMenuItem = function(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 */\n var addToFavourites = function(root, courseId) {\n var removeAction = getRemoveFavouriteMenuItem(root, courseId);\n var addAction = getAddFavouriteMenuItem(root, courseId);\n\n setCourseFavouriteState(courseId, true).then(function(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 */\n var removeFromFavourites = function(root, courseId) {\n var removeAction = getRemoveFavouriteMenuItem(root, courseId);\n var addAction = getAddFavouriteMenuItem(root, courseId);\n\n setCourseFavouriteState(courseId, false).then(function(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 * Reset the loadedPages dataset to take into account the hidden element\n *\n * @param {Object} root The course overview container\n * @param {Object} target The course that you want to hide\n */\n var hideElement = function(root, target) {\n var id = getCourseId(target);\n\n var pagingBar = root.find('[data-region=\"paging-bar\"]');\n var jumpto = parseInt(pagingBar.attr('data-active-page-number'));\n\n // Get a reduced dataset for the current page.\n var courseList = loadedPages[jumpto];\n var reducedCourse = courseList.courses.reduce(function(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 (loadedPages[jumpto + 1] != undefined) {\n var 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(function(courseList, index) {\n if (index > jumpto) {\n var popElement = [];\n if (loadedPages[index + 1] != undefined) {\n popElement = loadedPages[index + 1].courses.slice(0, 1);\n }\n\n loadedPages[index].courses = $.merge(loadedPages[index].courses.slice(1), popElement);\n }\n });\n\n\n reducedCourse = $.merge(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 var 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 var pagedContentPage = getPagedContentContainer(root, jumpto);\n renderCourses(root, loadedPages[jumpto]).then(function(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(function(courseList, index) {\n if (index > jumpto) {\n var 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 {Bool} status new favourite status.\n * @return {Promise} Repository promise.\n */\n var setCourseFavouriteState = function(courseId, status) {\n\n return Repository.setFavouriteCourses({\n courses: [\n {\n 'id': courseId,\n 'favourite': status\n }\n ]\n }).then(function(result) {\n if (result.warnings.length == 0) {\n loadedPages.forEach(function(courseList) {\n courseList.courses.forEach(function(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 * 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 */\n var renderCourses = function(root, coursesData) {\n\n var filters = getFilterValues(root);\n\n var 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 // Delete the course category if it is not to be displayed\n if (filters.displaycategories != 'on') {\n coursesData.courses = coursesData.courses.map(function(course) {\n delete course.coursecategory;\n return course;\n });\n }\n\n if (coursesData.courses.length) {\n return Templates.render(currentTemplate, {\n courses: coursesData.courses,\n });\n } else {\n var nocoursesimg = root.find(Selectors.courseView.region).attr('data-nocoursesimg');\n return Templates.render(TEMPLATES.NOCOURSES, {\n nocoursesimg: nocoursesimg\n });\n }\n };\n\n /**\n * Return the callback to be passed to the subscribe event\n *\n * @param {Number} limit The paged limit that is passed through the event\n */\n var setLimit = function(limit) {\n this.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 */\n var registerPagedEventHandlers = function(root, namespace) {\n var event = namespace + PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT;\n PubSub.subscribe(event, setLimit.bind(root));\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 * @param {object} content The content element for the courses view.\n */\n var initializePagedContent = function(root) {\n namespace = \"block_myoverview_\" + root.attr('id') + \"_\" + Math.random();\n\n var pagingLimit = parseInt(root.find(Selectors.courseView.region).attr('data-paging'), 10);\n var itemsPerPage = NUMCOURSES_PERPAGE.map(function(value) {\n var 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 var totalCourseCount = parseInt(root.find(Selectors.courseView.region).attr('data-totalcoursecount'), 10);\n if (totalCourseCount) {\n itemsPerPage = itemsPerPage.filter(function(pagingOption) {\n return pagingOption.value < totalCourseCount;\n });\n }\n\n var filters = getFilterValues(root);\n var config = $.extend({}, DEFAULT_PAGED_CONTENT_CONFIG);\n config.eventNamespace = namespace;\n\n var pagedContentPromise = PagedContentFactory.createWithLimit(\n itemsPerPage,\n function(pagesData, actions) {\n var promises = [];\n\n pagesData.forEach(function(pageData) {\n var currentPage = pageData.pageNumber;\n var 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 (loadedPages[currentPage + 1] == undefined) {\n if (loadedPages[currentPage] == undefined) {\n limit *= 2;\n }\n }\n\n var pagePromise = getMyCourses(\n filters,\n limit\n ).then(function(coursesData) {\n var courses = coursesData.courses;\n var nextPageStart = 0;\n var pageCourses = [];\n\n // If current page's data is loaded make sure we max it to page limit\n if (loadedPages[currentPage] != undefined) {\n pageCourses = loadedPages[currentPage].courses;\n var currentPageLength = pageCourses.length;\n if (currentPageLength < pageData.limit) {\n nextPageStart = pageData.limit - currentPageLength;\n pageCourses = $.merge(loadedPages[currentPage].courses, courses.slice(0, nextPageStart));\n }\n } else {\n nextPageStart = pageData.limit;\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\n var remainingCourses = nextPageStart ? 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 actions.allItemsLoaded(currentPage);\n } else if (loadedPages[currentPage + 1] != undefined\n && loadedPages[currentPage + 1].courses.length < pageData.limit) {\n lastPage = currentPage + 1;\n }\n\n courseOffset = coursesData.nextoffset;\n return renderCourses(root, loadedPages[currentPage]);\n })\n .catch(Notification.exception);\n\n promises.push(pagePromise);\n });\n\n return promises;\n },\n config\n );\n\n pagedContentPromise.then(function(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 */\n var registerEventListeners = function(root) {\n CustomEvents.define(root, [\n CustomEvents.events.activate\n ]);\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_ADD_FAVOURITE, function(e, data) {\n var favourite = $(e.target).closest(SELECTORS.ACTION_ADD_FAVOURITE);\n var courseId = getCourseId(favourite);\n addToFavourites(root, courseId);\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_REMOVE_FAVOURITE, function(e, data) {\n var favourite = $(e.target).closest(SELECTORS.ACTION_REMOVE_FAVOURITE);\n var courseId = getCourseId(favourite);\n removeFromFavourites(root, courseId);\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.FAVOURITE_ICON, function(e, data) {\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_HIDE_COURSE, function(e, data) {\n var target = $(e.target).closest(SELECTORS.ACTION_HIDE_COURSE);\n var id = getCourseId(target);\n\n var request = {\n preferences: [\n {\n type: 'block_myoverview_hidden_course_' + id,\n value: true\n }\n ]\n };\n Repository.updateUserPreferences(request);\n\n hideElement(root, target);\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.ACTION_SHOW_COURSE, function(e, data) {\n var target = $(e.target).closest(SELECTORS.ACTION_SHOW_COURSE);\n var id = getCourseId(target);\n\n var request = {\n preferences: [\n {\n type: 'block_myoverview_hidden_course_' + id,\n value: null\n }\n ]\n };\n\n Repository.updateUserPreferences(request);\n\n hideElement(root, target);\n data.originalEvent.preventDefault();\n });\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 */\n var init = function(root) {\n root = $(root);\n loadedPages = [];\n lastPage = 0;\n courseOffset = 0;\n\n initializePagedContent(root);\n\n if (!root.attr('data-init')) {\n registerEventListeners(root);\n root.attr('data-init', true);\n }\n };\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 */\n var reset = function(root) {\n if (loadedPages.length > 0) {\n loadedPages.forEach(function(courseList, index) {\n var pagedContentPage = getPagedContentContainer(root, index);\n renderCourses(root, courseList).then(function(html, js) {\n return Templates.replaceNodeContents(pagedContentPage, html, js);\n }).catch(Notification.exception);\n });\n } else {\n init(root);\n }\n };\n\n return {\n init: init,\n reset: reset\n };\n});\n"],"file":"view.min.js"} \ No newline at end of file diff --git a/blocks/myoverview/amd/src/view.js b/blocks/myoverview/amd/src/view.js index 0dc37ba13e7..3e53ea0fc99 100644 --- a/blocks/myoverview/amd/src/view.js +++ b/blocks/myoverview/amd/src/view.js @@ -67,7 +67,7 @@ function( NOCOURSES: 'core_course/no-courses' }; - var NUMCOURSES_PERPAGE = [12, 24, 48]; + var NUMCOURSES_PERPAGE = [12, 24, 48, 96, 0]; var loadedPages = []; @@ -421,19 +421,24 @@ function( var initializePagedContent = function(root) { namespace = "block_myoverview_" + root.attr('id') + "_" + Math.random(); - var itemsPerPage = NUMCOURSES_PERPAGE; var pagingLimit = parseInt(root.find(Selectors.courseView.region).attr('data-paging'), 10); - if (pagingLimit) { - itemsPerPage = NUMCOURSES_PERPAGE.map(function(value) { - var active = false; - if (value == pagingLimit) { - active = true; - } + var itemsPerPage = NUMCOURSES_PERPAGE.map(function(value) { + var active = false; + if (value == pagingLimit) { + active = true; + } - return { - value: value, - active: active - }; + return { + value: value, + active: active + }; + }); + + // Filter out all pagination options which are too large for the amount of courses user is enrolled in. + var totalCourseCount = parseInt(root.find(Selectors.courseView.region).attr('data-totalcoursecount'), 10); + if (totalCourseCount) { + itemsPerPage = itemsPerPage.filter(function(pagingOption) { + return pagingOption.value < totalCourseCount; }); } @@ -448,7 +453,7 @@ function( pagesData.forEach(function(pageData) { var currentPage = pageData.pageNumber; - var limit = pageData.limit; + var limit = (pageData.limit > 0) ? pageData.limit : 0; // Reset local variables if limits have changed if (lastLimit != limit) { @@ -491,7 +496,7 @@ function( } } else { nextPageStart = pageData.limit; - pageCourses = courses.slice(0, pageData.limit); + pageCourses = (pageData.limit > 0) ? courses.slice(0, pageData.limit) : courses; } // Finished setting up the current page @@ -500,7 +505,7 @@ function( }; // Set up the next page - var remainingCourses = courses.slice(nextPageStart, courses.length); + var remainingCourses = nextPageStart ? courses.slice(nextPageStart, courses.length) : []; if (remainingCourses.length) { loadedPages[currentPage + 1] = { courses: remainingCourses diff --git a/blocks/myoverview/classes/output/main.php b/blocks/myoverview/classes/output/main.php index 8df2b478a59..e1c92a98992 100644 --- a/blocks/myoverview/classes/output/main.php +++ b/blocks/myoverview/classes/output/main.php @@ -94,7 +94,11 @@ class main implements renderable, templatable { public function __construct($grouping, $sort, $view, $paging) { $this->grouping = $grouping ? $grouping : BLOCK_MYOVERVIEW_GROUPING_ALL; $this->sort = $sort ? $sort : BLOCK_MYOVERVIEW_SORTING_TITLE; - $this->paging = $paging ? $paging : BLOCK_MYOVERVIEW_PAGING_12; + if ($paging == BLOCK_MYOVERVIEW_PAGING_ALL) { + $this->paging = BLOCK_MYOVERVIEW_PAGING_ALL; + } else { + $this->paging = $paging ? $paging : BLOCK_MYOVERVIEW_PAGING_12; + } $config = get_config('block_myoverview'); if (!$config->displaycategories) { @@ -178,8 +182,11 @@ class main implements renderable, templatable { * * @param \renderer_base $output * @return array Context variables for the template + * @throws \coding_exception + * */ public function export_for_template(renderer_base $output) { + global $USER; $nocoursesurl = $output->image_url('courses', 'block_myoverview')->out(); @@ -187,6 +194,7 @@ class main implements renderable, templatable { $availablelayouts = $this->get_formatted_available_layouts_for_export(); $defaultvariables = [ + 'totalcoursecount' => count(enrol_get_all_users_courses($USER->id, true)), 'nocoursesimg' => $nocoursesurl, 'grouping' => $this->grouping, 'sort' => $this->sort == BLOCK_MYOVERVIEW_SORTING_TITLE ? 'fullname' : 'ul.timeaccess desc', diff --git a/blocks/myoverview/lib.php b/blocks/myoverview/lib.php index 652177f0fa3..7acbaffe882 100644 --- a/blocks/myoverview/lib.php +++ b/blocks/myoverview/lib.php @@ -54,6 +54,8 @@ define('BLOCK_MYOVERVIEW_VIEW_SUMMARY', 'summary'); define('BLOCK_MYOVERVIEW_PAGING_12', 12); define('BLOCK_MYOVERVIEW_PAGING_24', 24); define('BLOCK_MYOVERVIEW_PAGING_48', 48); +define('BLOCK_MYOVERVIEW_PAGING_96', 96); +define('BLOCK_MYOVERVIEW_PAGING_ALL', 0); /** * Constants for the admin category display setting @@ -115,7 +117,9 @@ function block_myoverview_user_preferences() { 'choices' => array( BLOCK_MYOVERVIEW_PAGING_12, BLOCK_MYOVERVIEW_PAGING_24, - BLOCK_MYOVERVIEW_PAGING_48 + BLOCK_MYOVERVIEW_PAGING_48, + BLOCK_MYOVERVIEW_PAGING_96, + BLOCK_MYOVERVIEW_PAGING_ALL ) ); diff --git a/blocks/myoverview/templates/courses-view.mustache b/blocks/myoverview/templates/courses-view.mustache index 951cef95324..5be3c986e86 100644 --- a/blocks/myoverview/templates/courses-view.mustache +++ b/blocks/myoverview/templates/courses-view.mustache @@ -35,6 +35,7 @@ data-prev-display="{{view}}" data-paging="{{paging}}" data-nocoursesimg="{{nocoursesimg}}" + data-totalcoursecount="{{totalcoursecount}}" data-displaycategories="{{displaycategories}}">
{{> block_myoverview/placeholders }} diff --git a/blocks/myoverview/tests/behat/block_myoverview_pagelimit_persistence.feature b/blocks/myoverview/tests/behat/block_myoverview_pagelimit_persistence.feature index 4135c0a3572..6e0e1074413 100644 --- a/blocks/myoverview/tests/behat/block_myoverview_pagelimit_persistence.feature +++ b/blocks/myoverview/tests/behat/block_myoverview_pagelimit_persistence.feature @@ -38,20 +38,20 @@ Feature: The my overview block allows users to persistence of their page limits Scenario: Toggle the page limit between page reloads Given I log in as "student1" - When I click on "Show 12 items per page" "button" in the "Course overview" "block" - And I click on "24" "link" - Then I should see "Course 9" + When I click on "[data-toggle='dropdown']" "css_element" in the "Course overview" "block" + And I click on "All" "link" + Then I should see "Course 13" And I reload the page - Then I should see "Course 9" - And I should see "24" in the "[data-action='limit-toggle']" "css_element" + Then I should see "Course 13" + And I should see "All" in the "[data-action='limit-toggle']" "css_element" And I log out Scenario: Toggle the page limit between grouping changes Given I log in as "student1" - When I click on "Show 12 items per page" "button" in the "Course overview" "block" - And I click on "24" "link" + When I click on "[data-toggle='dropdown']" "css_element" in the "Course overview" "block" + And I click on "All" "link" And I click on "All" "button" in the "Course overview" "block" And I click on "In progress" "link" in the "Course overview" "block" - Then I should see "Course 9" - And I should see "24" in the "[data-action='limit-toggle']" "css_element" + Then I should see "Course 13" + And I should see "All" in the "[data-action='limit-toggle']" "css_element" And I log out diff --git a/blocks/myoverview/version.php b/blocks/myoverview/version.php index 25b71946d99..4c93e24f4e4 100644 --- a/blocks/myoverview/version.php +++ b/blocks/myoverview/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2019060400; // The current plugin version (Date: YYYYMMDDXX). +$plugin->version = 2019070400; // The current plugin version (Date: YYYYMMDDXX). $plugin->requires = 2019051100; // Requires this Moodle version. $plugin->component = 'block_myoverview'; // Full name of the plugin (used for diagnostics). diff --git a/lib/amd/build/paged_content_factory.min.js b/lib/amd/build/paged_content_factory.min.js index 88b55690a0a..7988e3d7a7a 100644 --- a/lib/amd/build/paged_content_factory.min.js +++ b/lib/amd/build/paged_content_factory.min.js @@ -1,2 +1,2 @@ -define ("core/paged_content_factory",["jquery","core/templates","core/notification","core/paged_content","core/paged_content_events","core/pubsub","core/ajax"],function(a,b,c,d,e,f,g){var h={PAGED_CONTENT:"core/paged_content"},j={ITEMS_PER_PAGE_SINGLE:25,ITEMS_PER_PAGE_ARRAY:[25,50,100,0],MAX_PAGES:3},k=function(){return{pagingbar:!1,pagingdropdown:!1,skipjs:!0,ignorecontrolwhileloading:!0,controlplacementbottom:!1}},l=function(){return{showitemsperpageselector:!1,itemsperpage:35,previous:!0,next:!0,activepagenumber:1,hidecontrolonsinglepage:!0,pages:[]}},m=function(a,b){var c=1;if(0=h){k=b;f=b}else{f=2*f;k=f}e+=k;var l={itemcount:k,content:e};if(1==h){l.active=!0}d.options.push(l)}return d},s=function(a,b,c){var d=k();if(c.hasOwnProperty("ignoreControlWhileLoading")){d.ignorecontrolwhileloading=c.ignoreControlWhileLoading}if(c.hasOwnProperty("controlPlacementBottom")){d.controlplacementbottom=c.controlPlacementBottom}if(c.hasOwnProperty("hideControlOnSinglePage")){d.hidecontrolonsinglepage=c.hideControlOnSinglePage}if(c.hasOwnProperty("ariaLabels")){d.arialabels=c.ariaLabels}if(c.hasOwnProperty("dropdown")&&c.dropdown){d.pagingdropdown=r(b,c)}else{d.pagingbar=q(a,b)}return d},t=function(e,f,g,i){i=i||{};var j=a.Deferred(),k=s(e,f,i);b.render(h.PAGED_CONTENT,k).then(function(b,c){b=a(b);var e=b.attr("id");if(i.hasOwnProperty("eventNamespace")){e=i.eventNamespace}var f=b;d.init(f,g,e);v(e,i);j.resolve(b,c)}).fail(function(a){j.reject(a)}).fail(c.exception);return j.promise()},u=function(a){return function callback(b){g.call([{methodname:"core_user_update_user_preferences",args:{preferences:[{type:a,value:b}]}}])}},v=function(a,b){if(b.hasOwnProperty("persistentLimitKey")){f.subscribe(a+e.SET_ITEMS_PER_PAGE_LIMIT,u(b.persistentLimitKey))}};return{create:function create(a,b){return t(null,null,a,b)},createWithLimit:function createWithLimit(a,b,c){return t(null,a,b,c)},createWithTotalAndLimit:t,createFromStaticList:function createFromStaticList(a,b,c,d){if("undefined"==typeof d){d={}}var e=a.length;return t(e,b,function(b){var d=[];b.forEach(function(b){var c=b.offset,f=b.limit?c+b.limit:e,g=a.slice(c,f);d.push(g)});return c(d)},d)},createFromAjax:t,resetLastPageNumber:function resetLastPageNumber(a,b){f.publish(a+e.ALL_ITEMS_LOADED,b)}}}); +define ("core/paged_content_factory",["jquery","core/templates","core/notification","core/paged_content","core/paged_content_events","core/pubsub","core/ajax"],function(a,b,c,d,e,f,g){var h={PAGED_CONTENT:"core/paged_content"},j={ITEMS_PER_PAGE_SINGLE:25,ITEMS_PER_PAGE_ARRAY:[25,50,100,0],MAX_PAGES:3},k=function(){return{pagingbar:!1,pagingdropdown:!1,skipjs:!0,ignorecontrolwhileloading:!0,controlplacementbottom:!1}},l=function(){return{showitemsperpageselector:!1,itemsperpage:35,previous:!0,next:!0,activepagenumber:1,hidecontrolonsinglepage:!0,pages:[]}},m=function(a,b){var c=1;if(0=h){k=b;f=b}else{f=2*f;k=f}e+=k;var l={itemcount:k,content:e};if(1==h){l.active=!0}d.options.push(l)}return d},s=function(a,b,c){var d=k();if(c.hasOwnProperty("ignoreControlWhileLoading")){d.ignorecontrolwhileloading=c.ignoreControlWhileLoading}if(c.hasOwnProperty("controlPlacementBottom")){d.controlplacementbottom=c.controlPlacementBottom}if(c.hasOwnProperty("hideControlOnSinglePage")){d.hidecontrolonsinglepage=c.hideControlOnSinglePage}if(c.hasOwnProperty("ariaLabels")){d.arialabels=c.ariaLabels}if(c.hasOwnProperty("dropdown")&&c.dropdown){d.pagingdropdown=r(b,c)}else{d.pagingbar=q(a,b)}return d},t=function(e,f,g,i){i=i||{};var j=a.Deferred(),k=s(e,f,i);b.render(h.PAGED_CONTENT,k).then(function(b,c){b=a(b);var e=b.attr("id");if(i.hasOwnProperty("eventNamespace")){e=i.eventNamespace}var f=b;d.init(f,g,e);v(e,i);j.resolve(b,c)}).fail(function(a){j.reject(a)}).fail(c.exception);return j.promise()},u=function(a){return function callback(b){g.call([{methodname:"core_user_update_user_preferences",args:{preferences:[{type:a,value:b}]}}])}},v=function(a,b){if(b.hasOwnProperty("persistentLimitKey")){f.subscribe(a+e.SET_ITEMS_PER_PAGE_LIMIT,u(b.persistentLimitKey))}};return{create:function create(a,b){return t(null,null,a,b)},createWithLimit:function createWithLimit(a,b,c){return t(null,a,b,c)},createWithTotalAndLimit:t,createFromStaticList:function createFromStaticList(a,b,c,d){if("undefined"==typeof d){d={}}var e=a.length;return t(e,b,function(b){var d=[];b.forEach(function(b){var c=b.offset,f=b.limit?c+b.limit:e,g=a.slice(c,f);d.push(g)});return c(d)},d)},createFromAjax:t,resetLastPageNumber:function resetLastPageNumber(a,b){f.publish(a+e.ALL_ITEMS_LOADED,b)}}}); //# sourceMappingURL=paged_content_factory.min.js.map diff --git a/lib/amd/build/paged_content_factory.min.js.map b/lib/amd/build/paged_content_factory.min.js.map index e525b43bc69..a3c86aa4622 100644 --- a/lib/amd/build/paged_content_factory.min.js.map +++ b/lib/amd/build/paged_content_factory.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/paged_content_factory.js"],"names":["define","$","Templates","Notification","PagedContent","PagedContentEvents","PubSub","Ajax","TEMPLATES","PAGED_CONTENT","DEFAULT","ITEMS_PER_PAGE_SINGLE","ITEMS_PER_PAGE_ARRAY","MAX_PAGES","getDefaultTemplateContext","pagingbar","pagingdropdown","skipjs","ignorecontrolwhileloading","controlplacementbottom","getDefaultPagingBarTemplateContext","showitemsperpageselector","itemsperpage","previous","next","activepagenumber","hidecontrolonsinglepage","pages","calculateNumberOfPages","numberOfItems","itemsPerPage","numberOfPages","partial","buildPagingBarTemplateContextKnownLength","isArray","context","i","page","number","active","push","buildItemsPerPagePagingBarContext","map","num","value","activeItems","filter","item","length","buildPagingBarTemplateContextUnknownLength","buildPagingBarTemplateContext","buildPagingDropdownTemplateContext","config","options","totalItems","lastIncrease","maxPages","hasOwnProperty","itemCount","option","itemcount","content","buildTemplateContext","ignoreControlWhileLoading","controlPlacementBottom","hideControlOnSinglePage","arialabels","ariaLabels","dropdown","createWithTotalAndLimit","renderPagesContentCallback","deferred","Deferred","templateContext","render","then","html","js","id","attr","eventNamespace","container","init","registerEvents","resolve","fail","exception","reject","promise","generateLimitHandler","persistentLimitKey","callback","limit","call","methodname","args","preferences","type","namespace","subscribe","SET_ITEMS_PER_PAGE_LIMIT","create","createWithLimit","createFromStaticList","contentItems","renderContentCallback","pagesData","contentToRender","forEach","pageData","begin","offset","end","items","slice","createFromAjax","resetLastPageNumber","lastPageNumber","publish","ALL_ITEMS_LOADED"],"mappings":"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","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 * Factory to create a paged content widget.\n *\n * @module core/paged_content_factory\n * @copyright 2018 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(\n[\n 'jquery',\n 'core/templates',\n 'core/notification',\n 'core/paged_content',\n 'core/paged_content_events',\n 'core/pubsub',\n 'core/ajax'\n],\nfunction(\n $,\n Templates,\n Notification,\n PagedContent,\n PagedContentEvents,\n PubSub,\n Ajax\n) {\n var TEMPLATES = {\n PAGED_CONTENT: 'core/paged_content'\n };\n\n var DEFAULT = {\n ITEMS_PER_PAGE_SINGLE: 25,\n ITEMS_PER_PAGE_ARRAY: [25, 50, 100, 0],\n MAX_PAGES: 3\n };\n\n /**\n * Get the default context to render the paged content mustache\n * template.\n *\n * @return {object}\n */\n var getDefaultTemplateContext = function() {\n return {\n pagingbar: false,\n pagingdropdown: false,\n skipjs: true,\n ignorecontrolwhileloading: true,\n controlplacementbottom: false\n };\n };\n\n /**\n * Get the default context to render the paging bar mustache template.\n *\n * @return {object}\n */\n var getDefaultPagingBarTemplateContext = function() {\n return {\n showitemsperpageselector: false,\n itemsperpage: 35,\n previous: true,\n next: true,\n activepagenumber: 1,\n hidecontrolonsinglepage: true,\n pages: []\n };\n };\n\n /**\n * Calculate the number of pages required for the given number of items and\n * how many of each item should appear on a page.\n *\n * @param {Number} numberOfItems How many items in total.\n * @param {Number} itemsPerPage How many items will be shown per page.\n * @return {Number} The number of pages required.\n */\n var calculateNumberOfPages = function(numberOfItems, itemsPerPage) {\n var numberOfPages = 1;\n\n if (numberOfItems > 0) {\n var partial = numberOfItems % itemsPerPage;\n\n if (partial) {\n numberOfItems -= partial;\n numberOfPages = (numberOfItems / itemsPerPage) + 1;\n } else {\n numberOfPages = numberOfItems / itemsPerPage;\n }\n }\n\n return numberOfPages;\n };\n\n /**\n * Build the context for the paging bar template when we have a known number\n * of items.\n *\n * @param {Number} numberOfItems How many items in total.\n * @param {Number} itemsPerPage How many items will be shown per page.\n * @return {object} Mustache template\n */\n var buildPagingBarTemplateContextKnownLength = function(numberOfItems, itemsPerPage) {\n if (itemsPerPage === null) {\n itemsPerPage = DEFAULT.ITEMS_PER_PAGE_SINGLE;\n }\n\n if ($.isArray(itemsPerPage)) {\n // If we're given a total number of pages then we don't support a variable\n // set of items per page so just use the first one.\n itemsPerPage = itemsPerPage[0];\n }\n\n var context = getDefaultPagingBarTemplateContext();\n context.itemsperpage = itemsPerPage;\n var numberOfPages = calculateNumberOfPages(numberOfItems, itemsPerPage);\n\n for (var i = 1; i <= numberOfPages; i++) {\n var page = {\n number: i,\n page: \"\" + i,\n };\n\n // Make the first page active by default.\n if (i === 1) {\n page.active = true;\n }\n\n context.pages.push(page);\n }\n\n return context;\n };\n\n /**\n * Convert the itemsPerPage value into a format applicable for the mustache template.\n * The given value can be either a single integer or an array of integers / objects.\n *\n * E.g.\n * In: [5, 10]\n * out: [{value: 5, active: true}, {value: 10, active: false}]\n *\n * In: [5, {value: 10, active: true}]\n * Out: [{value: 5, active: false}, {value: 10, active: true}]\n *\n * In: [{value: 5, active: false}, {value: 10, active: true}]\n * Out: [{value: 5, active: false}, {value: 10, active: true}]\n *\n * @param {int|int[]} itemsPerPage Options for number of items per page.\n * @return {int|array}\n */\n var buildItemsPerPagePagingBarContext = function(itemsPerPage) {\n if ($.isArray(itemsPerPage)) {\n // Convert the array into a format accepted by the template.\n var context = itemsPerPage.map(function(num) {\n if (typeof num === 'number') {\n // If the item is just a plain number then convert it into\n // an object with value and active keys.\n return {\n value: num,\n active: false\n };\n } else {\n // Otherwise we assume the caller has specified things correctly.\n return num;\n }\n });\n\n var activeItems = context.filter(function(item) {\n return item.active;\n });\n\n // Default the first item to active if one hasn't been specified.\n if (!activeItems.length) {\n context[0].active = true;\n }\n\n return context;\n } else {\n return itemsPerPage;\n }\n };\n\n /**\n * Build the context for the paging bar template when we have an unknown\n * number of items.\n *\n * @param {Number} itemsPerPage How many items will be shown per page.\n * @return {object} Mustache template\n */\n var buildPagingBarTemplateContextUnknownLength = function(itemsPerPage) {\n if (itemsPerPage === null) {\n itemsPerPage = DEFAULT.ITEMS_PER_PAGE_ARRAY;\n }\n\n var context = getDefaultPagingBarTemplateContext();\n context.itemsperpage = buildItemsPerPagePagingBarContext(itemsPerPage);\n context.showitemsperpageselector = $.isArray(itemsPerPage);\n\n return context;\n };\n\n /**\n * Build the context to render the paging bar template with based on the number\n * of pages to show.\n *\n * @param {int|null} numberOfItems How many items are there total.\n * @param {int|null} itemsPerPage How many items will be shown per page.\n * @return {object} The template context.\n */\n var buildPagingBarTemplateContext = function(numberOfItems, itemsPerPage) {\n if (numberOfItems) {\n return buildPagingBarTemplateContextKnownLength(numberOfItems, itemsPerPage);\n } else {\n return buildPagingBarTemplateContextUnknownLength(itemsPerPage);\n }\n };\n\n /**\n * Build the context to render the paging dropdown template based on the number\n * of pages to show and items per page.\n *\n * This control is rendered with a gradual increase of the items per page to\n * limit the number of pages in the dropdown. Each page will show twice as much\n * as the previous page (except for the first two pages).\n *\n * By default there will only be 4 pages shown (including the \"All\" option) unless\n * a different number of pages is defined using the maxPages config value.\n *\n * For example:\n * Items per page = 25\n * Would render a dropdown will 4 options:\n * 25\n * 50\n * 100\n * All\n *\n * @param {Number} itemsPerPage How many items will be shown per page.\n * @param {object} config Configuration options provided by the client.\n * @return {object} The template context.\n */\n var buildPagingDropdownTemplateContext = function(itemsPerPage, config) {\n if (itemsPerPage === null) {\n itemsPerPage = DEFAULT.ITEMS_PER_PAGE_SINGLE;\n }\n\n if ($.isArray(itemsPerPage)) {\n // If we're given an array for the items per page, rather than a number,\n // then just use that as the options for the dropdown.\n return {\n options: itemsPerPage\n };\n }\n\n var context = {\n options: []\n };\n\n var totalItems = 0;\n var lastIncrease = 0;\n var maxPages = DEFAULT.MAX_PAGES;\n\n if (config.hasOwnProperty('maxPages')) {\n maxPages = config.maxPages;\n }\n\n for (var i = 1; i <= maxPages; i++) {\n var itemCount = 0;\n\n if (i <= 2) {\n itemCount = itemsPerPage;\n lastIncrease = itemsPerPage;\n } else {\n lastIncrease = lastIncrease * 2;\n itemCount = lastIncrease;\n }\n\n totalItems += itemCount;\n var option = {\n itemcount: itemCount,\n content: totalItems\n };\n\n // Make the first option active by default.\n if (i === 1) {\n option.active = true;\n }\n\n context.options.push(option);\n }\n\n return context;\n };\n\n /**\n * Build the context to render the paged content template with based on the number\n * of pages to show, items per page, and configuration option.\n *\n * By default the code will render a paging bar for the paging controls unless\n * otherwise specified in the provided config.\n *\n * @param {int|null} numberOfItems Total number of items.\n * @param {int|null|array} itemsPerPage How many items will be shown per page.\n * @param {object} config Configuration options provided by the client.\n * @return {object} The template context.\n */\n var buildTemplateContext = function(numberOfItems, itemsPerPage, config) {\n var context = getDefaultTemplateContext();\n\n if (config.hasOwnProperty('ignoreControlWhileLoading')) {\n context.ignorecontrolwhileloading = config.ignoreControlWhileLoading;\n }\n\n if (config.hasOwnProperty('controlPlacementBottom')) {\n context.controlplacementbottom = config.controlPlacementBottom;\n }\n\n if (config.hasOwnProperty('hideControlOnSinglePage')) {\n context.hidecontrolonsinglepage = config.hideControlOnSinglePage;\n }\n\n if (config.hasOwnProperty('ariaLabels')) {\n context.arialabels = config.ariaLabels;\n }\n\n if (config.hasOwnProperty('dropdown') && config.dropdown) {\n context.pagingdropdown = buildPagingDropdownTemplateContext(itemsPerPage, config);\n } else {\n context.pagingbar = buildPagingBarTemplateContext(numberOfItems, itemsPerPage);\n }\n\n return context;\n };\n\n /**\n * Create a paged content widget where the complete list of items is not loaded\n * up front but will instead be loaded by an ajax request (or similar).\n *\n * The client code must provide a callback function which loads and renders the\n * items for each page. See PagedContent.init for more details.\n *\n * The function will return a deferred that is resolved with a jQuery object\n * for the HTML content and a string for the JavaScript.\n *\n * The current list of configuration options available are:\n * dropdown {bool} True to render the page control as a dropdown (paging bar is default).\n * maxPages {Number} The maximum number of pages to show in the dropdown (only works with dropdown option)\n * ignoreControlWhileLoading {bool} Disable the pagination controls while loading a page (default to true)\n * controlPlacementBottom {bool} Render controls under paged content (default to false)\n *\n * @param {function} renderPagesContentCallback Callback for loading and rendering the items.\n * @param {object} config Configuration options provided by the client.\n * @return {promise} Resolved with jQuery HTML and string JS.\n */\n var create = function(renderPagesContentCallback, config) {\n return createWithTotalAndLimit(null, null, renderPagesContentCallback, config);\n };\n\n /**\n * Create a paged content widget where the complete list of items is not loaded\n * up front but will instead be loaded by an ajax request (or similar).\n *\n * The client code must provide a callback function which loads and renders the\n * items for each page. See PagedContent.init for more details.\n *\n * The function will return a deferred that is resolved with a jQuery object\n * for the HTML content and a string for the JavaScript.\n *\n * The current list of configuration options available are:\n * dropdown {bool} True to render the page control as a dropdown (paging bar is default).\n * maxPages {Number} The maximum number of pages to show in the dropdown (only works with dropdown option)\n * ignoreControlWhileLoading {bool} Disable the pagination controls while loading a page (default to true)\n * controlPlacementBottom {bool} Render controls under paged content (default to false)\n *\n * @param {int|array|null} itemsPerPage How many items will be shown per page.\n * @param {function} renderPagesContentCallback Callback for loading and rendering the items.\n * @param {object} config Configuration options provided by the client.\n * @return {promise} Resolved with jQuery HTML and string JS.\n */\n var createWithLimit = function(itemsPerPage, renderPagesContentCallback, config) {\n return createWithTotalAndLimit(null, itemsPerPage, renderPagesContentCallback, config);\n };\n\n /**\n * Create a paged content widget where the complete list of items is not loaded\n * up front but will instead be loaded by an ajax request (or similar).\n *\n * The client code must provide a callback function which loads and renders the\n * items for each page. See PagedContent.init for more details.\n *\n * The function will return a deferred that is resolved with a jQuery object\n * for the HTML content and a string for the JavaScript.\n *\n * The current list of configuration options available are:\n * dropdown {bool} True to render the page control as a dropdown (paging bar is default).\n * maxPages {Number} The maximum number of pages to show in the dropdown (only works with dropdown option)\n * ignoreControlWhileLoading {bool} Disable the pagination controls while loading a page (default to true)\n * controlPlacementBottom {bool} Render controls under paged content (default to false)\n *\n * @param {int|null} numberOfItems How many items are there in total.\n * @param {int|array|null} itemsPerPage How many items will be shown per page.\n * @param {function} renderPagesContentCallback Callback for loading and rendering the items.\n * @param {object} config Configuration options provided by the client.\n * @return {promise} Resolved with jQuery HTML and string JS.\n */\n var createWithTotalAndLimit = function(numberOfItems, itemsPerPage, renderPagesContentCallback, config) {\n config = config || {};\n\n var deferred = $.Deferred();\n var templateContext = buildTemplateContext(numberOfItems, itemsPerPage, config);\n\n Templates.render(TEMPLATES.PAGED_CONTENT, templateContext)\n .then(function(html, js) {\n html = $(html);\n var id = html.attr('id');\n\n // Set the id to the custom namespace provided\n if (config.hasOwnProperty('eventNamespace')) {\n id = config.eventNamespace;\n }\n\n var container = html;\n\n PagedContent.init(container, renderPagesContentCallback, id);\n\n registerEvents(id, config);\n\n deferred.resolve(html, js);\n return;\n })\n .fail(function(exception) {\n deferred.reject(exception);\n })\n .fail(Notification.exception);\n\n return deferred.promise();\n };\n\n /**\n * Create a paged content widget where the complete list of items is loaded\n * up front.\n *\n * The client code must provide a callback function which renders the\n * items for each page. The callback will be provided with an array where each\n * value in the array is a the list of items to render for the page.\n *\n * The function will return a deferred that is resolved with a jQuery object\n * for the HTML content and a string for the JavaScript.\n *\n * The current list of configuration options available are:\n * dropdown {bool} True to render the page control as a dropdown (paging bar is default).\n * maxPages {Number} The maximum number of pages to show in the dropdown (only works with dropdown option)\n * ignoreControlWhileLoading {bool} Disable the pagination controls while loading a page (default to true)\n * controlPlacementBottom {bool} Render controls under paged content (default to false)\n *\n * @param {array} contentItems The list of items to paginate.\n * @param {Number} itemsPerPage How many items will be shown per page.\n * @param {function} renderContentCallback Callback for rendering the items for the page.\n * @param {object} config Configuration options provided by the client.\n * @return {promise} Resolved with jQuery HTML and string JS.\n */\n var createFromStaticList = function(contentItems, itemsPerPage, renderContentCallback, config) {\n if (typeof config == 'undefined') {\n config = {};\n }\n\n var numberOfItems = contentItems.length;\n return createWithTotalAndLimit(numberOfItems, itemsPerPage, function(pagesData) {\n var contentToRender = [];\n pagesData.forEach(function(pageData) {\n var begin = pageData.offset;\n var end = pageData.limit ? begin + pageData.limit : numberOfItems;\n var items = contentItems.slice(begin, end);\n contentToRender.push(items);\n });\n\n return renderContentCallback(contentToRender);\n }, config);\n };\n\n /**\n * Reset the last page number for the generated paged-content\n * This is used when we need a way to update the last page number outside of the getters callback\n *\n * @param {String} id ID of the paged content container\n * @param {Int} lastPageNumber The last page number\n */\n var resetLastPageNumber = function(id, lastPageNumber) {\n PubSub.publish(id + PagedContentEvents.ALL_ITEMS_LOADED, lastPageNumber);\n };\n\n /**\n * Generate the callback handler for the page limit persistence functionality\n *\n * @param {String} persistentLimitKey\n * @return {callback}\n */\n var generateLimitHandler = function(persistentLimitKey) {\n var callback = function(limit) {\n var args = {\n preferences: [\n {\n type: persistentLimitKey,\n value: limit\n }\n ]\n };\n\n var request = {\n methodname: 'core_user_update_user_preferences',\n args: args\n };\n\n Ajax.call([request]);\n };\n\n return callback;\n };\n\n /**\n * Set up any events based on config key values\n *\n * @param {string} namespace The namespace for this component\n * @param {object} config Config options passed to the factory\n */\n var registerEvents = function(namespace, config) {\n if (config.hasOwnProperty('persistentLimitKey')) {\n PubSub.subscribe(namespace + PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT,\n generateLimitHandler(config.persistentLimitKey));\n }\n };\n\n return {\n create: create,\n createWithLimit: createWithLimit,\n createWithTotalAndLimit: createWithTotalAndLimit,\n createFromStaticList: createFromStaticList,\n // Backwards compatibility just in case anyone was using this.\n createFromAjax: createWithTotalAndLimit,\n resetLastPageNumber: resetLastPageNumber\n };\n});\n"],"file":"paged_content_factory.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/paged_content_factory.js"],"names":["define","$","Templates","Notification","PagedContent","PagedContentEvents","PubSub","Ajax","TEMPLATES","PAGED_CONTENT","DEFAULT","ITEMS_PER_PAGE_SINGLE","ITEMS_PER_PAGE_ARRAY","MAX_PAGES","getDefaultTemplateContext","pagingbar","pagingdropdown","skipjs","ignorecontrolwhileloading","controlplacementbottom","getDefaultPagingBarTemplateContext","showitemsperpageselector","itemsperpage","previous","next","activepagenumber","hidecontrolonsinglepage","pages","calculateNumberOfPages","numberOfItems","itemsPerPage","numberOfPages","partial","buildPagingBarTemplateContextKnownLength","isArray","context","i","page","number","active","push","buildItemsPerPagePagingBarContext","map","num","value","activeItems","filter","item","length","buildPagingBarTemplateContextUnknownLength","buildPagingBarTemplateContext","buildPagingDropdownTemplateContext","config","options","totalItems","lastIncrease","maxPages","hasOwnProperty","itemCount","option","itemcount","content","buildTemplateContext","ignoreControlWhileLoading","controlPlacementBottom","hideControlOnSinglePage","arialabels","ariaLabels","dropdown","createWithTotalAndLimit","renderPagesContentCallback","deferred","Deferred","templateContext","render","then","html","js","id","attr","eventNamespace","container","init","registerEvents","resolve","fail","exception","reject","promise","generateLimitHandler","persistentLimitKey","callback","limit","call","methodname","args","preferences","type","namespace","subscribe","SET_ITEMS_PER_PAGE_LIMIT","create","createWithLimit","createFromStaticList","contentItems","renderContentCallback","pagesData","contentToRender","forEach","pageData","begin","offset","end","items","slice","createFromAjax","resetLastPageNumber","lastPageNumber","publish","ALL_ITEMS_LOADED"],"mappings":"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","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 * Factory to create a paged content widget.\n *\n * @module core/paged_content_factory\n * @copyright 2018 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(\n[\n 'jquery',\n 'core/templates',\n 'core/notification',\n 'core/paged_content',\n 'core/paged_content_events',\n 'core/pubsub',\n 'core/ajax'\n],\nfunction(\n $,\n Templates,\n Notification,\n PagedContent,\n PagedContentEvents,\n PubSub,\n Ajax\n) {\n var TEMPLATES = {\n PAGED_CONTENT: 'core/paged_content'\n };\n\n var DEFAULT = {\n ITEMS_PER_PAGE_SINGLE: 25,\n ITEMS_PER_PAGE_ARRAY: [25, 50, 100, 0],\n MAX_PAGES: 3\n };\n\n /**\n * Get the default context to render the paged content mustache\n * template.\n *\n * @return {object}\n */\n var getDefaultTemplateContext = function() {\n return {\n pagingbar: false,\n pagingdropdown: false,\n skipjs: true,\n ignorecontrolwhileloading: true,\n controlplacementbottom: false\n };\n };\n\n /**\n * Get the default context to render the paging bar mustache template.\n *\n * @return {object}\n */\n var getDefaultPagingBarTemplateContext = function() {\n return {\n showitemsperpageselector: false,\n itemsperpage: 35,\n previous: true,\n next: true,\n activepagenumber: 1,\n hidecontrolonsinglepage: true,\n pages: []\n };\n };\n\n /**\n * Calculate the number of pages required for the given number of items and\n * how many of each item should appear on a page.\n *\n * @param {Number} numberOfItems How many items in total.\n * @param {Number} itemsPerPage How many items will be shown per page.\n * @return {Number} The number of pages required.\n */\n var calculateNumberOfPages = function(numberOfItems, itemsPerPage) {\n var numberOfPages = 1;\n\n if (numberOfItems > 0) {\n var partial = numberOfItems % itemsPerPage;\n\n if (partial) {\n numberOfItems -= partial;\n numberOfPages = (numberOfItems / itemsPerPage) + 1;\n } else {\n numberOfPages = numberOfItems / itemsPerPage;\n }\n }\n\n return numberOfPages;\n };\n\n /**\n * Build the context for the paging bar template when we have a known number\n * of items.\n *\n * @param {Number} numberOfItems How many items in total.\n * @param {Number} itemsPerPage How many items will be shown per page.\n * @return {object} Mustache template\n */\n var buildPagingBarTemplateContextKnownLength = function(numberOfItems, itemsPerPage) {\n if (itemsPerPage === null) {\n itemsPerPage = DEFAULT.ITEMS_PER_PAGE_SINGLE;\n }\n\n if ($.isArray(itemsPerPage)) {\n // If we're given a total number of pages then we don't support a variable\n // set of items per page so just use the first one.\n itemsPerPage = itemsPerPage[0];\n }\n\n var context = getDefaultPagingBarTemplateContext();\n context.itemsperpage = itemsPerPage;\n var numberOfPages = calculateNumberOfPages(numberOfItems, itemsPerPage);\n\n for (var i = 1; i <= numberOfPages; i++) {\n var page = {\n number: i,\n page: \"\" + i,\n };\n\n // Make the first page active by default.\n if (i === 1) {\n page.active = true;\n }\n\n context.pages.push(page);\n }\n\n return context;\n };\n\n /**\n * Convert the itemsPerPage value into a format applicable for the mustache template.\n * The given value can be either a single integer or an array of integers / objects.\n *\n * E.g.\n * In: [5, 10]\n * out: [{value: 5, active: true}, {value: 10, active: false}]\n *\n * In: [5, {value: 10, active: true}]\n * Out: [{value: 5, active: false}, {value: 10, active: true}]\n *\n * In: [{value: 5, active: false}, {value: 10, active: true}]\n * Out: [{value: 5, active: false}, {value: 10, active: true}]\n *\n * @param {int|int[]} itemsPerPage Options for number of items per page.\n * @return {int|array}\n */\n var buildItemsPerPagePagingBarContext = function(itemsPerPage) {\n if ($.isArray(itemsPerPage)) {\n // Convert the array into a format accepted by the template.\n var context = itemsPerPage.map(function(num) {\n if (typeof num === 'number') {\n // If the item is just a plain number then convert it into\n // an object with value and active keys.\n return {\n value: num,\n active: false\n };\n } else {\n // Otherwise we assume the caller has specified things correctly.\n return num;\n }\n });\n\n var activeItems = context.filter(function(item) {\n return item.active;\n });\n\n // Default the first item to active if one hasn't been specified.\n if (!activeItems.length) {\n context[0].active = true;\n }\n\n return context;\n } else {\n return itemsPerPage;\n }\n };\n\n /**\n * Build the context for the paging bar template when we have an unknown\n * number of items.\n *\n * @param {Number} itemsPerPage How many items will be shown per page.\n * @return {object} Mustache template\n */\n var buildPagingBarTemplateContextUnknownLength = function(itemsPerPage) {\n if (itemsPerPage === null) {\n itemsPerPage = DEFAULT.ITEMS_PER_PAGE_ARRAY;\n }\n\n var context = getDefaultPagingBarTemplateContext();\n context.itemsperpage = buildItemsPerPagePagingBarContext(itemsPerPage);\n // Only display the items per page selector if there is more than one to choose from.\n context.showitemsperpageselector = $.isArray(itemsPerPage) && itemsPerPage.length > 1;\n\n return context;\n };\n\n /**\n * Build the context to render the paging bar template with based on the number\n * of pages to show.\n *\n * @param {int|null} numberOfItems How many items are there total.\n * @param {int|null} itemsPerPage How many items will be shown per page.\n * @return {object} The template context.\n */\n var buildPagingBarTemplateContext = function(numberOfItems, itemsPerPage) {\n if (numberOfItems) {\n return buildPagingBarTemplateContextKnownLength(numberOfItems, itemsPerPage);\n } else {\n return buildPagingBarTemplateContextUnknownLength(itemsPerPage);\n }\n };\n\n /**\n * Build the context to render the paging dropdown template based on the number\n * of pages to show and items per page.\n *\n * This control is rendered with a gradual increase of the items per page to\n * limit the number of pages in the dropdown. Each page will show twice as much\n * as the previous page (except for the first two pages).\n *\n * By default there will only be 4 pages shown (including the \"All\" option) unless\n * a different number of pages is defined using the maxPages config value.\n *\n * For example:\n * Items per page = 25\n * Would render a dropdown will 4 options:\n * 25\n * 50\n * 100\n * All\n *\n * @param {Number} itemsPerPage How many items will be shown per page.\n * @param {object} config Configuration options provided by the client.\n * @return {object} The template context.\n */\n var buildPagingDropdownTemplateContext = function(itemsPerPage, config) {\n if (itemsPerPage === null) {\n itemsPerPage = DEFAULT.ITEMS_PER_PAGE_SINGLE;\n }\n\n if ($.isArray(itemsPerPage)) {\n // If we're given an array for the items per page, rather than a number,\n // then just use that as the options for the dropdown.\n return {\n options: itemsPerPage\n };\n }\n\n var context = {\n options: []\n };\n\n var totalItems = 0;\n var lastIncrease = 0;\n var maxPages = DEFAULT.MAX_PAGES;\n\n if (config.hasOwnProperty('maxPages')) {\n maxPages = config.maxPages;\n }\n\n for (var i = 1; i <= maxPages; i++) {\n var itemCount = 0;\n\n if (i <= 2) {\n itemCount = itemsPerPage;\n lastIncrease = itemsPerPage;\n } else {\n lastIncrease = lastIncrease * 2;\n itemCount = lastIncrease;\n }\n\n totalItems += itemCount;\n var option = {\n itemcount: itemCount,\n content: totalItems\n };\n\n // Make the first option active by default.\n if (i === 1) {\n option.active = true;\n }\n\n context.options.push(option);\n }\n\n return context;\n };\n\n /**\n * Build the context to render the paged content template with based on the number\n * of pages to show, items per page, and configuration option.\n *\n * By default the code will render a paging bar for the paging controls unless\n * otherwise specified in the provided config.\n *\n * @param {int|null} numberOfItems Total number of items.\n * @param {int|null|array} itemsPerPage How many items will be shown per page.\n * @param {object} config Configuration options provided by the client.\n * @return {object} The template context.\n */\n var buildTemplateContext = function(numberOfItems, itemsPerPage, config) {\n var context = getDefaultTemplateContext();\n\n if (config.hasOwnProperty('ignoreControlWhileLoading')) {\n context.ignorecontrolwhileloading = config.ignoreControlWhileLoading;\n }\n\n if (config.hasOwnProperty('controlPlacementBottom')) {\n context.controlplacementbottom = config.controlPlacementBottom;\n }\n\n if (config.hasOwnProperty('hideControlOnSinglePage')) {\n context.hidecontrolonsinglepage = config.hideControlOnSinglePage;\n }\n\n if (config.hasOwnProperty('ariaLabels')) {\n context.arialabels = config.ariaLabels;\n }\n\n if (config.hasOwnProperty('dropdown') && config.dropdown) {\n context.pagingdropdown = buildPagingDropdownTemplateContext(itemsPerPage, config);\n } else {\n context.pagingbar = buildPagingBarTemplateContext(numberOfItems, itemsPerPage);\n }\n\n return context;\n };\n\n /**\n * Create a paged content widget where the complete list of items is not loaded\n * up front but will instead be loaded by an ajax request (or similar).\n *\n * The client code must provide a callback function which loads and renders the\n * items for each page. See PagedContent.init for more details.\n *\n * The function will return a deferred that is resolved with a jQuery object\n * for the HTML content and a string for the JavaScript.\n *\n * The current list of configuration options available are:\n * dropdown {bool} True to render the page control as a dropdown (paging bar is default).\n * maxPages {Number} The maximum number of pages to show in the dropdown (only works with dropdown option)\n * ignoreControlWhileLoading {bool} Disable the pagination controls while loading a page (default to true)\n * controlPlacementBottom {bool} Render controls under paged content (default to false)\n *\n * @param {function} renderPagesContentCallback Callback for loading and rendering the items.\n * @param {object} config Configuration options provided by the client.\n * @return {promise} Resolved with jQuery HTML and string JS.\n */\n var create = function(renderPagesContentCallback, config) {\n return createWithTotalAndLimit(null, null, renderPagesContentCallback, config);\n };\n\n /**\n * Create a paged content widget where the complete list of items is not loaded\n * up front but will instead be loaded by an ajax request (or similar).\n *\n * The client code must provide a callback function which loads and renders the\n * items for each page. See PagedContent.init for more details.\n *\n * The function will return a deferred that is resolved with a jQuery object\n * for the HTML content and a string for the JavaScript.\n *\n * The current list of configuration options available are:\n * dropdown {bool} True to render the page control as a dropdown (paging bar is default).\n * maxPages {Number} The maximum number of pages to show in the dropdown (only works with dropdown option)\n * ignoreControlWhileLoading {bool} Disable the pagination controls while loading a page (default to true)\n * controlPlacementBottom {bool} Render controls under paged content (default to false)\n *\n * @param {int|array|null} itemsPerPage How many items will be shown per page.\n * @param {function} renderPagesContentCallback Callback for loading and rendering the items.\n * @param {object} config Configuration options provided by the client.\n * @return {promise} Resolved with jQuery HTML and string JS.\n */\n var createWithLimit = function(itemsPerPage, renderPagesContentCallback, config) {\n return createWithTotalAndLimit(null, itemsPerPage, renderPagesContentCallback, config);\n };\n\n /**\n * Create a paged content widget where the complete list of items is not loaded\n * up front but will instead be loaded by an ajax request (or similar).\n *\n * The client code must provide a callback function which loads and renders the\n * items for each page. See PagedContent.init for more details.\n *\n * The function will return a deferred that is resolved with a jQuery object\n * for the HTML content and a string for the JavaScript.\n *\n * The current list of configuration options available are:\n * dropdown {bool} True to render the page control as a dropdown (paging bar is default).\n * maxPages {Number} The maximum number of pages to show in the dropdown (only works with dropdown option)\n * ignoreControlWhileLoading {bool} Disable the pagination controls while loading a page (default to true)\n * controlPlacementBottom {bool} Render controls under paged content (default to false)\n *\n * @param {int|null} numberOfItems How many items are there in total.\n * @param {int|array|null} itemsPerPage How many items will be shown per page.\n * @param {function} renderPagesContentCallback Callback for loading and rendering the items.\n * @param {object} config Configuration options provided by the client.\n * @return {promise} Resolved with jQuery HTML and string JS.\n */\n var createWithTotalAndLimit = function(numberOfItems, itemsPerPage, renderPagesContentCallback, config) {\n config = config || {};\n\n var deferred = $.Deferred();\n var templateContext = buildTemplateContext(numberOfItems, itemsPerPage, config);\n\n Templates.render(TEMPLATES.PAGED_CONTENT, templateContext)\n .then(function(html, js) {\n html = $(html);\n var id = html.attr('id');\n\n // Set the id to the custom namespace provided\n if (config.hasOwnProperty('eventNamespace')) {\n id = config.eventNamespace;\n }\n\n var container = html;\n\n PagedContent.init(container, renderPagesContentCallback, id);\n\n registerEvents(id, config);\n\n deferred.resolve(html, js);\n return;\n })\n .fail(function(exception) {\n deferred.reject(exception);\n })\n .fail(Notification.exception);\n\n return deferred.promise();\n };\n\n /**\n * Create a paged content widget where the complete list of items is loaded\n * up front.\n *\n * The client code must provide a callback function which renders the\n * items for each page. The callback will be provided with an array where each\n * value in the array is a the list of items to render for the page.\n *\n * The function will return a deferred that is resolved with a jQuery object\n * for the HTML content and a string for the JavaScript.\n *\n * The current list of configuration options available are:\n * dropdown {bool} True to render the page control as a dropdown (paging bar is default).\n * maxPages {Number} The maximum number of pages to show in the dropdown (only works with dropdown option)\n * ignoreControlWhileLoading {bool} Disable the pagination controls while loading a page (default to true)\n * controlPlacementBottom {bool} Render controls under paged content (default to false)\n *\n * @param {array} contentItems The list of items to paginate.\n * @param {Number} itemsPerPage How many items will be shown per page.\n * @param {function} renderContentCallback Callback for rendering the items for the page.\n * @param {object} config Configuration options provided by the client.\n * @return {promise} Resolved with jQuery HTML and string JS.\n */\n var createFromStaticList = function(contentItems, itemsPerPage, renderContentCallback, config) {\n if (typeof config == 'undefined') {\n config = {};\n }\n\n var numberOfItems = contentItems.length;\n return createWithTotalAndLimit(numberOfItems, itemsPerPage, function(pagesData) {\n var contentToRender = [];\n pagesData.forEach(function(pageData) {\n var begin = pageData.offset;\n var end = pageData.limit ? begin + pageData.limit : numberOfItems;\n var items = contentItems.slice(begin, end);\n contentToRender.push(items);\n });\n\n return renderContentCallback(contentToRender);\n }, config);\n };\n\n /**\n * Reset the last page number for the generated paged-content\n * This is used when we need a way to update the last page number outside of the getters callback\n *\n * @param {String} id ID of the paged content container\n * @param {Int} lastPageNumber The last page number\n */\n var resetLastPageNumber = function(id, lastPageNumber) {\n PubSub.publish(id + PagedContentEvents.ALL_ITEMS_LOADED, lastPageNumber);\n };\n\n /**\n * Generate the callback handler for the page limit persistence functionality\n *\n * @param {String} persistentLimitKey\n * @return {callback}\n */\n var generateLimitHandler = function(persistentLimitKey) {\n var callback = function(limit) {\n var args = {\n preferences: [\n {\n type: persistentLimitKey,\n value: limit\n }\n ]\n };\n\n var request = {\n methodname: 'core_user_update_user_preferences',\n args: args\n };\n\n Ajax.call([request]);\n };\n\n return callback;\n };\n\n /**\n * Set up any events based on config key values\n *\n * @param {string} namespace The namespace for this component\n * @param {object} config Config options passed to the factory\n */\n var registerEvents = function(namespace, config) {\n if (config.hasOwnProperty('persistentLimitKey')) {\n PubSub.subscribe(namespace + PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT,\n generateLimitHandler(config.persistentLimitKey));\n }\n };\n\n return {\n create: create,\n createWithLimit: createWithLimit,\n createWithTotalAndLimit: createWithTotalAndLimit,\n createFromStaticList: createFromStaticList,\n // Backwards compatibility just in case anyone was using this.\n createFromAjax: createWithTotalAndLimit,\n resetLastPageNumber: resetLastPageNumber\n };\n});\n"],"file":"paged_content_factory.min.js"} \ No newline at end of file diff --git a/lib/amd/src/paged_content_factory.js b/lib/amd/src/paged_content_factory.js index 82671cf2b46..793fe32452a 100644 --- a/lib/amd/src/paged_content_factory.js +++ b/lib/amd/src/paged_content_factory.js @@ -210,7 +210,8 @@ function( var context = getDefaultPagingBarTemplateContext(); context.itemsperpage = buildItemsPerPagePagingBarContext(itemsPerPage); - context.showitemsperpageselector = $.isArray(itemsPerPage); + // Only display the items per page selector if there is more than one to choose from. + context.showitemsperpageselector = $.isArray(itemsPerPage) && itemsPerPage.length > 1; return context; }; diff --git a/lib/templates/paged_content_paging_bar.mustache b/lib/templates/paged_content_paging_bar.mustache index 15fe2234938..f9ce56a3d64 100644 --- a/lib/templates/paged_content_paging_bar.mustache +++ b/lib/templates/paged_content_paging_bar.mustache @@ -64,12 +64,13 @@ aria-label="{{.}}" {{/arialabels.itemsperpage}} {{^arialabels.itemsperpage}} - aria-label="{{#str}} pagedcontentpagingbaritemsperpage, core, {{#itemsperpage}}{{#active}}{{value}}{{/active}}{{/itemsperpage}}{{/str}}" + aria-label="{{#str}} pagedcontentpagingbaritemsperpage, core, {{#itemsperpage}}{{#active}}{{#value}}{{.}}{{/value}}{{^value}}{{#str}} all, core {{/str}}{{/value}}{{/active}}{{/itemsperpage}}{{/str}}" {{/arialabels.itemsperpage}} > {{#itemsperpage}} {{#active}} - {{value}} + {{#value}}{{.}}{{/value}} + {{^value}}{{#str}} all, core {{/str}}{{/value}} {{/active}} {{/itemsperpage}} @@ -101,7 +102,6 @@ {{/showitemsperpageselector}}