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}}