From 75adff5d73a4200fa0e360f1b95c274dac27d478 Mon Sep 17 00:00:00 2001 From: Jan Britz Date: Tue, 6 Feb 2024 12:55:37 +0100 Subject: [PATCH] feat: add sorting for search container --- .../package_search/components/sort.min.js | 3 ++ .../package_search/components/sort.min.js.map | 1 + .../components/tab_content.min.js | 2 +- .../components/tab_content.min.js.map | 2 +- amd/build/package_search/mutations.min.js | 2 +- amd/build/package_search/mutations.min.js.map | 2 +- amd/build/package_search/reactive.min.js | 2 +- amd/build/package_search/reactive.min.js.map | 2 +- amd/src/package_search/components/sort.js | 50 +++++++++++++++++++ .../package_search/components/tab_content.js | 12 +++++ amd/src/package_search/mutations.js | 21 ++++++-- amd/src/package_search/reactive.js | 7 +-- edit_questionpy_form.php | 2 +- lang/en/qtype_questionpy.php | 3 ++ templates/package_search/area.mustache | 3 ++ templates/package_search/sort.mustache | 33 ++++++++++++ 16 files changed, 133 insertions(+), 14 deletions(-) create mode 100644 amd/build/package_search/components/sort.min.js create mode 100644 amd/build/package_search/components/sort.min.js.map create mode 100644 amd/src/package_search/components/sort.js create mode 100644 templates/package_search/sort.mustache diff --git a/amd/build/package_search/components/sort.min.js b/amd/build/package_search/components/sort.min.js new file mode 100644 index 00000000..c2844db1 --- /dev/null +++ b/amd/build/package_search/components/sort.min.js @@ -0,0 +1,3 @@ +define("qtype_questionpy/package_search/components/sort",["exports","qtype_questionpy/package_search/component"],(function(_exports,_component){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_component=(obj=_component)&&obj.__esModule?obj:{default:obj};class _default extends _component.default{getWatchers(){return[{watch:"general.sorting:updated",handler:this.switchSortSelection}]}async stateReady(){this.addEventListener(this.element,"change",this.changeSort)}changeSort(event){const dataset=event.target.options[event.target.selectedIndex].dataset;this.reactive.dispatch("changeSort",dataset.sort,dataset.order)}switchSortSelection(){const{sort:sort,order:order}=this.reactive.stateManager.state.general.sorting;this.getElement('[data-sort="'.concat(sort,'"][data-order="').concat(order,'"]')).selected=!0}}return _exports.default=_default,_exports.default})); + +//# sourceMappingURL=sort.min.js.map \ No newline at end of file diff --git a/amd/build/package_search/components/sort.min.js.map b/amd/build/package_search/components/sort.min.js.map new file mode 100644 index 00000000..eaabbc64 --- /dev/null +++ b/amd/build/package_search/components/sort.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"sort.min.js","sources":["../../../src/package_search/components/sort.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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/**\n * @module qtype_questionpy/package_search/components/sort\n */\n\nimport Component from 'qtype_questionpy/package_search/component';\n\nexport default class extends Component {\n getWatchers() {\n return [\n {watch: \"general.sorting:updated\", handler: this.switchSortSelection},\n ];\n }\n\n async stateReady() {\n this.addEventListener(this.element, \"change\", this.changeSort);\n }\n\n /**\n * Dispatches mutation that retrieves packages with a new sort order.\n *\n * @param {Event} event\n */\n changeSort(event) {\n // Get `sort` and `order` by accessing the dataset of the selected options-element.\n const dataset = event.target.options[event.target.selectedIndex].dataset;\n this.reactive.dispatch(\"changeSort\", dataset.sort, dataset.order);\n }\n\n switchSortSelection() {\n const {sort, order} = this.reactive.stateManager.state.general.sorting;\n this.getElement(`[data-sort=\"${sort}\"][data-order=\"${order}\"]`).selected = true;\n }\n}\n"],"names":["Component","getWatchers","watch","handler","this","switchSortSelection","addEventListener","element","changeSort","event","dataset","target","options","selectedIndex","reactive","dispatch","sort","order","stateManager","state","general","sorting","getElement","selected"],"mappings":"6TAuB6BA,mBACzBC,oBACW,CACH,CAACC,MAAO,0BAA2BC,QAASC,KAAKC,8CAKhDC,iBAAiBF,KAAKG,QAAS,SAAUH,KAAKI,YAQvDA,WAAWC,aAEDC,QAAUD,MAAME,OAAOC,QAAQH,MAAME,OAAOE,eAAeH,aAC5DI,SAASC,SAAS,aAAcL,QAAQM,KAAMN,QAAQO,OAG/DZ,4BACUW,KAACA,KAADC,MAAOA,OAASb,KAAKU,SAASI,aAAaC,MAAMC,QAAQC,aAC1DC,iCAA0BN,+BAAsBC,aAAWM,UAAW"} \ No newline at end of file diff --git a/amd/build/package_search/components/tab_content.min.js b/amd/build/package_search/components/tab_content.min.js index 44e63a0b..0f0fae4e 100644 --- a/amd/build/package_search/components/tab_content.min.js +++ b/amd/build/package_search/components/tab_content.min.js @@ -1,3 +1,3 @@ -define("qtype_questionpy/package_search/components/tab_content",["exports","core/templates","core/notification","qtype_questionpy/package_search/component","qtype_questionpy/package_search/components/pagination"],(function(_exports,templates,_notification,_component,_pagination){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,templates=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(templates),_notification=_interopRequireDefault(_notification),_component=_interopRequireDefault(_component),_pagination=_interopRequireDefault(_pagination);class _default extends _component.default{getWatchers(){return[{watch:"".concat(this.category,":updated"),handler:this.render}]}async create(descriptor){this.category=descriptor.category,this.selectors={CONTENT:".qpy-tab-content",PAGINATION:'[data-for="pagination"]'},new _pagination.default({element:this.getElement(this.selectors.PAGINATION),name:"pagiation_".concat(this.category),reactive:descriptor.reactive,category:this.category})}_getPackageTemplatesPromise(contexts){let promises=[];for(const context of contexts){const promise=templates.renderForPromise("qtype_questionpy/package/package_selection",context);promises.push(promise)}return Promise.all(promises)}async render(){try{const state=this.getState()[this.category],packageTemplates=await this._getPackageTemplatesPromise(state.data.packages),element=this.getElement(this.selectors.CONTENT);element.innerHTML="";for(const{html:html,js:js}of packageTemplates)templates.appendNodeContents(element,html,js)}catch(exception){await _notification.default.exception(exception)}}}return _exports.default=_default,_exports.default})); +define("qtype_questionpy/package_search/components/tab_content",["exports","core/templates","core/notification","qtype_questionpy/package_search/component","qtype_questionpy/package_search/components/pagination","qtype_questionpy/package_search/components/sort"],(function(_exports,templates,_notification,_component,_pagination,_sort){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,templates=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(templates),_notification=_interopRequireDefault(_notification),_component=_interopRequireDefault(_component),_pagination=_interopRequireDefault(_pagination),_sort=_interopRequireDefault(_sort);class _default extends _component.default{getWatchers(){return[{watch:"".concat(this.category,":updated"),handler:this.render}]}async create(descriptor){this.category=descriptor.category,this.selectors={CONTENT:".qpy-tab-content",SORT:'[data-for="sort"]',PAGINATION:'[data-for="pagination"]'};const sortElement=this.getElement(this.selectors.SORT);sortElement&&new _sort.default({element:sortElement,name:"sort_".concat(this.category),reactive:descriptor.reactive}),new _pagination.default({element:this.getElement(this.selectors.PAGINATION),name:"pagiation_".concat(this.category),reactive:descriptor.reactive,category:this.category})}_getPackageTemplatesPromise(contexts){let promises=[];for(const context of contexts){const promise=templates.renderForPromise("qtype_questionpy/package/package_selection",context);promises.push(promise)}return Promise.all(promises)}async render(){try{const state=this.getState()[this.category],packageTemplates=await this._getPackageTemplatesPromise(state.data.packages),element=this.getElement(this.selectors.CONTENT);element.innerHTML="";for(const{html:html,js:js}of packageTemplates)templates.appendNodeContents(element,html,js)}catch(exception){await _notification.default.exception(exception)}}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=tab_content.min.js.map \ No newline at end of file diff --git a/amd/build/package_search/components/tab_content.min.js.map b/amd/build/package_search/components/tab_content.min.js.map index b6f49ab7..094e8694 100644 --- a/amd/build/package_search/components/tab_content.min.js.map +++ b/amd/build/package_search/components/tab_content.min.js.map @@ -1 +1 @@ -{"version":3,"file":"tab_content.min.js","sources":["../../../src/package_search/components/tab_content.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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/**\n * @module qtype_questionpy/package_search/components/tab_content\n */\n\nimport * as templates from 'core/templates';\nimport Notification from 'core/notification';\nimport Component from 'qtype_questionpy/package_search/component';\nimport Pagination from 'qtype_questionpy/package_search/components/pagination';\n\nexport default class extends Component {\n getWatchers() {\n return [\n {watch: `${this.category}:updated`, handler: this.render},\n ];\n }\n\n async create(descriptor) {\n this.category = descriptor.category;\n this.selectors = {\n CONTENT: \".qpy-tab-content\",\n PAGINATION: '[data-for=\"pagination\"]',\n };\n\n // Register pagination.\n new Pagination({\n element: this.getElement(this.selectors.PAGINATION),\n name: `pagiation_${this.category}`,\n reactive: descriptor.reactive,\n category: this.category,\n });\n }\n\n /**\n * Groups render promises for package templates.\n *\n * @param {Object[]} contexts\n * @returns {Promise}\n * @private\n */\n _getPackageTemplatesPromise(contexts) {\n let promises = [];\n for (const context of contexts) {\n const promise = templates.renderForPromise(\"qtype_questionpy/package/package_selection\", context);\n promises.push(promise);\n }\n return Promise.all(promises);\n }\n\n /**\n * Renders every package inside the current state.\n */\n async render() {\n try {\n const state = this.getState()[this.category];\n const packageTemplates = await this._getPackageTemplatesPromise(state.data.packages);\n const element = this.getElement(this.selectors.CONTENT);\n element.innerHTML = \"\";\n for (const {html, js} of packageTemplates) {\n templates.appendNodeContents(element, html, js);\n }\n } catch (exception) {\n await Notification.exception(exception);\n }\n }\n}\n"],"names":["Component","getWatchers","watch","this","category","handler","render","descriptor","selectors","CONTENT","PAGINATION","Pagination","element","getElement","name","reactive","_getPackageTemplatesPromise","contexts","promises","context","promise","templates","renderForPromise","push","Promise","all","state","getState","packageTemplates","data","packages","innerHTML","html","js","appendNodeContents","exception","Notification"],"mappings":"whDA0B6BA,mBACzBC,oBACW,CACH,CAACC,gBAAUC,KAAKC,qBAAoBC,QAASF,KAAKG,sBAI7CC,iBACJH,SAAWG,WAAWH,cACtBI,UAAY,CACbC,QAAS,mBACTC,WAAY,+BAIZC,oBAAW,CACXC,QAAST,KAAKU,WAAWV,KAAKK,UAAUE,YACxCI,yBAAmBX,KAAKC,UACxBW,SAAUR,WAAWQ,SACrBX,SAAUD,KAAKC,WAWvBY,4BAA4BC,cACpBC,SAAW,OACV,MAAMC,WAAWF,SAAU,OACtBG,QAAUC,UAAUC,iBAAiB,6CAA8CH,SACzFD,SAASK,KAAKH,gBAEXI,QAAQC,IAAIP,mCAQTQ,MAAQvB,KAAKwB,WAAWxB,KAAKC,UAC7BwB,uBAAyBzB,KAAKa,4BAA4BU,MAAMG,KAAKC,UACrElB,QAAUT,KAAKU,WAAWV,KAAKK,UAAUC,SAC/CG,QAAQmB,UAAY,OACf,MAAMC,KAACA,KAADC,GAAOA,MAAOL,iBACrBP,UAAUa,mBAAmBtB,QAASoB,KAAMC,IAElD,MAAOE,iBACCC,sBAAaD,UAAUA"} \ No newline at end of file +{"version":3,"file":"tab_content.min.js","sources":["../../../src/package_search/components/tab_content.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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/**\n * @module qtype_questionpy/package_search/components/tab_content\n */\n\nimport * as templates from 'core/templates';\nimport Notification from 'core/notification';\nimport Component from 'qtype_questionpy/package_search/component';\nimport Pagination from 'qtype_questionpy/package_search/components/pagination';\nimport Sort from 'qtype_questionpy/package_search/components/sort';\n\nexport default class extends Component {\n getWatchers() {\n return [\n {watch: `${this.category}:updated`, handler: this.render},\n ];\n }\n\n async create(descriptor) {\n this.category = descriptor.category;\n this.selectors = {\n CONTENT: \".qpy-tab-content\",\n SORT: '[data-for=\"sort\"]',\n PAGINATION: '[data-for=\"pagination\"]',\n };\n\n // Register sort if available.\n const sortElement = this.getElement(this.selectors.SORT);\n if (sortElement) {\n new Sort({\n element: sortElement,\n name: `sort_${this.category}`,\n reactive: descriptor.reactive,\n });\n }\n\n // Register pagination.\n new Pagination({\n element: this.getElement(this.selectors.PAGINATION),\n name: `pagiation_${this.category}`,\n reactive: descriptor.reactive,\n category: this.category,\n });\n }\n\n /**\n * Groups render promises for package templates.\n *\n * @param {Object[]} contexts\n * @returns {Promise}\n * @private\n */\n _getPackageTemplatesPromise(contexts) {\n let promises = [];\n for (const context of contexts) {\n const promise = templates.renderForPromise(\"qtype_questionpy/package/package_selection\", context);\n promises.push(promise);\n }\n return Promise.all(promises);\n }\n\n /**\n * Renders every package inside the current state.\n */\n async render() {\n try {\n const state = this.getState()[this.category];\n const packageTemplates = await this._getPackageTemplatesPromise(state.data.packages);\n const element = this.getElement(this.selectors.CONTENT);\n element.innerHTML = \"\";\n for (const {html, js} of packageTemplates) {\n templates.appendNodeContents(element, html, js);\n }\n } catch (exception) {\n await Notification.exception(exception);\n }\n }\n}\n"],"names":["Component","getWatchers","watch","this","category","handler","render","descriptor","selectors","CONTENT","SORT","PAGINATION","sortElement","getElement","Sort","element","name","reactive","Pagination","_getPackageTemplatesPromise","contexts","promises","context","promise","templates","renderForPromise","push","Promise","all","state","getState","packageTemplates","data","packages","innerHTML","html","js","appendNodeContents","exception","Notification"],"mappings":"onDA2B6BA,mBACzBC,oBACW,CACH,CAACC,gBAAUC,KAAKC,qBAAoBC,QAASF,KAAKG,sBAI7CC,iBACJH,SAAWG,WAAWH,cACtBI,UAAY,CACbC,QAAS,mBACTC,KAAM,oBACNC,WAAY,iCAIVC,YAAcT,KAAKU,WAAWV,KAAKK,UAAUE,MAC/CE,iBACIE,cAAK,CACLC,QAASH,YACTI,oBAAcb,KAAKC,UACnBa,SAAUV,WAAWU,eAKzBC,oBAAW,CACXH,QAASZ,KAAKU,WAAWV,KAAKK,UAAUG,YACxCK,yBAAmBb,KAAKC,UACxBa,SAAUV,WAAWU,SACrBb,SAAUD,KAAKC,WAWvBe,4BAA4BC,cACpBC,SAAW,OACV,MAAMC,WAAWF,SAAU,OACtBG,QAAUC,UAAUC,iBAAiB,6CAA8CH,SACzFD,SAASK,KAAKH,gBAEXI,QAAQC,IAAIP,mCAQTQ,MAAQ1B,KAAK2B,WAAW3B,KAAKC,UAC7B2B,uBAAyB5B,KAAKgB,4BAA4BU,MAAMG,KAAKC,UACrElB,QAAUZ,KAAKU,WAAWV,KAAKK,UAAUC,SAC/CM,QAAQmB,UAAY,OACf,MAAMC,KAACA,KAADC,GAAOA,MAAOL,iBACrBP,UAAUa,mBAAmBtB,QAASoB,KAAMC,IAElD,MAAOE,iBACCC,sBAAaD,UAAUA"} \ No newline at end of file diff --git a/amd/build/package_search/mutations.min.js b/amd/build/package_search/mutations.min.js index 9c4bbd99..f8325580 100644 --- a/amd/build/package_search/mutations.min.js +++ b/amd/build/package_search/mutations.min.js @@ -1,3 +1,3 @@ -define("qtype_questionpy/package_search/mutations",["exports","core/ajax","core/notification"],(function(_exports,_ajax,_notification){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification);return _exports.default=class{constructor(options){this.options=options}_getSearchPackagesInCategoriesPromise(state,page,categories){const methods=[];for(const category of categories){const method={methodname:"qtype_questionpy_search_packages",args:{query:state.general.query,tags:state.general.tags,category:category,sort:state.general.sort,order:state.general.order,limit:this.options.limit,page:"number"==typeof page?page:state[category].page,contextid:this.options.contextid}};methods.push(method)}return _ajax.default.call(methods)}async searchPackages(stateManager){let args=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,categories=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const state=stateManager.state;args=args||{},categories=categories||["all","recentlyused","favourites","mine"],stateManager.setReadOnly(!1),state.general.loading=!0,state.general.query="string"==typeof args.query?args.query:state.general.query,state.general.tags=[],state.general.sort=args.sort||state.general.sort,state.general.order=args.order||state.general.order,stateManager.setReadOnly(!0);try{let results=await this._getSearchPackagesInCategoriesPromise(state,args.page,categories);stateManager.setReadOnly(!1);for(const[index,category]of categories.entries())state[category].data=await results[index],"number"==typeof args.page&&(state[category].page=args.page);state.general.loading=!1,stateManager.setReadOnly(!0)}catch(exception){await _notification.default.exception(exception)}}async searchPackagesByQuery(stateManager,query){await this.searchPackages(stateManager,{page:0,query:query})}async changePage(stateManager,category,page){await this.searchPackages(stateManager,{page:page},[category])}},_exports.default})); +define("qtype_questionpy/package_search/mutations",["exports","core/ajax","core/notification"],(function(_exports,_ajax,_notification){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification);return _exports.default=class{constructor(options){this.options=options}_getSearchPackagesInCategoriesPromise(state,page,categories){const methods=[];for(const category of categories){const method={methodname:"qtype_questionpy_search_packages",args:{query:state.general.query,tags:state.general.tags,category:category,sort:state.general.sorting.sort,order:state.general.sorting.order,limit:this.options.limit,page:"number"==typeof page?page:state[category].page,contextid:this.options.contextid}};methods.push(method)}return _ajax.default.call(methods)}async searchPackages(stateManager){let args=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,categories=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const state=stateManager.state;args=args||{},categories=categories||["all","recentlyused","favourites","mine"],stateManager.setReadOnly(!1),state.general.loading=!0,state.general.query="string"==typeof args.query?args.query:state.general.query,state.general.tags=[],state.general.sorting={sort:args.sort||state.general.sorting.sort,order:args.order||state.general.sorting.order},stateManager.setReadOnly(!0);try{let results=await this._getSearchPackagesInCategoriesPromise(state,args.page,categories);stateManager.setReadOnly(!1);for(const[index,category]of categories.entries())state[category].data=await results[index],"number"==typeof args.page&&(state[category].page=args.page);state.general.loading=!1,stateManager.setReadOnly(!0)}catch(exception){await _notification.default.exception(exception)}}async searchPackagesByQuery(stateManager,query){await this.searchPackages(stateManager,{page:0,query:query})}async changePage(stateManager,category,page){await this.searchPackages(stateManager,{page:page},[category])}async changeSort(stateManager,sort,order){await this.searchPackages(stateManager,{sort:sort,order:order},["all","favourites","mine"])}},_exports.default})); //# sourceMappingURL=mutations.min.js.map \ No newline at end of file diff --git a/amd/build/package_search/mutations.min.js.map b/amd/build/package_search/mutations.min.js.map index ee291a0e..6f11a6f3 100644 --- a/amd/build/package_search/mutations.min.js.map +++ b/amd/build/package_search/mutations.min.js.map @@ -1 +1 @@ -{"version":3,"file":"mutations.min.js","sources":["../../src/package_search/mutations.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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/**\n * @module qtype_questionpy/package_search/mutations\n */\n\nimport Ajax from 'core/ajax';\nimport Notification from 'core/notification';\n\nexport default class {\n /**\n * @param {{contextid: number, limit: number}} options\n */\n constructor(options) {\n this.options = options;\n }\n\n /**\n * Search through given categories.\n *\n * If no page is provided the current page will be used.\n *\n * @param {any} state\n * @param {number|null} page\n * @param {string[]} categories\n * @returns {any}\n * @private\n */\n _getSearchPackagesInCategoriesPromise(state, page, categories) {\n const methods = [];\n for (const category of categories) {\n const method = {\n methodname: \"qtype_questionpy_search_packages\",\n args: {\n query: state.general.query,\n tags: state.general.tags,\n category: category,\n sort: state.general.sort,\n order: state.general.order,\n limit: this.options.limit,\n page: (typeof page === \"number\") ? page : state[category].page,\n contextid: this.options.contextid,\n },\n };\n methods.push(method);\n }\n return Ajax.call(methods);\n }\n\n /**\n * Used to search packages.\n *\n * Missing arguments are taken from the current state.\n *\n * @param {StateManager} stateManager\n * @param {Object|null} args\n * @param {string[]|null} categories\n */\n async searchPackages(stateManager, args = null, categories = null) {\n const state = stateManager.state;\n\n // Missing arguments are taken from the current state.\n args = args || {};\n\n // Search through every category if no categories are provided.\n categories = categories || [\"all\", \"recentlyused\", \"favourites\", \"mine\"];\n\n // Update general data.\n stateManager.setReadOnly(false);\n state.general.loading = true;\n state.general.query = (typeof args.query === \"string\") ? args.query : state.general.query;\n state.general.tags = [];\n state.general.sort = args.sort || state.general.sort;\n state.general.order = args.order || state.general.order;\n stateManager.setReadOnly(true);\n\n try {\n // Get search results for each category.\n let results = await this._getSearchPackagesInCategoriesPromise(state, args.page, categories);\n\n stateManager.setReadOnly(false);\n // Update category specific data.\n for (const [index, category] of categories.entries()) {\n state[category].data = await results[index];\n if (typeof args.page === \"number\") {\n state[category].page = args.page;\n }\n }\n // Update loading status.\n state.general.loading = false;\n stateManager.setReadOnly(true);\n } catch (exception) {\n await Notification.exception(exception);\n }\n }\n\n /**\n * Used to search for packages only by providing a query.\n *\n * @param {StateManager} stateManager\n * @param {string} query\n */\n async searchPackagesByQuery(stateManager, query) {\n await this.searchPackages(stateManager, {page: 0, query: query});\n }\n\n /**\n * Used to change the current page of a tab.\n *\n * @param {StateManager} stateManager\n * @param {string} category\n * @param {number} page\n */\n async changePage(stateManager, category, page) {\n await this.searchPackages(stateManager, {page: page}, [category]);\n }\n}\n"],"names":["constructor","options","_getSearchPackagesInCategoriesPromise","state","page","categories","methods","category","method","methodname","args","query","general","tags","sort","order","limit","this","contextid","push","Ajax","call","stateManager","setReadOnly","loading","results","index","entries","data","exception","Notification","searchPackages"],"mappings":"+ZA4BIA,YAAYC,cACHA,QAAUA,QAcnBC,sCAAsCC,MAAOC,KAAMC,kBACzCC,QAAU,OACX,MAAMC,YAAYF,WAAY,OACzBG,OAAS,CACXC,WAAY,mCACZC,KAAM,CACFC,MAAOR,MAAMS,QAAQD,MACrBE,KAAMV,MAAMS,QAAQC,KACpBN,SAAUA,SACVO,KAAMX,MAAMS,QAAQE,KACpBC,MAAOZ,MAAMS,QAAQG,MACrBC,MAAOC,KAAKhB,QAAQe,MACpBZ,KAAuB,iBAATA,KAAqBA,KAAOD,MAAMI,UAAUH,KAC1Dc,UAAWD,KAAKhB,QAAQiB,YAGhCZ,QAAQa,KAAKX,eAEVY,cAAKC,KAAKf,8BAYAgB,kBAAcZ,4DAAO,KAAML,kEAAa,WACnDF,MAAQmB,aAAanB,MAG3BO,KAAOA,MAAQ,GAGfL,WAAaA,YAAc,CAAC,MAAO,eAAgB,aAAc,QAGjEiB,aAAaC,aAAY,GACzBpB,MAAMS,QAAQY,SAAU,EACxBrB,MAAMS,QAAQD,MAA+B,iBAAfD,KAAKC,MAAsBD,KAAKC,MAAQR,MAAMS,QAAQD,MACpFR,MAAMS,QAAQC,KAAO,GACrBV,MAAMS,QAAQE,KAAOJ,KAAKI,MAAQX,MAAMS,QAAQE,KAChDX,MAAMS,QAAQG,MAAQL,KAAKK,OAASZ,MAAMS,QAAQG,MAClDO,aAAaC,aAAY,WAIjBE,cAAgBR,KAAKf,sCAAsCC,MAAOO,KAAKN,KAAMC,YAEjFiB,aAAaC,aAAY,OAEpB,MAAOG,MAAOnB,YAAaF,WAAWsB,UACvCxB,MAAMI,UAAUqB,WAAaH,QAAQC,OACZ,iBAAdhB,KAAKN,OACZD,MAAMI,UAAUH,KAAOM,KAAKN,MAIpCD,MAAMS,QAAQY,SAAU,EACxBF,aAAaC,aAAY,GAC3B,MAAOM,iBACCC,sBAAaD,UAAUA,wCAUTP,aAAcX,aAChCM,KAAKc,eAAeT,aAAc,CAAClB,KAAM,EAAGO,MAAOA,yBAU5CW,aAAcf,SAAUH,YAC/Ba,KAAKc,eAAeT,aAAc,CAAClB,KAAMA,MAAO,CAACG"} \ No newline at end of file +{"version":3,"file":"mutations.min.js","sources":["../../src/package_search/mutations.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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/**\n * @module qtype_questionpy/package_search/mutations\n */\n\nimport Ajax from 'core/ajax';\nimport Notification from 'core/notification';\n\nexport default class {\n /**\n * @param {{contextid: number, limit: number}} options\n */\n constructor(options) {\n this.options = options;\n }\n\n /**\n * Search through given categories.\n *\n * If no page is provided the current page will be used.\n *\n * @param {any} state\n * @param {number|null} page\n * @param {string[]} categories\n * @returns {any}\n * @private\n */\n _getSearchPackagesInCategoriesPromise(state, page, categories) {\n const methods = [];\n for (const category of categories) {\n const method = {\n methodname: \"qtype_questionpy_search_packages\",\n args: {\n query: state.general.query,\n tags: state.general.tags,\n category: category,\n sort: state.general.sorting.sort,\n order: state.general.sorting.order,\n limit: this.options.limit,\n page: (typeof page === \"number\") ? page : state[category].page,\n contextid: this.options.contextid,\n },\n };\n methods.push(method);\n }\n return Ajax.call(methods);\n }\n\n /**\n * Used to search packages.\n *\n * Missing arguments are taken from the current state.\n *\n * @param {StateManager} stateManager\n * @param {Object|null} args\n * @param {string[]|null} categories\n */\n async searchPackages(stateManager, args = null, categories = null) {\n const state = stateManager.state;\n\n // Missing arguments are taken from the current state.\n args = args || {};\n\n // Search through every category if no categories are provided.\n categories = categories || [\"all\", \"recentlyused\", \"favourites\", \"mine\"];\n\n // Update general data.\n stateManager.setReadOnly(false);\n state.general.loading = true;\n state.general.query = (typeof args.query === \"string\") ? args.query : state.general.query;\n state.general.tags = [];\n state.general.sorting = {\n sort: args.sort || state.general.sorting.sort,\n order: args.order || state.general.sorting.order,\n };\n stateManager.setReadOnly(true);\n\n try {\n // Get search results for each category.\n let results = await this._getSearchPackagesInCategoriesPromise(state, args.page, categories);\n\n stateManager.setReadOnly(false);\n // Update category specific data.\n for (const [index, category] of categories.entries()) {\n state[category].data = await results[index];\n if (typeof args.page === \"number\") {\n state[category].page = args.page;\n }\n }\n // Update loading status.\n state.general.loading = false;\n stateManager.setReadOnly(true);\n } catch (exception) {\n await Notification.exception(exception);\n }\n }\n\n /**\n * Used to search for packages only by providing a query.\n *\n * @param {StateManager} stateManager\n * @param {string} query\n */\n async searchPackagesByQuery(stateManager, query) {\n await this.searchPackages(stateManager, {page: 0, query: query});\n }\n\n /**\n * Used to change the current page of a tab.\n *\n * @param {StateManager} stateManager\n * @param {string} category\n * @param {number} page\n */\n async changePage(stateManager, category, page) {\n await this.searchPackages(stateManager, {page: page}, [category]);\n }\n\n /**\n * Used to change the current sorting.\n *\n * @param {StateManager} stateManager\n * @param {string} sort\n * @param {string} order\n */\n async changeSort(stateManager, sort, order) {\n await this.searchPackages(stateManager, {sort: sort, order: order}, [\"all\", \"favourites\", \"mine\"]);\n }\n}\n"],"names":["constructor","options","_getSearchPackagesInCategoriesPromise","state","page","categories","methods","category","method","methodname","args","query","general","tags","sort","sorting","order","limit","this","contextid","push","Ajax","call","stateManager","setReadOnly","loading","results","index","entries","data","exception","Notification","searchPackages"],"mappings":"+ZA4BIA,YAAYC,cACHA,QAAUA,QAcnBC,sCAAsCC,MAAOC,KAAMC,kBACzCC,QAAU,OACX,MAAMC,YAAYF,WAAY,OACzBG,OAAS,CACXC,WAAY,mCACZC,KAAM,CACFC,MAAOR,MAAMS,QAAQD,MACrBE,KAAMV,MAAMS,QAAQC,KACpBN,SAAUA,SACVO,KAAMX,MAAMS,QAAQG,QAAQD,KAC5BE,MAAOb,MAAMS,QAAQG,QAAQC,MAC7BC,MAAOC,KAAKjB,QAAQgB,MACpBb,KAAuB,iBAATA,KAAqBA,KAAOD,MAAMI,UAAUH,KAC1De,UAAWD,KAAKjB,QAAQkB,YAGhCb,QAAQc,KAAKZ,eAEVa,cAAKC,KAAKhB,8BAYAiB,kBAAcb,4DAAO,KAAML,kEAAa,WACnDF,MAAQoB,aAAapB,MAG3BO,KAAOA,MAAQ,GAGfL,WAAaA,YAAc,CAAC,MAAO,eAAgB,aAAc,QAGjEkB,aAAaC,aAAY,GACzBrB,MAAMS,QAAQa,SAAU,EACxBtB,MAAMS,QAAQD,MAA+B,iBAAfD,KAAKC,MAAsBD,KAAKC,MAAQR,MAAMS,QAAQD,MACpFR,MAAMS,QAAQC,KAAO,GACrBV,MAAMS,QAAQG,QAAU,CACpBD,KAAMJ,KAAKI,MAAQX,MAAMS,QAAQG,QAAQD,KACzCE,MAAON,KAAKM,OAASb,MAAMS,QAAQG,QAAQC,OAE/CO,aAAaC,aAAY,WAIjBE,cAAgBR,KAAKhB,sCAAsCC,MAAOO,KAAKN,KAAMC,YAEjFkB,aAAaC,aAAY,OAEpB,MAAOG,MAAOpB,YAAaF,WAAWuB,UACvCzB,MAAMI,UAAUsB,WAAaH,QAAQC,OACZ,iBAAdjB,KAAKN,OACZD,MAAMI,UAAUH,KAAOM,KAAKN,MAIpCD,MAAMS,QAAQa,SAAU,EACxBF,aAAaC,aAAY,GAC3B,MAAOM,iBACCC,sBAAaD,UAAUA,wCAUTP,aAAcZ,aAChCO,KAAKc,eAAeT,aAAc,CAACnB,KAAM,EAAGO,MAAOA,yBAU5CY,aAAchB,SAAUH,YAC/Bc,KAAKc,eAAeT,aAAc,CAACnB,KAAMA,MAAO,CAACG,4BAU1CgB,aAAcT,KAAME,aAC3BE,KAAKc,eAAeT,aAAc,CAACT,KAAMA,KAAME,MAAOA,OAAQ,CAAC,MAAO,aAAc"} \ No newline at end of file diff --git a/amd/build/package_search/reactive.min.js b/amd/build/package_search/reactive.min.js index 0c71f3ec..681ed87a 100644 --- a/amd/build/package_search/reactive.min.js +++ b/amd/build/package_search/reactive.min.js @@ -1,3 +1,3 @@ -define("qtype_questionpy/package_search/reactive",["exports","core/reactive","qtype_questionpy/package_search/mutations","qtype_questionpy/package_search/events","qtype_questionpy/package_search/components/area"],(function(_exports,_reactive,_mutations,_events,_area){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_mutations=_interopRequireDefault(_mutations),_area=_interopRequireDefault(_area);let counter=0;class _default extends _reactive.Reactive{constructor(target,options){super({name:"PackageSearch".concat(counter++),eventName:_events.eventNames.stateChanged,eventDispatch:_events.notifyStateChanged,target:target,mutations:new _mutations.default(options),state:{general:{loading:!0,selected:"all",sort:"alpha",order:"asc",query:""},all:{data:{packages:[],count:0,total:0},page:0},recentlyused:{data:{packages:[],count:0,total:0},page:0},favourites:{data:{packages:[],count:0,total:0},page:0},mine:{data:{packages:[],count:0,total:0},page:0}}}),this.options=options}load(){new _area.default({element:this.target,name:"search_area",reactive:this})}}return _exports.default=_default,_exports.default})); +define("qtype_questionpy/package_search/reactive",["exports","core/reactive","qtype_questionpy/package_search/mutations","qtype_questionpy/package_search/events","qtype_questionpy/package_search/components/area"],(function(_exports,_reactive,_mutations,_events,_area){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_mutations=_interopRequireDefault(_mutations),_area=_interopRequireDefault(_area);let counter=0;class _default extends _reactive.Reactive{constructor(target,options){super({name:"PackageSearch".concat(counter++),eventName:_events.eventNames.stateChanged,eventDispatch:_events.notifyStateChanged,target:target,mutations:new _mutations.default(options),state:{general:{loading:!0,sorting:{sort:"alpha",order:"asc"},query:""},all:{data:{packages:[],count:0,total:0},page:0},recentlyused:{data:{packages:[],count:0,total:0},page:0},favourites:{data:{packages:[],count:0,total:0},page:0},mine:{data:{packages:[],count:0,total:0},page:0}}}),this.options=options}load(){new _area.default({element:this.target,name:"search_area",reactive:this})}}return _exports.default=_default,_exports.default})); //# sourceMappingURL=reactive.min.js.map \ No newline at end of file diff --git a/amd/build/package_search/reactive.min.js.map b/amd/build/package_search/reactive.min.js.map index ff49c85a..86575c2f 100644 --- a/amd/build/package_search/reactive.min.js.map +++ b/amd/build/package_search/reactive.min.js.map @@ -1 +1 @@ -{"version":3,"file":"reactive.min.js","sources":["../../src/package_search/reactive.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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/**\n * @module qtype_questionpy/package_search/reactive\n */\n\nimport {Reactive} from 'core/reactive';\n\nimport SearchMutations from 'qtype_questionpy/package_search/mutations';\nimport {eventNames, notifyStateChanged} from 'qtype_questionpy/package_search/events';\nimport Area from 'qtype_questionpy/package_search/components/area';\n\nlet counter = 0;\n\nexport default class extends Reactive {\n /**\n * Reactive element used for package search.\n *\n * @param {HTMLDivElement} target\n * @param {{contextid: number, limit: number}} options\n */\n constructor(target, options) {\n super({\n name: `PackageSearch${counter++}`,\n eventName: eventNames.stateChanged,\n eventDispatch: notifyStateChanged,\n target: target,\n mutations: new SearchMutations(options),\n state: {\n general: {\n loading: true,\n selected: \"all\",\n sort: \"alpha\",\n order: \"asc\",\n query: \"\",\n },\n all: {\n data: {\n packages: [],\n count: 0,\n total: 0,\n },\n page: 0,\n },\n recentlyused: {\n data: {\n packages: [],\n count: 0,\n total: 0,\n },\n page: 0,\n },\n favourites: {\n data: {\n packages: [],\n count: 0,\n total: 0,\n },\n page: 0,\n },\n mine: {\n data: {\n packages: [],\n count: 0,\n total: 0,\n },\n page: 0,\n },\n },\n });\n this.options = options;\n }\n\n /**\n * Loads every component of the package search area.\n */\n load() {\n new Area({\n element: this.target,\n name: \"search_area\",\n reactive: this\n });\n }\n}\n"],"names":["counter","Reactive","constructor","target","options","name","eventName","eventNames","stateChanged","eventDispatch","notifyStateChanged","mutations","SearchMutations","state","general","loading","selected","sort","order","query","all","data","packages","count","total","page","recentlyused","favourites","mine","load","Area","element","this","reactive"],"mappings":"ogBA2BIA,QAAU,yBAEeC,mBAOzBC,YAAYC,OAAQC,eACV,CACFC,4BAAsBL,WACtBM,UAAWC,mBAAWC,aACtBC,cAAeC,2BACfP,OAAQA,OACRQ,UAAW,IAAIC,mBAAgBR,SAC/BS,MAAO,CACHC,QAAS,CACLC,SAAS,EACTC,SAAU,MACVC,KAAM,QACNC,MAAO,MACPC,MAAO,IAEXC,IAAK,CACDC,KAAM,CACFC,SAAU,GACVC,MAAO,EACPC,MAAO,GAEXC,KAAM,GAEVC,aAAc,CACVL,KAAM,CACFC,SAAU,GACVC,MAAO,EACPC,MAAO,GAEXC,KAAM,GAEVE,WAAY,CACRN,KAAM,CACFC,SAAU,GACVC,MAAO,EACPC,MAAO,GAEXC,KAAM,GAEVG,KAAM,CACFP,KAAM,CACFC,SAAU,GACVC,MAAO,EACPC,MAAO,GAEXC,KAAM,WAIbrB,QAAUA,QAMnByB,WACQC,cAAK,CACLC,QAASC,KAAK7B,OACdE,KAAM,cACN4B,SAAUD"} \ No newline at end of file +{"version":3,"file":"reactive.min.js","sources":["../../src/package_search/reactive.js"],"sourcesContent":["/*\n * This file is part of the QuestionPy Moodle plugin - https://questionpy.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/**\n * @module qtype_questionpy/package_search/reactive\n */\n\nimport {Reactive} from 'core/reactive';\n\nimport SearchMutations from 'qtype_questionpy/package_search/mutations';\nimport {eventNames, notifyStateChanged} from 'qtype_questionpy/package_search/events';\nimport Area from 'qtype_questionpy/package_search/components/area';\n\nlet counter = 0;\n\nexport default class extends Reactive {\n /**\n * Reactive element used for package search.\n *\n * @param {HTMLDivElement} target\n * @param {{contextid: number, limit: number}} options\n */\n constructor(target, options) {\n super({\n name: `PackageSearch${counter++}`,\n eventName: eventNames.stateChanged,\n eventDispatch: notifyStateChanged,\n target: target,\n mutations: new SearchMutations(options),\n state: {\n general: {\n loading: true,\n sorting: {\n sort: \"alpha\",\n order: \"asc\",\n },\n query: \"\",\n },\n all: {\n data: {\n packages: [],\n count: 0,\n total: 0,\n },\n page: 0,\n },\n recentlyused: {\n data: {\n packages: [],\n count: 0,\n total: 0,\n },\n page: 0,\n },\n favourites: {\n data: {\n packages: [],\n count: 0,\n total: 0,\n },\n page: 0,\n },\n mine: {\n data: {\n packages: [],\n count: 0,\n total: 0,\n },\n page: 0,\n },\n },\n });\n this.options = options;\n }\n\n /**\n * Loads every component of the package search area.\n */\n load() {\n new Area({\n element: this.target,\n name: \"search_area\",\n reactive: this\n });\n }\n}\n"],"names":["counter","Reactive","constructor","target","options","name","eventName","eventNames","stateChanged","eventDispatch","notifyStateChanged","mutations","SearchMutations","state","general","loading","sorting","sort","order","query","all","data","packages","count","total","page","recentlyused","favourites","mine","load","Area","element","this","reactive"],"mappings":"ogBA2BIA,QAAU,yBAEeC,mBAOzBC,YAAYC,OAAQC,eACV,CACFC,4BAAsBL,WACtBM,UAAWC,mBAAWC,aACtBC,cAAeC,2BACfP,OAAQA,OACRQ,UAAW,IAAIC,mBAAgBR,SAC/BS,MAAO,CACHC,QAAS,CACLC,SAAS,EACTC,QAAS,CACPC,KAAM,QACNC,MAAO,OAETC,MAAO,IAEXC,IAAK,CACDC,KAAM,CACFC,SAAU,GACVC,MAAO,EACPC,MAAO,GAEXC,KAAM,GAEVC,aAAc,CACVL,KAAM,CACFC,SAAU,GACVC,MAAO,EACPC,MAAO,GAEXC,KAAM,GAEVE,WAAY,CACRN,KAAM,CACFC,SAAU,GACVC,MAAO,EACPC,MAAO,GAEXC,KAAM,GAEVG,KAAM,CACFP,KAAM,CACFC,SAAU,GACVC,MAAO,EACPC,MAAO,GAEXC,KAAM,WAIbrB,QAAUA,QAMnByB,WACQC,cAAK,CACLC,QAASC,KAAK7B,OACdE,KAAM,cACN4B,SAAUD"} \ No newline at end of file diff --git a/amd/src/package_search/components/sort.js b/amd/src/package_search/components/sort.js new file mode 100644 index 00000000..13920137 --- /dev/null +++ b/amd/src/package_search/components/sort.js @@ -0,0 +1,50 @@ +/* + * This file is part of the QuestionPy Moodle plugin - https://questionpy.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 . + */ + +/** + * @module qtype_questionpy/package_search/components/sort + */ + +import Component from 'qtype_questionpy/package_search/component'; + +export default class extends Component { + getWatchers() { + return [ + {watch: "general.sorting:updated", handler: this.switchSortSelection}, + ]; + } + + async stateReady() { + this.addEventListener(this.element, "change", this.changeSort); + } + + /** + * Dispatches mutation that retrieves packages with a new sort order. + * + * @param {Event} event + */ + changeSort(event) { + // Get `sort` and `order` by accessing the dataset of the selected options-element. + const dataset = event.target.options[event.target.selectedIndex].dataset; + this.reactive.dispatch("changeSort", dataset.sort, dataset.order); + } + + switchSortSelection() { + const {sort, order} = this.reactive.stateManager.state.general.sorting; + this.getElement(`[data-sort="${sort}"][data-order="${order}"]`).selected = true; + } +} diff --git a/amd/src/package_search/components/tab_content.js b/amd/src/package_search/components/tab_content.js index 03a6b526..92f0fe8a 100644 --- a/amd/src/package_search/components/tab_content.js +++ b/amd/src/package_search/components/tab_content.js @@ -23,6 +23,7 @@ import * as templates from 'core/templates'; import Notification from 'core/notification'; import Component from 'qtype_questionpy/package_search/component'; import Pagination from 'qtype_questionpy/package_search/components/pagination'; +import Sort from 'qtype_questionpy/package_search/components/sort'; export default class extends Component { getWatchers() { @@ -35,9 +36,20 @@ export default class extends Component { this.category = descriptor.category; this.selectors = { CONTENT: ".qpy-tab-content", + SORT: '[data-for="sort"]', PAGINATION: '[data-for="pagination"]', }; + // Register sort if available. + const sortElement = this.getElement(this.selectors.SORT); + if (sortElement) { + new Sort({ + element: sortElement, + name: `sort_${this.category}`, + reactive: descriptor.reactive, + }); + } + // Register pagination. new Pagination({ element: this.getElement(this.selectors.PAGINATION), diff --git a/amd/src/package_search/mutations.js b/amd/src/package_search/mutations.js index 85e8063e..907b47f1 100644 --- a/amd/src/package_search/mutations.js +++ b/amd/src/package_search/mutations.js @@ -50,8 +50,8 @@ export default class { query: state.general.query, tags: state.general.tags, category: category, - sort: state.general.sort, - order: state.general.order, + sort: state.general.sorting.sort, + order: state.general.sorting.order, limit: this.options.limit, page: (typeof page === "number") ? page : state[category].page, contextid: this.options.contextid, @@ -85,8 +85,10 @@ export default class { state.general.loading = true; state.general.query = (typeof args.query === "string") ? args.query : state.general.query; state.general.tags = []; - state.general.sort = args.sort || state.general.sort; - state.general.order = args.order || state.general.order; + state.general.sorting = { + sort: args.sort || state.general.sorting.sort, + order: args.order || state.general.sorting.order, + }; stateManager.setReadOnly(true); try { @@ -129,4 +131,15 @@ export default class { async changePage(stateManager, category, page) { await this.searchPackages(stateManager, {page: page}, [category]); } + + /** + * Used to change the current sorting. + * + * @param {StateManager} stateManager + * @param {string} sort + * @param {string} order + */ + async changeSort(stateManager, sort, order) { + await this.searchPackages(stateManager, {sort: sort, order: order}, ["all", "favourites", "mine"]); + } } diff --git a/amd/src/package_search/reactive.js b/amd/src/package_search/reactive.js index befbc626..a5242f21 100644 --- a/amd/src/package_search/reactive.js +++ b/amd/src/package_search/reactive.js @@ -44,9 +44,10 @@ export default class extends Reactive { state: { general: { loading: true, - selected: "all", - sort: "alpha", - order: "asc", + sorting: { + sort: "alpha", + order: "asc", + }, query: "", }, all: { diff --git a/edit_questionpy_form.php b/edit_questionpy_form.php index a74963c5..fe5bd170 100644 --- a/edit_questionpy_form.php +++ b/edit_questionpy_form.php @@ -55,7 +55,7 @@ protected function definition_package_selection(MoodleQuickForm $mform): void { // Create a group which contains the package container - the group is used to simplify the styling. // TODO: get limit from settings. $group[] = $mform->createElement('html', $OUTPUT->render_from_template('qtype_questionpy/package_search/area', - ['contextid' => $PAGE->context->id, 'limit' => 10])); + ['contextid' => $PAGE->context->id, 'limit' => 2])); $mform->addGroup($group, 'questionpy_package_container', get_string('selection_title', 'qtype_questionpy'), null, false); $mform->addRule( 'questionpy_package_container', diff --git a/lang/en/qtype_questionpy.php b/lang/en/qtype_questionpy.php index 35a1b2fb..4ba0c1a5 100644 --- a/lang/en/qtype_questionpy.php +++ b/lang/en/qtype_questionpy.php @@ -77,6 +77,9 @@ $string['search_pagination_label_aria'] = 'Search results pages'; $string['search_pagination_previous_aria'] = 'Previous'; $string['search_pagination_next_aria'] = 'Next'; +$string['search_sort_label_aria'] = 'Sorting'; +$string['search_sort_alphabetical'] = 'Alphabetical'; +$string['search_sort_creation_date'] = 'Creation Date'; // Question management. $string['package_not_found'] = 'The requested package {$a->packagehash} does not exist.'; diff --git a/templates/package_search/area.mustache b/templates/package_search/area.mustache index 10cbffde..3b0507f8 100644 --- a/templates/package_search/area.mustache +++ b/templates/package_search/area.mustache @@ -50,6 +50,7 @@
+ {{> qtype_questionpy/package_search/sort }}
{{> qtype_questionpy/package_search/pagination }}
@@ -58,10 +59,12 @@ {{> qtype_questionpy/package_search/pagination }}
+ {{> qtype_questionpy/package_search/sort }}
{{> qtype_questionpy/package_search/pagination }}
+ {{> qtype_questionpy/package_search/sort }}
{{> qtype_questionpy/package_search/pagination }}
diff --git a/templates/package_search/sort.mustache b/templates/package_search/sort.mustache new file mode 100644 index 00000000..93803a4d --- /dev/null +++ b/templates/package_search/sort.mustache @@ -0,0 +1,33 @@ +{{! + This file is part of the QuestionPy Moodle plugin - https://questionpy.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 . +}} +{{! + @template qtype_questionpy/package_search/sort + + Represents a sort section of a package container. + + Classes required for JS: + * qpy-sort + + Example context (json): + {} +}} +