From e2f12c2220bb8f00af2169eaae599551fac4c09b Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Fri, 17 Apr 2020 08:33:40 +0800 Subject: [PATCH] MDL-67915 core_table: add support for hide and show of columns --- 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 | 50 ++++++++++++++ lib/table/amd/src/local/dynamic/repository.js | 2 + lib/table/amd/src/local/dynamic/selectors.js | 2 + lib/table/classes/external/dynamic/fetch.php | 17 ++++- .../tests/external/dynamic/fetch_test.php | 10 ++- lib/tablelib.php | 69 +++++++++++++------ 12 files changed, 131 insertions(+), 31 deletions(-) diff --git a/lib/table/amd/build/dynamic.min.js b/lib/table/amd/build/dynamic.min.js index 96cc2ca97ef..4632a52583c 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.setPageSize=a.setPageNumber=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.tableComponent,\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 +{"version":3,"sources":["../src/dynamic.js"],"names":["watching","checkTableIsDynamic","tableRoot","Error","matches","Selectors","main","region","getFiltersetFromTable","JSON","parse","dataset","tableFilters","refreshTableContent","filterset","tableComponent","tableHandler","tableUniqueid","sortBy","tableSortBy","sortOrder","tableSortOrder","joinType","jointype","filters","firstinitial","tableFirstInitial","lastinitial","tableLastInitial","pageNumber","tablePageNumber","pageSize","tablePageSize","hiddenColumns","tableHiddenColumns","then","data","placeholder","document","createElement","innerHTML","html","replaceWith","childNodes","updateTable","firstInitial","lastInitial","refreshContent","stringify","Promise","resolve","setFilters","setSortOrder","setPageNumber","setPageSize","setFirstInitial","setLastInitial","hideColumn","columnToHide","push","showColumn","columnToShow","filter","columnName","init","addEventListener","e","target","closest","sortableLink","table","links","sortableColumn","preventDefault","sortby","sortorder","firstInitialLink","initialsBar","initial","lastInitialLink","pageItem","paginationBar","hide","column","show"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * 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.tableComponent,\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 hiddenColumns: JSON.parse(tableRoot.dataset.tableHiddenColumns),\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 hiddenColumns = 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 // Update hidden columns.\n if (hiddenColumns) {\n tableRoot.dataset.tableHiddenColumns = JSON.stringify(hiddenColumns);\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 * Hide a column in the participants table.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} columnToHide\n * @param {Bool} refreshContent\n */\nexport const hideColumn = (tableRoot, columnToHide, refreshContent = true) => {\n const hiddenColumns = JSON.parse(tableRoot.dataset.tableHiddenColumns);\n hiddenColumns.push(columnToHide);\n\n updateTable(tableRoot, {hiddenColumns}, refreshContent);\n};\n\n/**\n * Make a hidden column visible in the participants table.\n *\n * @param {HTMLElement} tableRoot\n * @param {String} columnToShow\n * @param {Bool} refreshContent\n */\nexport const showColumn = (tableRoot, columnToShow, refreshContent = true) => {\n let hiddenColumns = JSON.parse(tableRoot.dataset.tableHiddenColumns);\n hiddenColumns = hiddenColumns.filter(columnName => columnName !== columnToShow);\n\n updateTable(tableRoot, {hiddenColumns}, refreshContent);\n};\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 const hide = e.target.closest(Selectors.table.links.hide);\n if (hide) {\n e.preventDefault();\n\n hideColumn(tableRoot, hide.dataset.column);\n }\n\n const show = e.target.closest(Selectors.table.links.show);\n if (show) {\n e.preventDefault();\n\n showColumn(tableRoot, show.dataset.column);\n }\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 db1dc71eeb9..a377b54c266 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,d){var e=3.\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} component The component\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 = (component, 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 component,\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 +{"version":3,"sources":["../../../src/local/dynamic/repository.js"],"names":["fetch","component","handler","uniqueid","sortBy","sortOrder","joinType","filters","firstinitial","lastinitial","pageNumber","pageSize","hiddenColumns","methodname","args","sortby","sortorder","jointype","pagenumber","pagesize","hiddencolumns"],"mappings":"yKAyCqB,QAARA,CAAAA,KAAQ,CAACC,CAAD,CAAYC,CAAZ,CAAqBC,CAArB,CAWhB,8DADG,EACH,KAVGC,MAUH,CAVGA,CAUH,YAVY,IAUZ,OATGC,SASH,CATGA,CASH,YATe,IASf,OARGC,QAQH,CARGA,CAQH,YARc,IAQd,OAPGC,OAOH,CAPGA,CAOH,YAPa,EAOb,OANGC,YAMH,CANGA,CAMH,YANkB,IAMlB,OALGC,WAKH,CALGA,CAKH,YALiB,IAKjB,OAJGC,UAIH,CAJGA,CAIH,YAJgB,IAIhB,OAHGC,QAGH,CAHGA,CAGH,YAHc,IAGd,OAFGC,aAEH,CAFGA,CAEH,YAFmB,EAEnB,GACD,MAAO,WAAU,CAAC,CACdC,UAAU,2BADI,CAEdC,IAAI,CAAE,CACFb,SAAS,CAATA,CADE,CAEFC,OAAO,CAAPA,CAFE,CAGFC,QAAQ,CAARA,CAHE,CAIFY,MAAM,CAAEX,CAJN,CAKFY,SAAS,CAAEX,CALT,CAMFY,QAAQ,CAAEX,CANR,CAOFC,OAAO,CAAPA,CAPE,CAQFC,YAAY,CAAZA,CARE,CASFC,WAAW,CAAXA,CATE,CAUFS,UAAU,CAAER,CAVV,CAWFS,QAAQ,CAAER,CAXR,CAYFS,aAAa,CAAER,CAZb,CAFQ,CAAD,CAAV,EAgBH,CAhBG,CAiBV,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} component The component\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 = (component, 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 hiddenColumns = {}\n } = {}\n) => {\n return fetchMany([{\n methodname: `core_table_dynamic_fetch`,\n args: {\n component,\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 hiddencolumns: hiddenColumns,\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 f4dc44a485b..2844c553ed8 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]"}},paginationBar:{links:{pageItem:".pagination [data-page-number]"}}};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\"]",hide:"a[data-action=\"hide\"]",show:"a[data-action=\"show\"]"}},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 73059fccd1d..7a6ed15e9da 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","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 +{"version":3,"sources":["../../../src/local/dynamic/selectors.js"],"names":["main","region","table","links","sortableColumn","hide","show","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,CAEHC,IAAI,CAAE,yBAFH,CAGHC,IAAI,CAAE,yBAHH,CADJ,CAJI,CAWXC,WAAW,CAAE,CACTJ,KAAK,CAAE,CACHK,YAAY,CAAE,8BADX,CAEHC,WAAW,CAAE,6BAFV,CADE,CAXF,CAiBXC,aAAa,CAAE,CACXP,KAAK,CAAE,CACHQ,QAAQ,CAAE,gCADP,CADI,CAjBJ,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 hide: 'a[data-action=\"hide\"]',\n show: 'a[data-action=\"show\"]',\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 c3f264f07d1..3c875910c03 100644 --- a/lib/table/amd/src/dynamic.js +++ b/lib/table/amd/src/dynamic.js @@ -78,6 +78,7 @@ export const refreshTableContent = tableRoot => { lastinitial: tableRoot.dataset.tableLastInitial, pageNumber: tableRoot.dataset.tablePageNumber, pageSize: tableRoot.dataset.tablePageSize, + hiddenColumns: JSON.parse(tableRoot.dataset.tableHiddenColumns), } ) .then(data => { @@ -97,6 +98,7 @@ export const updateTable = (tableRoot, { lastInitial = null, pageNumber = null, pageSize = null, + hiddenColumns = null, } = {}, refreshContent = true) => { checkTableIsDynamic(tableRoot); @@ -128,6 +130,11 @@ export const updateTable = (tableRoot, { tableRoot.dataset.tableFilters = JSON.stringify(filters); } + // Update hidden columns. + if (hiddenColumns) { + tableRoot.dataset.tableHiddenColumns = JSON.stringify(hiddenColumns); + } + // Refresh. if (refreshContent) { return refreshTableContent(tableRoot); @@ -203,6 +210,34 @@ export const setFirstInitial = (tableRoot, firstInitial, refreshContent = true) export const setLastInitial = (tableRoot, lastInitial, refreshContent = true) => updateTable(tableRoot, {lastInitial}, refreshContent); +/** + * Hide a column in the participants table. + * + * @param {HTMLElement} tableRoot + * @param {String} columnToHide + * @param {Bool} refreshContent + */ +export const hideColumn = (tableRoot, columnToHide, refreshContent = true) => { + const hiddenColumns = JSON.parse(tableRoot.dataset.tableHiddenColumns); + hiddenColumns.push(columnToHide); + + updateTable(tableRoot, {hiddenColumns}, refreshContent); +}; + +/** + * Make a hidden column visible in the participants table. + * + * @param {HTMLElement} tableRoot + * @param {String} columnToShow + * @param {Bool} refreshContent + */ +export const showColumn = (tableRoot, columnToShow, refreshContent = true) => { + let hiddenColumns = JSON.parse(tableRoot.dataset.tableHiddenColumns); + hiddenColumns = hiddenColumns.filter(columnName => columnName !== columnToShow); + + updateTable(tableRoot, {hiddenColumns}, refreshContent); +}; + /** * Set up listeners to handle table updates. */ @@ -247,5 +282,20 @@ export const init = () => { setPageNumber(tableRoot, pageItem.dataset.pageNumber); } + + const hide = e.target.closest(Selectors.table.links.hide); + if (hide) { + e.preventDefault(); + + hideColumn(tableRoot, hide.dataset.column); + } + + const show = e.target.closest(Selectors.table.links.show); + if (show) { + e.preventDefault(); + + showColumn(tableRoot, show.dataset.column); + } + }); }; diff --git a/lib/table/amd/src/local/dynamic/repository.js b/lib/table/amd/src/local/dynamic/repository.js index 9083c6f0ae8..344de98e171 100644 --- a/lib/table/amd/src/local/dynamic/repository.js +++ b/lib/table/amd/src/local/dynamic/repository.js @@ -48,6 +48,7 @@ export const fetch = (component, handler, uniqueid, { lastinitial = null, pageNumber = null, pageSize = null, + hiddenColumns = {} } = {} ) => { return fetchMany([{ @@ -64,6 +65,7 @@ export const fetch = (component, handler, uniqueid, { lastinitial, pagenumber: pageNumber, pagesize: pageSize, + hiddencolumns: hiddenColumns, }, }])[0]; }; diff --git a/lib/table/amd/src/local/dynamic/selectors.js b/lib/table/amd/src/local/dynamic/selectors.js index 118f328a08a..2a52d91c13b 100644 --- a/lib/table/amd/src/local/dynamic/selectors.js +++ b/lib/table/amd/src/local/dynamic/selectors.js @@ -28,6 +28,8 @@ export default { table: { links: { sortableColumn: 'a[data-sortable="1"]', + hide: 'a[data-action="hide"]', + show: 'a[data-action="show"]', }, }, initialsBar: { diff --git a/lib/table/classes/external/dynamic/fetch.php b/lib/table/classes/external/dynamic/fetch.php index f49b6b43426..6e117e9cb9b 100644 --- a/lib/table/classes/external/dynamic/fetch.php +++ b/lib/table/classes/external/dynamic/fetch.php @@ -115,6 +115,14 @@ class fetch extends external_api { VALUE_REQUIRED, null ), + 'hiddencolumns' => new external_multiple_structure( + new external_value( + PARAM_ALPHANUMEXT, + 'Name of column', + VALUE_REQUIRED, + null + ) + ), ]); } @@ -146,7 +154,8 @@ class fetch extends external_api { ?string $firstinitial = null, ?string $lastinitial = null, ?int $pagenumber = null, - ?int $pagesize = null + ?int $pagesize = null, + ?array $hiddencolumns = null ) { global $PAGE; @@ -163,6 +172,7 @@ class fetch extends external_api { 'lastinitial' => $lastinitial, 'pagenumber' => $pagenumber, 'pagesize' => $pagesize, + 'hiddencolumns' => $hiddencolumns, ] = self::validate_parameters(self::execute_parameters(), [ 'component' => $component, 'handler' => $handler, @@ -175,6 +185,7 @@ class fetch extends external_api { 'lastinitial' => $lastinitial, 'pagenumber' => $pagenumber, 'pagesize' => $pagesize, + 'hiddencolumns' => $hiddencolumns, ]); $tableclass = "\\{$component}\\table\\{$handler}"; @@ -221,6 +232,10 @@ class fetch extends external_api { $pagesize = 20; } + if ($hiddencolumns !== null) { + $instance->set_hidden_columns($hiddencolumns); + } + $context = $instance->get_context(); self::validate_context($context); $PAGE->set_url($instance->get_base_url()); diff --git a/lib/table/tests/external/dynamic/fetch_test.php b/lib/table/tests/external/dynamic/fetch_test.php index b5ae34326d7..111b221bf30 100644 --- a/lib/table/tests/external/dynamic/fetch_test.php +++ b/lib/table/tests/external/dynamic/fetch_test.php @@ -65,7 +65,8 @@ class fetch_test extends advanced_testcase { $this->resetAfterTest(); $this->expectException(\UnexpectedValueException::class); - fetch::execute("core_users", "participants", "", "email", "4", [], "1"); + fetch::execute("core_users", "participants", "", "email", "4", [], (string)filter::JOINTYPE_ANY, + null, null, null, null, []); } /** @@ -79,7 +80,8 @@ class fetch_test extends advanced_testcase { $this->expectExceptionMessage("Table handler class {$handler} not found. Please make sure that your table handler class is under the \\core_user\\table namespace."); // Tests that invalid users_participants_table class gets an exception. - fetch::execute("core_user", "users_participants_table", "", "email", "4", [], "1"); + fetch::execute("core_user", "users_participants_table", "", "email", "4", [], (string)filter::JOINTYPE_ANY, + null, null, null, null, []); } /** @@ -129,7 +131,9 @@ class fetch_test extends advanced_testcase { ]; $participantstable = fetch::execute("core_user", "participants", - "user-index-participants-{$course->id}", "firstname", "4", $filter, (string)filter::JOINTYPE_ANY); + "user-index-participants-{$course->id}", "firstname", "4", $filter, (string)filter::JOINTYPE_ANY, + null, null, null, null, []); + $html = $participantstable['html']; $this->assertStringContainsString($user1->email, $html); diff --git a/lib/tablelib.php b/lib/tablelib.php index 33375ebaafd..7e669a26517 100644 --- a/lib/tablelib.php +++ b/lib/tablelib.php @@ -154,6 +154,9 @@ class flexible_table { /** @var $filename */ protected $filename; + /** @var array $hiddencolumns List of hidden columns. */ + protected $hiddencolumns; + /** * Constructor * @param string $uniqueid all tables have to have a unique id, this is used @@ -511,25 +514,7 @@ class flexible_table { $oldprefs = $this->prefs; } - if (($showcol = optional_param($this->request[TABLE_VAR_SHOW], '', PARAM_ALPHANUMEXT)) && - isset($this->columns[$showcol])) { - $this->prefs['collapse'][$showcol] = false; - - } else if (($hidecol = optional_param($this->request[TABLE_VAR_HIDE], '', PARAM_ALPHANUMEXT)) && - isset($this->columns[$hidecol])) { - $this->prefs['collapse'][$hidecol] = true; - if (array_key_exists($hidecol, $this->prefs['sortby'])) { - unset($this->prefs['sortby'][$hidecol]); - } - } - - // Now, update the column attributes for collapsed columns - foreach (array_keys($this->columns) as $column) { - if (!empty($this->prefs['collapse'][$column])) { - $this->column_style[$column]['width'] = '10px'; - } - } - + $this->set_hide_show_preferences(); $this->set_sorting_preferences(); $this->set_initials_preferences(); @@ -1205,14 +1190,18 @@ class flexible_table { if (!empty($this->prefs['collapse'][$column])) { $linkattributes = array('title' => get_string('show') . ' ' . strip_tags($this->headers[$index]), 'aria-expanded' => 'false', - 'aria-controls' => $ariacontrols); + 'aria-controls' => $ariacontrols, + 'data-action' => 'show', + 'data-column' => $column); return html_writer::link($this->baseurl->out(false, array($this->request[TABLE_VAR_SHOW] => $column)), $OUTPUT->pix_icon('t/switch_plus', get_string('show')), $linkattributes); } else if ($this->headers[$index] !== NULL) { $linkattributes = array('title' => get_string('hide') . ' ' . strip_tags($this->headers[$index]), 'aria-expanded' => 'true', - 'aria-controls' => $ariacontrols); + 'aria-controls' => $ariacontrols, + 'data-action' => 'hide', + 'data-column' => $column); return html_writer::link($this->baseurl->out(false, array($this->request[TABLE_VAR_HIDE] => $column)), $OUTPUT->pix_icon('t/switch_minus', get_string('hide')), $linkattributes); } @@ -1380,6 +1369,43 @@ class flexible_table { } + /** + * Set hide and show preferences. + */ + protected function set_hide_show_preferences(): void { + + if ($this->hiddencolumns !== null) { + $this->prefs['collapse'] = array_fill_keys(array_filter($this->hiddencolumns, function($column) { + return array_key_exists($column, $this->columns); + }), true); + } else { + if ($column = optional_param($this->request[TABLE_VAR_HIDE], '', PARAM_ALPHANUMEXT)) { + if (isset($this->columns[$column])) { + $this->prefs['collapse'][$column] = true; + } + } + } + + if ($column = optional_param($this->request[TABLE_VAR_SHOW], '', PARAM_ALPHANUMEXT)) { + unset($this->prefs['collapse'][$column]); + } + + foreach (array_keys($this->prefs['collapse']) as $column) { + if (array_key_exists($column, $this->prefs['sortby'])) { + unset($this->prefs['sortby'][$column]); + } + } + } + + /** + * Set the list of hidden columns. + * + * @param array $columns The list of hidden columns. + */ + public function set_hidden_columns(array $columns): void { + $this->hiddencolumns = $columns; + } + /** * Set the preferred table sorting attributes. * @@ -1540,6 +1566,7 @@ class flexible_table { 'data-table-last-initial' => $this->prefs['i_last'], 'data-table-page-number' => $this->currpage + 1, 'data-table-page-size' => $this->pagesize, + 'data-table-hidden-columns' => json_encode(array_keys($this->prefs['collapse'])), ]); }