Sindbad~EG File Manager
{"version":3,"file":"search.min.js","sources":["../src/search.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 * Allow the user to search for learners within the grader report.\n * Have to basically search twice on the dataset to avoid passing around massive csv params whilst allowing debouncing.\n *\n * @module gradereport_grader/search\n * @copyright 2023 Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport GradebookSearchClass from 'gradereport_grader/search/search_class';\nimport * as Repository from 'gradereport_grader/search/repository';\nimport {get_strings as getStrings} from 'core/str';\nimport Url from 'core/url';\nimport {renderForPromise, replaceNodeContents} from 'core/templates';\n\n// Define our standard lookups.\nconst selectors = {\n component: '.user-search',\n courseid: '[data-region=\"courseid\"]',\n resetPageButton: '[data-action=\"resetpage\"]',\n};\nconst component = document.querySelector(selectors.component);\nconst courseID = component.querySelector(selectors.courseid).dataset.courseid;\n\nexport default class UserSearch extends GradebookSearchClass {\n\n // A map of user profile field names that is human-readable.\n profilestringmap = null;\n\n constructor() {\n super();\n }\n\n static init() {\n return new UserSearch();\n }\n\n /**\n * The overall div that contains the searching widget.\n *\n * @returns {string}\n */\n setComponentSelector() {\n return '.user-search';\n }\n\n /**\n * The dropdown div that contains the searching widget result space.\n *\n * @returns {string}\n */\n setDropdownSelector() {\n return '.usersearchdropdown';\n }\n\n /**\n * The triggering div that contains the searching widget.\n *\n * @returns {string}\n */\n setTriggerSelector() {\n return '.usersearchwidget';\n }\n\n /**\n * Build the content then replace the node.\n */\n async renderDropdown() {\n const {html, js} = await renderForPromise('gradereport_grader/search/resultset', {\n users: this.getMatchedResults().slice(0, 5),\n hasusers: this.getMatchedResults().length > 0,\n matches: this.getMatchedResults().length,\n showing: this.getMatchedResults().slice(0, 5).length,\n searchterm: this.getSearchTerm(),\n selectall: this.selectAllResultsLink(),\n });\n replaceNodeContents(this.getHTMLElements().searchDropdown, html, js);\n }\n\n /**\n * Get the data we will be searching against in this component.\n *\n * @returns {Promise<*>}\n */\n fetchDataset() {\n return Repository.userFetch(courseID).then((r) => r.users);\n }\n\n /**\n * Dictate to the search component how and what we want to match upon.\n *\n * @param {Array} filterableData\n * @returns {Array} The users that match the given criteria.\n */\n async filterDataset(filterableData) {\n const stringMap = await this.getStringMap();\n return filterableData.filter((user) => Object.keys(user).some((key) => {\n if (user[key] === \"\" || !stringMap.get(key)) {\n return false;\n }\n return user[key].toString().toLowerCase().includes(this.getPreppedSearchTerm());\n }));\n }\n\n /**\n * Given we have a subset of the dataset, set the field that we matched upon to inform the end user.\n *\n * @returns {Array} The results with the matched fields inserted.\n */\n async filterMatchDataset() {\n const stringMap = await this.getStringMap();\n this.setMatchedResults(\n this.getMatchedResults().map((user) => {\n for (const [key, value] of Object.entries(user)) {\n const valueString = value.toString().toLowerCase();\n const preppedSearchTerm = this.getPreppedSearchTerm();\n const searchTerm = this.getSearchTerm();\n\n if (!valueString.includes(preppedSearchTerm)) {\n continue;\n }\n\n // Ensure we have a good string, otherwise fallback to the key.\n user.matchingFieldName = stringMap.get(key) ?? key;\n\n // Safely prepare our matching results.\n const escapedValueString = valueString.replace(/</g, '<');\n const escapedMatchingField = escapedValueString.replace(\n preppedSearchTerm.replace(/</g, '<'),\n `<span class=\"font-weight-bold\">${searchTerm.replace(/</g, '<')}</span>`\n );\n\n if (user.email) {\n user.matchingField = `${escapedMatchingField} (${user.email})`;\n } else {\n user.matchingField = escapedMatchingField;\n }\n user.link = this.selectOneLink(user.id);\n break;\n }\n return user;\n })\n );\n }\n\n /**\n * The handler for when a user interacts with the component.\n *\n * @param {MouseEvent} e The triggering event that we are working with.\n */\n clickHandler(e) {\n super.clickHandler(e);\n if (e.target === this.getHTMLElements().currentViewAll && e.button === 0) {\n window.location = this.selectAllResultsLink();\n }\n if (e.target.closest(selectors.resetPageButton)) {\n window.location = e.target.closest(selectors.resetPageButton).href;\n }\n }\n\n /**\n * The handler for when a user presses a key within the component.\n *\n * @param {KeyboardEvent} e The triggering event that we are working with.\n */\n keyHandler(e) {\n super.keyHandler(e);\n\n if (e.target === this.getHTMLElements().currentViewAll && (e.key === 'Enter' || e.key === 'Space')) {\n window.location = this.selectAllResultsLink();\n }\n\n // Switch the key presses to handle keyboard nav.\n switch (e.key) {\n case 'Enter':\n case ' ':\n if (document.activeElement === this.getHTMLElements().searchInput) {\n if (e.key === ' ') {\n break;\n } else {\n window.location = this.selectAllResultsLink();\n break;\n }\n }\n if (document.activeElement === this.getHTMLElements().clearSearchButton) {\n this.closeSearch(true);\n break;\n }\n if (e.target.closest(selectors.resetPageButton)) {\n window.location = e.target.closest(selectors.resetPageButton).href;\n break;\n }\n if (e.target.closest('.dropdown-item')) {\n e.preventDefault();\n window.location = e.target.closest('.dropdown-item').href;\n break;\n }\n break;\n case 'Escape':\n this.toggleDropdown();\n this.searchInput.focus({preventScroll: true});\n break;\n case 'Tab':\n // If the current focus is on clear search, then check if viewall exists then around tab to it.\n if (e.target.closest(this.selectors.clearSearch)) {\n if (this.currentViewAll && !e.shiftKey) {\n e.preventDefault();\n this.currentViewAll.focus({preventScroll: true});\n } else {\n this.closeSearch();\n }\n }\n break;\n }\n }\n\n /**\n * Build up the view all link.\n *\n * @returns {string|*}\n */\n selectAllResultsLink() {\n return Url.relativeUrl('/grade/report/grader/index.php', {\n id: courseID,\n gpr_search: this.getSearchTerm()\n }, false);\n }\n\n /**\n * Build up the view all link that is dedicated to a particular result.\n *\n * @param {Number} userID The ID of the user selected.\n * @returns {string|*}\n */\n selectOneLink(userID) {\n return Url.relativeUrl('/grade/report/grader/index.php', {\n id: courseID,\n gpr_search: this.getSearchTerm(),\n gpr_userid: userID,\n }, false);\n }\n\n /**\n * Given the set of profile fields we can possibly search, fetch their strings,\n * so we can report to screen readers the field that matched.\n *\n * @returns {Promise<void>}\n */\n getStringMap() {\n if (!this.profilestringmap) {\n const requiredStrings = [\n 'username',\n 'fullname',\n 'firstname',\n 'lastname',\n 'email',\n 'city',\n 'country',\n 'department',\n 'institution',\n 'idnumber',\n 'phone1',\n 'phone2',\n ];\n this.profilestringmap = getStrings(requiredStrings.map((key) => ({key})))\n .then((stringArray) => new Map(\n requiredStrings.map((key, index) => ([key, stringArray[index]]))\n ));\n }\n return this.profilestringmap;\n }\n}\n"],"names":["selectors","courseID","document","querySelector","dataset","courseid","UserSearch","GradebookSearchClass","constructor","setComponentSelector","setDropdownSelector","setTriggerSelector","html","js","users","this","getMatchedResults","slice","hasusers","length","matches","showing","searchterm","getSearchTerm","selectall","selectAllResultsLink","getHTMLElements","searchDropdown","fetchDataset","Repository","userFetch","then","r","filterableData","stringMap","getStringMap","filter","user","Object","keys","some","key","get","toString","toLowerCase","includes","getPreppedSearchTerm","setMatchedResults","map","value","entries","valueString","preppedSearchTerm","searchTerm","matchingFieldName","escapedMatchingField","replace","email","matchingField","link","selectOneLink","id","clickHandler","e","target","currentViewAll","button","window","location","closest","href","keyHandler","activeElement","searchInput","clearSearchButton","closeSearch","preventDefault","toggleDropdown","focus","preventScroll","clearSearch","shiftKey","Url","relativeUrl","gpr_search","userID","gpr_userid","profilestringmap","requiredStrings","stringArray","Map","index"],"mappings":"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"}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists