Proyectos de Subversion Moodle

Rev

Rev 1 | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |

{"version":3,"file":"filter.min.js","sources":["../src/filter.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Question bank filter management.\n *\n * @module     core_question/filter\n * @copyright  2021 Tomo Tsuyuki <tomotsuyuki@catalyst-au.net>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport CoreFilter from 'core/datafilter';\nimport Notification from 'core/notification';\nimport Selectors from 'core/datafilter/selectors';\nimport Templates from 'core/templates';\nimport Fragment from 'core/fragment';\nimport {getString} from 'core/str';\nimport {addIconToContainerRemoveOnCompletion} from 'core/loadingicon';\n\n/**\n * Initialise the question bank filter on the element with the given id.\n *\n * @param {String} filterRegionId ID of the HTML element containing the filters.\n * @param {String} defaultcourseid Course ID for the default course to pass back to the view.\n * @param {String} defaultcategoryid Question bank category ID for the default course to pass back to the view.\n * @param {Number} perpage The number of questions to display per page.\n * @param {Number} bankContextId Context ID of the question bank being filtered.\n * @param {Number} quizCmId Course module ID of the quiz as the viewing context.\n * @param {string} component Frankenstyle name of the component for the fragment API callback (e.g. core_question)\n * @param {string} callback Name of the callback for the fragment API (e.g question_data)\n * @param {string} view The class name of the question bank view class used for this page.\n * @param {Number} cmid If we are in an activitiy, the course module ID.\n * @param {Object} pagevars JSON-encoded parameters from passed from the view, including filters and jointype.\n * @param {Object} extraparams JSON-encoded additional parameters specific to this view class, used for re-rendering the view.\n */\nexport const init = async(\n    filterRegionId,\n    defaultcourseid,\n    defaultcategoryid,\n    perpage,\n    bankContextId,\n    quizCmId,\n    component,\n    callback,\n    view,\n    cmid,\n    pagevars,\n    extraparams,\n) => {\n\n    const SELECTORS = {\n        QUESTION_CONTAINER_ID: '#questionscontainer',\n        QUESTION_TABLE: '#questionscontainer table',\n        SORT_LINK: '#questionscontainer div.sorters a',\n        PAGINATION_LINK: '#questionscontainer a[href].page-link',\n        LASTCHANGED_FIELD: '#questionsubmit input[name=lastchanged]',\n        BULK_ACTIONS: '#bulkactionsui-container input',\n        MENU_ACTIONS: '.menu-action',\n        EDIT_SWITCH: '.editmode-switch-form input[name=setmode]',\n        EDIT_SWITCH_URL: '.editmode-switch-form input[name=pageurl]',\n        SHOW_ALL_LINK: '[data-filteraction=\"showall\"]',\n    };\n\n    const filterSet = document.querySelector(`#${filterRegionId}`);\n\n    const viewData = {\n        extraparams: JSON.stringify(extraparams),\n        cmid,\n        view,\n        cat: defaultcategoryid,\n        courseid: defaultcourseid,\n        filter: {},\n        jointype: 0,\n        qpage: 0,\n        qperpage: perpage,\n        sortdata: {},\n        lastchanged: document.querySelector(SELECTORS.LASTCHANGED_FIELD)?.value ?? null,\n    };\n\n    let sortData = {};\n    const defaultSort = document.querySelector(SELECTORS.QUESTION_TABLE)?.dataset?.defaultsort;\n    if (defaultSort) {\n        sortData = JSON.parse(defaultSort);\n    }\n\n    const [\n        showAllText,\n        showPerPageText,\n    ] = await Promise.all([\n        getString('showall', 'core', ''),\n        getString('showperpage', 'core', extraparams.defaultqperpage),\n    ]);\n\n    /**\n     * Retrieve table data.\n     *\n     * @param {Object} filterdata data\n     * @param {Promise} pendingPromise pending promise\n     */\n    const applyFilter = (filterdata, pendingPromise) => {\n        // Reload the questions based on the specified filters. If no filters are provided,\n        // use the default category filter condition.\n        if (filterdata) {\n            // Main join types.\n            viewData.jointype = parseInt(filterSet.dataset.filterverb, 10);\n            delete filterdata.jointype;\n            // Retrieve filter info.\n            viewData.filter = filterdata;\n            if (Object.keys(filterdata).length !== 0) {\n                if (!isNaN(viewData.jointype)) {\n                    filterdata.jointype = viewData.jointype;\n                }\n            }\n        }\n        // Load questions for first page.\n        viewData.filter = JSON.stringify(filterdata);\n        viewData.sortdata = JSON.stringify(sortData);\n        viewData.quizcmid = quizCmId;\n\n        const questionscontainer = document.querySelector(SELECTORS.QUESTION_CONTAINER_ID);\n        // Clear the contents of the element, then append the loading icon.\n        questionscontainer.innerHTML = '';\n        addIconToContainerRemoveOnCompletion(questionscontainer, pendingPromise);\n\n        Fragment.loadFragment(component, callback, bankContextId, viewData)\n            // Render questions for first page and pagination.\n            .then((questionhtml, jsfooter) => {\n                updateUrlParams(filterdata);\n                if (questionhtml === undefined) {\n                    questionhtml = '';\n                }\n                if (jsfooter === undefined) {\n                    jsfooter = '';\n                }\n                Templates.replaceNode(questionscontainer, questionhtml, jsfooter);\n                // Resolve filter promise.\n                if (pendingPromise) {\n                    pendingPromise.resolve();\n                }\n                return {questionhtml, jsfooter};\n            })\n            .catch(Notification.exception);\n    };\n\n    // Init core filter processor with apply callback.\n    const coreFilter = new CoreFilter(filterSet, applyFilter);\n    coreFilter.activeFilters = {}; // Unset useless courseid filter.\n    coreFilter.init();\n\n    /**\n     * Update URL Param based upon the current filter.\n     *\n     * @param {Object} filters Active filters.\n     */\n    const updateUrlParams = (filters) => {\n        const url = new URL(location.href);\n        const filterQuery = JSON.stringify(filters);\n        url.searchParams.set('filter', filterQuery);\n        history.pushState(filters, '', url);\n        const editSwitch = document.querySelector(SELECTORS.EDIT_SWITCH);\n        if (editSwitch) {\n            const editSwitchUrlInput = document.querySelector(SELECTORS.EDIT_SWITCH_URL);\n            const editSwitchUrl = new URL(editSwitchUrlInput.value);\n            editSwitchUrl.searchParams.set('filter', filterQuery);\n            editSwitchUrlInput.value = editSwitchUrl;\n            editSwitch.dataset.pageurl = editSwitchUrl;\n        }\n    };\n\n    /**\n     * Cleans URL parameters.\n     */\n    const cleanUrlParams = () => {\n        const queryString = location.search;\n        const urlParams = new URLSearchParams(queryString);\n        if (urlParams.has('cmid')) {\n            const cleanedUrl = new URL(location.href.replace(location.search, ''));\n            cleanedUrl.searchParams.set('cmid', urlParams.get('cmid'));\n            history.pushState({}, '', cleanedUrl);\n        }\n\n        if (urlParams.has('courseid')) {\n            const cleanedUrl = new URL(location.href.replace(location.search, ''));\n            cleanedUrl.searchParams.set('courseid', urlParams.get('courseid'));\n            history.pushState({}, '', cleanedUrl);\n        }\n    };\n\n    // Add listeners for the sorting, paging and clear actions.\n    document.querySelector('.questionbankwindow').addEventListener('click', e => {\n        const sortableLink = e.target.closest(SELECTORS.SORT_LINK);\n        const paginationLink = e.target.closest(SELECTORS.PAGINATION_LINK);\n        const clearLink = e.target.closest(Selectors.filterset.actions.resetFilters);\n        const showallLink = e.target.closest(SELECTORS.SHOW_ALL_LINK);\n        if (sortableLink) {\n            e.preventDefault();\n            const oldSort = sortData;\n            sortData = {};\n            sortData[sortableLink.dataset.sortname] = sortableLink.dataset.sortorder;\n            for (const sortname in oldSort) {\n                if (sortname !== sortableLink.dataset.sortname) {\n                    sortData[sortname] = oldSort[sortname];\n                }\n            }\n            viewData.qpage = 0;\n            coreFilter.updateTableFromFilter(false);\n        }\n        if (paginationLink) {\n            e.preventDefault();\n            const paginationURL = new URL(paginationLink.getAttribute(\"href\"));\n            const qpage = paginationURL.searchParams.get('qpage');\n            if (paginationURL.search !== null) {\n                viewData.qpage = qpage;\n                coreFilter.updateTableFromFilter(false);\n            }\n        }\n        if (clearLink) {\n            cleanUrlParams();\n        }\n        if (showallLink) {\n\n            e.preventDefault();\n\n            // Toggle between showing all and going back to the original qperpage.\n            if (Number(showallLink.dataset.status) === 0) {\n                viewData.qperpage = extraparams.maxqperpage;\n                showallLink.dataset.status = 1;\n                showallLink.innerText = showPerPageText;\n            } else {\n                viewData.qperpage = extraparams.defaultqperpage;\n                showallLink.dataset.status = 0;\n                showallLink.innerText = showAllText;\n            }\n            viewData.qpage = 0;\n            coreFilter.updateTableFromFilter();\n        }\n    });\n\n    // Run apply filter at page load.\n    let initialFilters;\n    let jointype = null;\n    if (pagevars.filter) {\n        // Load initial filter based on page vars.\n        initialFilters = pagevars.filter;\n        if (pagevars.jointype) {\n            jointype = pagevars.jointype;\n        }\n    }\n\n    if (Object.entries(initialFilters).length !== 0) {\n        // Remove the default empty filter row.\n        const emptyFilterRow = filterSet.querySelector(Selectors.filterset.regions.emptyFilterRow);\n        if (emptyFilterRow) {\n            emptyFilterRow.remove();\n        }\n\n        // Add filters.\n        let rowcount = 0;\n        for (const urlFilter in initialFilters) {\n            if (urlFilter === 'jointype') {\n                jointype = initialFilters[urlFilter];\n                continue;\n            }\n            // Add each filter row.\n            rowcount += 1;\n            const filterdata = {\n                filtertype: urlFilter,\n                values:  initialFilters[urlFilter].values,\n                jointype: initialFilters[urlFilter].jointype,\n                filteroptions: initialFilters[urlFilter].filteroptions,\n                rownum: rowcount\n            };\n            coreFilter.addFilterRow(filterdata);\n        }\n        coreFilter.filterSet.dataset.filterverb = jointype;\n\n        // Since we must filter by category, it does not make sense to allow the top-level \"match any\" or \"match none\" conditions,\n        // as this would exclude the category. Remove those options and disable the select.\n        const join = coreFilter.filterSet.querySelector(Selectors.filterset.fields.join);\n        join.querySelectorAll(`option:not([value=\"${jointype}\"])`).forEach((option) => option.remove());\n        join.disabled = true;\n    }\n};\n"],"names":["async","filterRegionId","defaultcourseid","defaultcategoryid","perpage","bankContextId","quizCmId","component","callback","view","cmid","pagevars","extraparams","SELECTORS","filterSet","document","querySelector","viewData","JSON","stringify","cat","courseid","filter","jointype","qpage","qperpage","sortdata","lastchanged","_document$querySelect2","value","sortData","defaultSort","_document$querySelect3","dataset","_document$querySelect4","defaultsort","parse","showAllText","showPerPageText","Promise","all","defaultqperpage","coreFilter","CoreFilter","filterdata","pendingPromise","parseInt","filterverb","Object","keys","length","isNaN","quizcmid","questionscontainer","innerHTML","loadFragment","then","questionhtml","jsfooter","updateUrlParams","undefined","replaceNode","resolve","catch","Notification","exception","activeFilters","init","filters","url","URL","location","href","filterQuery","searchParams","set","history","pushState","editSwitch","editSwitchUrlInput","editSwitchUrl","pageurl","initialFilters","addEventListener","e","sortableLink","target","closest","paginationLink","clearLink","Selectors","filterset","actions","resetFilters","showallLink","preventDefault","oldSort","sortname","sortorder","updateTableFromFilter","paginationURL","getAttribute","get","search","queryString","urlParams","URLSearchParams","has","cleanedUrl","replace","cleanUrlParams","Number","status","maxqperpage","innerText","entries","emptyFilterRow","regions","remove","rowcount","urlFilter","filtertype","values","filteroptions","rownum","addFilterRow","join","fields","querySelectorAll","forEach","option","disabled"],"mappings":";;;;;;;4UA+CoBA,MAChBC,eACAC,gBACAC,kBACAC,QACAC,cACAC,SACAC,UACAC,SACAC,KACAC,KACAC,SACAC,oHAGMC,gCACqB,sBADrBA,yBAEc,4BAFdA,oBAGS,oCAHTA,0BAIe,wCAJfA,4BAKiB,0CALjBA,sBAQW,4CARXA,0BASe,4CATfA,wBAUa,gCAGbC,UAAYC,SAASC,yBAAkBf,iBAEvCgB,SAAW,CACbL,YAAaM,KAAKC,UAAUP,aAC5BF,KAAAA,KACAD,KAAAA,KACAW,IAAKjB,kBACLkB,SAAUnB,gBACVoB,OAAQ,GACRC,SAAU,EACVC,MAAO,EACPC,SAAUrB,QACVsB,SAAU,GACVC,yEAAaZ,SAASC,cAAcH,sEAAvBe,uBAAqDC,6DAAS,UAG3EC,SAAW,SACTC,2CAAchB,SAASC,cAAcH,4FAAvBmB,uBAAkDC,iDAAlDC,uBAA2DC,YAC3EJ,cACAD,SAAWZ,KAAKkB,MAAML,oBAItBM,YACAC,uBACMC,QAAQC,IAAI,EAClB,kBAAU,UAAW,OAAQ,KAC7B,kBAAU,cAAe,OAAQ5B,YAAY6B,mBAuD3CC,WAAa,IAAIC,oBAAW7B,WA9Cd,CAAC8B,WAAYC,kBAGzBD,aAEA3B,SAASM,SAAWuB,SAAShC,UAAUmB,QAAQc,WAAY,WACpDH,WAAWrB,SAElBN,SAASK,OAASsB,WACqB,IAAnCI,OAAOC,KAAKL,YAAYM,SACnBC,MAAMlC,SAASM,YAChBqB,WAAWrB,SAAWN,SAASM,YAK3CN,SAASK,OAASJ,KAAKC,UAAUyB,YACjC3B,SAASS,SAAWR,KAAKC,UAAUW,UACnCb,SAASmC,SAAW9C,eAEd+C,mBAAqBtC,SAASC,cAAcH,iCAElDwC,mBAAmBC,UAAY,yDACMD,mBAAoBR,kCAEhDU,aAAahD,UAAWC,SAAUH,cAAeY,UAErDuC,MAAK,CAACC,aAAcC,YACjBC,gBAAgBf,iBACKgB,IAAjBH,eACAA,aAAe,SAEFG,IAAbF,WACAA,SAAW,uBAELG,YAAYR,mBAAoBI,aAAcC,UAEpDb,gBACAA,eAAeiB,UAEZ,CAACL,aAAAA,aAAcC,SAAAA,aAEzBK,MAAMC,sBAAaC,cAK5BvB,WAAWwB,cAAgB,GAC3BxB,WAAWyB,aAOLR,gBAAmBS,gBACfC,IAAM,IAAIC,IAAIC,SAASC,MACvBC,YAAcvD,KAAKC,UAAUiD,SACnCC,IAAIK,aAAaC,IAAI,SAAUF,aAC/BG,QAAQC,UAAUT,QAAS,GAAIC,WACzBS,WAAa/D,SAASC,cAAcH,0BACtCiE,WAAY,OACNC,mBAAqBhE,SAASC,cAAcH,2BAC5CmE,cAAgB,IAAIV,IAAIS,mBAAmBlD,OACjDmD,cAAcN,aAAaC,IAAI,SAAUF,aACzCM,mBAAmBlD,MAAQmD,cAC3BF,WAAW7C,QAAQgD,QAAUD,oBA0EjCE,eAlDJnE,SAASC,cAAc,uBAAuBmE,iBAAiB,SAASC,UAC9DC,aAAeD,EAAEE,OAAOC,QAAQ1E,qBAChC2E,eAAiBJ,EAAEE,OAAOC,QAAQ1E,2BAClC4E,UAAYL,EAAEE,OAAOC,QAAQG,mBAAUC,UAAUC,QAAQC,cACzDC,YAAcV,EAAEE,OAAOC,QAAQ1E,4BACjCwE,aAAc,CACdD,EAAEW,uBACIC,QAAUlE,SAChBA,SAAW,GACXA,SAASuD,aAAapD,QAAQgE,UAAYZ,aAAapD,QAAQiE,cAC1D,MAAMD,YAAYD,QACfC,WAAaZ,aAAapD,QAAQgE,WAClCnE,SAASmE,UAAYD,QAAQC,WAGrChF,SAASO,MAAQ,EACjBkB,WAAWyD,uBAAsB,MAEjCX,eAAgB,CAChBJ,EAAEW,uBACIK,cAAgB,IAAI9B,IAAIkB,eAAea,aAAa,SACpD7E,MAAQ4E,cAAc1B,aAAa4B,IAAI,SAChB,OAAzBF,cAAcG,SACdtF,SAASO,MAAQA,MACjBkB,WAAWyD,uBAAsB,IAGrCV,WA5Ce,YACbe,YAAcjC,SAASgC,OACvBE,UAAY,IAAIC,gBAAgBF,gBAClCC,UAAUE,IAAI,QAAS,OACjBC,WAAa,IAAItC,IAAIC,SAASC,KAAKqC,QAAQtC,SAASgC,OAAQ,KAClEK,WAAWlC,aAAaC,IAAI,OAAQ8B,UAAUH,IAAI,SAClD1B,QAAQC,UAAU,GAAI,GAAI+B,eAG1BH,UAAUE,IAAI,YAAa,OACrBC,WAAa,IAAItC,IAAIC,SAASC,KAAKqC,QAAQtC,SAASgC,OAAQ,KAClEK,WAAWlC,aAAaC,IAAI,WAAY8B,UAAUH,IAAI,aACtD1B,QAAQC,UAAU,GAAI,GAAI+B,cAiC1BE,GAEAhB,cAEAV,EAAEW,iBAGyC,IAAvCgB,OAAOjB,YAAY7D,QAAQ+E,SAC3B/F,SAASQ,SAAWb,YAAYqG,YAChCnB,YAAY7D,QAAQ+E,OAAS,EAC7BlB,YAAYoB,UAAY5E,kBAExBrB,SAASQ,SAAWb,YAAY6B,gBAChCqD,YAAY7D,QAAQ+E,OAAS,EAC7BlB,YAAYoB,UAAY7E,aAE5BpB,SAASO,MAAQ,EACjBkB,WAAWyD,gCAMf5E,SAAW,QACXZ,SAASW,SAET4D,eAAiBvE,SAASW,OACtBX,SAASY,WACTA,SAAWZ,SAASY,WAIkB,IAA1CyB,OAAOmE,QAAQjC,gBAAgBhC,OAAc,OAEvCkE,eAAiBtG,UAAUE,cAAc0E,mBAAUC,UAAU0B,QAAQD,gBACvEA,gBACAA,eAAeE,aAIfC,SAAW,MACV,MAAMC,aAAatC,eAAgB,IAClB,aAAdsC,UAA0B,CAC1BjG,SAAW2D,eAAesC,oBAI9BD,UAAY,QACN3E,WAAa,CACf6E,WAAYD,UACZE,OAASxC,eAAesC,WAAWE,OACnCnG,SAAU2D,eAAesC,WAAWjG,SACpCoG,cAAezC,eAAesC,WAAWG,cACzCC,OAAQL,UAEZ7E,WAAWmF,aAAajF,YAE5BF,WAAW5B,UAAUmB,QAAQc,WAAaxB,eAIpCuG,KAAOpF,WAAW5B,UAAUE,cAAc0E,mBAAUC,UAAUoC,OAAOD,MAC3EA,KAAKE,8CAAuCzG,iBAAe0G,SAASC,QAAWA,OAAOZ,WACtFQ,KAAKK,UAAW"}