diff --git a/blocks/myoverview/amd/build/view.min.js b/blocks/myoverview/amd/build/view.min.js index d9e5ceb9b4b..7ee4ae4a7f9 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={GROUPING_ALLINCLUDINGHIDDEN:"allincludinghidden",GROUPING_ALL:"all",GROUPING_INPROGRESS:"inprogress",GROUPING_FUTURE:"future",GROUPING_PAST:"past",GROUPING_FAVOURITES:"favourites",GROUPING_HIDDEN:"hidden"},n=[12,24,48,96,0],o=[],p=0,q=0,r=0,s=null,t=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")}},u={ignoreControlWhileLoading:!0,controlPlacementBottom:!0,persistentLimitKey:"block_myoverview_user_paging_preference"},v=function(a,c){return b.getEnrolledCoursesByTimeline({offset:p,limit:c,classification:a.grouping,sort:a.sort})},w=function(a,b){return a.find(k.FAVOURITE_ICON+"[data-course-id=\""+b+"\"]")},x=function(a,b){return a.find("[data-region=\"paged-content-page\"][data-page=\""+b+"\"]")},y=function(a){return a.attr("data-course-id")},z=function(a,b){var c=w(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)},A=function(a,b){var c=w(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)},B=function(a,b){return a.find("[data-action=\"add-favourite\"][data-course-id=\""+b+"\"]")},C=function(a,b){return a.find("[data-action=\"remove-favourite\"][data-course-id=\""+b+"\"]")},D=function(a,b){var c=C(a,b),e=B(a,b);L(b,!0).then(function(g){if(g){d.publish(h.favourited,b);c.removeClass("hidden");e.addClass("hidden");A(a,b)}else{f.alert("Starring course failed","Could not change favourite state")}}).catch(f.exception)},E=function(a,b){var c=C(a,b),e=B(a,b);L(b,!1).then(function(g){if(g){d.publish(h.unfavorited,b);c.addClass("hidden");e.removeClass("hidden");z(a,b)}else{f.alert("Starring course failed","Could not change favourite state")}}).catch(f.exception)},F=function(a,b){return a.find("[data-action=\"hide-course\"][data-course-id=\""+b+"\"]")},G=function(a,b){return a.find("[data-action=\"show-course\"][data-course-id=\""+b+"\"]")},H=function(a,b){var c=F(a,b),d=G(a,b),e=t(a);J(b,!0);if(e.grouping!=m.GROUPING_ALLINCLUDINGHIDDEN){K(a,b)}c.addClass("hidden");d.removeClass("hidden")},I=function(a,b){var c=F(a,b),d=G(a,b),e=t(a);J(b,null);if(e.grouping!=m.GROUPING_ALLINCLUDINGHIDDEN){K(a,b)}c.removeClass("hidden");d.addClass("hidden")},J=function(a,c){if(!1===c){c=null}return b.updateUserPreferences({preferences:[{type:"block_myoverview_hidden_course_"+a,value:c}]})},K=function(b,d){var e=b.find("[data-region=\"paging-bar\"]"),h=parseInt(e.attr("data-active-page-number")),i=o[h],j=i.courses.reduce(function(a,b){if(d!=b.id){a.push(b)}return a},[]);if(o[h+1]!=void 0){var k=o[h+1].courses.slice(0,1);o.forEach(function(b,c){if(c>h){var d=[];if(o[c+1]!=void 0){d=o[c+1].courses.slice(0,1)}o[c].courses=a.merge(o[c].courses.slice(1),d)}});j=a.merge(j,k)}if(q==h+1&&0==o[h+1].courses.length){var l=b.find("[data-region=\"paged-content-container\"]");c.resetLastPageNumber(a(l).attr("id"),h)}o[h].courses=j;p--;var m=x(b,h);M(b,o[h]).then(function(a,b){return g.replaceNodeContents(m,a,b)}).catch(f.exception);o.forEach(function(a,c){if(c>h){var d=x(b,c);d.remove()}})},L=function(a,c){return b.setFavouriteCourses({courses:[{id:a,favourite:c}]}).then(function(b){if(0==b.warnings.length){o.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)},M=function(a,b){var c=t(a),d="";if("card"==c.display){d=l.COURSES_CARDS}else if("list"==c.display){d=l.COURSES_LIST}else{d=l.COURSES_SUMMARY}b.courses=b.courses.map(function(a){a.showcoursecategory="on"==c.displaycategories?!0:!1;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})}},N=function(a){this.find(i.courseView.region).attr("data-paging",a)},O=function(a,b){var c=b+j.SET_ITEMS_PER_PAGE_LIMIT;d.subscribe(c,N.bind(a))},P=function(b){s="block_myoverview_"+b.attr("id")+"_"+Math.random();var d=parseInt(b.find(i.courseView.region).attr("data-paging"),10),e=n.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.valueh){var d=[];if(o[c+1]!=void 0){d=o[c+1].courses.slice(0,1)}o[c].courses=a.merge(o[c].courses.slice(1),d)}});j=a.merge(j,k)}if(q==h+1&&0==o[h+1].courses.length){var l=b.find("[data-region=\"paged-content-container\"]");c.resetLastPageNumber(a(l).attr("id"),h)}o[h].courses=j;p--;var m=x(b,h);M(b,o[h]).then(function(a,b){return g.replaceNodeContents(m,a,b)}).catch(f.exception);o.forEach(function(a,c){if(c>h){var d=x(b,c);d.remove()}})},L=function(a,c){return b.setFavouriteCourses({courses:[{id:a,favourite:c}]}).then(function(b){if(0==b.warnings.length){o.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)},M=function(a,b){var c=t(a),d="";if("card"==c.display){d=l.COURSES_CARDS}else if("list"==c.display){d=l.COURSES_LIST}else{d=l.COURSES_SUMMARY}b.courses=b.courses.map(function(a){a.showcoursecategory="on"==c.displaycategories?!0:!1;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})}},N=function(a){this.find(i.courseView.region).attr("data-paging",a)},O=function(a,b){var c=b+j.SET_ITEMS_PER_PAGE_LIMIT;d.subscribe(c,N.bind(a))},P=function(b){s="block_myoverview_"+b.attr("id")+"_"+Math.random();var d=parseInt(b.find(i.courseView.region).attr("data-paging"),10),e=n.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 GROUPINGS = {\n GROUPING_ALLINCLUDINGHIDDEN: 'allincludinghidden',\n GROUPING_ALL: 'all',\n GROUPING_INPROGRESS: 'inprogress',\n GROUPING_FUTURE: 'future',\n GROUPING_PAST: 'past',\n GROUPING_FAVOURITES: 'favourites',\n GROUPING_HIDDEN: 'hidden'\n };\n\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 * 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 hide course menu item.\n */\n var getHideCourseMenuItem = function(root, courseId) {\n return root.find('[data-action=\"hide-course\"][data-course-id=\"' + courseId + '\"]');\n };\n\n /**\n * Get the action menu item\n *\n * @param {Object} root root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The show course menu item.\n */\n var getShowCourseMenuItem = function(root, courseId) {\n return root.find('[data-action=\"show-course\"][data-course-id=\"' + courseId + '\"]');\n };\n\n /**\n * Hide course\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n */\n var hideCourse = function(root, courseId) {\n var hideAction = getHideCourseMenuItem(root, courseId);\n var showAction = getShowCourseMenuItem(root, courseId);\n var filters = getFilterValues(root);\n\n setCourseHiddenState(courseId, true);\n\n // Remove the course from this view as it is now hidden and thus not covered by this view anymore.\n // Do only if we are not in \"All\" view mode where really all courses are shown.\n if (filters.grouping != GROUPINGS.GROUPING_ALLINCLUDINGHIDDEN) {\n hideElement(root, courseId);\n }\n\n hideAction.addClass('hidden');\n showAction.removeClass('hidden');\n };\n\n /**\n * Show course\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n */\n var showCourse = function(root, courseId) {\n var hideAction = getHideCourseMenuItem(root, courseId);\n var showAction = getShowCourseMenuItem(root, courseId);\n var filters = getFilterValues(root);\n\n setCourseHiddenState(courseId, null);\n\n // Remove the course from this view as it is now shown again and thus not covered by this view anymore.\n // Do only if we are not in \"All\" view mode where really all courses are shown.\n if (filters.grouping != GROUPINGS.GROUPING_ALLINCLUDINGHIDDEN) {\n hideElement(root, courseId);\n }\n\n hideAction.removeClass('hidden');\n showAction.addClass('hidden');\n };\n\n /**\n * Set the courses hidden status and push to repository\n *\n * @param {Number} courseId Course id to favourite.\n * @param {Bool} status new hidden status.\n * @return {Promise} Repository promise.\n */\n var setCourseHiddenState = function(courseId, status) {\n\n // If the given status is not hidden, the preference has to be deleted with a null value.\n if (status === false) {\n status = null;\n }\n return Repository.updateUserPreferences({\n preferences: [\n {\n type: 'block_myoverview_hidden_course_' + courseId,\n value: status\n }\n ]\n });\n };\n\n /**\n * Reset the loadedPages dataset to take into account the hidden element\n *\n * @param {Object} root The course overview container\n * @param {Number} id The course id number\n */\n var hideElement = function(root, id) {\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 // Whether the course category should be displayed in the course item.\n coursesData.courses = coursesData.courses.map(function(course) {\n course.showcoursecategory = filters.displaycategories == 'on' ? true : false;\n return course;\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 courseId = getCourseId(target);\n hideCourse(root, courseId);\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 courseId = getCourseId(target);\n showCourse(root, courseId);\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","GROUPINGS","GROUPING_ALLINCLUDINGHIDDEN","GROUPING_ALL","GROUPING_INPROGRESS","GROUPING_FUTURE","GROUPING_PAST","GROUPING_FAVOURITES","GROUPING_HIDDEN","NUMCOURSES_PERPAGE","loadedPages","courseOffset","lastPage","lastLimit","namespace","getFilterValues","root","courseRegion","find","courseView","region","display","attr","grouping","sort","displaycategories","customfieldname","customfieldvalue","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","getHideCourseMenuItem","getShowCourseMenuItem","hideCourse","hideAction","showAction","setCourseHiddenState","hideElement","showCourse","status","updateUserPreferences","preferences","type","value","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","setFavouriteCourses","result","warnings","course","isfavourite","coursesData","currentTemplate","map","showcoursecategory","render","nocoursesimg","setLimit","registerPagedEventHandlers","event","SET_ITEMS_PER_PAGE_LIMIT","subscribe","bind","initializePagedContent","Math","random","pagingLimit","itemsPerPage","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","target","closest","originalEvent","preventDefault","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 GROUPINGS = {\n GROUPING_ALLINCLUDINGHIDDEN: 'allincludinghidden',\n GROUPING_ALL: 'all',\n GROUPING_INPROGRESS: 'inprogress',\n GROUPING_FUTURE: 'future',\n GROUPING_PAST: 'past',\n GROUPING_FAVOURITES: 'favourites',\n GROUPING_HIDDEN: 'hidden'\n };\n\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 customfieldname: courseRegion.attr('data-customfieldname'),\n customfieldvalue: courseRegion.attr('data-customfieldvalue'),\n };\n };\n\n // We want the paged content controls below the paged content area.\n // and the controls should be ignored while data is loading.\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 customfieldname: filters.customfieldname,\n customfieldvalue: filters.customfieldvalue\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 * 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 hide course menu item.\n */\n var getHideCourseMenuItem = function(root, courseId) {\n return root.find('[data-action=\"hide-course\"][data-course-id=\"' + courseId + '\"]');\n };\n\n /**\n * Get the action menu item\n *\n * @param {Object} root root The course overview container\n * @param {Number} courseId Course id.\n * @return {Object} The show course menu item.\n */\n var getShowCourseMenuItem = function(root, courseId) {\n return root.find('[data-action=\"show-course\"][data-course-id=\"' + courseId + '\"]');\n };\n\n /**\n * Hide course\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n */\n var hideCourse = function(root, courseId) {\n var hideAction = getHideCourseMenuItem(root, courseId);\n var showAction = getShowCourseMenuItem(root, courseId);\n var filters = getFilterValues(root);\n\n setCourseHiddenState(courseId, true);\n\n // Remove the course from this view as it is now hidden and thus not covered by this view anymore.\n // Do only if we are not in \"All\" view mode where really all courses are shown.\n if (filters.grouping != GROUPINGS.GROUPING_ALLINCLUDINGHIDDEN) {\n hideElement(root, courseId);\n }\n\n hideAction.addClass('hidden');\n showAction.removeClass('hidden');\n };\n\n /**\n * Show course\n *\n * @param {Object} root The course overview container\n * @param {Number} courseId Course id number\n */\n var showCourse = function(root, courseId) {\n var hideAction = getHideCourseMenuItem(root, courseId);\n var showAction = getShowCourseMenuItem(root, courseId);\n var filters = getFilterValues(root);\n\n setCourseHiddenState(courseId, null);\n\n // Remove the course from this view as it is now shown again and thus not covered by this view anymore.\n // Do only if we are not in \"All\" view mode where really all courses are shown.\n if (filters.grouping != GROUPINGS.GROUPING_ALLINCLUDINGHIDDEN) {\n hideElement(root, courseId);\n }\n\n hideAction.removeClass('hidden');\n showAction.addClass('hidden');\n };\n\n /**\n * Set the courses hidden status and push to repository\n *\n * @param {Number} courseId Course id to favourite.\n * @param {Bool} status new hidden status.\n * @return {Promise} Repository promise.\n */\n var setCourseHiddenState = function(courseId, status) {\n\n // If the given status is not hidden, the preference has to be deleted with a null value.\n if (status === false) {\n status = null;\n }\n return Repository.updateUserPreferences({\n preferences: [\n {\n type: 'block_myoverview_hidden_course_' + courseId,\n value: status\n }\n ]\n });\n };\n\n /**\n * Reset the loadedPages dataset to take into account the hidden element\n *\n * @param {Object} root The course overview container\n * @param {Number} id The course id number\n */\n var hideElement = function(root, id) {\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 // Whether the course category should be displayed in the course item.\n coursesData.courses = coursesData.courses.map(function(course) {\n course.showcoursecategory = filters.displaycategories == 'on' ? true : false;\n return course;\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 courseId = getCourseId(target);\n hideCourse(root, courseId);\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 courseId = getCourseId(target);\n showCourse(root, courseId);\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/build/view_nav.min.js b/blocks/myoverview/amd/build/view_nav.min.js index ce56253686e..565b7b993d2 100644 --- a/blocks/myoverview/amd/build/view_nav.min.js +++ b/blocks/myoverview/amd/build/view_nav.min.js @@ -1,2 +1,2 @@ -define ("block_myoverview/view_nav",["jquery","core/custom_interaction_events","block_myoverview/repository","block_myoverview/view","block_myoverview/selectors"],function(a,b,c,d,f){var g={FILTERS:"[data-region=\"filter\"]",FILTER_OPTION:"[data-filter]",DISPLAY_OPTION:"[data-display-option]"},h=function(a,b){var d=null;if("display"==a){d="block_myoverview_user_view_preference"}else if("sort"==a){d="block_myoverview_user_sort_preference"}else{d="block_myoverview_user_grouping_preference"}c.updateUserPreferences({preferences:[{type:d,value:b}]})},i=function(c){var e=c.find(g.FILTERS);b.define(e,[b.events.activate]);e.on(b.events.activate,g.FILTER_OPTION,function(b,e){var g=a(b.target);if(g.hasClass("active")){return}var i=g.attr("data-filter"),j=g.attr("data-pref");c.find(f.courseView.region).attr("data-"+i,g.attr("data-value"));h(i,j);d.init(c);e.originalEvent.preventDefault()});b.define(e,[b.events.activate]);e.on(b.events.activate,g.DISPLAY_OPTION,function(b,e){var g=a(b.target);if(g.hasClass("active")){return}var i=g.attr("data-display-option"),j=g.attr("data-pref");c.find(f.courseView.region).attr("data-display",g.attr("data-value"));h(i,j);d.reset(c);e.originalEvent.preventDefault()})};return{init:function init(b){b=a(b);i(b)}}}); +define ("block_myoverview/view_nav",["jquery","core/custom_interaction_events","block_myoverview/repository","block_myoverview/view","block_myoverview/selectors"],function(a,b,c,d,f){var g={FILTERS:"[data-region=\"filter\"]",FILTER_OPTION:"[data-filter]",DISPLAY_OPTION:"[data-display-option]"},h=function(a,b){var d=null;if("display"==a){d="block_myoverview_user_view_preference"}else if("sort"==a){d="block_myoverview_user_sort_preference"}else if("customfieldvalue"==a){d="block_myoverview_user_grouping_customfieldvalue_preference"}else{d="block_myoverview_user_grouping_preference"}c.updateUserPreferences({preferences:[{type:d,value:b}]})},i=function(c){var e=c.find(g.FILTERS);b.define(e,[b.events.activate]);e.on(b.events.activate,g.FILTER_OPTION,function(b,e){var g=a(b.target);if(g.hasClass("active")){return}var i=g.attr("data-filter"),j=g.attr("data-pref"),k=g.attr("data-customfieldvalue");c.find(f.courseView.region).attr("data-"+i,g.attr("data-value"));h(i,j);if(k){c.find(f.courseView.region).attr("data-customfieldvalue",k);h("customfieldvalue",k)}d.init(c);e.originalEvent.preventDefault()});b.define(e,[b.events.activate]);e.on(b.events.activate,g.DISPLAY_OPTION,function(b,e){var g=a(b.target);if(g.hasClass("active")){return}var i=g.attr("data-display-option"),j=g.attr("data-pref");c.find(f.courseView.region).attr("data-display",g.attr("data-value"));h(i,j);d.reset(c);e.originalEvent.preventDefault()})};return{init:function init(b){b=a(b);i(b)}}}); //# sourceMappingURL=view_nav.min.js.map diff --git a/blocks/myoverview/amd/build/view_nav.min.js.map b/blocks/myoverview/amd/build/view_nav.min.js.map index dfa381d8c3d..815b2ae722c 100644 --- a/blocks/myoverview/amd/build/view_nav.min.js.map +++ b/blocks/myoverview/amd/build/view_nav.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/view_nav.js"],"names":["define","$","CustomEvents","Repository","View","Selectors","SELECTORS","FILTERS","FILTER_OPTION","DISPLAY_OPTION","updatePreferences","filter","value","type","updateUserPreferences","preferences","registerSelector","root","Selector","find","events","activate","on","e","data","option","target","hasClass","attr","pref","courseView","region","init","originalEvent","preventDefault","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 timeline view navigation 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 'core/custom_interaction_events',\n 'block_myoverview/repository',\n 'block_myoverview/view',\n 'block_myoverview/selectors'\n],\nfunction(\n $,\n CustomEvents,\n Repository,\n View,\n Selectors\n) {\n\n var SELECTORS = {\n FILTERS: '[data-region=\"filter\"]',\n FILTER_OPTION: '[data-filter]',\n DISPLAY_OPTION: '[data-display-option]'\n };\n\n /**\n * Update the user preference for the block.\n *\n * @param {String} filter The type of filter: display/sort/grouping.\n * @param {String} value The current preferred value.\n */\n var updatePreferences = function(filter, value) {\n var type = null;\n if (filter == 'display') {\n type = 'block_myoverview_user_view_preference';\n } else if (filter == 'sort') {\n type = 'block_myoverview_user_sort_preference';\n } else {\n type = 'block_myoverview_user_grouping_preference';\n }\n\n Repository.updateUserPreferences({\n preferences: [\n {\n type: type,\n value: value\n }\n ]\n });\n };\n\n /**\n * Event listener for the Display filter (cards, list).\n *\n * @param {object} root The root element for the overview block\n */\n var registerSelector = function(root) {\n\n var Selector = root.find(SELECTORS.FILTERS);\n\n CustomEvents.define(Selector, [CustomEvents.events.activate]);\n Selector.on(\n CustomEvents.events.activate,\n SELECTORS.FILTER_OPTION,\n function(e, data) {\n var option = $(e.target);\n\n if (option.hasClass('active')) {\n // If it's already active then we don't need to do anything.\n return;\n }\n\n var filter = option.attr('data-filter');\n var pref = option.attr('data-pref');\n\n root.find(Selectors.courseView.region).attr('data-' + filter, option.attr('data-value'));\n updatePreferences(filter, pref);\n\n // Reset the views.\n View.init(root);\n\n data.originalEvent.preventDefault();\n }\n );\n\n CustomEvents.define(Selector, [CustomEvents.events.activate]);\n Selector.on(\n CustomEvents.events.activate,\n SELECTORS.DISPLAY_OPTION,\n function(e, data) {\n var option = $(e.target);\n\n if (option.hasClass('active')) {\n return;\n }\n\n var filter = option.attr('data-display-option');\n var pref = option.attr('data-pref');\n\n root.find(Selectors.courseView.region).attr('data-display', option.attr('data-value'));\n updatePreferences(filter, pref);\n View.reset(root);\n data.originalEvent.preventDefault();\n }\n );\n };\n\n /**\n * Initialise the timeline view navigation by adding event listeners to\n * the navigation elements.\n *\n * @param {object} root The root element for the myoverview block\n */\n var init = function(root) {\n root = $(root);\n registerSelector(root);\n };\n\n return {\n init: init\n };\n});\n"],"file":"view_nav.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/view_nav.js"],"names":["define","$","CustomEvents","Repository","View","Selectors","SELECTORS","FILTERS","FILTER_OPTION","DISPLAY_OPTION","updatePreferences","filter","value","type","updateUserPreferences","preferences","registerSelector","root","Selector","find","events","activate","on","e","data","option","target","hasClass","attr","pref","customfieldvalue","courseView","region","init","originalEvent","preventDefault","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 timeline view navigation 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 'core/custom_interaction_events',\n 'block_myoverview/repository',\n 'block_myoverview/view',\n 'block_myoverview/selectors'\n],\nfunction(\n $,\n CustomEvents,\n Repository,\n View,\n Selectors\n) {\n\n var SELECTORS = {\n FILTERS: '[data-region=\"filter\"]',\n FILTER_OPTION: '[data-filter]',\n DISPLAY_OPTION: '[data-display-option]'\n };\n\n /**\n * Update the user preference for the block.\n *\n * @param {String} filter The type of filter: display/sort/grouping.\n * @param {String} value The current preferred value.\n */\n var updatePreferences = function(filter, value) {\n var type = null;\n if (filter == 'display') {\n type = 'block_myoverview_user_view_preference';\n } else if (filter == 'sort') {\n type = 'block_myoverview_user_sort_preference';\n } else if (filter == 'customfieldvalue') {\n type = 'block_myoverview_user_grouping_customfieldvalue_preference';\n } else {\n type = 'block_myoverview_user_grouping_preference';\n }\n\n Repository.updateUserPreferences({\n preferences: [\n {\n type: type,\n value: value\n }\n ]\n });\n };\n\n /**\n * Event listener for the Display filter (cards, list).\n *\n * @param {object} root The root element for the overview block\n */\n var registerSelector = function(root) {\n\n var Selector = root.find(SELECTORS.FILTERS);\n\n CustomEvents.define(Selector, [CustomEvents.events.activate]);\n Selector.on(\n CustomEvents.events.activate,\n SELECTORS.FILTER_OPTION,\n function(e, data) {\n var option = $(e.target);\n\n if (option.hasClass('active')) {\n // If it's already active then we don't need to do anything.\n return;\n }\n\n var filter = option.attr('data-filter');\n var pref = option.attr('data-pref');\n var customfieldvalue = option.attr('data-customfieldvalue');\n\n root.find(Selectors.courseView.region).attr('data-' + filter, option.attr('data-value'));\n updatePreferences(filter, pref);\n\n if (customfieldvalue) {\n root.find(Selectors.courseView.region).attr('data-customfieldvalue', customfieldvalue);\n updatePreferences('customfieldvalue', customfieldvalue);\n }\n\n // Reset the views.\n View.init(root);\n\n data.originalEvent.preventDefault();\n }\n );\n\n CustomEvents.define(Selector, [CustomEvents.events.activate]);\n Selector.on(\n CustomEvents.events.activate,\n SELECTORS.DISPLAY_OPTION,\n function(e, data) {\n var option = $(e.target);\n\n if (option.hasClass('active')) {\n return;\n }\n\n var filter = option.attr('data-display-option');\n var pref = option.attr('data-pref');\n\n root.find(Selectors.courseView.region).attr('data-display', option.attr('data-value'));\n updatePreferences(filter, pref);\n View.reset(root);\n data.originalEvent.preventDefault();\n }\n );\n };\n\n /**\n * Initialise the timeline view navigation by adding event listeners to\n * the navigation elements.\n *\n * @param {object} root The root element for the myoverview block\n */\n var init = function(root) {\n root = $(root);\n registerSelector(root);\n };\n\n return {\n init: init\n };\n});\n"],"file":"view_nav.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 b43983403d6..9d637b74412 100644 --- a/blocks/myoverview/amd/src/view.js +++ b/blocks/myoverview/amd/src/view.js @@ -102,6 +102,8 @@ function( grouping: courseRegion.attr('data-grouping'), sort: courseRegion.attr('data-sort'), displaycategories: courseRegion.attr('data-displaycategories'), + customfieldname: courseRegion.attr('data-customfieldname'), + customfieldvalue: courseRegion.attr('data-customfieldvalue'), }; }; @@ -126,7 +128,9 @@ function( offset: courseOffset, limit: limit, classification: filters.grouping, - sort: filters.sort + sort: filters.sort, + customfieldname: filters.customfieldname, + customfieldvalue: filters.customfieldvalue }); }; diff --git a/blocks/myoverview/amd/src/view_nav.js b/blocks/myoverview/amd/src/view_nav.js index 29d114e1491..99ee87122d7 100644 --- a/blocks/myoverview/amd/src/view_nav.js +++ b/blocks/myoverview/amd/src/view_nav.js @@ -55,6 +55,8 @@ function( type = 'block_myoverview_user_view_preference'; } else if (filter == 'sort') { type = 'block_myoverview_user_sort_preference'; + } else if (filter == 'customfieldvalue') { + type = 'block_myoverview_user_grouping_customfieldvalue_preference'; } else { type = 'block_myoverview_user_grouping_preference'; } @@ -92,10 +94,16 @@ function( var filter = option.attr('data-filter'); var pref = option.attr('data-pref'); + var customfieldvalue = option.attr('data-customfieldvalue'); root.find(Selectors.courseView.region).attr('data-' + filter, option.attr('data-value')); updatePreferences(filter, pref); + if (customfieldvalue) { + root.find(Selectors.courseView.region).attr('data-customfieldvalue', customfieldvalue); + updatePreferences('customfieldvalue', customfieldvalue); + } + // Reset the views. View.init(root); diff --git a/blocks/myoverview/block_myoverview.php b/blocks/myoverview/block_myoverview.php index 01744b96149..3a7dd138c42 100644 --- a/blocks/myoverview/block_myoverview.php +++ b/blocks/myoverview/block_myoverview.php @@ -53,8 +53,9 @@ class block_myoverview extends block_base { $sort = get_user_preferences('block_myoverview_user_sort_preference'); $view = get_user_preferences('block_myoverview_user_view_preference'); $paging = get_user_preferences('block_myoverview_user_paging_preference'); + $customfieldvalue = get_user_preferences('block_myoverview_user_grouping_customfieldvalue_preference'); - $renderable = new \block_myoverview\output\main($group, $sort, $view, $paging); + $renderable = new \block_myoverview\output\main($group, $sort, $view, $paging, $customfieldvalue); $renderer = $this->page->get_renderer('block_myoverview'); $this->content = new stdClass(); diff --git a/blocks/myoverview/classes/output/main.php b/blocks/myoverview/classes/output/main.php index 5f4a033d0d3..869718bf6a5 100644 --- a/blocks/myoverview/classes/output/main.php +++ b/blocks/myoverview/classes/output/main.php @@ -130,6 +130,27 @@ class main implements renderable, templatable { */ private $displaygroupinghidden; + /** + * Store a course grouping option setting. + * + * @var bool + */ + private $displaygroupingcustomfield; + + /** + * Store the custom field used by customfield grouping. + * + * @var string + */ + private $customfiltergrouping; + + /** + * Store the selected custom field value to group by. + * + * @var string + */ + private $customfieldvalue; + /** * main constructor. * Initialize the user preferences @@ -137,10 +158,12 @@ class main implements renderable, templatable { * @param string $grouping Grouping user preference * @param string $sort Sort user preference * @param string $view Display user preference + * @param int $paging + * @param string $customfieldvalue * * @throws \dml_exception */ - public function __construct($grouping, $sort, $view, $paging) { + public function __construct($grouping, $sort, $view, $paging, $customfieldvalue = null) { // Get plugin config. $config = get_config('block_myoverview'); @@ -153,28 +176,14 @@ class main implements renderable, templatable { // Otherwise fall back to another grouping in a reasonable order. // This is done to prevent one-time UI glitches in the case when a user has chosen a grouping option previously which // was then disabled by the admin in the meantime. - } else if ($config->displaygroupingall == true) { - $this->grouping = BLOCK_MYOVERVIEW_GROUPING_ALL; - } else if ($config->displaygroupingallincludinghidden == true) { - $this->grouping = BLOCK_MYOVERVIEW_GROUPING_ALLINCLUDINGHIDDEN; - } else if ($config->displaygroupinginprogress == true) { - $this->grouping = BLOCK_MYOVERVIEW_GROUPING_INPROGRESS; - } else if ($config->displaygroupingfuture == true) { - $this->grouping = BLOCK_MYOVERVIEW_GROUPING_FUTURE; - } else if ($config->displaygroupingpast == true) { - $this->grouping = BLOCK_MYOVERVIEW_GROUPING_PAST; - } else if ($config->displaygroupingstarred == true) { - $this->grouping = BLOCK_MYOVERVIEW_GROUPING_FAVOURITES; - } else if ($config->displaygroupinghidden == true) { - $this->grouping = BLOCK_MYOVERVIEW_GROUPING_HIDDEN; - - // In this case, no grouping option is enabled and the grouping is not needed at all. - // But it's better not to leave $this->grouping unset for any unexpected case. } else { - $this->grouping = BLOCK_MYOVERVIEW_GROUPING_ALLINCLUDINGHIDDEN; + $this->grouping = $this->get_fallback_grouping($config); } unset ($groupingconfigname); + // Remember which custom field value we were using, if grouping by custom field. + $this->customfieldvalue = $customfieldvalue; + // Check and remember the given sorting. $this->sort = $sort ? $sort : BLOCK_MYOVERVIEW_SORTING_TITLE; @@ -207,6 +216,8 @@ class main implements renderable, templatable { $this->displaygroupingpast = $config->displaygroupingpast; $this->displaygroupingstarred = $config->displaygroupingstarred; $this->displaygroupinghidden = $config->displaygroupinghidden; + $this->displaygroupingcustomfield = ($config->displaygroupingcustomfield && $config->customfiltergrouping); + $this->customfiltergrouping = $config->customfiltergrouping; // Check and remember if the grouping selector should be shown at all or not. // It will be shown if more than 1 grouping option is enabled. @@ -218,7 +229,7 @@ class main implements renderable, templatable { $this->displaygroupingstarred, $this->displaygroupinghidden); $displaygroupingselectorscount = count(array_filter($displaygroupingselectors)); - if ($displaygroupingselectorscount > 1) { + if ($displaygroupingselectorscount > 1 || $this->displaygroupingcustomfield) { $this->displaygroupingselector = true; } else { $this->displaygroupingselector = false; @@ -226,6 +237,41 @@ class main implements renderable, templatable { unset ($displaygroupingselectors, $displaygroupingselectorscount); } + /** + * Determine the most sensible fallback grouping to use (in cases where the stored selection + * is no longer available). + * @param object $config + * @return string + */ + private function get_fallback_grouping($config) { + if ($config->displaygroupingall == true) { + return BLOCK_MYOVERVIEW_GROUPING_ALL; + } + if ($config->displaygroupingallincludinghidden == true) { + return BLOCK_MYOVERVIEW_GROUPING_ALLINCLUDINGHIDDEN; + } + if ($config->displaygroupinginprogress == true) { + return BLOCK_MYOVERVIEW_GROUPING_INPROGRESS; + } + if ($config->displaygroupingfuture == true) { + return BLOCK_MYOVERVIEW_GROUPING_FUTURE; + } + if ($config->displaygroupingpast == true) { + return BLOCK_MYOVERVIEW_GROUPING_PAST; + } + if ($config->displaygroupingstarred == true) { + return BLOCK_MYOVERVIEW_GROUPING_FAVOURITES; + } + if ($config->displaygroupinghidden == true) { + return BLOCK_MYOVERVIEW_GROUPING_HIDDEN; + } + if ($config->displaygroupingcustomfield == true) { + return BLOCK_MYOVERVIEW_GROUPING_CUSTOMFIELD; + } + // In this case, no grouping option is enabled and the grouping is not needed at all. + // But it's better not to leave $this->grouping unset for any unexpected case. + return BLOCK_MYOVERVIEW_GROUPING_ALLINCLUDINGHIDDEN; + } /** * Set the available layouts based on the config table settings, @@ -292,6 +338,49 @@ class main implements renderable, templatable { } + /** + * Get the list of values to add to the grouping dropdown + * @return object[] containing name, value and active fields + */ + public function get_customfield_values_for_export() { + global $DB, $USER; + if (!$this->displaygroupingcustomfield) { + return []; + } + $fieldid = $DB->get_field('customfield_field', 'id', ['shortname' => $this->customfiltergrouping]); + if (!$fieldid) { + return []; + } + $courses = enrol_get_all_users_courses($USER->id, true); + if (!$courses) { + return []; + } + list($csql, $params) = $DB->get_in_or_equal(array_keys($courses), SQL_PARAMS_NAMED); + $select = "instanceid $csql AND fieldid = :fieldid"; + $params['fieldid'] = $fieldid; + $values = $DB->get_records_select_menu('customfield_data', $select, $params, 'value', + 'DISTINCT value, value AS value2'); + $values = array_filter($values); + if (!$values) { + return []; + } + $field = \core_customfield\field_controller::create($fieldid); + if (!$field->supports_course_grouping()) { + return []; // The field shouldn't have been selectable in the global settings, but just skip it now. + } + $values = $field->course_grouping_format_values($values); + $customfieldactive = ($this->grouping === BLOCK_MYOVERVIEW_GROUPING_CUSTOMFIELD); + $ret = []; + foreach ($values as $value => $name) { + $ret[] = (object)[ + 'name' => $name, + 'value' => $value, + 'active' => ($customfieldactive && ($this->customfieldvalue == $value)), + ]; + } + return $ret; + } + /** * Export this data so it can be used as the context for a mustache template. * @@ -305,6 +394,29 @@ class main implements renderable, templatable { $nocoursesurl = $output->image_url('courses', 'block_myoverview')->out(); + $customfieldvalues = $this->get_customfield_values_for_export(); + $selectedcustomfield = ''; + if ($this->grouping == BLOCK_MYOVERVIEW_GROUPING_CUSTOMFIELD) { + foreach ($customfieldvalues as $field) { + if ($field->value == $this->customfieldvalue) { + $selectedcustomfield = $field->name; + break; + } + } + // If the selected custom field value has not been found (possibly because the field has + // been changed in the settings) find a suitable fallback. + if (!$selectedcustomfield) { + $this->grouping = $this->get_fallback_grouping(get_config('block_myoverview')); + if ($this->grouping == BLOCK_MYOVERVIEW_GROUPING_CUSTOMFIELD) { + // If the fallback grouping is still customfield, then select the first field. + $firstfield = reset($customfieldvalues); + if ($firstfield) { + $selectedcustomfield = $firstfield->name; + $this->customfieldvalue = $firstfield->value; + } + } + } + } $preferences = $this->get_preferences_as_booleans(); $availablelayouts = $this->get_formatted_available_layouts_for_export(); @@ -327,8 +439,13 @@ class main implements renderable, templatable { 'displaygroupingstarred' => $this->displaygroupingstarred, 'displaygroupinghidden' => $this->displaygroupinghidden, 'displaygroupingselector' => $this->displaygroupingselector, + 'displaygroupingcustomfield' => $this->displaygroupingcustomfield && $customfieldvalues, + 'customfieldname' => $this->customfiltergrouping, + 'customfieldvalue' => $this->customfieldvalue, + 'customfieldvalues' => $customfieldvalues, + 'selectedcustomfield' => $selectedcustomfield, ]; return array_merge($defaultvariables, $preferences); } -} \ No newline at end of file +} diff --git a/blocks/myoverview/lang/en/block_myoverview.php b/blocks/myoverview/lang/en/block_myoverview.php index e95ce8cd5fc..7c5520f6f3e 100644 --- a/blocks/myoverview/lang/en/block_myoverview.php +++ b/blocks/myoverview/lang/en/block_myoverview.php @@ -33,6 +33,7 @@ $string['aria:controls'] = 'Course overview controls'; $string['aria:courseactions'] = 'Actions for current course'; $string['aria:coursesummary'] = 'Course summary text:'; $string['aria:courseprogress'] = 'Course progress:'; +$string['aria:customfield'] = 'Show {$a} courses'; $string['aria:displaydropdown'] = 'Display drop-down menu'; $string['aria:favourites'] = 'Show starred courses'; $string['aria:future'] = 'Show future courses'; @@ -51,6 +52,9 @@ $string['card'] = 'Card'; $string['cards'] = 'Cards'; $string['courseprogress'] = 'Course progress:'; $string['completepercent'] = '{$a}% complete'; +$string['customfield'] = 'Custom field'; +$string['customfiltergrouping'] = 'Field to use'; +$string['customfiltergrouping_nofields'] = 'You need to add at least one course custom field in order to use this setting'; $string['displaycategories'] = 'Display categories'; $string['displaycategories_help'] = 'Display the course category on dashboard course items including cards, list items and summary items.'; $string['favourites'] = 'Starred'; @@ -61,6 +65,7 @@ $string['layouts'] = 'Available layouts'; $string['layouts_help'] = 'Course overview layouts which are available for selection by users. If none are selected, the card layout will be used.'; $string['list'] = 'List'; $string['myoverview:myaddinstance'] = 'Add a new course overview block to Dashboard'; +$string['nocustomvalue'] = 'No {$a}'; $string['past'] = 'Past'; $string['pluginname'] = 'Course overview'; $string['privacy:metadata:overviewsortpreference'] = 'The Course overview block sort preference.'; diff --git a/blocks/myoverview/lib.php b/blocks/myoverview/lib.php index 36fc201919a..21f9b70a724 100644 --- a/blocks/myoverview/lib.php +++ b/blocks/myoverview/lib.php @@ -34,6 +34,12 @@ define('BLOCK_MYOVERVIEW_GROUPING_FUTURE', 'future'); define('BLOCK_MYOVERVIEW_GROUPING_PAST', 'past'); define('BLOCK_MYOVERVIEW_GROUPING_FAVOURITES', 'favourites'); define('BLOCK_MYOVERVIEW_GROUPING_HIDDEN', 'hidden'); +define('BLOCK_MYOVERVIEW_GROUPING_CUSTOMFIELD', 'customfield'); + +/** + * Allows selection of all courses without a value for the custom field. + */ +define('BLOCK_MYOVERVIEW_CUSTOMFIELD_EMPTY', -1); /** * Constants for the user preferences sorting options @@ -81,9 +87,17 @@ function block_myoverview_user_preferences() { BLOCK_MYOVERVIEW_GROUPING_FUTURE, BLOCK_MYOVERVIEW_GROUPING_PAST, BLOCK_MYOVERVIEW_GROUPING_FAVOURITES, - BLOCK_MYOVERVIEW_GROUPING_HIDDEN + BLOCK_MYOVERVIEW_GROUPING_HIDDEN, + BLOCK_MYOVERVIEW_GROUPING_CUSTOMFIELD, ) ); + + $preferences['block_myoverview_user_grouping_customfieldvalue_preference'] = [ + 'null' => NULL_ALLOWED, + 'default' => null, + 'type' => PARAM_RAW, + ]; + $preferences['block_myoverview_user_sort_preference'] = array( 'null' => NULL_NOT_ALLOWED, 'default' => BLOCK_MYOVERVIEW_SORTING_TITLE, diff --git a/blocks/myoverview/settings.php b/blocks/myoverview/settings.php index b633f22d4d0..0ec6ebea45a 100644 --- a/blocks/myoverview/settings.php +++ b/blocks/myoverview/settings.php @@ -86,6 +86,29 @@ if ($ADMIN->fulltree) { '', 1)); + $settings->add(new admin_setting_configcheckbox( + 'block_myoverview/displaygroupingcustomfield', + get_string('customfield', 'block_myoverview'), + '', + 0)); + + $choices = \core_customfield\api::get_fields_supporting_course_grouping(); + if ($choices) { + $choices = ['' => get_string('choosedots')] + $choices; + $settings->add(new admin_setting_configselect( + 'block_myoverview/customfiltergrouping', + get_string('customfiltergrouping', 'block_myoverview'), + '', + '', + $choices)); + } else { + $settings->add(new admin_setting_configempty( + 'block_myoverview/customfiltergrouping', + get_string('customfiltergrouping', 'block_myoverview'), + get_string('customfiltergrouping_nofields', 'block_myoverview'))); + } + $settings->hide_if('block_myoverview/customfiltergrouping', 'block_myoverview/displaygroupingcustomfield'); + $settings->add(new admin_setting_configcheckbox( 'block_myoverview/displaygroupingstarred', get_string('favourites', 'block_myoverview'), diff --git a/blocks/myoverview/templates/courses-view.mustache b/blocks/myoverview/templates/courses-view.mustache index 5be3c986e86..76f73b91ece 100644 --- a/blocks/myoverview/templates/courses-view.mustache +++ b/blocks/myoverview/templates/courses-view.mustache @@ -31,6 +31,8 @@ data-region="courses-view" data-display="{{view}}" data-grouping="{{grouping}}" + data-customfieldname="{{customfieldname}}" + data-customfieldvalue="{{customfieldvalue}}" data-sort="{{sort}}" data-prev-display="{{view}}" data-paging="{{paging}}" @@ -40,4 +42,4 @@
{{> block_myoverview/placeholders }}
- \ No newline at end of file + diff --git a/blocks/myoverview/templates/nav-grouping-selector.mustache b/blocks/myoverview/templates/nav-grouping-selector.mustache index 703482f5432..5d6b5983b15 100644 --- a/blocks/myoverview/templates/nav-grouping-selector.mustache +++ b/blocks/myoverview/templates/nav-grouping-selector.mustache @@ -50,6 +50,7 @@ {{#past}}{{#str}} past, block_myoverview {{/str}}{{/past}} {{#favourites}}{{#str}} favourites, block_myoverview {{/str}}{{/favourites}} {{#hidden}}{{#str}} hiddencourses, block_myoverview {{/str}}{{/hidden}} + {{selectedcustomfield}}