From f7b84afe15873c50b79ab1c4470225c975668bcc Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Mon, 6 Apr 2020 11:14:40 +0800 Subject: [PATCH] MDL-68288 core_table: support pagination bar for dynamic tables --- lib/outputcomponents.php | 1 + lib/table/amd/build/dynamic.min.js | 2 +- lib/table/amd/build/dynamic.min.js.map | 2 +- .../amd/build/local/dynamic/repository.min.js | 2 +- .../build/local/dynamic/repository.min.js.map | 2 +- .../amd/build/local/dynamic/selectors.min.js | 2 +- .../build/local/dynamic/selectors.min.js.map | 2 +- lib/table/amd/src/dynamic.js | 41 +++++++++++++++++++ lib/table/amd/src/local/dynamic/repository.js | 6 +++ lib/table/amd/src/local/dynamic/selectors.js | 5 +++ lib/table/classes/external/dynamic/fetch.php | 34 +++++++++++++-- lib/tablelib.php | 17 +++++++- lib/templates/paging_bar.mustache | 16 ++++---- 13 files changed, 114 insertions(+), 18 deletions(-) diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php index fa9a76f5ed5..f33fda9995a 100644 --- a/lib/outputcomponents.php +++ b/lib/outputcomponents.php @@ -3085,6 +3085,7 @@ class paging_bar implements renderable, templatable { $data->label = get_string('page'); $data->pages = []; $data->haspages = $this->totalcount > $this->perpage; + $data->pagesize = $this->perpage; if (!$data->haspages) { return $data; diff --git a/lib/table/amd/build/dynamic.min.js b/lib/table/amd/build/dynamic.min.js index 2a30ca5dabc..26453f9a86e 100644 --- a/lib/table/amd/build/dynamic.min.js +++ b/lib/table/amd/build/dynamic.min.js @@ -1,2 +1,2 @@ -define ("core_table/dynamic",["exports","core_table/local/dynamic/repository","core_table/local/dynamic/selectors"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=a.setLastInitial=a.setFirstInitial=a.setSortOrder=a.setFilters=a.updateTable=a.refreshTableContent=void 0;c=function(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}(c);function d(a){return g(a)||f(a)||e()}function e(){throw new TypeError("Invalid attempt to spread non-iterable instance")}function f(a){if(Symbol.iterator in Object(a)||"[object Arguments]"===Object.prototype.toString.call(a))return Array.from(a)}function g(a){if(Array.isArray(a)){for(var b=0,c=Array(a.length);b.\n\n/**\n * Module to handle dynamic table features.\n *\n * @module core_table/dynamic\n * @package core_table\n * @copyright 2020 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport {fetch as fetchTableData} from 'core_table/local/dynamic/repository';\nimport * as Selectors from 'core_table/local/dynamic/selectors';\n\nlet watching = false;\n\n/**\n * Ensure that a table is a dynamic table.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Bool}\n */\nconst checkTableIsDynamic = tableRoot => {\n if (!tableRoot) {\n // The table is not a dynamic table.\n throw new Error(\"The table specified is not a dynamic table and cannot be updated\");\n }\n\n if (!tableRoot.matches(Selectors.main.region)) {\n // The table is not a dynamic table.\n throw new Error(\"The table specified is not a dynamic table and cannot be updated\");\n }\n\n return true;\n};\n\n/**\n * Get the filterset data from a known dynamic table.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Object}\n */\nconst getFiltersetFromTable = tableRoot => {\n return JSON.parse(tableRoot.dataset.tableFilters);\n};\n\n/**\n * Update the specified table based on its current values.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Promise}\n */\nexport const refreshTableContent = tableRoot => {\n const filterset = getFiltersetFromTable(tableRoot);\n\n return fetchTableData(\n tableRoot.dataset.tableHandler,\n tableRoot.dataset.tableUniqueid,\n {\n sortBy: tableRoot.dataset.tableSortBy,\n sortOrder: tableRoot.dataset.tableSortOrder,\n joinType: filterset.jointype,\n filters: filterset.filters,\n firstinitial: tableRoot.dataset.tableFirstInitial,\n lastinitial: tableRoot.dataset.tableLastInitial,\n }\n )\n .then(data => {\n const placeholder = document.createElement('div');\n placeholder.innerHTML = data.html;\n tableRoot.replaceWith(...placeholder.childNodes);\n\n return data;\n });\n};\n\nexport const updateTable = (tableRoot, {\n sortBy = null,\n sortOrder = null,\n filters = null,\n firstInitial = null,\n lastInitial = null,\n} = {}, refreshContent = true) => {\n checkTableIsDynamic(tableRoot);\n\n // Update sort fields.\n if (sortBy && sortOrder) {\n tableRoot.dataset.tableSortBy = sortBy;\n tableRoot.dataset.tableSortOrder = sortOrder;\n }\n\n // Update initials.\n if (firstInitial !== null) {\n tableRoot.dataset.tableFirstInitial = firstInitial;\n }\n\n if (lastInitial !== null) {\n tableRoot.dataset.tableLastInitial = lastInitial;\n }\n\n // Update filters.\n if (filters) {\n tableRoot.dataset.tableFilters = JSON.stringify(filters);\n }\n\n // Refresh.\n if (refreshContent) {\n return refreshTableContent(tableRoot);\n } else {\n return Promise.resolve();\n }\n};\n\n/**\n * Update the specified table using the new filters.\n *\n * @param {HTMLElement} tableRoot\n * @param {Object} filters\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setFilters = (tableRoot, filters, refreshContent = true) =>\n updateTable(tableRoot, {filters}, refreshContent);\n\n/**\n * Update the sort order.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} sortBy\n * @param {Number} sortOrder\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setSortOrder = (tableRoot, sortBy, sortOrder, refreshContent = true) =>\n updateTable(tableRoot, {sortBy, sortOrder}, refreshContent);\n\n/**\n * Update the first initial to show.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} firstInitial\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setFirstInitial = (tableRoot, firstInitial, refreshContent = true) =>\n updateTable(tableRoot, {firstInitial}, refreshContent);\n\n/**\n * Update the last initial to show.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} lastInitial\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setLastInitial = (tableRoot, lastInitial, refreshContent = true) =>\n updateTable(tableRoot, {lastInitial}, refreshContent);\n\n/**\n * Set up listeners to handle table updates.\n */\nexport const init = () => {\n if (watching) {\n // Already watching.\n return;\n }\n watching = true;\n\n document.addEventListener('click', e => {\n const tableRoot = e.target.closest(Selectors.main.region);\n\n if (!tableRoot) {\n return;\n }\n\n const sortableLink = e.target.closest(Selectors.table.links.sortableColumn);\n if (sortableLink) {\n e.preventDefault();\n\n setSortOrder(tableRoot, sortableLink.dataset.sortby, sortableLink.dataset.sortorder);\n }\n\n const firstInitialLink = e.target.closest(Selectors.initialsBar.links.firstInitial);\n if (firstInitialLink !== null) {\n e.preventDefault();\n\n setFirstInitial(tableRoot, firstInitialLink.dataset.initial);\n }\n\n const lastInitialLink = e.target.closest(Selectors.initialsBar.links.lastInitial);\n if (lastInitialLink !== null) {\n e.preventDefault();\n\n setLastInitial(tableRoot, lastInitialLink.dataset.initial);\n }\n });\n};\n"],"file":"dynamic.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/dynamic.js"],"names":["watching","checkTableIsDynamic","tableRoot","Error","matches","Selectors","main","region","getFiltersetFromTable","JSON","parse","dataset","tableFilters","refreshTableContent","filterset","tableHandler","tableUniqueid","sortBy","tableSortBy","sortOrder","tableSortOrder","joinType","jointype","filters","firstinitial","tableFirstInitial","lastinitial","tableLastInitial","pageNumber","tablePageNumber","pageSize","tablePageSize","then","data","placeholder","document","createElement","innerHTML","html","replaceWith","childNodes","updateTable","firstInitial","lastInitial","refreshContent","stringify","Promise","resolve","setFilters","setSortOrder","setPageNumber","setPageSize","setFirstInitial","setLastInitial","init","addEventListener","e","target","closest","sortableLink","table","links","sortableColumn","preventDefault","sortby","sortorder","firstInitialLink","initialsBar","initial","lastInitialLink","pageItem","paginationBar"],"mappings":"iVAwBA,kU,8VAEIA,CAAAA,CAAQ,G,CAQNC,CAAmB,CAAG,SAAAC,CAAS,CAAI,CACrC,GAAI,CAACA,CAAL,CAAgB,CAEZ,KAAM,IAAIC,CAAAA,KAAJ,CAAU,kEAAV,CACT,CAED,GAAI,CAACD,CAAS,CAACE,OAAV,CAAkBC,CAAS,CAACC,IAAV,CAAeC,MAAjC,CAAL,CAA+C,CAE3C,KAAM,IAAIJ,CAAAA,KAAJ,CAAU,kEAAV,CACT,CAED,QACH,C,CAQKK,CAAqB,CAAG,SAAAN,CAAS,CAAI,CACvC,MAAOO,CAAAA,IAAI,CAACC,KAAL,CAAWR,CAAS,CAACS,OAAV,CAAkBC,YAA7B,CACV,C,CAQYC,CAAmB,CAAG,SAAAX,CAAS,CAAI,CAC5C,GAAMY,CAAAA,CAAS,CAAGN,CAAqB,CAACN,CAAD,CAAvC,CAEA,MAAO,YACHA,CAAS,CAACS,OAAV,CAAkBI,YADf,CAEHb,CAAS,CAACS,OAAV,CAAkBK,aAFf,CAGH,CACIC,MAAM,CAAEf,CAAS,CAACS,OAAV,CAAkBO,WAD9B,CAEIC,SAAS,CAAEjB,CAAS,CAACS,OAAV,CAAkBS,cAFjC,CAGIC,QAAQ,CAAEP,CAAS,CAACQ,QAHxB,CAIIC,OAAO,CAAET,CAAS,CAACS,OAJvB,CAKIC,YAAY,CAAEtB,CAAS,CAACS,OAAV,CAAkBc,iBALpC,CAMIC,WAAW,CAAExB,CAAS,CAACS,OAAV,CAAkBgB,gBANnC,CAOIC,UAAU,CAAE1B,CAAS,CAACS,OAAV,CAAkBkB,eAPlC,CAQIC,QAAQ,CAAE5B,CAAS,CAACS,OAAV,CAAkBoB,aARhC,CAHG,EAcNC,IAdM,CAcD,SAAAC,CAAI,CAAI,CACV,GAAMC,CAAAA,CAAW,CAAGC,QAAQ,CAACC,aAAT,CAAuB,KAAvB,CAApB,CACAF,CAAW,CAACG,SAAZ,CAAwBJ,CAAI,CAACK,IAA7B,CACApC,CAAS,CAACqC,WAAV,OAAArC,CAAS,GAAgBgC,CAAW,CAACM,UAA5B,EAAT,CAEA,MAAOP,CAAAA,CACV,CApBM,CAqBV,C,yBAEM,GAAMQ,CAAAA,CAAW,CAAG,SAACvC,CAAD,CAQO,8DAA9B,EAA8B,KAP9Be,MAO8B,CAP9BA,CAO8B,YAPrB,IAOqB,OAN9BE,SAM8B,CAN9BA,CAM8B,YANlB,IAMkB,OAL9BI,OAK8B,CAL9BA,CAK8B,YALpB,IAKoB,OAJ9BmB,YAI8B,CAJ9BA,CAI8B,YAJf,IAIe,OAH9BC,WAG8B,CAH9BA,CAG8B,YAHhB,IAGgB,OAF9Bf,UAE8B,CAF9BA,CAE8B,YAFjB,IAEiB,OAD9BE,QAC8B,CAD9BA,CAC8B,YADnB,IACmB,GAA1Bc,CAA0B,2DAC9B3C,CAAmB,CAACC,CAAD,CAAnB,CAGA,GAAIe,CAAM,EAAIE,CAAd,CAAyB,CACrBjB,CAAS,CAACS,OAAV,CAAkBO,WAAlB,CAAgCD,CAAhC,CACAf,CAAS,CAACS,OAAV,CAAkBS,cAAlB,CAAmCD,CACtC,CAGD,GAAqB,IAAjB,GAAAuB,CAAJ,CAA2B,CACvBxC,CAAS,CAACS,OAAV,CAAkBc,iBAAlB,CAAsCiB,CACzC,CAED,GAAoB,IAAhB,GAAAC,CAAJ,CAA0B,CACtBzC,CAAS,CAACS,OAAV,CAAkBgB,gBAAlB,CAAqCgB,CACxC,CAED,GAAmB,IAAf,GAAAf,CAAJ,CAAyB,CACrB1B,CAAS,CAACS,OAAV,CAAkBkB,eAAlB,CAAoCD,CACvC,CAED,GAAiB,IAAb,GAAAE,CAAJ,CAAuB,CACnB5B,CAAS,CAACS,OAAV,CAAkBoB,aAAlB,CAAkCD,CACrC,CAGD,GAAIP,CAAJ,CAAa,CACTrB,CAAS,CAACS,OAAV,CAAkBC,YAAlB,CAAiCH,IAAI,CAACoC,SAAL,CAAetB,CAAf,CACpC,CAGD,GAAIqB,CAAJ,CAAoB,CAChB,MAAO/B,CAAAA,CAAmB,CAACX,CAAD,CAC7B,CAFD,IAEO,CACH,MAAO4C,CAAAA,OAAO,CAACC,OAAR,EACV,CACJ,CA7CM,C,6BAuDmB,QAAbC,CAAAA,UAAa,CAAC9C,CAAD,CAAYqB,CAAZ,KAAqBqB,CAAAA,CAArB,iEACtBH,CAAAA,CAAW,CAACvC,CAAD,CAAY,CAACqB,OAAO,CAAPA,CAAD,CAAZ,CAAuBqB,CAAvB,CADW,C,CAYnB,GAAMK,CAAAA,CAAY,CAAG,SAAC/C,CAAD,CAAYe,CAAZ,CAAoBE,CAApB,KAA+ByB,CAAAA,CAA/B,iEACxBH,CAAAA,CAAW,CAACvC,CAAD,CAAY,CAACe,MAAM,CAANA,CAAD,CAASE,SAAS,CAATA,CAAT,CAAZ,CAAiCyB,CAAjC,CADa,CAArB,C,iBAWA,GAAMM,CAAAA,CAAa,CAAG,SAAChD,CAAD,CAAY0B,CAAZ,KAAwBgB,CAAAA,CAAxB,iEACzBH,CAAAA,CAAW,CAACvC,CAAD,CAAY,CAAC0B,UAAU,CAAVA,CAAD,CAAZ,CAA0BgB,CAA1B,CADc,CAAtB,C,gCAWoB,QAAdO,CAAAA,WAAc,CAACjD,CAAD,CAAY4B,CAAZ,KAAsBc,CAAAA,CAAtB,iEACvBH,CAAAA,CAAW,CAACvC,CAAD,CAAY,CAAC4B,QAAQ,CAARA,CAAD,CAAWF,UAAU,CAAE,CAAvB,CAAZ,CAAuCgB,CAAvC,CADY,C,CAWpB,GAAMQ,CAAAA,CAAe,CAAG,SAAClD,CAAD,CAAYwC,CAAZ,KAA0BE,CAAAA,CAA1B,iEAC3BH,CAAAA,CAAW,CAACvC,CAAD,CAAY,CAACwC,YAAY,CAAZA,CAAD,CAAZ,CAA4BE,CAA5B,CADgB,CAAxB,C,oBAWA,GAAMS,CAAAA,CAAc,CAAG,SAACnD,CAAD,CAAYyC,CAAZ,KAAyBC,CAAAA,CAAzB,iEAC1BH,CAAAA,CAAW,CAACvC,CAAD,CAAY,CAACyC,WAAW,CAAXA,CAAD,CAAZ,CAA2BC,CAA3B,CADe,CAAvB,C,mBAMA,GAAMU,CAAAA,CAAI,CAAG,UAAM,CACtB,GAAItD,CAAJ,CAAc,CAEV,MACH,CACDA,CAAQ,GAAR,CAEAmC,QAAQ,CAACoB,gBAAT,CAA0B,OAA1B,CAAmC,SAAAC,CAAC,CAAI,CACpC,GAAMtD,CAAAA,CAAS,CAAGsD,CAAC,CAACC,MAAF,CAASC,OAAT,CAAiBrD,CAAS,CAACC,IAAV,CAAeC,MAAhC,CAAlB,CAEA,GAAI,CAACL,CAAL,CAAgB,CACZ,MACH,CAED,GAAMyD,CAAAA,CAAY,CAAGH,CAAC,CAACC,MAAF,CAASC,OAAT,CAAiBrD,CAAS,CAACuD,KAAV,CAAgBC,KAAhB,CAAsBC,cAAvC,CAArB,CACA,GAAIH,CAAJ,CAAkB,CACdH,CAAC,CAACO,cAAF,GAEAd,CAAY,CAAC/C,CAAD,CAAYyD,CAAY,CAAChD,OAAb,CAAqBqD,MAAjC,CAAyCL,CAAY,CAAChD,OAAb,CAAqBsD,SAA9D,CACf,CAED,GAAMC,CAAAA,CAAgB,CAAGV,CAAC,CAACC,MAAF,CAASC,OAAT,CAAiBrD,CAAS,CAAC8D,WAAV,CAAsBN,KAAtB,CAA4BnB,YAA7C,CAAzB,CACA,GAAyB,IAArB,GAAAwB,CAAJ,CAA+B,CAC3BV,CAAC,CAACO,cAAF,GAEAX,CAAe,CAAClD,CAAD,CAAYgE,CAAgB,CAACvD,OAAjB,CAAyByD,OAArC,CAClB,CAED,GAAMC,CAAAA,CAAe,CAAGb,CAAC,CAACC,MAAF,CAASC,OAAT,CAAiBrD,CAAS,CAAC8D,WAAV,CAAsBN,KAAtB,CAA4BlB,WAA7C,CAAxB,CACA,GAAwB,IAApB,GAAA0B,CAAJ,CAA8B,CAC1Bb,CAAC,CAACO,cAAF,GAEAV,CAAc,CAACnD,CAAD,CAAYmE,CAAe,CAAC1D,OAAhB,CAAwByD,OAApC,CACjB,CAED,GAAME,CAAAA,CAAQ,CAAGd,CAAC,CAACC,MAAF,CAASC,OAAT,CAAiBrD,CAAS,CAACkE,aAAV,CAAwBV,KAAxB,CAA8BS,QAA/C,CAAjB,CACA,GAAIA,CAAJ,CAAc,CACVd,CAAC,CAACO,cAAF,GAEAb,CAAa,CAAChD,CAAD,CAAYoE,CAAQ,CAAC3D,OAAT,CAAiBiB,UAA7B,CAChB,CACJ,CAlCD,CAmCH,CA1CM,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 .\n\n/**\n * Module to handle dynamic table features.\n *\n * @module core_table/dynamic\n * @package core_table\n * @copyright 2020 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport {fetch as fetchTableData} from 'core_table/local/dynamic/repository';\nimport * as Selectors from 'core_table/local/dynamic/selectors';\n\nlet watching = false;\n\n/**\n * Ensure that a table is a dynamic table.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Bool}\n */\nconst checkTableIsDynamic = tableRoot => {\n if (!tableRoot) {\n // The table is not a dynamic table.\n throw new Error(\"The table specified is not a dynamic table and cannot be updated\");\n }\n\n if (!tableRoot.matches(Selectors.main.region)) {\n // The table is not a dynamic table.\n throw new Error(\"The table specified is not a dynamic table and cannot be updated\");\n }\n\n return true;\n};\n\n/**\n * Get the filterset data from a known dynamic table.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Object}\n */\nconst getFiltersetFromTable = tableRoot => {\n return JSON.parse(tableRoot.dataset.tableFilters);\n};\n\n/**\n * Update the specified table based on its current values.\n *\n * @param {HTMLElement} tableRoot\n * @returns {Promise}\n */\nexport const refreshTableContent = tableRoot => {\n const filterset = getFiltersetFromTable(tableRoot);\n\n return fetchTableData(\n tableRoot.dataset.tableHandler,\n tableRoot.dataset.tableUniqueid,\n {\n sortBy: tableRoot.dataset.tableSortBy,\n sortOrder: tableRoot.dataset.tableSortOrder,\n joinType: filterset.jointype,\n filters: filterset.filters,\n firstinitial: tableRoot.dataset.tableFirstInitial,\n lastinitial: tableRoot.dataset.tableLastInitial,\n pageNumber: tableRoot.dataset.tablePageNumber,\n pageSize: tableRoot.dataset.tablePageSize,\n }\n )\n .then(data => {\n const placeholder = document.createElement('div');\n placeholder.innerHTML = data.html;\n tableRoot.replaceWith(...placeholder.childNodes);\n\n return data;\n });\n};\n\nexport const updateTable = (tableRoot, {\n sortBy = null,\n sortOrder = null,\n filters = null,\n firstInitial = null,\n lastInitial = null,\n pageNumber = null,\n pageSize = null,\n} = {}, refreshContent = true) => {\n checkTableIsDynamic(tableRoot);\n\n // Update sort fields.\n if (sortBy && sortOrder) {\n tableRoot.dataset.tableSortBy = sortBy;\n tableRoot.dataset.tableSortOrder = sortOrder;\n }\n\n // Update initials.\n if (firstInitial !== null) {\n tableRoot.dataset.tableFirstInitial = firstInitial;\n }\n\n if (lastInitial !== null) {\n tableRoot.dataset.tableLastInitial = lastInitial;\n }\n\n if (pageNumber !== null) {\n tableRoot.dataset.tablePageNumber = pageNumber;\n }\n\n if (pageSize !== null) {\n tableRoot.dataset.tablePageSize = pageSize;\n }\n\n // Update filters.\n if (filters) {\n tableRoot.dataset.tableFilters = JSON.stringify(filters);\n }\n\n // Refresh.\n if (refreshContent) {\n return refreshTableContent(tableRoot);\n } else {\n return Promise.resolve();\n }\n};\n\n/**\n * Update the specified table using the new filters.\n *\n * @param {HTMLElement} tableRoot\n * @param {Object} filters\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setFilters = (tableRoot, filters, refreshContent = true) =>\n updateTable(tableRoot, {filters}, refreshContent);\n\n/**\n * Update the sort order.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} sortBy\n * @param {Number} sortOrder\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setSortOrder = (tableRoot, sortBy, sortOrder, refreshContent = true) =>\n updateTable(tableRoot, {sortBy, sortOrder}, refreshContent);\n\n/**\n * Set the page number.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} pageNumber\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setPageNumber = (tableRoot, pageNumber, refreshContent = true) =>\n updateTable(tableRoot, {pageNumber}, refreshContent);\n\n/**\n * Set the page size.\n *\n * @param {HTMLElement} tableRoot\n * @param {Number} pageSize\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setPageSize = (tableRoot, pageSize, refreshContent = true) =>\n updateTable(tableRoot, {pageSize, pageNumber: 0}, refreshContent);\n\n/**\n * Update the first initial to show.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} firstInitial\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setFirstInitial = (tableRoot, firstInitial, refreshContent = true) =>\n updateTable(tableRoot, {firstInitial}, refreshContent);\n\n/**\n * Update the last initial to show.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} lastInitial\n * @param {Bool} refreshContent\n * @returns {Promise}\n */\nexport const setLastInitial = (tableRoot, lastInitial, refreshContent = true) =>\n updateTable(tableRoot, {lastInitial}, refreshContent);\n\n/**\n * Set up listeners to handle table updates.\n */\nexport const init = () => {\n if (watching) {\n // Already watching.\n return;\n }\n watching = true;\n\n document.addEventListener('click', e => {\n const tableRoot = e.target.closest(Selectors.main.region);\n\n if (!tableRoot) {\n return;\n }\n\n const sortableLink = e.target.closest(Selectors.table.links.sortableColumn);\n if (sortableLink) {\n e.preventDefault();\n\n setSortOrder(tableRoot, sortableLink.dataset.sortby, sortableLink.dataset.sortorder);\n }\n\n const firstInitialLink = e.target.closest(Selectors.initialsBar.links.firstInitial);\n if (firstInitialLink !== null) {\n e.preventDefault();\n\n setFirstInitial(tableRoot, firstInitialLink.dataset.initial);\n }\n\n const lastInitialLink = e.target.closest(Selectors.initialsBar.links.lastInitial);\n if (lastInitialLink !== null) {\n e.preventDefault();\n\n setLastInitial(tableRoot, lastInitialLink.dataset.initial);\n }\n\n const pageItem = e.target.closest(Selectors.paginationBar.links.pageItem);\n if (pageItem) {\n e.preventDefault();\n\n setPageNumber(tableRoot, pageItem.dataset.pageNumber);\n }\n });\n};\n"],"file":"dynamic.min.js"} \ No newline at end of file diff --git a/lib/table/amd/build/local/dynamic/repository.min.js b/lib/table/amd/build/local/dynamic/repository.min.js index 849507d094a..439fe85ffb3 100644 --- a/lib/table/amd/build/local/dynamic/repository.min.js +++ b/lib/table/amd/build/local/dynamic/repository.min.js @@ -1,2 +1,2 @@ -define ("core_table/local/dynamic/repository",["exports","core/ajax"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.fetch=void 0;a.fetch=function fetch(a,c){var d=2.\n\n/**\n * A javascript module to handle calendar ajax actions.\n *\n * @module core_calendar/repository\n * @class repository\n * @package core_calendar\n * @copyright 2017 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport {call as fetchMany} from 'core/ajax';\n\n/**\n * Fetch table view.\n *\n * @method fetch\n * @param {String} handler The name of the handler\n * @param {String} uniqueid The unique id of the table\n * @param {Object} filters The filters to apply when searching\n * @param {String} firstinitial The first name initial to filter on\n * @param {String} lastinitial The last name initial to filter on\n * @param {Number} params parameters to request table\n * @return {Promise} Resolved with requested table view\n */\nexport const fetch = (handler, uniqueid, {\n sortBy = null,\n sortOrder = null,\n joinType = null,\n filters = {},\n firstinitial = null,\n lastinitial = null,\n } = {}\n) => {\n return fetchMany([{\n methodname: `core_table_dynamic_fetch`,\n args: {\n handler,\n uniqueid,\n sortby: sortBy,\n sortorder: sortOrder,\n jointype: joinType,\n filters,\n firstinitial,\n lastinitial,\n },\n }])[0];\n};\n"],"file":"repository.min.js"} \ No newline at end of file +{"version":3,"sources":["../../../src/local/dynamic/repository.js"],"names":["fetch","handler","uniqueid","sortBy","sortOrder","joinType","filters","firstinitial","lastinitial","pageNumber","pageSize","methodname","args","sortby","sortorder","jointype","pagenumber","pagesize"],"mappings":"yKAwCqB,QAARA,CAAAA,KAAQ,CAACC,CAAD,CAAUC,CAAV,CAUhB,8DADG,EACH,KATGC,MASH,CATGA,CASH,YATY,IASZ,OARGC,SAQH,CARGA,CAQH,YARe,IAQf,OAPGC,QAOH,CAPGA,CAOH,YAPc,IAOd,OANGC,OAMH,CANGA,CAMH,YANa,EAMb,OALGC,YAKH,CALGA,CAKH,YALkB,IAKlB,OAJGC,WAIH,CAJGA,CAIH,YAJiB,IAIjB,OAHGC,UAGH,CAHGA,CAGH,YAHgB,IAGhB,OAFGC,QAEH,CAFGA,CAEH,YAFc,IAEd,GACD,MAAO,WAAU,CAAC,CACdC,UAAU,2BADI,CAEdC,IAAI,CAAE,CACFX,OAAO,CAAPA,CADE,CAEFC,QAAQ,CAARA,CAFE,CAGFW,MAAM,CAAEV,CAHN,CAIFW,SAAS,CAAEV,CAJT,CAKFW,QAAQ,CAAEV,CALR,CAMFC,OAAO,CAAPA,CANE,CAOFC,YAAY,CAAZA,CAPE,CAQFC,WAAW,CAAXA,CARE,CASFQ,UAAU,CAAEP,CATV,CAUFQ,QAAQ,CAAEP,CAVR,CAFQ,CAAD,CAAV,EAcH,CAdG,CAeV,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 .\n\n/**\n * A javascript module to handle calendar ajax actions.\n *\n * @module core_calendar/repository\n * @class repository\n * @package core_calendar\n * @copyright 2017 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport {call as fetchMany} from 'core/ajax';\n\n/**\n * Fetch table view.\n *\n * @method fetch\n * @param {String} handler The name of the handler\n * @param {String} uniqueid The unique id of the table\n * @param {Object} filters The filters to apply when searching\n * @param {String} firstinitial The first name initial to filter on\n * @param {String} lastinitial The last name initial to filter on\n * @param {String} pageNumber The page number\n * @param {Number} pageSize The page size\n * @param {Number} params parameters to request table\n * @return {Promise} Resolved with requested table view\n */\nexport const fetch = (handler, uniqueid, {\n sortBy = null,\n sortOrder = null,\n joinType = null,\n filters = {},\n firstinitial = null,\n lastinitial = null,\n pageNumber = null,\n pageSize = null,\n } = {}\n) => {\n return fetchMany([{\n methodname: `core_table_dynamic_fetch`,\n args: {\n handler,\n uniqueid,\n sortby: sortBy,\n sortorder: sortOrder,\n jointype: joinType,\n filters,\n firstinitial,\n lastinitial,\n pagenumber: pageNumber,\n pagesize: pageSize,\n },\n }])[0];\n};\n"],"file":"repository.min.js"} \ No newline at end of file diff --git a/lib/table/amd/build/local/dynamic/selectors.min.js b/lib/table/amd/build/local/dynamic/selectors.min.js index 7e047e0e0a8..f4dc44a485b 100644 --- a/lib/table/amd/build/local/dynamic/selectors.min.js +++ b/lib/table/amd/build/local/dynamic/selectors.min.js @@ -1,2 +1,2 @@ -define ("core_table/local/dynamic/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;a.default={main:{region:"[data-region=\"core_table/dynamic\"]"},table:{links:{sortableColumn:"a[data-sortable=\"1\"]"}},initialsBar:{links:{firstInitial:".firstinitial [data-initial]",lastInitial:".lastinitial [data-initial]"}}};return a.default}); +define ("core_table/local/dynamic/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;a.default={main:{region:"[data-region=\"core_table/dynamic\"]"},table:{links:{sortableColumn:"a[data-sortable=\"1\"]"}},initialsBar:{links:{firstInitial:".firstinitial [data-initial]",lastInitial:".lastinitial [data-initial]"}},paginationBar:{links:{pageItem:".pagination [data-page-number]"}}};return a.default}); //# sourceMappingURL=selectors.min.js.map diff --git a/lib/table/amd/build/local/dynamic/selectors.min.js.map b/lib/table/amd/build/local/dynamic/selectors.min.js.map index 525cf305c74..73059fccd1d 100644 --- a/lib/table/amd/build/local/dynamic/selectors.min.js.map +++ b/lib/table/amd/build/local/dynamic/selectors.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../../src/local/dynamic/selectors.js"],"names":["main","region","table","links","sortableColumn","initialsBar","firstInitial","lastInitial"],"mappings":"8JAuBe,CACXA,IAAI,CAAE,CACFC,MAAM,CAAE,sCADN,CADK,CAIXC,KAAK,CAAE,CACHC,KAAK,CAAE,CACHC,cAAc,CAAE,wBADb,CADJ,CAJI,CASXC,WAAW,CAAE,CACTF,KAAK,CAAE,CACHG,YAAY,CAAE,8BADX,CAEHC,WAAW,CAAE,6BAFV,CADE,CATF,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 .\n\n/**\n * Dynamic table selectors.\n *\n * @module core_table/selectors\n * @package core_table\n * @copyright 2020 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default {\n main: {\n region: '[data-region=\"core_table/dynamic\"]',\n },\n table: {\n links: {\n sortableColumn: 'a[data-sortable=\"1\"]',\n },\n },\n initialsBar: {\n links: {\n firstInitial: '.firstinitial [data-initial]',\n lastInitial: '.lastinitial [data-initial]',\n },\n },\n};\n"],"file":"selectors.min.js"} \ No newline at end of file +{"version":3,"sources":["../../../src/local/dynamic/selectors.js"],"names":["main","region","table","links","sortableColumn","initialsBar","firstInitial","lastInitial","paginationBar","pageItem"],"mappings":"8JAuBe,CACXA,IAAI,CAAE,CACFC,MAAM,CAAE,sCADN,CADK,CAIXC,KAAK,CAAE,CACHC,KAAK,CAAE,CACHC,cAAc,CAAE,wBADb,CADJ,CAJI,CASXC,WAAW,CAAE,CACTF,KAAK,CAAE,CACHG,YAAY,CAAE,8BADX,CAEHC,WAAW,CAAE,6BAFV,CADE,CATF,CAeXC,aAAa,CAAE,CACXL,KAAK,CAAE,CACHM,QAAQ,CAAE,gCADP,CADI,CAfJ,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 .\n\n/**\n * Dynamic table selectors.\n *\n * @module core_table/selectors\n * @package core_table\n * @copyright 2020 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default {\n main: {\n region: '[data-region=\"core_table/dynamic\"]',\n },\n table: {\n links: {\n sortableColumn: 'a[data-sortable=\"1\"]',\n },\n },\n initialsBar: {\n links: {\n firstInitial: '.firstinitial [data-initial]',\n lastInitial: '.lastinitial [data-initial]',\n },\n },\n paginationBar: {\n links: {\n pageItem: '.pagination [data-page-number]'\n }\n },\n};\n"],"file":"selectors.min.js"} \ No newline at end of file diff --git a/lib/table/amd/src/dynamic.js b/lib/table/amd/src/dynamic.js index 4cddc4d0bd5..5f11a38e07d 100644 --- a/lib/table/amd/src/dynamic.js +++ b/lib/table/amd/src/dynamic.js @@ -75,6 +75,8 @@ export const refreshTableContent = tableRoot => { filters: filterset.filters, firstinitial: tableRoot.dataset.tableFirstInitial, lastinitial: tableRoot.dataset.tableLastInitial, + pageNumber: tableRoot.dataset.tablePageNumber, + pageSize: tableRoot.dataset.tablePageSize, } ) .then(data => { @@ -92,6 +94,8 @@ export const updateTable = (tableRoot, { filters = null, firstInitial = null, lastInitial = null, + pageNumber = null, + pageSize = null, } = {}, refreshContent = true) => { checkTableIsDynamic(tableRoot); @@ -110,6 +114,14 @@ export const updateTable = (tableRoot, { tableRoot.dataset.tableLastInitial = lastInitial; } + if (pageNumber !== null) { + tableRoot.dataset.tablePageNumber = pageNumber; + } + + if (pageSize !== null) { + tableRoot.dataset.tablePageSize = pageSize; + } + // Update filters. if (filters) { tableRoot.dataset.tableFilters = JSON.stringify(filters); @@ -146,6 +158,28 @@ export const setFilters = (tableRoot, filters, refreshContent = true) => export const setSortOrder = (tableRoot, sortBy, sortOrder, refreshContent = true) => updateTable(tableRoot, {sortBy, sortOrder}, refreshContent); +/** + * Set the page number. + * + * @param {HTMLElement} tableRoot + * @param {String} pageNumber + * @param {Bool} refreshContent + * @returns {Promise} + */ +export const setPageNumber = (tableRoot, pageNumber, refreshContent = true) => + updateTable(tableRoot, {pageNumber}, refreshContent); + +/** + * Set the page size. + * + * @param {HTMLElement} tableRoot + * @param {Number} pageSize + * @param {Bool} refreshContent + * @returns {Promise} + */ +export const setPageSize = (tableRoot, pageSize, refreshContent = true) => + updateTable(tableRoot, {pageSize, pageNumber: 0}, refreshContent); + /** * Update the first initial to show. * @@ -205,5 +239,12 @@ export const init = () => { setLastInitial(tableRoot, lastInitialLink.dataset.initial); } + + const pageItem = e.target.closest(Selectors.paginationBar.links.pageItem); + if (pageItem) { + e.preventDefault(); + + setPageNumber(tableRoot, pageItem.dataset.pageNumber); + } }); }; diff --git a/lib/table/amd/src/local/dynamic/repository.js b/lib/table/amd/src/local/dynamic/repository.js index 67437751f45..5ef99c49c5c 100644 --- a/lib/table/amd/src/local/dynamic/repository.js +++ b/lib/table/amd/src/local/dynamic/repository.js @@ -33,6 +33,8 @@ import {call as fetchMany} from 'core/ajax'; * @param {Object} filters The filters to apply when searching * @param {String} firstinitial The first name initial to filter on * @param {String} lastinitial The last name initial to filter on + * @param {String} pageNumber The page number + * @param {Number} pageSize The page size * @param {Number} params parameters to request table * @return {Promise} Resolved with requested table view */ @@ -43,6 +45,8 @@ export const fetch = (handler, uniqueid, { filters = {}, firstinitial = null, lastinitial = null, + pageNumber = null, + pageSize = null, } = {} ) => { return fetchMany([{ @@ -56,6 +60,8 @@ export const fetch = (handler, uniqueid, { filters, firstinitial, lastinitial, + pagenumber: pageNumber, + pagesize: pageSize, }, }])[0]; }; diff --git a/lib/table/amd/src/local/dynamic/selectors.js b/lib/table/amd/src/local/dynamic/selectors.js index 6803571d4e5..118f328a08a 100644 --- a/lib/table/amd/src/local/dynamic/selectors.js +++ b/lib/table/amd/src/local/dynamic/selectors.js @@ -36,4 +36,9 @@ export default { lastInitial: '.lastinitial [data-initial]', }, }, + paginationBar: { + links: { + pageItem: '.pagination [data-page-number]' + } + }, }; diff --git a/lib/table/classes/external/dynamic/fetch.php b/lib/table/classes/external/dynamic/fetch.php index b029ff56554..194822face5 100644 --- a/lib/table/classes/external/dynamic/fetch.php +++ b/lib/table/classes/external/dynamic/fetch.php @@ -98,6 +98,18 @@ class fetch extends external_api { VALUE_REQUIRED, null ), + 'pagenumber' => new external_value( + PARAM_INT, + 'The page number', + VALUE_REQUIRED, + null + ), + 'pagesize' => new external_value( + PARAM_INT, + 'The number of records per page', + VALUE_REQUIRED, + null + ), ]); } @@ -112,6 +124,9 @@ class fetch extends external_api { * @param string $jointype The join type. * @param string $firstinitial The first name initial to filter on * @param string $lastinitial The last name initial to filter on + * @param int $pagenumber The page number. + * @param int $pagesize The number of records. + * @param string $jointype The join type. * * @return array */ @@ -123,7 +138,9 @@ class fetch extends external_api { ?array $filters = null, ?string $jointype = null, ?string $firstinitial = null, - ?string $lastinitial = null + ?string $lastinitial = null, + ?int $pagenumber = null, + ?int $pagesize = null ) { global $PAGE; @@ -141,6 +158,8 @@ class fetch extends external_api { 'jointype' => $jointype, 'firstinitial' => $firstinitial, 'lastinitial' => $lastinitial, + 'pagenumber' => $pagenumber, + 'pagesize' => $pagesize, ] = self::validate_parameters(self::execute_parameters(), [ 'handler' => $handler, 'uniqueid' => $uniqueid, @@ -150,6 +169,8 @@ class fetch extends external_api { 'jointype' => $jointype, 'firstinitial' => $firstinitial, 'lastinitial' => $lastinitial, + 'pagenumber' => $pagenumber, + 'pagesize' => $pagesize, ]); $filterset = new \core_user\table\participants_filterset(); @@ -173,13 +194,20 @@ class fetch extends external_api { $instance->set_last_initial($lastinitial); } - $context = $instance->get_context(); + if ($pagenumber !== null) { + $instance->set_page_number($pagenumber); + } + if ($pagesize === null) { + $pagesize = 20; + } + + $context = $instance->get_context(); self::validate_context($context); $PAGE->set_url($instance->get_base_url()); ob_start(); - $instance->out(20, true); + $instance->out($pagesize, true); $participanttablehtml = ob_get_contents(); ob_end_clean(); diff --git a/lib/tablelib.php b/lib/tablelib.php index 02035439489..3f79a592ea1 100644 --- a/lib/tablelib.php +++ b/lib/tablelib.php @@ -549,7 +549,10 @@ class flexible_table { $this->baseurl = $PAGE->url; } - $this->currpage = optional_param($this->request[TABLE_VAR_PAGE], 0, PARAM_INT); + if ($this->currpage == null) { + $this->currpage = optional_param($this->request[TABLE_VAR_PAGE], 0, PARAM_INT); + } + $this->setup = true; // Always introduce the "flexible" class for the table if not specified @@ -1406,6 +1409,15 @@ class flexible_table { $this->ilast = $initial; } + /** + * Set the page number. + * + * @param int $pagenumber The page number. + */ + public function set_page_number(int $pagenumber): void { + $this->currpage = $pagenumber - 1; + } + /** * Generate the HTML for the sort icon. This is a helper method used by {@link sort_link()}. * @param bool $isprimary whether an icon is needed (it is only needed for the primary sort column.) @@ -1505,6 +1517,8 @@ class flexible_table { 'data-table-sort-order' => $sortdata['sortorder'], 'data-table-first-initial' => $this->prefs['i_first'], 'data-table-last-initial' => $this->prefs['i_last'], + 'data-table-page-number' => $this->currpage + 1, + 'data-table-page-size' => $this->pagesize, ]); } @@ -1810,6 +1824,7 @@ class table_sql extends flexible_table { $this->define_columns(array_keys((array)$onerow)); $this->define_headers(array_keys((array)$onerow)); } + $this->pagesize = $pagesize; $this->setup(); $this->query_db($pagesize, $useinitialsbar); $this->build_table(); diff --git a/lib/templates/paging_bar.mustache b/lib/templates/paging_bar.mustache index 735b5cf1495..56a793c55b0 100644 --- a/lib/templates/paging_bar.mustache +++ b/lib/templates/paging_bar.mustache @@ -1,8 +1,8 @@ {{#haspages}}