This commit is contained in:
Sara Arjona 2021-08-24 12:35:10 +02:00
commit c5183622d6
27 changed files with 1417 additions and 973 deletions

View File

@ -1,2 +1,2 @@
define ("block_myoverview/main",["jquery","block_myoverview/view","block_myoverview/view_nav"],function(a,b,c){return{init:function init(d){d=a(d);c.init(d);b.init(d)}}});
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("block_myoverview/main",["exports","block_myoverview/view","block_myoverview/view_nav"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=e(b);c=e(c);function d(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;d=function(){return a};return a}function e(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=d();if(b&&b.has(a)){return b.get(a)}var c={},e=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in a){if(Object.prototype.hasOwnProperty.call(a,f)){var g=e?Object.getOwnPropertyDescriptor(a,f):null;if(g&&(g.get||g.set)){Object.defineProperty(c,f,g)}else{c[f]=a[f]}}}c.default=a;if(b){b.set(a,c)}return c}var f=function(a){c.init(a);b.init(a)};a.init=f});
//# sourceMappingURL=main.min.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["../src/main.js"],"names":["define","$","View","ViewNav","init","root"],"mappings":"AAsBAA,OAAM,yBACN,CACI,QADJ,CAEI,uBAFJ,CAGI,2BAHJ,CADM,CAMN,SACIC,CADJ,CAEIC,CAFJ,CAGIC,CAHJ,CAIE,CAcE,MAAO,CACHC,IAAI,CATG,QAAPA,CAAAA,IAAO,CAASC,CAAT,CAAe,CACtBA,CAAI,CAAGJ,CAAC,CAACI,CAAD,CAAR,CAEAF,CAAO,CAACC,IAAR,CAAaC,CAAb,EAEAH,CAAI,CAACE,IAAL,CAAUC,CAAV,CACH,CAEM,CAGV,CA3BK,CAAN","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 <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript to initialise the myoverview block.\n *\n * @copyright 2018 Bas Brands <bas@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(\n[\n 'jquery',\n 'block_myoverview/view',\n 'block_myoverview/view_nav'\n],\nfunction(\n $,\n View,\n ViewNav\n) {\n /**\n * Initialise all of the modules for the overview block.\n *\n * @param {object} root The root element for the overview block.\n */\n var init = function(root) {\n root = $(root);\n // Initialise the course navigation elements.\n ViewNav.init(root);\n // Initialise the courses view modules.\n View.init(root);\n };\n\n return {\n init: init\n };\n});\n"],"file":"main.min.js"}
{"version":3,"sources":["../src/main.js"],"names":["init","root","ViewNav","View"],"mappings":"+dAsBA,OACA,O,siBAOO,GAAMA,CAAAA,CAAI,CAAG,SAACC,CAAD,CAAU,CAE1BC,CAAO,CAACF,IAAR,CAAaC,CAAb,EAEAE,CAAI,CAACH,IAAL,CAAUC,CAAV,CACH,CALM,C","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 <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript to initialise the myoverview block.\n *\n * @copyright 2018 Bas Brands <bas@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as View from 'block_myoverview/view';\nimport * as ViewNav from 'block_myoverview/view_nav';\n\n/**\n * Initialise all of the modules for the overview block.\n *\n * @param {object} root The root element for the overview block.\n */\nexport const init = (root) => {\n // Initialise the course navigation elements.\n ViewNav.init(root);\n // Initialise the courses view modules.\n View.init(root);\n};\n"],"file":"main.min.js"}

View File

@ -1,2 +1,2 @@
define ("block_myoverview/repository",["core/ajax","core/notification"],function(a,b){return{getEnrolledCoursesByTimeline:function getEnrolledCoursesByTimeline(b){var c=a.call([{methodname:"core_course_get_enrolled_courses_by_timeline_classification",args:b}])[0];return c},setFavouriteCourses:function setFavouriteCourses(b){var c=a.call([{methodname:"core_course_set_favourite_courses",args:b}])[0];return c},updateUserPreferences:function updateUserPreferences(c){a.call([{methodname:"core_user_update_user_preferences",args:c}])[0].fail(b.exception)}}});
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("block_myoverview/repository",["exports","core/ajax","core/notification"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.updateUserPreferences=a.setFavouriteCourses=a.getEnrolledCoursesByTimeline=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);c=e(c);function d(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;d=function(){return a};return a}function e(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=d();if(b&&b.has(a)){return b.get(a)}var c={},e=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in a){if(Object.prototype.hasOwnProperty.call(a,f)){var g=e?Object.getOwnPropertyDescriptor(a,f):null;if(g&&(g.get||g.set)){Object.defineProperty(c,f,g)}else{c[f]=a[f]}}}c.default=a;if(b){b.set(a,c)}return c}var f=function(a){return b.default.call([{methodname:"core_course_get_enrolled_courses_by_timeline_classification",args:a}])[0]};a.getEnrolledCoursesByTimeline=f;var g=function(a){return b.default.call([{methodname:"core_course_set_favourite_courses",args:a}])[0]};a.setFavouriteCourses=g;var h=function(a){b.default.call([{methodname:"core_user_update_user_preferences",args:a}])[0].fail(c.exception)};a.updateUserPreferences=h});
//# sourceMappingURL=repository.min.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["../src/repository.js"],"names":["define","Ajax","Notification","getEnrolledCoursesByTimeline","args","promise","call","methodname","setFavouriteCourses","updateUserPreferences","fail","exception"],"mappings":"AAsBAA,OAAM,+BAAC,CAAC,WAAD,CAAc,mBAAd,CAAD,CAAqC,SAASC,CAAT,CAAeC,CAAf,CAA6B,CAyEpE,MAAO,CACHC,4BAA4B,CA3DG,QAA/BA,CAAAA,4BAA+B,CAASC,CAAT,CAAe,IAO1CC,CAAAA,CAAO,CAAGJ,CAAI,CAACK,IAAL,CAAU,CALV,CACVC,UAAU,CAAE,6DADF,CAEVH,IAAI,CAAEA,CAFI,CAKU,CAAV,EAAqB,CAArB,CAPgC,CAS9C,MAAOC,CAAAA,CACV,CAgDM,CAEHG,mBAAmB,CAvCG,QAAtBA,CAAAA,mBAAsB,CAASJ,CAAT,CAAe,IAOjCC,CAAAA,CAAO,CAAGJ,CAAI,CAACK,IAAL,CAAU,CALV,CACVC,UAAU,CAAE,mCADF,CAEVH,IAAI,CAAEA,CAFI,CAKU,CAAV,EAAqB,CAArB,CAPuB,CASrC,MAAOC,CAAAA,CACV,CA2BM,CAGHI,qBAAqB,CAbG,QAAxBA,CAAAA,qBAAwB,CAASL,CAAT,CAAe,CAMvCH,CAAI,CAACK,IAAL,CAAU,CALI,CACVC,UAAU,CAAE,mCADF,CAEVH,IAAI,CAAEA,CAFI,CAKJ,CAAV,EAAqB,CAArB,EACKM,IADL,CACUR,CAAY,CAACS,SADvB,CAEH,CAEM,CAKV,CA9EK,CAAN","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 <http://www.gnu.org/licenses/>.\n\n/**\n * A javascript module to retrieve enrolled coruses from the server.\n *\n * @module block_myoverview/repository\n * @copyright 2018 Bas Brands <base@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['core/ajax', 'core/notification'], function(Ajax, Notification) {\n\n /**\n * Retrieve a list of enrolled courses.\n *\n * Valid args are:\n * string classification future, inprogress, past\n * int limit number of records to retreive\n * int Offset offset for pagination\n * int sort sort by lastaccess or name\n *\n * @method getEnrolledCoursesByTimeline\n * @param {object} args The request arguments\n * @return {promise} Resolved with an array of courses\n */\n var getEnrolledCoursesByTimeline = function(args) {\n\n var request = {\n methodname: 'core_course_get_enrolled_courses_by_timeline_classification',\n args: args\n };\n\n var promise = Ajax.call([request])[0];\n\n return promise;\n };\n\n /**\n * Set the favourite state on a list of courses.\n *\n * Valid args are:\n * Array courses list of course id numbers.\n *\n * @param {Object} args Arguments send to the webservice.\n * @return {Promise} Resolve with warnings.\n */\n var setFavouriteCourses = function(args) {\n\n var request = {\n methodname: 'core_course_set_favourite_courses',\n args: args\n };\n\n var promise = Ajax.call([request])[0];\n\n return promise;\n };\n\n /**\n * Update the user preferences.\n *\n * @param {Object} args Arguments send to the webservice.\n *\n * Sample args:\n * {\n * preferences: [\n * {\n * type: 'block_example_user_sort_preference'\n * value: 'title'\n * }\n * ]\n * }\n */\n var updateUserPreferences = function(args) {\n var request = {\n methodname: 'core_user_update_user_preferences',\n args: args\n };\n\n Ajax.call([request])[0]\n .fail(Notification.exception);\n };\n\n return {\n getEnrolledCoursesByTimeline: getEnrolledCoursesByTimeline,\n setFavouriteCourses: setFavouriteCourses,\n updateUserPreferences: updateUserPreferences\n };\n});\n"],"file":"repository.min.js"}
{"version":3,"sources":["../src/repository.js"],"names":["getEnrolledCoursesByTimeline","args","Ajax","call","methodname","setFavouriteCourses","updateUserPreferences","fail","Notification","exception"],"mappings":"uhBAuBA,uDACA,O,siBAeO,GAAMA,CAAAA,CAA4B,CAAG,SAAAC,CAAI,CAAI,CAMhD,MAAOC,WAAKC,IAAL,CAAU,CALD,CACZC,UAAU,CAAE,6DADA,CAEZH,IAAI,CAAEA,CAFM,CAKC,CAAV,EAAqB,CAArB,CACV,CAPM,C,iCAkBA,GAAMI,CAAAA,CAAmB,CAAG,SAAAJ,CAAI,CAAI,CAMvC,MAAOC,WAAKC,IAAL,CAAU,CALD,CACZC,UAAU,CAAE,mCADA,CAEZH,IAAI,CAAEA,CAFM,CAKC,CAAV,EAAqB,CAArB,CACV,CAPM,C,wBAwBA,GAAMK,CAAAA,CAAqB,CAAG,SAAAL,CAAI,CAAI,CAMzCC,UAAKC,IAAL,CAAU,CALM,CACZC,UAAU,CAAE,mCADA,CAEZH,IAAI,CAAEA,CAFM,CAKN,CAAV,EAAqB,CAArB,EACKM,IADL,CACUC,CAAY,CAACC,SADvB,CAEH,CARM,C","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 <http://www.gnu.org/licenses/>.\n\n/**\n * A javascript module to retrieve enrolled coruses from the server.\n *\n * @module block_myoverview/repository\n * @copyright 2018 Bas Brands <base@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\nimport * as Notification from 'core/notification';\n\n/**\n * Retrieve a list of enrolled courses.\n *\n * Valid args are:\n * string classification future, inprogress, past\n * int limit number of records to retreive\n * int Offset offset for pagination\n * int sort sort by lastaccess or name\n *\n * @method getEnrolledCoursesByTimeline\n * @param {object} args The request arguments\n * @return {promise} Resolved with an array of courses\n */\nexport const getEnrolledCoursesByTimeline = args => {\n const request = {\n methodname: 'core_course_get_enrolled_courses_by_timeline_classification',\n args: args\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Set the favourite state on a list of courses.\n *\n * Valid args are:\n * Array courses list of course id numbers.\n *\n * @param {Object} args Arguments send to the webservice.\n * @return {Promise} Resolve with warnings.\n */\nexport const setFavouriteCourses = args => {\n const request = {\n methodname: 'core_course_set_favourite_courses',\n args: args\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Update the user preferences.\n *\n * @param {Object} args Arguments send to the webservice.\n *\n * Sample args:\n * {\n * preferences: [\n * {\n * type: 'block_example_user_sort_preference'\n * value: 'title'\n * }\n * ]\n * }\n */\nexport const updateUserPreferences = args => {\n const request = {\n methodname: 'core_user_update_user_preferences',\n args: args\n };\n\n Ajax.call([request])[0]\n .fail(Notification.exception);\n};\n"],"file":"repository.min.js"}

View File

@ -1,2 +1,2 @@
define ("block_myoverview/selectors",[],function(){return{courseView:{region:"[data-region=\"courses-view\"]",regionContent:"[data-region=\"course-view-content\"]"}}});
define ("block_myoverview/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;a.default={courseView:{region:"[data-region=\"courses-view\"]",regionContent:"[data-region=\"course-view-content\"]"},FILTERS:"[data-region=\"filter\"]",FILTER_OPTION:"[data-filter]",DISPLAY_OPTION:"[data-display-option]",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\"]",region:{selectBlock:"[data-region=\"myoverview\"]",clearIcon:"[data-region=\"clear-icon\"]",searchIcon:"[data-region=\"search-icon\"]",searchInput:"[data-region=\"search-input\"]"}};return a.default});
//# sourceMappingURL=selectors.min.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["../src/selectors.js"],"names":["define","courseView","region","regionContent"],"mappings":"AAsBAA,OAAM,8BAAC,EAAD,CAAK,UAAW,CAClB,MAAO,CACHC,UAAU,CAAE,CACRC,MAAM,CAAE,gCADA,CAERC,aAAa,CAAE,uCAFP,CADT,CAMV,CAPK,CAAN","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 <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript to initialise the selectors for the myoverview block.\n *\n * @copyright 2018 Peter Dias <peter@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine([], function() {\n return {\n courseView: {\n region: '[data-region=\"courses-view\"]',\n regionContent: '[data-region=\"course-view-content\"]'\n }\n };\n});\n"],"file":"selectors.min.js"}
{"version":3,"sources":["../src/selectors.js"],"names":["courseView","region","regionContent","FILTERS","FILTER_OPTION","DISPLAY_OPTION","ACTION_HIDE_COURSE","ACTION_SHOW_COURSE","ACTION_ADD_FAVOURITE","ACTION_REMOVE_FAVOURITE","FAVOURITE_ICON","ICON_IS_FAVOURITE","ICON_NOT_FAVOURITE","selectBlock","clearIcon","searchIcon","searchInput"],"mappings":"sJAsBe,CACXA,UAAU,CAAE,CACRC,MAAM,CAAE,gCADA,CAERC,aAAa,CAAE,uCAFP,CADD,CAKXC,OAAO,CAAE,0BALE,CAMXC,aAAa,CAAE,eANJ,CAOXC,cAAc,CAAE,uBAPL,CAQXC,kBAAkB,CAAE,+BART,CASXC,kBAAkB,CAAE,+BATT,CAUXC,oBAAoB,CAAE,iCAVX,CAWXC,uBAAuB,CAAE,oCAXd,CAYXC,cAAc,CAAE,kCAZL,CAaXC,iBAAiB,CAAE,gCAbR,CAcXC,kBAAkB,CAAE,iCAdT,CAeXX,MAAM,CAAE,CACJY,WAAW,CAAE,8BADT,CAEJC,SAAS,CAAE,8BAFP,CAGJC,UAAU,CAAE,+BAHR,CAIJC,WAAW,CAAE,gCAJT,CAfG,C","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 <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript to initialise the selectors for the myoverview block.\n *\n * @copyright 2018 Peter Dias <peter@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n courseView: {\n region: '[data-region=\"courses-view\"]',\n regionContent: '[data-region=\"course-view-content\"]'\n },\n FILTERS: '[data-region=\"filter\"]',\n FILTER_OPTION: '[data-filter]',\n DISPLAY_OPTION: '[data-display-option]',\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 region: {\n selectBlock: '[data-region=\"myoverview\"]',\n clearIcon: '[data-region=\"clear-icon\"]',\n searchIcon: '[data-region=\"search-icon\"]',\n searchInput: '[data-region=\"search-input\"]',\n },\n};\n"],"file":"selectors.min.js"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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 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)}}});
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("block_myoverview/view_nav",["exports","jquery","core/custom_interaction_events","block_myoverview/repository","block_myoverview/view","block_myoverview/selectors"],function(a,b,c,d,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=j(b);c=i(c);d=i(d);f=i(f);g=j(g);function h(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;h=function(){return a};return a}function i(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=h();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function j(a){return a&&a.__esModule?a:{default:a}}var k=function(a,b){var c=null;if("display"===a){c="block_myoverview_user_view_preference"}else if("sort"===a){c="block_myoverview_user_sort_preference"}else if("customfieldvalue"===a){c="block_myoverview_user_grouping_customfieldvalue_preference"}else{c="block_myoverview_user_grouping_preference"}d.updateUserPreferences({preferences:[{type:c,value:b}]})},l=function(a){var d=a.find(g.default.FILTERS);c.define(d,[c.events.activate]);d.on(c.events.activate,g.default.FILTER_OPTION,function(c,d){var e=(0,b.default)(c.target);if(e.hasClass("active")){return}var h=e.attr("data-filter"),i=e.attr("data-pref"),j=e.attr("data-customfieldvalue");a.find(g.default.courseView.region).attr("data-"+h,e.attr("data-value"));k(h,i);if(j){a.find(g.default.courseView.region).attr("data-customfieldvalue",j);k("customfieldvalue",j)}var l=document.querySelector(g.default.region.selectBlock),m=l.querySelector(g.default.region.searchInput);if(""!==m.value){var n=l.querySelector(g.default.region.clearIcon),o=l.querySelector(g.default.region.searchIcon);m.value="";f.clearSearch(o,n,a)}else{f.init(a)}d.originalEvent.preventDefault()});d.on(c.events.activate,g.default.DISPLAY_OPTION,function(c,d){var e=(0,b.default)(c.target);if(e.hasClass("active")){return}var h=e.attr("data-display-option"),i=e.attr("data-pref");a.find(g.default.courseView.region).attr("data-display",e.attr("data-value"));k(h,i);f.reset(a);d.originalEvent.preventDefault()})},m=function(a){a=(0,b.default)(a);l(a)};a.init=m});
//# sourceMappingURL=view_nav.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -20,31 +20,17 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(
[
'jquery',
'block_myoverview/view',
'block_myoverview/view_nav'
],
function(
$,
View,
ViewNav
) {
/**
* Initialise all of the modules for the overview block.
*
* @param {object} root The root element for the overview block.
*/
var init = function(root) {
root = $(root);
// Initialise the course navigation elements.
ViewNav.init(root);
// Initialise the courses view modules.
View.init(root);
};
import * as View from 'block_myoverview/view';
import * as ViewNav from 'block_myoverview/view_nav';
return {
init: init
};
});
/**
* Initialise all of the modules for the overview block.
*
* @param {object} root The root element for the overview block.
*/
export const init = (root) => {
// Initialise the course navigation elements.
ViewNav.init(root);
// Initialise the courses view modules.
View.init(root);
};

View File

@ -20,82 +20,71 @@
* @copyright 2018 Bas Brands <base@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['core/ajax', 'core/notification'], function(Ajax, Notification) {
/**
* Retrieve a list of enrolled courses.
*
* Valid args are:
* string classification future, inprogress, past
* int limit number of records to retreive
* int Offset offset for pagination
* int sort sort by lastaccess or name
*
* @method getEnrolledCoursesByTimeline
* @param {object} args The request arguments
* @return {promise} Resolved with an array of courses
*/
var getEnrolledCoursesByTimeline = function(args) {
import Ajax from 'core/ajax';
import * as Notification from 'core/notification';
var request = {
methodname: 'core_course_get_enrolled_courses_by_timeline_classification',
args: args
};
var promise = Ajax.call([request])[0];
return promise;
/**
* Retrieve a list of enrolled courses.
*
* Valid args are:
* string classification future, inprogress, past
* int limit number of records to retreive
* int Offset offset for pagination
* int sort sort by lastaccess or name
*
* @method getEnrolledCoursesByTimeline
* @param {object} args The request arguments
* @return {promise} Resolved with an array of courses
*/
export const getEnrolledCoursesByTimeline = args => {
const request = {
methodname: 'core_course_get_enrolled_courses_by_timeline_classification',
args: args
};
/**
* Set the favourite state on a list of courses.
*
* Valid args are:
* Array courses list of course id numbers.
*
* @param {Object} args Arguments send to the webservice.
* @return {Promise} Resolve with warnings.
*/
var setFavouriteCourses = function(args) {
return Ajax.call([request])[0];
};
var request = {
methodname: 'core_course_set_favourite_courses',
args: args
};
var promise = Ajax.call([request])[0];
return promise;
/**
* Set the favourite state on a list of courses.
*
* Valid args are:
* Array courses list of course id numbers.
*
* @param {Object} args Arguments send to the webservice.
* @return {Promise} Resolve with warnings.
*/
export const setFavouriteCourses = args => {
const request = {
methodname: 'core_course_set_favourite_courses',
args: args
};
/**
* Update the user preferences.
*
* @param {Object} args Arguments send to the webservice.
*
* Sample args:
* {
* preferences: [
* {
* type: 'block_example_user_sort_preference'
* value: 'title'
* }
* ]
* }
*/
var updateUserPreferences = function(args) {
var request = {
methodname: 'core_user_update_user_preferences',
args: args
};
return Ajax.call([request])[0];
};
Ajax.call([request])[0]
.fail(Notification.exception);
/**
* Update the user preferences.
*
* @param {Object} args Arguments send to the webservice.
*
* Sample args:
* {
* preferences: [
* {
* type: 'block_example_user_sort_preference'
* value: 'title'
* }
* ]
* }
*/
export const updateUserPreferences = args => {
const request = {
methodname: 'core_user_update_user_preferences',
args: args
};
return {
getEnrolledCoursesByTimeline: getEnrolledCoursesByTimeline,
setFavouriteCourses: setFavouriteCourses,
updateUserPreferences: updateUserPreferences
};
});
Ajax.call([request])[0]
.fail(Notification.exception);
};

View File

@ -20,11 +20,25 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([], function() {
return {
courseView: {
region: '[data-region="courses-view"]',
regionContent: '[data-region="course-view-content"]'
}
};
});
export default {
courseView: {
region: '[data-region="courses-view"]',
regionContent: '[data-region="course-view-content"]'
},
FILTERS: '[data-region="filter"]',
FILTER_OPTION: '[data-filter]',
DISPLAY_OPTION: '[data-display-option]',
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"]',
region: {
selectBlock: '[data-region="myoverview"]',
clearIcon: '[data-region="clear-icon"]',
searchIcon: '[data-region="search-icon"]',
searchInput: '[data-region="search-input"]',
},
};

File diff suppressed because it is too large Load Diff

View File

@ -20,130 +20,120 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(
[
'jquery',
'core/custom_interaction_events',
'block_myoverview/repository',
'block_myoverview/view',
'block_myoverview/selectors'
],
function(
$,
CustomEvents,
Repository,
View,
Selectors
) {
import $ from 'jquery';
import * as CustomEvents from 'core/custom_interaction_events';
import * as Repository from 'block_myoverview/repository';
import * as View from 'block_myoverview/view';
import SELECTORS from 'block_myoverview/selectors';
var SELECTORS = {
FILTERS: '[data-region="filter"]',
FILTER_OPTION: '[data-filter]',
DISPLAY_OPTION: '[data-display-option]'
};
/**
* Update the user preference for the block.
*
* @param {String} filter The type of filter: display/sort/grouping.
* @param {String} value The current preferred value.
*/
const updatePreferences = (filter, value) => {
let type = null;
if (filter === 'display') {
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';
}
/**
* Update the user preference for the block.
*
* @param {String} filter The type of filter: display/sort/grouping.
* @param {String} value The current preferred value.
*/
var updatePreferences = function(filter, value) {
var type = null;
if (filter == 'display') {
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';
}
Repository.updateUserPreferences({
preferences: [
{
type: type,
value: value
}
]
});
};
Repository.updateUserPreferences({
preferences: [
{
type: type,
value: value
}
]
});
};
/**
* Event listener for the Display filter (cards, list).
*
* @param {object} root The root element for the overview block
*/
const registerSelector = root => {
/**
* Event listener for the Display filter (cards, list).
*
* @param {object} root The root element for the overview block
*/
var registerSelector = function(root) {
const Selector = root.find(SELECTORS.FILTERS);
var Selector = root.find(SELECTORS.FILTERS);
CustomEvents.define(Selector, [CustomEvents.events.activate]);
Selector.on(
CustomEvents.events.activate,
SELECTORS.FILTER_OPTION,
(e, data) => {
const option = $(e.target);
CustomEvents.define(Selector, [CustomEvents.events.activate]);
Selector.on(
CustomEvents.events.activate,
SELECTORS.FILTER_OPTION,
function(e, data) {
var option = $(e.target);
if (option.hasClass('active')) {
// If it's already active then we don't need to do anything.
return;
}
if (option.hasClass('active')) {
// If it's already active then we don't need to do anything.
return;
}
const filter = option.attr('data-filter');
const pref = option.attr('data-pref');
const customfieldvalue = option.attr('data-customfieldvalue');
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);
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);
}
if (customfieldvalue) {
root.find(Selectors.courseView.region).attr('data-customfieldvalue', customfieldvalue);
updatePreferences('customfieldvalue', customfieldvalue);
}
// Reset the views.
// Reset the views.
// Check if the user is currently in a searching state, if so we'll reset it.
const page = document.querySelector(SELECTORS.region.selectBlock);
const input = page.querySelector(SELECTORS.region.searchInput);
if (input.value !== '') {
const clearIcon = page.querySelector(SELECTORS.region.clearIcon);
const searchIcon = page.querySelector(SELECTORS.region.searchIcon);
input.value = '';
// Triggers the init so wont need to call it again.
View.clearSearch(searchIcon, clearIcon, root);
} else {
View.init(root);
data.originalEvent.preventDefault();
}
);
CustomEvents.define(Selector, [CustomEvents.events.activate]);
Selector.on(
CustomEvents.events.activate,
SELECTORS.DISPLAY_OPTION,
function(e, data) {
var option = $(e.target);
data.originalEvent.preventDefault();
}
);
if (option.hasClass('active')) {
return;
}
Selector.on(
CustomEvents.events.activate,
SELECTORS.DISPLAY_OPTION,
(e, data) => {
const option = $(e.target);
var filter = option.attr('data-display-option');
var pref = option.attr('data-pref');
root.find(Selectors.courseView.region).attr('data-display', option.attr('data-value'));
updatePreferences(filter, pref);
View.reset(root);
data.originalEvent.preventDefault();
if (option.hasClass('active')) {
return;
}
);
};
/**
* Initialise the timeline view navigation by adding event listeners to
* the navigation elements.
*
* @param {object} root The root element for the myoverview block
*/
var init = function(root) {
root = $(root);
registerSelector(root);
};
const filter = option.attr('data-display-option');
const pref = option.attr('data-pref');
return {
init: init
};
});
root.find(SELECTORS.courseView.region).attr('data-display', option.attr('data-value'));
updatePreferences(filter, pref);
View.reset(root);
data.originalEvent.preventDefault();
}
);
};
/**
* Initialise the timeline view navigation by adding event listeners to
* the navigation elements.
*
* @param {object} root The root element for the myoverview block
*/
export const init = root => {
root = $(root);
registerSelector(root);
};

View File

@ -51,6 +51,7 @@ $string['availablegroupings'] = 'Available filters';
$string['availablegroupings_desc'] = 'Course filters which are available for selection by users. If none are selected, all courses will be displayed.';
$string['card'] = 'Card';
$string['cards'] = 'Cards';
$string['clearsearch'] = "Clear search";
$string['courseprogress'] = 'Course progress:';
$string['completepercent'] = '{$a}% complete';
$string['customfield'] = 'Custom field';
@ -74,6 +75,7 @@ $string['privacy:metadata:overviewviewpreference'] = 'The Course overview block
$string['privacy:metadata:overviewgroupingpreference'] = 'The Course overview block grouping preference.';
$string['privacy:metadata:overviewpagingpreference'] = 'The Course overview block paging preference.';
$string['removefromfavourites'] = 'Unstar this course';
$string['searchcourses'] = "Search courses";
$string['shortname'] = 'Short name';
$string['summary'] = 'Summary';
$string['title'] = 'Course name';

View File

@ -77,4 +77,4 @@
</div>
</a>
</div>
</div>
</div>

View File

@ -25,14 +25,17 @@
<div id="block-myoverview-{{uniqid}}" class="block-myoverview block-cards" data-region="myoverview" role="navigation">
<div data-region="filter" class="d-flex align-items-center flex-wrap" aria-label="{{#str}} aria:controls, block_myoverview {{/str}}">
{{> block_myoverview/nav-grouping-selector }}
<div data-region="filter" class="d-flex align-items-center flex-wrap" aria-label="{{#str}} aria:controls, block_myoverview {{/str}}">
{{> block_myoverview/nav-grouping-selector }}
{{> block_myoverview/nav-sort-selector }}
{{#displaydropdown}}
{{> block_myoverview/nav-display-selector }}
{{/displaydropdown}}
</div>
{{> block_myoverview/nav-search-widget }}
{{> block_myoverview/nav-sort-selector }}
{{#displaydropdown}}
{{> block_myoverview/nav-display-selector }}
{{/displaydropdown}}
</div>
<div class="container-fluid p-0">
{{> block_myoverview/courses-view }}

View File

@ -0,0 +1,48 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template block_myoverview/nav-search-widget
This template renders the search input within the filters area.
Example context (json):
{}
}}
<div class="searchbar input-group mb-1 mr-1 p-0 col-lg-3 col-md-6 col-sm-8 col-12" role="search">
<label for="searchinput">
<span class="sr-only">{{#str}} searchcourses, block_myoverview {{/str}}</span>
</label>
<input type="text"
data-region="search-input"
id="searchinput"
class="form-control searchinput border-right-0 h-100 px-3 py-2"
placeholder="{{#str}} search, core {{/str}}"
name="search"
autocomplete="off"
>
<div class="input-group-append">
<div data-region="search-icon" class="input-group-text">
{{#pix}} a/search, core {{/pix}}
</div>
<div class="clear input-group-text d-none">
<button class="btn p-0" data-region="clear-icon">
<span class="d-flex" aria-hidden="true">{{#pix}} e/cancel, core {{/pix}}</span>
<span class="sr-only">{{#str}} clearsearch, block_myoverview {{/str}}</span>
</button>
</div>
</div>
</div>

View File

@ -37,55 +37,55 @@
}}
<ul class="list-group">
{{#courses}}
<li class="list-group-item course-listitem"
data-region="course-content"
data-course-id="{{{id}}}">
<div class="row">
<div class="{{#hasprogress}}col-md-6{{/hasprogress}}{{^hasprogress}}col-md-11 col-md-11{{/hasprogress}} d-flex align-items-center">
<div>
<div class="text-muted muted d-flex flex-wrap">
{{#showcoursecategory}}
<span class="sr-only">
{{#str}}aria:coursecategory, core_course{{/str}}
</span>
<span class="categoryname">
{{{coursecategory}}}
</span>
{{/showcoursecategory}}
{{#showshortname}}
{{#courses}}
<li class="list-group-item course-listitem"
data-region="course-content"
data-course-id="{{{id}}}">
<div class="row">
<div class="{{#hasprogress}}col-md-6{{/hasprogress}}{{^hasprogress}}col-md-11 col-md-11{{/hasprogress}} d-flex align-items-center">
<div>
<div class="text-muted muted d-flex flex-wrap">
{{#showcoursecategory}}
<div class="pl-1 pr-1">|</div>
<span class="sr-only">
{{#str}}aria:coursecategory, core_course{{/str}}
</span>
<span class="categoryname">
{{{coursecategory}}}
</span>
{{/showcoursecategory}}
<span class="sr-only">
{{#str}}aria:courseshortname, core_course{{/str}}
</span>
<div>{{{shortname}}}</div>
{{/showshortname}}
</div>
<a href="{{viewurl}}" class="aalink coursename">
{{> core_course/favouriteicon }}
<span class="sr-only">
{{#str}}aria:coursename, core_course{{/str}}
</span>
{{{fullname}}}
</a>
{{^visible}}
<div class="d-flex flex-wrap">
<span class="badge badge-info">{{#str}} hiddenfromstudents {{/str}}</span>
{{#showshortname}}
{{#showcoursecategory}}
<div class="pl-1 pr-1">|</div>
{{/showcoursecategory}}
<span class="sr-only">
{{#str}}aria:courseshortname, core_course{{/str}}
</span>
<div>{{{shortname}}}</div>
{{/showshortname}}
</div>
{{/visible}}
<a href="{{viewurl}}" class="aalink coursename">
{{> core_course/favouriteicon }}
<span class="sr-only">
{{#str}}aria:coursename, core_course{{/str}}
</span>
{{{fullname}}}
</a>
{{^visible}}
<div class="d-flex flex-wrap">
<span class="badge badge-info">{{#str}} hiddenfromstudents {{/str}}</span>
</div>
{{/visible}}
</div>
</div>
{{#hasprogress}}
<div class="col-md-5 pt-1">
{{> block_myoverview/progress-bar}}
</div>
{{/hasprogress}}
<div class="col-md-1 p-0 d-flex">
{{> block_myoverview/course-action-menu }}
</div>
</div>
{{#hasprogress}}
<div class="col-md-5 pt-1">
{{> block_myoverview/progress-bar}}
</div>
{{/hasprogress}}
<div class="col-md-1 p-0 d-flex">
{{> block_myoverview/course-action-menu }}
</div>
</div>
</li>
{{/courses}}
</li>
{{/courses}}
</ul>

View File

@ -0,0 +1,63 @@
@block @block_myoverview @javascript
Feature: My overview block searching
Background:
Given the following "users" exist:
| username | firstname | lastname | email | idnumber |
| student1 | Student | X | student1@example.com | S1 |
| student2 | Student | Y | student2@example.com | S2 |
And the following "courses" exist:
| fullname | shortname | category |
| Course 01 | C1 | 0 |
| Course 02 | C2 | 0 |
| Course 03 | C3 | 0 |
| Course 04 | C4 | 0 |
| Course 05 | C5 | 0 |
| Course 06 | C6 | 0 |
| Course 07 | C7 | 0 |
| Course 08 | C8 | 0 |
| Course 09 | C9 | 0 |
| Course 10 | C10 | 0 |
| Course 11 | C11 | 0 |
| Course 12 | C12 | 0 |
| Course 13 | C13 | 0 |
| Fake example | Fake | 0 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
| student1 | C4 | student |
| student1 | C5 | student |
| student1 | C6 | student |
| student1 | C7 | student |
| student1 | C8 | student |
| student1 | C9 | student |
| student1 | C10 | student |
| student1 | C11 | student |
| student1 | C12 | student |
| student1 | C13 | student |
Scenario: The search should return no courses if I am not enrolled in any
When I log in as "student2"
Then I should see "No courses" in the "Course overview" "block"
And I set the field "Search courses" to "Fake example"
And I should see "No courses" in the "Course overview" "block"
And I log out
Scenario: Single page search
Given I log in as "student1"
And I set the field "Search courses" to "Course 0"
Then I should see "Course 01" in the "Course overview" "block"
And I should not see "Course 13" in the "Course overview" "block"
And I log out
Scenario: Paginated search
Given I log in as "student1"
And I set the field "Search courses" to "Course"
And I should see "Course 01" in the "Course overview" "block"
And I should not see "Course 13" in the "Course overview" "block"
And I click on "[data-control='next']" "css_element" in the "Course overview" "block"
And I wait until ".block_myoverview [data-control='next']" "css_element" exists
Then I should see "Course 13" in the "Course overview" "block"
And I should not see "Course 01" in the "Course overview" "block"

View File

@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
$plugin->version = 2021052503; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'block_myoverview'; // Full name of the plugin (used for diagnostics).

View File

@ -3755,6 +3755,8 @@ class core_course_external extends external_api {
VALUE_DEFAULT, null),
'customfieldvalue' => new external_value(PARAM_RAW, 'Used when classification = customfield',
VALUE_DEFAULT, null),
'searchvalue' => new external_value(PARAM_TEXT, 'The value a user wishes to search against',
VALUE_DEFAULT, null),
)
);
}
@ -3779,6 +3781,7 @@ class core_course_external extends external_api {
* @param string $sort SQL sort string for results
* @param string $customfieldname
* @param string $customfieldvalue
* @param string $searchvalue
* @return array list of courses and warnings
* @throws invalid_parameter_exception
*/
@ -3788,7 +3791,8 @@ class core_course_external extends external_api {
int $offset = 0,
string $sort = null,
string $customfieldname = null,
string $customfieldvalue = null
string $customfieldvalue = null,
string $searchvalue = null
) {
global $CFG, $PAGE, $USER;
require_once($CFG->dirroot . '/course/lib.php');
@ -3800,6 +3804,7 @@ class core_course_external extends external_api {
'offset' => $offset,
'sort' => $sort,
'customfieldvalue' => $customfieldvalue,
'searchvalue' => $searchvalue,
)
);
@ -3808,6 +3813,7 @@ class core_course_external extends external_api {
$offset = $params['offset'];
$sort = $params['sort'];
$customfieldvalue = $params['customfieldvalue'];
$searchvalue = $params['searchvalue'];
switch($classification) {
case COURSE_TIMELINE_ALLINCLUDINGHIDDEN:
@ -3824,6 +3830,8 @@ class core_course_external extends external_api {
break;
case COURSE_TIMELINE_HIDDEN:
break;
case COURSE_TIMELINE_SEARCH:
break;
case COURSE_CUSTOMFIELD:
break;
default:
@ -3847,6 +3855,19 @@ class core_course_external extends external_api {
COURSE_DB_QUERY_LIMIT, $hiddencourses);
// Otherwise get the requested courses and exclude the hidden courses.
} else if ($classification == COURSE_TIMELINE_SEARCH) {
// Prepare the search API options.
$searchcriteria['search'] = $searchvalue;
$options = ['idonly' => true];
$courses = course_get_enrolled_courses_for_logged_in_user_from_search(
0,
$offset,
$sort,
$fields,
COURSE_DB_QUERY_LIMIT,
$searchcriteria,
$options
);
} else {
$courses = course_get_enrolled_courses_for_logged_in_user(0, $offset, $sort, $fields,
COURSE_DB_QUERY_LIMIT, [], $hiddencourses);
@ -3886,6 +3907,9 @@ class core_course_external extends external_api {
$renderer = $PAGE->get_renderer('core');
$formattedcourses = array_map(function($course) use ($renderer, $favouritecourseids) {
if ($course == null) {
return;
}
context_helper::preload_from_record($course);
$context = context_course::instance($course->id);
$isfavourite = false;
@ -3896,6 +3920,12 @@ class core_course_external extends external_api {
return $exporter->export($renderer);
}, $filteredcourses);
$formattedcourses = array_filter($formattedcourses, function($course) {
if ($course != null) {
return $course;
}
});
return [
'courses' => $formattedcourses,
'nextoffset' => $offset + $processedcount

View File

@ -63,6 +63,7 @@ define('COURSE_TIMELINE_ALL', 'all');
define('COURSE_TIMELINE_PAST', 'past');
define('COURSE_TIMELINE_INPROGRESS', 'inprogress');
define('COURSE_TIMELINE_FUTURE', 'future');
define('COURSE_TIMELINE_SEARCH', 'search');
define('COURSE_FAVOURITES', 'favourites');
define('COURSE_TIMELINE_HIDDEN', 'hidden');
define('COURSE_CUSTOMFIELD', 'customfield');
@ -4347,6 +4348,58 @@ function course_get_enrolled_courses_for_logged_in_user(
}
}
/**
* Get the list of enrolled courses the current user searched for.
*
* This function returns a Generator. The courses will be loaded from the database
* in chunks rather than a single query.
*
* @param int $limit Restrict result set to this amount
* @param int $offset Skip this number of records from the start of the result set
* @param string|null $sort SQL string for sorting
* @param string|null $fields SQL string for fields to be returned
* @param int $dbquerylimit The number of records to load per DB request
* @param array $searchcriteria contains search criteria
* @param array $options display options, same as in get_courses() except 'recursive' is ignored -
* search is always category-independent
* @return Generator
*/
function course_get_enrolled_courses_for_logged_in_user_from_search(
int $limit = 0,
int $offset = 0,
string $sort = null,
string $fields = null,
int $dbquerylimit = COURSE_DB_QUERY_LIMIT,
array $searchcriteria = [],
array $options = []
) : Generator {
$haslimit = !empty($limit);
$recordsloaded = 0;
$querylimit = (!$haslimit || $limit > $dbquerylimit) ? $dbquerylimit : $limit;
$ids = core_course_category::search_courses($searchcriteria, $options);
// If no courses were found matching the criteria return back.
if (empty($ids)) {
return;
}
while ($courses = enrol_get_my_courses($fields, $sort, $querylimit, $ids, false, $offset)) {
yield from $courses;
$recordsloaded += $querylimit;
if (count($courses) < $querylimit) {
break;
}
if ($haslimit && $recordsloaded >= $limit) {
break;
}
$offset += $querylimit;
}
}
/**
* Search the given $courses for any that match the given $classification up to the specified
* $limit.
@ -4370,9 +4423,9 @@ function course_filter_courses_by_timeline_classification(
if (!in_array($classification,
[COURSE_TIMELINE_ALLINCLUDINGHIDDEN, COURSE_TIMELINE_ALL, COURSE_TIMELINE_PAST, COURSE_TIMELINE_INPROGRESS,
COURSE_TIMELINE_FUTURE, COURSE_TIMELINE_HIDDEN])) {
COURSE_TIMELINE_FUTURE, COURSE_TIMELINE_HIDDEN, COURSE_TIMELINE_SEARCH])) {
$message = 'Classification must be one of COURSE_TIMELINE_ALLINCLUDINGHIDDEN, COURSE_TIMELINE_ALL, COURSE_TIMELINE_PAST, '
. 'COURSE_TIMELINE_INPROGRESS or COURSE_TIMELINE_FUTURE';
. 'COURSE_TIMELINE_INPROGRESS, COURSE_TIMELINE_SEARCH or COURSE_TIMELINE_FUTURE';
throw new moodle_exception($message);
}
@ -4386,6 +4439,7 @@ function course_filter_courses_by_timeline_classification(
// Added as of MDL-63457 toggle viewability for each user.
if ($classification == COURSE_TIMELINE_ALLINCLUDINGHIDDEN || ($classification == COURSE_TIMELINE_HIDDEN && $pref) ||
$classification == COURSE_TIMELINE_SEARCH||
(($classification == COURSE_TIMELINE_ALL || $classification == course_classify_for_timeline($course)) && !$pref)) {
$filteredcourses[] = $course;
$filtermatches++;

View File

@ -4831,6 +4831,104 @@ class core_course_courselib_testcase extends advanced_testcase {
];
}
/**
* Test the course_get_enrolled_courses_for_logged_in_user_from_search function.
*/
public function test_course_get_enrolled_courses_for_logged_in_user_from_search() {
global $DB;
// Set up.
$this->resetAfterTest();
$generator = $this->getDataGenerator();
$student = $generator->create_user();
$cat1 = core_course_category::create(['name' => 'Cat1']);
$cat2 = core_course_category::create(['name' => 'Cat2', 'parent' => $cat1->id]);
$c1 = $this->getDataGenerator()->create_course(['category' => $cat1->id, 'fullname' => 'Test 3', 'summary' => 'Magic', 'idnumber' => 'ID3']);
$c2 = $this->getDataGenerator()->create_course(['category' => $cat1->id, 'fullname' => 'Test 1', 'summary' => 'Magic']);
$c3 = $this->getDataGenerator()->create_course(['category' => $cat1->id, 'fullname' => 'Математика', 'summary' => ' Test Magic']);
$c4 = $this->getDataGenerator()->create_course(['category' => $cat1->id, 'fullname' => 'Test 4', 'summary' => 'Magic', 'idnumber' => 'ID4']);
$c5 = $this->getDataGenerator()->create_course(['category' => $cat2->id, 'fullname' => 'Test 5', 'summary' => 'Magic']);
$c6 = $this->getDataGenerator()->create_course(['category' => $cat2->id, 'fullname' => 'Дискретная Математика', 'summary' => 'Magic']);
$c7 = $this->getDataGenerator()->create_course(['category' => $cat2->id, 'fullname' => 'Test 7', 'summary' => 'Magic']);
$c8 = $this->getDataGenerator()->create_course(['category' => $cat2->id, 'fullname' => 'Test 8', 'summary' => 'Magic']);
for ($i = 1; $i < 9; $i++) {
$generator->enrol_user($student->id, ${"c$i"}->id, 'student');
}
$this->setUser($student);
$returnedcourses = course_get_enrolled_courses_for_logged_in_user_from_search(
0,
0,
'id ASC',
null,
COURSE_DB_QUERY_LIMIT,
['search' => 'test'],
['idonly' => true]
);
$actualresult = array_map(function($course) {
return $course->id;
}, iterator_to_array($returnedcourses, false));
$this->assertEquals([$c1->id, $c2->id, $c3->id, $c4->id, $c5->id, $c7->id, $c8->id], $actualresult);
// Test no courses matching the search.
$returnedcourses = course_get_enrolled_courses_for_logged_in_user_from_search(
0,
0,
'id ASC',
null,
COURSE_DB_QUERY_LIMIT,
['search' => 'foobar'],
['idonly' => true]
);
$actualresult = array_map(function($course) {
return $course->id;
}, iterator_to_array($returnedcourses, false));
$this->assertEquals([], $actualresult);
// Test returning all courses that have a mutual summary.
$returnedcourses = course_get_enrolled_courses_for_logged_in_user_from_search(
0,
0,
'id ASC',
null,
COURSE_DB_QUERY_LIMIT,
['search' => 'Magic'],
['idonly' => true]
);
$actualresult = array_map(function($course) {
return $course->id;
}, iterator_to_array($returnedcourses, false));
$this->assertEquals([$c1->id, $c2->id, $c3->id, $c4->id, $c5->id, $c6->id, $c7->id, $c8->id], $actualresult);
// Test returning a unique course.
$returnedcourses = course_get_enrolled_courses_for_logged_in_user_from_search(
0,
0,
'id ASC',
null,
COURSE_DB_QUERY_LIMIT,
['search' => 'Дискретная'],
['idonly' => true]
);
$actualresult = array_map(function($course) {
return $course->id;
}, iterator_to_array($returnedcourses, false));
$this->assertEquals([$c6->id], $actualresult);
}
/**
* Test the course_filter_courses_by_timeline_classification function.
*

View File

@ -37,7 +37,8 @@ require_once($CFG->dirroot . '/webservice/tests/helpers.php');
* @copyright 2012 Jerome Mouneyrac
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_course_externallib_testcase extends externallib_advanced_testcase {
class externallib_test extends externallib_advanced_testcase {
//core_course_externallib_testcase
/**
* Tests set up
@ -3068,7 +3069,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'offset' => 0,
'sort' => 'shortname ASC',
'expectedcourses' => [],
'expectednextoffset' => 0
'expectednextoffset' => 0,
],
// COURSE_TIMELINE_FUTURE.
'future not limit no offset' => [
@ -3078,7 +3079,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'offset' => 0,
'sort' => 'shortname ASC',
'expectedcourses' => ['afuture', 'bfuture', 'cfuture', 'dfuture', 'efuture'],
'expectednextoffset' => 15
'expectednextoffset' => 15,
],
'future no offset' => [
'coursedata' => $coursedata,
@ -3087,7 +3088,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'offset' => 0,
'sort' => 'shortname ASC',
'expectedcourses' => ['afuture', 'bfuture'],
'expectednextoffset' => 4
'expectednextoffset' => 4,
],
'future offset' => [
'coursedata' => $coursedata,
@ -3096,7 +3097,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'offset' => 2,
'sort' => 'shortname ASC',
'expectedcourses' => ['bfuture', 'cfuture'],
'expectednextoffset' => 7
'expectednextoffset' => 7,
],
'future exact limit' => [
'coursedata' => $coursedata,
@ -3105,7 +3106,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'offset' => 0,
'sort' => 'shortname ASC',
'expectedcourses' => ['afuture', 'bfuture', 'cfuture', 'dfuture', 'efuture'],
'expectednextoffset' => 13
'expectednextoffset' => 13,
],
'future limit less results' => [
'coursedata' => $coursedata,
@ -3114,7 +3115,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'offset' => 0,
'sort' => 'shortname ASC',
'expectedcourses' => ['afuture', 'bfuture', 'cfuture', 'dfuture', 'efuture'],
'expectednextoffset' => 15
'expectednextoffset' => 15,
],
'future limit less results with offset' => [
'coursedata' => $coursedata,
@ -3123,7 +3124,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'offset' => 5,
'sort' => 'shortname ASC',
'expectedcourses' => ['cfuture', 'dfuture', 'efuture'],
'expectednextoffset' => 15
'expectednextoffset' => 15,
],
'all no limit or offset' => [
'coursedata' => $coursedata,
@ -3148,7 +3149,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'einprogress',
'epast'
],
'expectednextoffset' => 15
'expectednextoffset' => 15,
],
'all limit no offset' => [
'coursedata' => $coursedata,
@ -3163,7 +3164,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'bfuture',
'binprogress'
],
'expectednextoffset' => 5
'expectednextoffset' => 5,
],
'all limit and offset' => [
'coursedata' => $coursedata,
@ -3178,7 +3179,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'cpast',
'dfuture'
],
'expectednextoffset' => 10
'expectednextoffset' => 10,
],
'all offset past result set' => [
'coursedata' => $coursedata,
@ -3187,7 +3188,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'offset' => 50,
'sort' => 'shortname ASC',
'expectedcourses' => [],
'expectednextoffset' => 50
'expectednextoffset' => 50,
],
'all limit and offset with sort ul.timeaccess desc' => [
'coursedata' => $coursedata,
@ -3202,7 +3203,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'dinprogress',
'einprogress'
],
'expectednextoffset' => 15
'expectednextoffset' => 15,
],
'all limit and offset with sort sql injection for sort or 1==1' => [
'coursedata' => $coursedata,
@ -3212,7 +3213,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'sort' => 'ul.timeaccess desc or 1==1',
'expectedcourses' => [],
'expectednextoffset' => 0,
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()',
],
'all limit and offset with sql injection of sort a custom one' => [
'coursedata' => $coursedata,
@ -3222,7 +3223,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'sort' => "ul.timeaccess LIMIT 1--",
'expectedcourses' => [],
'expectednextoffset' => 0,
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()',
],
'all limit and offset with wrong sort direction' => [
'coursedata' => $coursedata,
@ -3232,7 +3233,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'sort' => "ul.timeaccess abcdasc",
'expectedcourses' => [],
'expectednextoffset' => 0,
'expectedexception' => 'Invalid sort direction in $sort parameter in enrol_get_my_courses()'
'expectedexception' => 'Invalid sort direction in $sort parameter in enrol_get_my_courses()',
],
'all limit and offset with wrong sort direction' => [
'coursedata' => $coursedata,
@ -3242,7 +3243,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'sort' => "ul.timeaccess.foo ascd",
'expectedcourses' => [],
'expectednextoffset' => 0,
'expectedexception' => 'Invalid sort direction in $sort parameter in enrol_get_my_courses()'
'expectedexception' => 'Invalid sort direction in $sort parameter in enrol_get_my_courses()',
],
'all limit and offset with wrong sort param' => [
'coursedata' => $coursedata,
@ -3252,7 +3253,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'sort' => "foobar",
'expectedcourses' => [],
'expectednextoffset' => 0,
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()',
],
'all limit and offset with wrong field name' => [
'coursedata' => $coursedata,
@ -3262,7 +3263,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'sort' => "ul.foobar",
'expectedcourses' => [],
'expectednextoffset' => 0,
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()',
],
'all limit and offset with wrong field separator' => [
'coursedata' => $coursedata,
@ -3272,7 +3273,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'sort' => "ul.timeaccess.foo",
'expectedcourses' => [],
'expectednextoffset' => 0,
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()',
],
'all limit and offset with wrong field separator #' => [
'coursedata' => $coursedata,
@ -3282,7 +3283,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'sort' => "ul#timeaccess",
'expectedcourses' => [],
'expectednextoffset' => 0,
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()',
],
'all limit and offset with wrong field separator $' => [
'coursedata' => $coursedata,
@ -3292,7 +3293,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'sort' => 'ul$timeaccess',
'expectedcourses' => [],
'expectednextoffset' => 0,
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()',
],
'all limit and offset with wrong field name' => [
'coursedata' => $coursedata,
@ -3302,7 +3303,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'sort' => 'timeaccess123',
'expectedcourses' => [],
'expectednextoffset' => 0,
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()',
],
'all limit and offset with no sort direction for ul' => [
'coursedata' => $coursedata,
@ -3340,6 +3341,50 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'expectedcourses' => ['bpast', 'cpast', 'dfuture', 'dpast', 'efuture'],
'expectednextoffset' => 10,
],
'Search courses for courses containing bfut' => [
'coursedata' => $coursedata,
'classification' => 'search',
'limit' => 0,
'offset' => 0,
'sort' => null,
'expectedcourses' => ['bfuture'],
'expectednextoffset' => 1,
'expectedexception' => null,
'searchvalue' => 'bfut',
],
'Search courses for courses containing inp' => [
'coursedata' => $coursedata,
'classification' => 'search',
'limit' => 0,
'offset' => 0,
'sort' => null,
'expectedcourses' => ['ainprogress', 'binprogress', 'cinprogress', 'dinprogress', 'einprogress'],
'expectednextoffset' => 5,
'expectedexception' => null,
'searchvalue' => 'inp',
],
'Search courses for courses containing fail' => [
'coursedata' => $coursedata,
'classification' => 'search',
'limit' => 0,
'offset' => 0,
'sort' => null,
'expectedcourses' => [],
'expectednextoffset' => 0,
'expectedexception' => null,
'searchvalue' => 'fail',
],
'Search courses for courses containing !`~[]C' => [
'coursedata' => $coursedata,
'classification' => 'search',
'limit' => 0,
'offset' => 0,
'sort' => null,
'expectedcourses' => [],
'expectednextoffset' => 0,
'expectedexception' => null,
'searchvalue' => '!`~[]C',
],
];
}
@ -3355,6 +3400,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
* @param array $expectedcourses Expected courses in result
* @param int $expectednextoffset Expected next offset value in result
* @param string|null $expectedexception Expected exception string
* @param string|null $searchvalue If we are searching, what do we need to look for?
*/
public function test_get_enrolled_courses_by_timeline_classification(
$coursedata,
@ -3364,7 +3410,8 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
$sort,
$expectedcourses,
$expectednextoffset,
$expectedexception = null
$expectedexception = null,
$searchvalue = null
) {
$this->resetAfterTest();
$generator = $this->getDataGenerator();
@ -3394,7 +3441,10 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
$classification,
$limit,
$offset,
$sort
$sort,
null,
null,
$searchvalue
);
$result = external_api::clean_returnvalue(
core_course_external::get_enrolled_courses_by_timeline_classification_returns(),

View File

@ -54,6 +54,8 @@ course formats don't have their own renderer.
available inside event observers via `$event->get_record_snapshot`
* New include_course_editor() function to include and configure course editor modules.
* New core_course_drawer() function to render the message drawer in the top of the body of each page.
* New course_get_enrolled_courses_for_logged_in_user_from_search which hooks in with external\get_enrolled_courses_by_timeline_classification
given COURSE_TIMELINE_SEARCH is set then get_enrolled_courses_by_timeline_classification will deviate to use a string search of enrolled courses.
=== 3.11 ===
* A new callback xxx_coursemodule_definition_after_data that allows plugins to extend activity forms after the data is set.