diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php index daf0382bca4..d1a1f131f5c 100644 --- a/backup/moodle2/restore_stepslib.php +++ b/backup/moodle2/restore_stepslib.php @@ -6218,15 +6218,30 @@ trait restore_question_set_reference_data_trait { $data = (object) $data; $data->usingcontextid = $this->get_mappingid('context', $data->usingcontextid); $data->itemid = $this->get_new_parentid('quiz_question_instance'); - $filtercondition = json_decode($data->filtercondition); - if ($category = $this->get_mappingid('question_category', $filtercondition->questioncategoryid)) { - $filtercondition->questioncategoryid = $category; + $filtercondition = json_decode($data->filtercondition, true); + + if (!isset($filtercondition['filter'])) { + // Pre-4.3, convert the old filtercondition format to the new format. + $filtercondition = \core_question\question_reference_manager::convert_legacy_set_reference_filter_condition( + $filtercondition); } - $data->filtercondition = json_encode($filtercondition); + + // Map category id used for category filter condition and corresponding context id. + $oldcategoryid = $filtercondition['filter']['category']['values'][0]; + $newcategoryid = $this->get_mappingid('question_category', $oldcategoryid); + $filtercondition['filter']['category']['values'][0] = $newcategoryid; + if ($context = $this->get_mappingid('context', $data->questionscontextid)) { $data->questionscontextid = $context; } + $filtercondition['cat'] = implode(',', [ + $filtercondition['filter']['category']['values'][0], + $data->questionscontextid, + ]); + + $data->filtercondition = json_encode($filtercondition); + $DB->insert_record('question_set_references', $data); } } diff --git a/comment/lib.php b/comment/lib.php index 8a392840916..7c95224fc15 100644 --- a/comment/lib.php +++ b/comment/lib.php @@ -506,6 +506,9 @@ class comment { $html .= html_writer::start_tag('div', array('class' => 'comment-area')); $html .= html_writer::start_tag('div', array('class' => 'db')); + $html .= html_writer::tag('label', + get_string('comment', 'comment'), + ['for' => 'dlg-content-'.$this->cid, 'class' => 'sr-only']); $html .= html_writer::tag('textarea', '', $textareaattrs); $html .= html_writer::end_tag('div'); // .db diff --git a/lang/en/question.php b/lang/en/question.php index 821a1276a2c..cef4b112288 100644 --- a/lang/en/question.php +++ b/lang/en/question.php @@ -398,6 +398,7 @@ $string['markedoutof'] = 'Marked out of'; $string['markedoutofmax'] = 'Marked out of {$a}'; $string['markoutofmax'] = 'Mark {$a->mark} out of {$a->max}'; $string['marks'] = 'Marks'; +$string['noconditionspecified'] = 'Please specify a condition'; $string['noresponse'] = '[No response]'; $string['notanswered'] = 'Not answered'; $string['notgraded'] = 'Not graded'; @@ -465,9 +466,9 @@ $string['rightanswer'] = 'Right answer'; $string['rightanswer_help'] = 'An automatically generated summary of the correct response. This can be limited, so you may wish to consider explaining the correct solution in the general feedback for the question, and turning this option off.'; $string['saved'] = 'Saved: {$a}'; $string['settingsformultipletries'] = 'Multiple tries'; +$string['showhidden'] = 'Show hidden questions'; $string['shortversioninfo'] = 'v{$a->version} (of {$a->latestversion})'; $string['shortversioninfolatest'] = 'v{$a->version} (latest)'; -$string['showhidden'] = 'Also show old questions'; $string['showmarkandmax'] = 'Show mark and max'; $string['showmaxmarkonly'] = 'Show max mark only'; $string['showquestiontext'] = 'Show question text in the question list?'; diff --git a/lib/amd/build/datafilter.min.js b/lib/amd/build/datafilter.min.js index 2378450a148..f29b872f85c 100644 --- a/lib/amd/build/datafilter.min.js +++ b/lib/amd/build/datafilter.min.js @@ -1,3 +1,3 @@ -define("core/datafilter",["exports","core/datafilter/filtertypes/courseid","core/datafilter/filtertype","core/str","core/notification","core/pending","core/datafilter/selectors","core/templates","core/custom_interaction_events","jquery"],(function(_exports,_courseid,_filtertype,_str,_notification,_pending,_selectors,_templates,_custom_interaction_events,_jquery){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_courseid=_interopRequireDefault(_courseid),_filtertype=_interopRequireDefault(_filtertype),_notification=_interopRequireDefault(_notification),_pending=_interopRequireDefault(_pending),_selectors=_interopRequireDefault(_selectors),_templates=_interopRequireDefault(_templates),_custom_interaction_events=_interopRequireDefault(_custom_interaction_events),_jquery=_interopRequireDefault(_jquery);var _systemImportTransformerGlobalIdentifier="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}return _exports.default=class{constructor(filterSet,applyCallback){this.filterSet=filterSet,this.applyCallback=applyCallback,this.activeFilters={courseid:new _courseid.default("courseid",filterSet)}}init(){this.filterSet.querySelector(_selectors.default.filterset.region).addEventListener("click",(e=>{e.target.closest(_selectors.default.filterset.actions.addRow)&&(e.preventDefault(),this.addFilterRow()),e.target.closest(_selectors.default.filterset.actions.applyFilters)&&(e.preventDefault(),this.updateTableFromFilter()),e.target.closest(_selectors.default.filterset.actions.resetFilters)&&(e.preventDefault(),this.removeAllFilters())})),this.filterSet.querySelector(_selectors.default.filterset.regions.filterlist).addEventListener("click",(e=>{e.target.closest(_selectors.default.filter.actions.remove)&&(e.preventDefault(),this.removeOrReplaceFilterRow(e.target.closest(_selectors.default.filter.region),!0))}));let filterRegion=(0,_jquery.default)(this.getFilterRegion());_custom_interaction_events.default.define(filterRegion,[_custom_interaction_events.default.events.accessibleChange]),filterRegion.on(_custom_interaction_events.default.events.accessibleChange,(e=>{const typeField=e.target.closest(_selectors.default.filter.fields.type);if(typeField&&typeField.value){const filter=e.target.closest(_selectors.default.filter.region);this.addFilter(filter,typeField.value)}})),this.filterSet.querySelector(_selectors.default.filterset.fields.join).addEventListener("change",(e=>{this.filterSet.dataset.filterverb=e.target.value}))}getFilterRegion(){return this.filterSet.querySelector(_selectors.default.filterset.regions.filterlist)}addFilterRow(){const pendingPromise=new _pending.default("core/datafilter:addFilterRow"),rownum=1+this.getFilterRegion().querySelectorAll(_selectors.default.filter.region).length;return _templates.default.renderForPromise("core/datafilter/filter_row",{rownumber:rownum}).then((_ref=>{let{html:html,js:js}=_ref;return _templates.default.appendNodeContents(this.getFilterRegion(),html,js)})).then((filterRow=>{const typeList=this.filterSet.querySelector(_selectors.default.data.typeList);return filterRow.forEach((contentNode=>{const contentTypeList=contentNode.querySelector(_selectors.default.filter.fields.type);contentTypeList&&(contentTypeList.innerHTML=typeList.innerHTML)})),filterRow})).then((filterRow=>(this.updateFiltersOptions(),filterRow))).then((result=>(pendingPromise.resolve(),result))).catch(_notification.default.exception)}getFilterDataSource(filterType){return this.filterSet.querySelector(_selectors.default.filterset.regions.datasource).querySelector(_selectors.default.data.fields.byName(filterType))}async addFilter(filterRow,filterType,initialFilterValues){filterRow.dataset.filterType=filterType;const filterDataNode=this.getFilterDataSource(filterType);let Filter=_filtertype.default;filterDataNode.dataset.filterTypeClass&&(Filter=await("function"==typeof _systemImportTransformerGlobalIdentifier.define&&_systemImportTransformerGlobalIdentifier.define.amd?new Promise((function(resolve,reject){_systemImportTransformerGlobalIdentifier.require([filterDataNode.dataset.filterTypeClass],resolve,reject)})):"undefined"!=typeof module&&module.exports&&"undefined"!=typeof require||"undefined"!=typeof module&&module.component&&_systemImportTransformerGlobalIdentifier.require&&"component"===_systemImportTransformerGlobalIdentifier.require.loader?Promise.resolve(require(filterDataNode.dataset.filterTypeClass)):Promise.resolve(_systemImportTransformerGlobalIdentifier[filterDataNode.dataset.filterTypeClass]))),this.activeFilters[filterType]=new Filter(filterType,this.filterSet,initialFilterValues);const typeField=filterRow.querySelector(_selectors.default.filter.fields.type);return typeField.value=filterType,typeField.disabled="disabled",this.updateFiltersOptions(),this.activeFilters[filterType]}getFilterObject(name){return this.activeFilters[name]}removeOrReplaceFilterRow(filterRow,refreshContent){1===this.getFilterRegion().querySelectorAll(_selectors.default.filter.region).length?this.replaceFilterRow(filterRow,refreshContent):this.removeFilterRow(filterRow,refreshContent)}async removeFilterRow(filterRow){let refreshContent=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];const hasFilterValue=!!filterRow.querySelector(_selectors.default.filter.fields.type).value;this.removeFilterObject(filterRow.dataset.filterType),filterRow.remove(),this.updateFiltersOptions(),hasFilterValue&&refreshContent&&this.updateTableFromFilter();const filterLegends=await this.getAvailableFilterLegends();this.getFilterRegion().querySelectorAll(_selectors.default.filter.region).forEach(((filterRow,index)=>{filterRow.querySelector("legend").innerText=filterLegends[index]}))}replaceFilterRow(filterRow){let refreshContent=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],rowNum=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return this.removeFilterObject(filterRow.dataset.filterType),_templates.default.renderForPromise("core/datafilter/filter_row",{rownumber:rowNum}).then((_ref2=>{let{html:html,js:js}=_ref2;return _templates.default.replaceNode(filterRow,html,js)})).then((filterRow=>{const typeList=this.filterSet.querySelector(_selectors.default.data.typeList);return filterRow.forEach((contentNode=>{const contentTypeList=contentNode.querySelector(_selectors.default.filter.fields.type);contentTypeList&&(contentTypeList.innerHTML=typeList.innerHTML)})),filterRow})).then((filterRow=>(this.updateFiltersOptions(),filterRow))).then((filterRow=>refreshContent?this.updateTableFromFilter():filterRow)).catch(_notification.default.exception)}removeFilterObject(filterName){if(filterName){const filter=this.getFilterObject(filterName);filter&&(filter.tearDown(),delete this.activeFilters[filterName])}}removeAllFilters(){return this.getFilterRegion().querySelectorAll(_selectors.default.filter.region).forEach((filterRow=>this.removeOrReplaceFilterRow(filterRow,!1))),this.updateTableFromFilter()}removeEmptyFilters(){this.getFilterRegion().querySelectorAll(_selectors.default.filter.region).forEach((filterRow=>{filterRow.querySelector(_selectors.default.filter.fields.type).value||this.removeOrReplaceFilterRow(filterRow,!1)}))}updateFiltersOptions(){const filters=this.getFilterRegion().querySelectorAll(_selectors.default.filter.region);filters.forEach((filterRow=>{filterRow.querySelectorAll(_selectors.default.filter.fields.type+" option").forEach((option=>{option.value===filterRow.dataset.filterType?(option.classList.remove("hidden"),option.disabled=!1):this.activeFilters[option.value]?(option.classList.add("hidden"),option.disabled=!0):(option.classList.remove("hidden"),option.disabled=!1)}))}));const addRowButton=this.filterSet.querySelector(_selectors.default.filterset.actions.addRow);this.filterSet.querySelectorAll(_selectors.default.data.fields.all).length<=filters.length?addRowButton.setAttribute("disabled","disabled"):addRowButton.removeAttribute("disabled"),1===filters.length?(this.filterSet.querySelector(_selectors.default.filterset.regions.filtermatch).classList.add("hidden"),this.filterSet.querySelector(_selectors.default.filterset.fields.join).value=2,this.filterSet.dataset.filterverb=2):this.filterSet.querySelector(_selectors.default.filterset.regions.filtermatch).classList.remove("hidden")}updateTableFromFilter(){const pendingPromise=new _pending.default("core/datafilter:updateTableFromFilter"),filters={};Object.values(this.activeFilters).forEach((filter=>{filters[filter.filterValue.name]=filter.filterValue})),this.applyCallback&&this.applyCallback(filters,pendingPromise)}async getAvailableFilterLegends(){const maxFilters=document.querySelector(_selectors.default.data.typeListSelect).length-1;let requests=[];[...Array(maxFilters)].forEach(((_,rowIndex)=>{requests.push({key:"filterrowlegend",component:"core",param:rowIndex+1})}));return await(0,_str.getStrings)(requests).then((fetchedStrings=>fetchedStrings)).catch(_notification.default.exception)}},_exports.default})); +define("core/datafilter",["exports","core/datafilter/filtertypes/courseid","core/datafilter/filtertype","core/str","core/notification","core/pending","core/datafilter/selectors","core/templates","core/custom_interaction_events","jquery"],(function(_exports,_courseid,_filtertype,_str,_notification,_pending,_selectors,_templates,_custom_interaction_events,_jquery){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_courseid=_interopRequireDefault(_courseid),_filtertype=_interopRequireDefault(_filtertype),_notification=_interopRequireDefault(_notification),_pending=_interopRequireDefault(_pending),_selectors=_interopRequireDefault(_selectors),_templates=_interopRequireDefault(_templates),_custom_interaction_events=_interopRequireDefault(_custom_interaction_events),_jquery=_interopRequireDefault(_jquery);var _systemImportTransformerGlobalIdentifier="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}return _exports.default=class{constructor(filterSet,applyCallback){this.filterSet=filterSet,this.applyCallback=applyCallback,this.activeFilters={courseid:new _courseid.default("courseid",filterSet)}}init(){this.filterSet.querySelector(_selectors.default.filterset.region).addEventListener("click",(e=>{e.target.closest(_selectors.default.filterset.actions.addRow)&&(e.preventDefault(),this.addFilterRow()),e.target.closest(_selectors.default.filterset.actions.applyFilters)&&(e.preventDefault(),this.updateTableFromFilter()),e.target.closest(_selectors.default.filterset.actions.resetFilters)&&(e.preventDefault(),this.removeAllFilters())})),this.filterSet.querySelector(_selectors.default.filterset.regions.filterlist).addEventListener("click",(e=>{e.target.closest(_selectors.default.filter.actions.remove)&&(e.preventDefault(),this.removeOrReplaceFilterRow(e.target.closest(_selectors.default.filter.region),!0))}));let filterRegion=(0,_jquery.default)(this.getFilterRegion());_custom_interaction_events.default.define(filterRegion,[_custom_interaction_events.default.events.accessibleChange]),filterRegion.on(_custom_interaction_events.default.events.accessibleChange,(e=>{const typeField=e.target.closest(_selectors.default.filter.fields.type);if(typeField&&typeField.value){const filter=e.target.closest(_selectors.default.filter.region);this.addFilter(filter,typeField.value)}})),this.filterSet.querySelector(_selectors.default.filterset.fields.join).addEventListener("change",(e=>{this.filterSet.dataset.filterverb=e.target.value}))}getFilterRegion(){return this.filterSet.querySelector(_selectors.default.filterset.regions.filterlist)}addFilterRow(){var _filterdata$rownum;let filterdata=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const pendingPromise=new _pending.default("core/datafilter:addFilterRow"),rownum=null!==(_filterdata$rownum=filterdata.rownum)&&void 0!==_filterdata$rownum?_filterdata$rownum:1+this.getFilterRegion().querySelectorAll(_selectors.default.filter.region).length;return _templates.default.renderForPromise("core/datafilter/filter_row",{rownumber:rownum}).then((_ref=>{let{html:html,js:js}=_ref;return _templates.default.appendNodeContents(this.getFilterRegion(),html,js)})).then((filterRow=>{const typeList=this.filterSet.querySelector(_selectors.default.data.typeList);return filterRow.forEach((contentNode=>{const contentTypeList=contentNode.querySelector(_selectors.default.filter.fields.type);contentTypeList&&(contentTypeList.innerHTML=typeList.innerHTML)})),filterRow})).then((filterRow=>(this.updateFiltersOptions(),filterRow))).then((result=>(pendingPromise.resolve(),filterdata.filtertype&&result.forEach((filter=>{this.addFilter(filter,filterdata.filtertype,filterdata.values,filterdata.jointype,filterdata.filteroptions)})),result))).catch(_notification.default.exception)}getFilterDataSource(filterType){return this.filterSet.querySelector(_selectors.default.filterset.regions.datasource).querySelector(_selectors.default.data.fields.byName(filterType))}async addFilter(filterRow,filterType,initialFilterValues,filterJoin,filterOptions){filterRow.dataset.filterType=filterType;const filterDataNode=this.getFilterDataSource(filterType);let Filter=_filtertype.default;filterDataNode.dataset.filterTypeClass&&(Filter=await("function"==typeof _systemImportTransformerGlobalIdentifier.define&&_systemImportTransformerGlobalIdentifier.define.amd?new Promise((function(resolve,reject){_systemImportTransformerGlobalIdentifier.require([filterDataNode.dataset.filterTypeClass],resolve,reject)})):"undefined"!=typeof module&&module.exports&&"undefined"!=typeof require||"undefined"!=typeof module&&module.component&&_systemImportTransformerGlobalIdentifier.require&&"component"===_systemImportTransformerGlobalIdentifier.require.loader?Promise.resolve(require(filterDataNode.dataset.filterTypeClass)):Promise.resolve(_systemImportTransformerGlobalIdentifier[filterDataNode.dataset.filterTypeClass]))),this.activeFilters[filterType]=new Filter(filterType,this.filterSet,initialFilterValues,filterOptions);const typeField=filterRow.querySelector(_selectors.default.filter.fields.type);typeField.value=filterType,typeField.disabled="disabled",this.updateJoinList(JSON.parse(filterDataNode.dataset.joinList),filterRow);const joinField=filterRow.querySelector(_selectors.default.filter.fields.join);return joinField.disabled=!1,isNaN(filterJoin)||(joinField.value=filterJoin),this.updateFiltersOptions(),this.activeFilters[filterType]}getFilterObject(name){return this.activeFilters[name]}removeOrReplaceFilterRow(filterRow,refreshContent){1===this.getFilterRegion().querySelectorAll(_selectors.default.filter.region).length?this.replaceFilterRow(filterRow,refreshContent):this.removeFilterRow(filterRow,refreshContent)}async removeFilterRow(filterRow){let refreshContent=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];if(filterRow.querySelector(_selectors.default.data.required))return;const hasFilterValue=!!filterRow.querySelector(_selectors.default.filter.fields.type).value;this.removeFilterObject(filterRow.dataset.filterType),filterRow.remove(),this.updateFiltersOptions(),hasFilterValue&&refreshContent&&this.updateTableFromFilter();const filterLegends=await this.getAvailableFilterLegends();this.getFilterRegion().querySelectorAll(_selectors.default.filter.region).forEach(((filterRow,index)=>{filterRow.querySelector("legend").innerText=filterLegends[index]}))}replaceFilterRow(filterRow){let refreshContent=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],rowNum=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;if(!filterRow.querySelector(_selectors.default.data.required))return this.removeFilterObject(filterRow.dataset.filterType),_templates.default.renderForPromise("core/datafilter/filter_row",{rownumber:rowNum}).then((_ref2=>{let{html:html,js:js}=_ref2;return _templates.default.replaceNode(filterRow,html,js)})).then((filterRow=>{const typeList=this.filterSet.querySelector(_selectors.default.data.typeList);return filterRow.forEach((contentNode=>{const contentTypeList=contentNode.querySelector(_selectors.default.filter.fields.type);contentTypeList&&(contentTypeList.innerHTML=typeList.innerHTML)})),filterRow})).then((filterRow=>(this.updateFiltersOptions(),filterRow))).then((filterRow=>refreshContent?this.updateTableFromFilter():filterRow)).catch(_notification.default.exception)}removeFilterObject(filterName){if(filterName){const filter=this.getFilterObject(filterName);filter&&(filter.tearDown(),delete this.activeFilters[filterName])}}removeAllFilters(){return this.getFilterRegion().querySelectorAll(_selectors.default.filter.region).forEach((filterRow=>this.removeOrReplaceFilterRow(filterRow,!1))),this.updateTableFromFilter()}removeEmptyFilters(){this.getFilterRegion().querySelectorAll(_selectors.default.filter.region).forEach((filterRow=>{filterRow.querySelector(_selectors.default.filter.fields.type).value||this.removeOrReplaceFilterRow(filterRow,!1)}))}updateFiltersOptions(){const filters=this.getFilterRegion().querySelectorAll(_selectors.default.filter.region);filters.forEach((filterRow=>{filterRow.querySelectorAll(_selectors.default.filter.fields.type+" option").forEach((option=>{option.value===filterRow.dataset.filterType?(option.classList.remove("hidden"),option.disabled=!1):this.activeFilters[option.value]?(option.classList.add("hidden"),option.disabled=!0):(option.classList.remove("hidden"),option.disabled=!1)}))}));const addRowButton=this.filterSet.querySelector(_selectors.default.filterset.actions.addRow);this.filterSet.querySelectorAll(_selectors.default.data.fields.all).length<=filters.length?addRowButton.setAttribute("disabled","disabled"):addRowButton.removeAttribute("disabled"),1===filters.length?(this.filterSet.querySelector(_selectors.default.filterset.regions.filtermatch).classList.add("hidden"),this.filterSet.querySelector(_selectors.default.filterset.fields.join).value=2,this.filterSet.dataset.filterverb=2):this.filterSet.querySelector(_selectors.default.filterset.regions.filtermatch).classList.remove("hidden")}updateTableFromFilter(){const pendingPromise=new _pending.default("core/datafilter:updateTableFromFilter"),filters={};Object.values(this.activeFilters).forEach((filter=>{filters[filter.filterValue.name]=filter.filterValue})),this.applyCallback&&this.applyCallback(filters,pendingPromise)}async getAvailableFilterLegends(){const maxFilters=document.querySelector(_selectors.default.data.typeListSelect).length-1;let requests=[];[...Array(maxFilters)].forEach(((_,rowIndex)=>{requests.push({key:"filterrowlegend",component:"core",param:rowIndex+1})}));return await(0,_str.getStrings)(requests).then((fetchedStrings=>fetchedStrings)).catch(_notification.default.exception)}updateJoinList(filterJoinList,filterRow){const regularJoinList=[0,1,2];if(0!==filterJoinList.length){const joinField=filterRow.querySelector(_selectors.default.filter.fields.join);regularJoinList.forEach((join=>{filterJoinList.includes(join)||(joinField.options[join].classList.add("hidden"),joinField.options[join].disabled=!0)})),joinField.options.forEach(((element,index)=>{element.disabled&&(joinField.options[index]=null)})),1===joinField.options.length&&(joinField.hidden=!0)}}},_exports.default})); //# sourceMappingURL=datafilter.min.js.map \ No newline at end of file diff --git a/lib/amd/build/datafilter.min.js.map b/lib/amd/build/datafilter.min.js.map index bdd8c2ec619..cafa96e94f5 100644 --- a/lib/amd/build/datafilter.min.js.map +++ b/lib/amd/build/datafilter.min.js.map @@ -1 +1 @@ -{"version":3,"file":"datafilter.min.js","sources":["../src/datafilter.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 .\n\n/**\n * Data filter management.\n *\n * @module core/datafilter\n * @copyright 2020 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport CourseFilter from 'core/datafilter/filtertypes/courseid';\nimport GenericFilter from 'core/datafilter/filtertype';\nimport {getStrings} from 'core/str';\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\nimport Selectors from 'core/datafilter/selectors';\nimport Templates from 'core/templates';\nimport CustomEvents from 'core/custom_interaction_events';\nimport jQuery from 'jquery';\n\nexport default class {\n\n /**\n * Initialise the filter on the element with the given filterSet and callback.\n *\n * @param {HTMLElement} filterSet The filter element.\n * @param {Function} applyCallback Callback function when updateTableFromFilter\n */\n constructor(filterSet, applyCallback) {\n\n this.filterSet = filterSet;\n this.applyCallback = applyCallback;\n // Keep a reference to all of the active filters.\n this.activeFilters = {\n courseid: new CourseFilter('courseid', filterSet),\n };\n }\n\n /**\n * Initialise event listeners to the filter.\n */\n init() {\n // Add listeners for the main actions.\n this.filterSet.querySelector(Selectors.filterset.region).addEventListener('click', e => {\n if (e.target.closest(Selectors.filterset.actions.addRow)) {\n e.preventDefault();\n\n this.addFilterRow();\n }\n\n if (e.target.closest(Selectors.filterset.actions.applyFilters)) {\n e.preventDefault();\n\n this.updateTableFromFilter();\n }\n\n if (e.target.closest(Selectors.filterset.actions.resetFilters)) {\n e.preventDefault();\n\n this.removeAllFilters();\n }\n });\n\n // Add the listener to remove a single filter.\n this.filterSet.querySelector(Selectors.filterset.regions.filterlist).addEventListener('click', e => {\n if (e.target.closest(Selectors.filter.actions.remove)) {\n e.preventDefault();\n\n this.removeOrReplaceFilterRow(e.target.closest(Selectors.filter.region), true);\n }\n });\n\n // Add listeners for the filter type selection.\n let filterRegion = jQuery(this.getFilterRegion());\n CustomEvents.define(filterRegion, [CustomEvents.events.accessibleChange]);\n filterRegion.on(CustomEvents.events.accessibleChange, e => {\n const typeField = e.target.closest(Selectors.filter.fields.type);\n if (typeField && typeField.value) {\n const filter = e.target.closest(Selectors.filter.region);\n\n this.addFilter(filter, typeField.value);\n }\n });\n\n this.filterSet.querySelector(Selectors.filterset.fields.join).addEventListener('change', e => {\n this.filterSet.dataset.filterverb = e.target.value;\n });\n }\n\n /**\n * Get the filter list region.\n *\n * @return {HTMLElement}\n */\n getFilterRegion() {\n return this.filterSet.querySelector(Selectors.filterset.regions.filterlist);\n }\n\n /**\n * Add an unselected filter row.\n *\n * @return {Promise}\n */\n addFilterRow() {\n const pendingPromise = new Pending('core/datafilter:addFilterRow');\n const rownum = 1 + this.getFilterRegion().querySelectorAll(Selectors.filter.region).length;\n return Templates.renderForPromise('core/datafilter/filter_row', {\"rownumber\": rownum})\n .then(({html, js}) => {\n const newContentNodes = Templates.appendNodeContents(this.getFilterRegion(), html, js);\n\n return newContentNodes;\n })\n .then(filterRow => {\n // Note: This is a nasty hack.\n // We should try to find a better way of doing this.\n // We do not have the list of types in a readily consumable format, so we take the pre-rendered one and copy\n // it in place.\n const typeList = this.filterSet.querySelector(Selectors.data.typeList);\n\n filterRow.forEach(contentNode => {\n const contentTypeList = contentNode.querySelector(Selectors.filter.fields.type);\n\n if (contentTypeList) {\n contentTypeList.innerHTML = typeList.innerHTML;\n }\n });\n\n return filterRow;\n })\n .then(filterRow => {\n this.updateFiltersOptions();\n\n return filterRow;\n })\n .then(result => {\n pendingPromise.resolve();\n\n return result;\n })\n .catch(Notification.exception);\n }\n\n /**\n * Get the filter data source node fro the specified filter type.\n *\n * @param {String} filterType\n * @return {HTMLElement}\n */\n getFilterDataSource(filterType) {\n const filterDataNode = this.filterSet.querySelector(Selectors.filterset.regions.datasource);\n\n return filterDataNode.querySelector(Selectors.data.fields.byName(filterType));\n }\n\n /**\n * Add a filter to the list of active filters, performing any necessary setup.\n *\n * @param {HTMLElement} filterRow\n * @param {String} filterType\n * @param {Array} initialFilterValues The initially selected values for the filter\n * @returns {Filter}\n */\n async addFilter(filterRow, filterType, initialFilterValues) {\n // Name the filter on the filter row.\n filterRow.dataset.filterType = filterType;\n\n const filterDataNode = this.getFilterDataSource(filterType);\n\n // Instantiate the Filter class.\n let Filter = GenericFilter;\n if (filterDataNode.dataset.filterTypeClass) {\n Filter = await import(filterDataNode.dataset.filterTypeClass);\n }\n this.activeFilters[filterType] = new Filter(filterType, this.filterSet, initialFilterValues);\n\n // Disable the select.\n const typeField = filterRow.querySelector(Selectors.filter.fields.type);\n typeField.value = filterType;\n typeField.disabled = 'disabled';\n\n // Update the list of available filter types.\n this.updateFiltersOptions();\n\n return this.activeFilters[filterType];\n }\n\n /**\n * Get the registered filter class for the named filter.\n *\n * @param {String} name\n * @return {Object} See the Filter class.\n */\n getFilterObject(name) {\n return this.activeFilters[name];\n }\n\n /**\n * Remove or replace the specified filter row and associated class, ensuring that if there is only one filter row,\n * that it is replaced instead of being removed.\n *\n * @param {HTMLElement} filterRow\n * @param {Bool} refreshContent Whether to refresh the table content when removing\n */\n removeOrReplaceFilterRow(filterRow, refreshContent) {\n const filterCount = this.getFilterRegion().querySelectorAll(Selectors.filter.region).length;\n if (filterCount === 1) {\n this.replaceFilterRow(filterRow, refreshContent);\n } else {\n this.removeFilterRow(filterRow, refreshContent);\n }\n }\n\n /**\n * Remove the specified filter row and associated class.\n *\n * @param {HTMLElement} filterRow\n * @param {Bool} refreshContent Whether to refresh the table content when removing\n */\n async removeFilterRow(filterRow, refreshContent = true) {\n const filterType = filterRow.querySelector(Selectors.filter.fields.type);\n const hasFilterValue = !!filterType.value;\n\n // Remove the filter object.\n this.removeFilterObject(filterRow.dataset.filterType);\n\n // Remove the actual filter HTML.\n filterRow.remove();\n\n // Update the list of available filter types.\n this.updateFiltersOptions();\n\n if (hasFilterValue && refreshContent) {\n // Refresh the table if there was any content in this row.\n this.updateTableFromFilter();\n }\n\n // Update filter fieldset legends.\n const filterLegends = await this.getAvailableFilterLegends();\n\n this.getFilterRegion().querySelectorAll(Selectors.filter.region).forEach((filterRow, index) => {\n filterRow.querySelector('legend').innerText = filterLegends[index];\n });\n\n }\n\n /**\n * Replace the specified filter row with a new one.\n *\n * @param {HTMLElement} filterRow\n * @param {Bool} refreshContent Whether to refresh the table content when removing\n * @param {Number} rowNum The number used to label the filter fieldset legend (eg Row 1). Defaults to 1 (the first filter).\n * @return {Promise}\n */\n replaceFilterRow(filterRow, refreshContent = true, rowNum = 1) {\n // Remove the filter object.\n this.removeFilterObject(filterRow.dataset.filterType);\n\n return Templates.renderForPromise('core/datafilter/filter_row', {\"rownumber\": rowNum})\n .then(({html, js}) => {\n const newContentNodes = Templates.replaceNode(filterRow, html, js);\n\n return newContentNodes;\n })\n .then(filterRow => {\n // Note: This is a nasty hack.\n // We should try to find a better way of doing this.\n // We do not have the list of types in a readily consumable format, so we take the pre-rendered one and copy\n // it in place.\n const typeList = this.filterSet.querySelector(Selectors.data.typeList);\n\n filterRow.forEach(contentNode => {\n const contentTypeList = contentNode.querySelector(Selectors.filter.fields.type);\n\n if (contentTypeList) {\n contentTypeList.innerHTML = typeList.innerHTML;\n }\n });\n\n return filterRow;\n })\n .then(filterRow => {\n this.updateFiltersOptions();\n\n return filterRow;\n })\n .then(filterRow => {\n // Refresh the table.\n if (refreshContent) {\n return this.updateTableFromFilter();\n } else {\n return filterRow;\n }\n })\n .catch(Notification.exception);\n }\n\n /**\n * Remove the Filter Object from the register.\n *\n * @param {string} filterName The name of the filter to be removed\n */\n removeFilterObject(filterName) {\n if (filterName) {\n const filter = this.getFilterObject(filterName);\n if (filter) {\n filter.tearDown();\n\n // Remove from the list of active filters.\n delete this.activeFilters[filterName];\n }\n }\n }\n\n /**\n * Remove all filters.\n *\n * @returns {Promise}\n */\n removeAllFilters() {\n const filters = this.getFilterRegion().querySelectorAll(Selectors.filter.region);\n filters.forEach(filterRow => this.removeOrReplaceFilterRow(filterRow, false));\n\n // Refresh the table.\n return this.updateTableFromFilter();\n }\n\n /**\n * Remove any empty filters.\n */\n removeEmptyFilters() {\n const filters = this.getFilterRegion().querySelectorAll(Selectors.filter.region);\n filters.forEach(filterRow => {\n const filterType = filterRow.querySelector(Selectors.filter.fields.type);\n if (!filterType.value) {\n this.removeOrReplaceFilterRow(filterRow, false);\n }\n });\n }\n\n /**\n * Update the list of filter types to filter out those already selected.\n */\n updateFiltersOptions() {\n const filters = this.getFilterRegion().querySelectorAll(Selectors.filter.region);\n filters.forEach(filterRow => {\n const options = filterRow.querySelectorAll(Selectors.filter.fields.type + ' option');\n options.forEach(option => {\n if (option.value === filterRow.dataset.filterType) {\n option.classList.remove('hidden');\n option.disabled = false;\n } else if (this.activeFilters[option.value]) {\n option.classList.add('hidden');\n option.disabled = true;\n } else {\n option.classList.remove('hidden');\n option.disabled = false;\n }\n });\n });\n\n // Configure the state of the \"Add row\" button.\n // This button is disabled when there is a filter row available for each condition.\n const addRowButton = this.filterSet.querySelector(Selectors.filterset.actions.addRow);\n const filterDataNode = this.filterSet.querySelectorAll(Selectors.data.fields.all);\n if (filterDataNode.length <= filters.length) {\n addRowButton.setAttribute('disabled', 'disabled');\n } else {\n addRowButton.removeAttribute('disabled');\n }\n\n if (filters.length === 1) {\n this.filterSet.querySelector(Selectors.filterset.regions.filtermatch).classList.add('hidden');\n this.filterSet.querySelector(Selectors.filterset.fields.join).value = 2;\n this.filterSet.dataset.filterverb = 2;\n } else {\n this.filterSet.querySelector(Selectors.filterset.regions.filtermatch).classList.remove('hidden');\n }\n }\n\n /**\n * Update the Dynamic table based upon the current filter.\n */\n updateTableFromFilter() {\n const pendingPromise = new Pending('core/datafilter:updateTableFromFilter');\n\n const filters = {};\n Object.values(this.activeFilters).forEach(filter => {\n filters[filter.filterValue.name] = filter.filterValue;\n });\n\n if (this.applyCallback) {\n this.applyCallback(filters, pendingPromise);\n }\n }\n\n /**\n * Fetch the strings used to populate the fieldset legends for the maximum number of filters possible.\n *\n * @return {array}\n */\n async getAvailableFilterLegends() {\n const maxFilters = document.querySelector(Selectors.data.typeListSelect).length - 1;\n let requests = [];\n\n [...Array(maxFilters)].forEach((_, rowIndex) => {\n requests.push({\n \"key\": \"filterrowlegend\",\n \"component\": \"core\",\n // Add 1 since rows begin at 1 (index begins at zero).\n \"param\": rowIndex + 1\n });\n });\n\n const legendStrings = await getStrings(requests)\n .then(fetchedStrings => {\n return fetchedStrings;\n })\n .catch(Notification.exception);\n\n return legendStrings;\n }\n\n}\n"],"names":["constructor","filterSet","applyCallback","activeFilters","courseid","CourseFilter","init","querySelector","Selectors","filterset","region","addEventListener","e","target","closest","actions","addRow","preventDefault","addFilterRow","applyFilters","updateTableFromFilter","resetFilters","removeAllFilters","regions","filterlist","filter","remove","removeOrReplaceFilterRow","filterRegion","this","getFilterRegion","define","CustomEvents","events","accessibleChange","on","typeField","fields","type","value","addFilter","join","dataset","filterverb","pendingPromise","Pending","rownum","querySelectorAll","length","Templates","renderForPromise","then","_ref","html","js","appendNodeContents","filterRow","typeList","data","forEach","contentNode","contentTypeList","innerHTML","updateFiltersOptions","result","resolve","catch","Notification","exception","getFilterDataSource","filterType","datasource","byName","initialFilterValues","filterDataNode","Filter","GenericFilter","filterTypeClass","disabled","getFilterObject","name","refreshContent","replaceFilterRow","removeFilterRow","hasFilterValue","removeFilterObject","filterLegends","getAvailableFilterLegends","index","innerText","rowNum","_ref2","replaceNode","filterName","tearDown","removeEmptyFilters","filters","option","classList","add","addRowButton","all","setAttribute","removeAttribute","filtermatch","Object","values","filterValue","maxFilters","document","typeListSelect","requests","Array","_","rowIndex","push","fetchedStrings"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"datafilter.min.js","sources":["../src/datafilter.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 .\n\n/**\n * Data filter management.\n *\n * @module core/datafilter\n * @copyright 2020 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport CourseFilter from 'core/datafilter/filtertypes/courseid';\nimport GenericFilter from 'core/datafilter/filtertype';\nimport {getStrings} from 'core/str';\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\nimport Selectors from 'core/datafilter/selectors';\nimport Templates from 'core/templates';\nimport CustomEvents from 'core/custom_interaction_events';\nimport jQuery from 'jquery';\n\nexport default class {\n\n /**\n * Initialise the filter on the element with the given filterSet and callback.\n *\n * @param {HTMLElement} filterSet The filter element.\n * @param {Function} applyCallback Callback function when updateTableFromFilter\n */\n constructor(filterSet, applyCallback) {\n\n this.filterSet = filterSet;\n this.applyCallback = applyCallback;\n // Keep a reference to all of the active filters.\n this.activeFilters = {\n courseid: new CourseFilter('courseid', filterSet),\n };\n }\n\n /**\n * Initialise event listeners to the filter.\n */\n init() {\n // Add listeners for the main actions.\n this.filterSet.querySelector(Selectors.filterset.region).addEventListener('click', e => {\n if (e.target.closest(Selectors.filterset.actions.addRow)) {\n e.preventDefault();\n\n this.addFilterRow();\n }\n\n if (e.target.closest(Selectors.filterset.actions.applyFilters)) {\n e.preventDefault();\n\n this.updateTableFromFilter();\n }\n\n if (e.target.closest(Selectors.filterset.actions.resetFilters)) {\n e.preventDefault();\n\n this.removeAllFilters();\n }\n });\n\n // Add the listener to remove a single filter.\n this.filterSet.querySelector(Selectors.filterset.regions.filterlist).addEventListener('click', e => {\n if (e.target.closest(Selectors.filter.actions.remove)) {\n e.preventDefault();\n\n this.removeOrReplaceFilterRow(e.target.closest(Selectors.filter.region), true);\n }\n });\n\n // Add listeners for the filter type selection.\n let filterRegion = jQuery(this.getFilterRegion());\n CustomEvents.define(filterRegion, [CustomEvents.events.accessibleChange]);\n filterRegion.on(CustomEvents.events.accessibleChange, e => {\n const typeField = e.target.closest(Selectors.filter.fields.type);\n if (typeField && typeField.value) {\n const filter = e.target.closest(Selectors.filter.region);\n\n this.addFilter(filter, typeField.value);\n }\n });\n\n this.filterSet.querySelector(Selectors.filterset.fields.join).addEventListener('change', e => {\n this.filterSet.dataset.filterverb = e.target.value;\n });\n }\n\n /**\n * Get the filter list region.\n *\n * @return {HTMLElement}\n */\n getFilterRegion() {\n return this.filterSet.querySelector(Selectors.filterset.regions.filterlist);\n }\n\n /**\n * Add a filter row.\n *\n * @param {Object} filterdata Optional, data for adding for row with an existing filter.\n * @return {Promise}\n */\n addFilterRow(filterdata = {}) {\n const pendingPromise = new Pending('core/datafilter:addFilterRow');\n const rownum = filterdata.rownum ?? 1 + this.getFilterRegion().querySelectorAll(Selectors.filter.region).length;\n return Templates.renderForPromise('core/datafilter/filter_row', {\"rownumber\": rownum})\n .then(({html, js}) => {\n const newContentNodes = Templates.appendNodeContents(this.getFilterRegion(), html, js);\n\n return newContentNodes;\n })\n .then(filterRow => {\n // Note: This is a nasty hack.\n // We should try to find a better way of doing this.\n // We do not have the list of types in a readily consumable format, so we take the pre-rendered one and copy\n // it in place.\n const typeList = this.filterSet.querySelector(Selectors.data.typeList);\n\n filterRow.forEach(contentNode => {\n const contentTypeList = contentNode.querySelector(Selectors.filter.fields.type);\n\n if (contentTypeList) {\n contentTypeList.innerHTML = typeList.innerHTML;\n }\n });\n\n return filterRow;\n })\n .then(filterRow => {\n this.updateFiltersOptions();\n\n return filterRow;\n })\n .then(result => {\n pendingPromise.resolve();\n\n // If an existing filter is passed in, add it. Otherwise, leave the row empty.\n if (filterdata.filtertype) {\n result.forEach(filter => {\n this.addFilter(filter, filterdata.filtertype, filterdata.values,\n filterdata.jointype, filterdata.filteroptions);\n });\n }\n return result;\n })\n .catch(Notification.exception);\n }\n\n /**\n * Get the filter data source node fro the specified filter type.\n *\n * @param {String} filterType\n * @return {HTMLElement}\n */\n getFilterDataSource(filterType) {\n const filterDataNode = this.filterSet.querySelector(Selectors.filterset.regions.datasource);\n\n return filterDataNode.querySelector(Selectors.data.fields.byName(filterType));\n }\n\n /**\n * Add a filter to the list of active filters, performing any necessary setup.\n *\n * @param {HTMLElement} filterRow\n * @param {String} filterType\n * @param {Array} initialFilterValues The initially selected values for the filter\n * @param {String} filterJoin\n * @param {Object} filterOptions\n * @returns {Filter}\n */\n async addFilter(filterRow, filterType, initialFilterValues, filterJoin, filterOptions) {\n // Name the filter on the filter row.\n filterRow.dataset.filterType = filterType;\n\n const filterDataNode = this.getFilterDataSource(filterType);\n\n // Instantiate the Filter class.\n let Filter = GenericFilter;\n if (filterDataNode.dataset.filterTypeClass) {\n Filter = await import(filterDataNode.dataset.filterTypeClass);\n }\n this.activeFilters[filterType] = new Filter(filterType, this.filterSet, initialFilterValues, filterOptions);\n\n // Disable the select.\n const typeField = filterRow.querySelector(Selectors.filter.fields.type);\n typeField.value = filterType;\n typeField.disabled = 'disabled';\n // Update the join list.\n this.updateJoinList(JSON.parse(filterDataNode.dataset.joinList), filterRow);\n const joinField = filterRow.querySelector(Selectors.filter.fields.join);\n joinField.disabled = false;\n if (!isNaN(filterJoin)) {\n joinField.value = filterJoin;\n }\n // Update the list of available filter types.\n this.updateFiltersOptions();\n\n return this.activeFilters[filterType];\n }\n\n /**\n * Get the registered filter class for the named filter.\n *\n * @param {String} name\n * @return {Object} See the Filter class.\n */\n getFilterObject(name) {\n return this.activeFilters[name];\n }\n\n /**\n * Remove or replace the specified filter row and associated class, ensuring that if there is only one filter row,\n * that it is replaced instead of being removed.\n *\n * @param {HTMLElement} filterRow\n * @param {Bool} refreshContent Whether to refresh the table content when removing\n */\n removeOrReplaceFilterRow(filterRow, refreshContent) {\n const filterCount = this.getFilterRegion().querySelectorAll(Selectors.filter.region).length;\n if (filterCount === 1) {\n this.replaceFilterRow(filterRow, refreshContent);\n } else {\n this.removeFilterRow(filterRow, refreshContent);\n }\n }\n\n /**\n * Remove the specified filter row and associated class.\n *\n * @param {HTMLElement} filterRow\n * @param {Bool} refreshContent Whether to refresh the table content when removing\n */\n async removeFilterRow(filterRow, refreshContent = true) {\n if (filterRow.querySelector(Selectors.data.required)) {\n return;\n }\n const filterType = filterRow.querySelector(Selectors.filter.fields.type);\n const hasFilterValue = !!filterType.value;\n\n // Remove the filter object.\n this.removeFilterObject(filterRow.dataset.filterType);\n\n // Remove the actual filter HTML.\n filterRow.remove();\n\n // Update the list of available filter types.\n this.updateFiltersOptions();\n\n if (hasFilterValue && refreshContent) {\n // Refresh the table if there was any content in this row.\n this.updateTableFromFilter();\n }\n\n // Update filter fieldset legends.\n const filterLegends = await this.getAvailableFilterLegends();\n\n this.getFilterRegion().querySelectorAll(Selectors.filter.region).forEach((filterRow, index) => {\n filterRow.querySelector('legend').innerText = filterLegends[index];\n });\n\n }\n\n /**\n * Replace the specified filter row with a new one.\n *\n * @param {HTMLElement} filterRow\n * @param {Bool} refreshContent Whether to refresh the table content when removing\n * @param {Number} rowNum The number used to label the filter fieldset legend (eg Row 1). Defaults to 1 (the first filter).\n * @return {Promise}\n */\n replaceFilterRow(filterRow, refreshContent = true, rowNum = 1) {\n if (filterRow.querySelector(Selectors.data.required)) {\n return;\n }\n // Remove the filter object.\n this.removeFilterObject(filterRow.dataset.filterType);\n\n return Templates.renderForPromise('core/datafilter/filter_row', {\"rownumber\": rowNum})\n .then(({html, js}) => {\n const newContentNodes = Templates.replaceNode(filterRow, html, js);\n\n return newContentNodes;\n })\n .then(filterRow => {\n // Note: This is a nasty hack.\n // We should try to find a better way of doing this.\n // We do not have the list of types in a readily consumable format, so we take the pre-rendered one and copy\n // it in place.\n const typeList = this.filterSet.querySelector(Selectors.data.typeList);\n\n filterRow.forEach(contentNode => {\n const contentTypeList = contentNode.querySelector(Selectors.filter.fields.type);\n\n if (contentTypeList) {\n contentTypeList.innerHTML = typeList.innerHTML;\n }\n });\n\n return filterRow;\n })\n .then(filterRow => {\n this.updateFiltersOptions();\n\n return filterRow;\n })\n .then(filterRow => {\n // Refresh the table.\n if (refreshContent) {\n return this.updateTableFromFilter();\n } else {\n return filterRow;\n }\n })\n .catch(Notification.exception);\n }\n\n /**\n * Remove the Filter Object from the register.\n *\n * @param {string} filterName The name of the filter to be removed\n */\n removeFilterObject(filterName) {\n if (filterName) {\n const filter = this.getFilterObject(filterName);\n if (filter) {\n filter.tearDown();\n\n // Remove from the list of active filters.\n delete this.activeFilters[filterName];\n }\n }\n }\n\n /**\n * Remove all filters.\n *\n * @returns {Promise}\n */\n removeAllFilters() {\n const filters = this.getFilterRegion().querySelectorAll(Selectors.filter.region);\n filters.forEach(filterRow => this.removeOrReplaceFilterRow(filterRow, false));\n\n // Refresh the table.\n return this.updateTableFromFilter();\n }\n\n /**\n * Remove any empty filters.\n */\n removeEmptyFilters() {\n const filters = this.getFilterRegion().querySelectorAll(Selectors.filter.region);\n filters.forEach(filterRow => {\n const filterType = filterRow.querySelector(Selectors.filter.fields.type);\n if (!filterType.value) {\n this.removeOrReplaceFilterRow(filterRow, false);\n }\n });\n }\n\n /**\n * Update the list of filter types to filter out those already selected.\n */\n updateFiltersOptions() {\n const filters = this.getFilterRegion().querySelectorAll(Selectors.filter.region);\n filters.forEach(filterRow => {\n const options = filterRow.querySelectorAll(Selectors.filter.fields.type + ' option');\n options.forEach(option => {\n if (option.value === filterRow.dataset.filterType) {\n option.classList.remove('hidden');\n option.disabled = false;\n } else if (this.activeFilters[option.value]) {\n option.classList.add('hidden');\n option.disabled = true;\n } else {\n option.classList.remove('hidden');\n option.disabled = false;\n }\n });\n });\n\n // Configure the state of the \"Add row\" button.\n // This button is disabled when there is a filter row available for each condition.\n const addRowButton = this.filterSet.querySelector(Selectors.filterset.actions.addRow);\n const filterDataNode = this.filterSet.querySelectorAll(Selectors.data.fields.all);\n if (filterDataNode.length <= filters.length) {\n addRowButton.setAttribute('disabled', 'disabled');\n } else {\n addRowButton.removeAttribute('disabled');\n }\n\n if (filters.length === 1) {\n this.filterSet.querySelector(Selectors.filterset.regions.filtermatch).classList.add('hidden');\n this.filterSet.querySelector(Selectors.filterset.fields.join).value = 2;\n this.filterSet.dataset.filterverb = 2;\n } else {\n this.filterSet.querySelector(Selectors.filterset.regions.filtermatch).classList.remove('hidden');\n }\n }\n\n /**\n * Update the Dynamic table based upon the current filter.\n */\n updateTableFromFilter() {\n const pendingPromise = new Pending('core/datafilter:updateTableFromFilter');\n\n const filters = {};\n Object.values(this.activeFilters).forEach(filter => {\n filters[filter.filterValue.name] = filter.filterValue;\n });\n\n if (this.applyCallback) {\n this.applyCallback(filters, pendingPromise);\n }\n }\n\n /**\n * Fetch the strings used to populate the fieldset legends for the maximum number of filters possible.\n *\n * @return {array}\n */\n async getAvailableFilterLegends() {\n const maxFilters = document.querySelector(Selectors.data.typeListSelect).length - 1;\n let requests = [];\n\n [...Array(maxFilters)].forEach((_, rowIndex) => {\n requests.push({\n \"key\": \"filterrowlegend\",\n \"component\": \"core\",\n // Add 1 since rows begin at 1 (index begins at zero).\n \"param\": rowIndex + 1\n });\n });\n\n const legendStrings = await getStrings(requests)\n .then(fetchedStrings => {\n return fetchedStrings;\n })\n .catch(Notification.exception);\n\n return legendStrings;\n }\n\n /**\n * Update the list of join types for a filter.\n *\n * This will update the list of join types based on the allowed types defined for a filter.\n * If only one type is allowed, the list will be hidden.\n *\n * @param {Array} filterJoinList Array of join types, a subset of the regularJoinList array in this function.\n * @param {Element} filterRow The row being updated.\n */\n updateJoinList(filterJoinList, filterRow) {\n const regularJoinList = [0, 1, 2];\n // If a join list was specified for this filter, find the default join list and disable the options that are not allowed\n // for this filter.\n if (filterJoinList.length !== 0) {\n const joinField = filterRow.querySelector(Selectors.filter.fields.join);\n // Check each option from the default list, and disable the option in this filter row if it is not allowed\n // for this filter.\n regularJoinList.forEach((join) => {\n if (!filterJoinList.includes(join)) {\n joinField.options[join].classList.add('hidden');\n joinField.options[join].disabled = true;\n }\n });\n // Now remove the disabled options, and hide the select list of there is only one option left.\n joinField.options.forEach((element, index) => {\n if (element.disabled) {\n joinField.options[index] = null;\n }\n });\n if (joinField.options.length === 1) {\n joinField.hidden = true;\n }\n }\n }\n}\n"],"names":["constructor","filterSet","applyCallback","activeFilters","courseid","CourseFilter","init","querySelector","Selectors","filterset","region","addEventListener","e","target","closest","actions","addRow","preventDefault","addFilterRow","applyFilters","updateTableFromFilter","resetFilters","removeAllFilters","regions","filterlist","filter","remove","removeOrReplaceFilterRow","filterRegion","this","getFilterRegion","define","CustomEvents","events","accessibleChange","on","typeField","fields","type","value","addFilter","join","dataset","filterverb","filterdata","pendingPromise","Pending","rownum","querySelectorAll","length","Templates","renderForPromise","then","_ref","html","js","appendNodeContents","filterRow","typeList","data","forEach","contentNode","contentTypeList","innerHTML","updateFiltersOptions","result","resolve","filtertype","values","jointype","filteroptions","catch","Notification","exception","getFilterDataSource","filterType","datasource","byName","initialFilterValues","filterJoin","filterOptions","filterDataNode","Filter","GenericFilter","filterTypeClass","disabled","updateJoinList","JSON","parse","joinList","joinField","isNaN","getFilterObject","name","refreshContent","replaceFilterRow","removeFilterRow","required","hasFilterValue","removeFilterObject","filterLegends","getAvailableFilterLegends","index","innerText","rowNum","_ref2","replaceNode","filterName","tearDown","removeEmptyFilters","filters","option","classList","add","addRowButton","all","setAttribute","removeAttribute","filtermatch","Object","filterValue","maxFilters","document","typeListSelect","requests","Array","_","rowIndex","push","fetchedStrings","filterJoinList","regularJoinList","includes","options","element","hidden"],"mappings":"2kCAyCIA,YAAYC,UAAWC,oBAEdD,UAAYA,eACZC,cAAgBA,mBAEhBC,cAAgB,CACjBC,SAAU,IAAIC,kBAAa,WAAYJ,YAO/CK,YAESL,UAAUM,cAAcC,mBAAUC,UAAUC,QAAQC,iBAAiB,SAASC,IAC3EA,EAAEC,OAAOC,QAAQN,mBAAUC,UAAUM,QAAQC,UAC7CJ,EAAEK,sBAEGC,gBAGLN,EAAEC,OAAOC,QAAQN,mBAAUC,UAAUM,QAAQI,gBAC7CP,EAAEK,sBAEGG,yBAGLR,EAAEC,OAAOC,QAAQN,mBAAUC,UAAUM,QAAQM,gBAC7CT,EAAEK,sBAEGK,4BAKRrB,UAAUM,cAAcC,mBAAUC,UAAUc,QAAQC,YAAYb,iBAAiB,SAASC,IACvFA,EAAEC,OAAOC,QAAQN,mBAAUiB,OAAOV,QAAQW,UAC1Cd,EAAEK,sBAEGU,yBAAyBf,EAAEC,OAAOC,QAAQN,mBAAUiB,OAAOf,SAAS,WAK7EkB,cAAe,mBAAOC,KAAKC,sDAClBC,OAAOH,aAAc,CAACI,mCAAaC,OAAOC,mBACvDN,aAAaO,GAAGH,mCAAaC,OAAOC,kBAAkBtB,UAC5CwB,UAAYxB,EAAEC,OAAOC,QAAQN,mBAAUiB,OAAOY,OAAOC,SACvDF,WAAaA,UAAUG,MAAO,OACxBd,OAASb,EAAEC,OAAOC,QAAQN,mBAAUiB,OAAOf,aAE5C8B,UAAUf,OAAQW,UAAUG,gBAIpCtC,UAAUM,cAAcC,mBAAUC,UAAU4B,OAAOI,MAAM9B,iBAAiB,UAAUC,SAChFX,UAAUyC,QAAQC,WAAa/B,EAAEC,OAAO0B,SASrDT,yBACWD,KAAK5B,UAAUM,cAAcC,mBAAUC,UAAUc,QAAQC,YASpEN,0CAAa0B,kEAAa,SAChBC,eAAiB,IAAIC,iBAAQ,gCAC7BC,kCAASH,WAAWG,wDAAU,EAAIlB,KAAKC,kBAAkBkB,iBAAiBxC,mBAAUiB,OAAOf,QAAQuC,cAClGC,mBAAUC,iBAAiB,6BAA8B,WAAcJ,SACzEK,MAAKC,WAACC,KAACA,KAADC,GAAOA,gBACcL,mBAAUM,mBAAmB3B,KAAKC,kBAAmBwB,KAAMC,OAItFH,MAAKK,kBAKIC,SAAW7B,KAAK5B,UAAUM,cAAcC,mBAAUmD,KAAKD,iBAE7DD,UAAUG,SAAQC,oBACRC,gBAAkBD,YAAYtD,cAAcC,mBAAUiB,OAAOY,OAAOC,MAEtEwB,kBACAA,gBAAgBC,UAAYL,SAASK,cAItCN,aAEVL,MAAKK,iBACGO,uBAEEP,aAEVL,MAAKa,SACFpB,eAAeqB,UAGXtB,WAAWuB,YACXF,OAAOL,SAAQnC,cACNe,UAAUf,OAAQmB,WAAWuB,WAAYvB,WAAWwB,OACrDxB,WAAWyB,SAAUzB,WAAW0B,kBAGrCL,UAEVM,MAAMC,sBAAaC,WAS5BC,oBAAoBC,mBACO9C,KAAK5B,UAAUM,cAAcC,mBAAUC,UAAUc,QAAQqD,YAE1DrE,cAAcC,mBAAUmD,KAAKtB,OAAOwC,OAAOF,6BAarDlB,UAAWkB,WAAYG,oBAAqBC,WAAYC,eAEpEvB,UAAUf,QAAQiC,WAAaA,iBAEzBM,eAAiBpD,KAAK6C,oBAAoBC,gBAG5CO,OAASC,oBACTF,eAAevC,QAAQ0C,kBACvBF,6NAAsBD,eAAevC,QAAQ0C,2SAAvBH,eAAevC,QAA5B,2EAAauC,eAAevC,QAAQ0C,yBAE5CjF,cAAcwE,YAAc,IAAIO,OAAOP,WAAY9C,KAAK5B,UAAW6E,oBAAqBE,qBAGvF5C,UAAYqB,UAAUlD,cAAcC,mBAAUiB,OAAOY,OAAOC,MAClEF,UAAUG,MAAQoC,WAClBvC,UAAUiD,SAAW,gBAEhBC,eAAeC,KAAKC,MAAMP,eAAevC,QAAQ+C,UAAWhC,iBAC3DiC,UAAYjC,UAAUlD,cAAcC,mBAAUiB,OAAOY,OAAOI,aAClEiD,UAAUL,UAAW,EAChBM,MAAMZ,cACPW,UAAUnD,MAAQwC,iBAGjBf,uBAEEnC,KAAK1B,cAAcwE,YAS9BiB,gBAAgBC,aACLhE,KAAK1B,cAAc0F,MAU9BlE,yBAAyB8B,UAAWqC,gBAEZ,IADAjE,KAAKC,kBAAkBkB,iBAAiBxC,mBAAUiB,OAAOf,QAAQuC,YAE5E8C,iBAAiBtC,UAAWqC,qBAE5BE,gBAAgBvC,UAAWqC,sCAUlBrC,eAAWqC,6EACzBrC,UAAUlD,cAAcC,mBAAUmD,KAAKsC,uBAIrCC,iBADazC,UAAUlD,cAAcC,mBAAUiB,OAAOY,OAAOC,MAC/BC,WAG/B4D,mBAAmB1C,UAAUf,QAAQiC,YAG1ClB,UAAU/B,cAGLsC,uBAEDkC,gBAAkBJ,qBAEb1E,8BAIHgF,oBAAsBvE,KAAKwE,iCAE5BvE,kBAAkBkB,iBAAiBxC,mBAAUiB,OAAOf,QAAQkD,SAAQ,CAACH,UAAW6C,SACjF7C,UAAUlD,cAAc,UAAUgG,UAAYH,cAAcE,UAapEP,iBAAiBtC,eAAWqC,0EAAuBU,8DAAS,MACpD/C,UAAUlD,cAAcC,mBAAUmD,KAAKsC,sBAItCE,mBAAmB1C,UAAUf,QAAQiC,YAEnCzB,mBAAUC,iBAAiB,6BAA8B,WAAcqD,SACzEpD,MAAKqD,YAACnD,KAACA,KAADC,GAAOA,iBACcL,mBAAUwD,YAAYjD,UAAWH,KAAMC,OAIlEH,MAAKK,kBAKIC,SAAW7B,KAAK5B,UAAUM,cAAcC,mBAAUmD,KAAKD,iBAE7DD,UAAUG,SAAQC,oBACRC,gBAAkBD,YAAYtD,cAAcC,mBAAUiB,OAAOY,OAAOC,MAEtEwB,kBACAA,gBAAgBC,UAAYL,SAASK,cAItCN,aAEVL,MAAKK,iBACGO,uBAEEP,aAEVL,MAAKK,WAEEqC,eACOjE,KAAKT,wBAELqC,YAGdc,MAAMC,sBAAaC,WAQ5B0B,mBAAmBQ,eACXA,WAAY,OACNlF,OAASI,KAAK+D,gBAAgBe,YAChClF,SACAA,OAAOmF,kBAGA/E,KAAK1B,cAAcwG,cAUtCrF,0BACoBO,KAAKC,kBAAkBkB,iBAAiBxC,mBAAUiB,OAAOf,QACjEkD,SAAQH,WAAa5B,KAAKF,yBAAyB8B,WAAW,KAG/D5B,KAAKT,wBAMhByF,qBACoBhF,KAAKC,kBAAkBkB,iBAAiBxC,mBAAUiB,OAAOf,QACjEkD,SAAQH,YACOA,UAAUlD,cAAcC,mBAAUiB,OAAOY,OAAOC,MACnDC,YACPZ,yBAAyB8B,WAAW,MAQrDO,6BACU8C,QAAUjF,KAAKC,kBAAkBkB,iBAAiBxC,mBAAUiB,OAAOf,QACzEoG,QAAQlD,SAAQH,YACIA,UAAUT,iBAAiBxC,mBAAUiB,OAAOY,OAAOC,KAAO,WAClEsB,SAAQmD,SACRA,OAAOxE,QAAUkB,UAAUf,QAAQiC,YACnCoC,OAAOC,UAAUtF,OAAO,UACxBqF,OAAO1B,UAAW,GACXxD,KAAK1B,cAAc4G,OAAOxE,QACjCwE,OAAOC,UAAUC,IAAI,UACrBF,OAAO1B,UAAW,IAElB0B,OAAOC,UAAUtF,OAAO,UACxBqF,OAAO1B,UAAW,eAOxB6B,aAAerF,KAAK5B,UAAUM,cAAcC,mBAAUC,UAAUM,QAAQC,QACvDa,KAAK5B,UAAU+C,iBAAiBxC,mBAAUmD,KAAKtB,OAAO8E,KAC1DlE,QAAU6D,QAAQ7D,OACjCiE,aAAaE,aAAa,WAAY,YAEtCF,aAAaG,gBAAgB,YAGV,IAAnBP,QAAQ7D,aACHhD,UAAUM,cAAcC,mBAAUC,UAAUc,QAAQ+F,aAAaN,UAAUC,IAAI,eAC/EhH,UAAUM,cAAcC,mBAAUC,UAAU4B,OAAOI,MAAMF,MAAQ,OACjEtC,UAAUyC,QAAQC,WAAa,QAE/B1C,UAAUM,cAAcC,mBAAUC,UAAUc,QAAQ+F,aAAaN,UAAUtF,OAAO,UAO/FN,8BACUyB,eAAiB,IAAIC,iBAAQ,yCAE7BgE,QAAU,GAChBS,OAAOnD,OAAOvC,KAAK1B,eAAeyD,SAAQnC,SACtCqF,QAAQrF,OAAO+F,YAAY3B,MAAQpE,OAAO+F,eAG1C3F,KAAK3B,oBACAA,cAAc4G,QAASjE,wDAU1B4E,WAAaC,SAASnH,cAAcC,mBAAUmD,KAAKgE,gBAAgB1E,OAAS,MAC9E2E,SAAW,OAEXC,MAAMJ,aAAa7D,SAAQ,CAACkE,EAAGC,YAC/BH,SAASI,KAAK,KACH,4BACM,aAEJD,SAAW,oBAIA,mBAAWH,UAClCxE,MAAK6E,gBACKA,iBAEV1D,MAAMC,sBAAaC,WAc5Ba,eAAe4C,eAAgBzE,iBACrB0E,gBAAkB,CAAC,EAAG,EAAG,MAGD,IAA1BD,eAAejF,OAAc,OACvByC,UAAYjC,UAAUlD,cAAcC,mBAAUiB,OAAOY,OAAOI,MAGlE0F,gBAAgBvE,SAASnB,OAChByF,eAAeE,SAAS3F,QACzBiD,UAAU2C,QAAQ5F,MAAMuE,UAAUC,IAAI,UACtCvB,UAAU2C,QAAQ5F,MAAM4C,UAAW,MAI3CK,UAAU2C,QAAQzE,SAAQ,CAAC0E,QAAShC,SAC5BgC,QAAQjD,WACRK,UAAU2C,QAAQ/B,OAAS,SAGF,IAA7BZ,UAAU2C,QAAQpF,SAClByC,UAAU6C,QAAS"} \ No newline at end of file diff --git a/lib/amd/build/datafilter/filtertype.min.js b/lib/amd/build/datafilter/filtertype.min.js index 720174fb58d..0ad526909bb 100644 --- a/lib/amd/build/datafilter/filtertype.min.js +++ b/lib/amd/build/datafilter/filtertype.min.js @@ -1,10 +1,10 @@ -define("core/datafilter/filtertype",["exports","core/form-autocomplete","core/datafilter/selectors","core/str"],(function(_exports,_formAutocomplete,_selectors,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} +define("core/datafilter/filtertype",["exports","core/form-autocomplete","core/datafilter/selectors","core/str","core/notification"],(function(_exports,_formAutocomplete,_selectors,_str,_notification){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} /** * Base Filter class for a filter type in the filter UI. * * @module core/datafilter/filtertype * @copyright 2020 Andrew Nicols * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_formAutocomplete=_interopRequireDefault(_formAutocomplete),_selectors=_interopRequireDefault(_selectors);return _exports.default=class{constructor(filterType,rootNode,initialValues){this.filterType=filterType,this.rootNode=rootNode,this.addValueSelector(initialValues)}tearDown(){}get placeholder(){return(0,_str.getString)("placeholdertypeorselect","core")}get showSuggestions(){return!0}async addValueSelector(){let initialValues=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];const filterValueNode=this.getFilterValueNode(),sourceDataNode=this.getSourceDataForFilter();if(!sourceDataNode)return;filterValueNode.innerHTML=sourceDataNode.outerHTML;const dataSource=filterValueNode.querySelector("select");dataSource.id="filter-value-"+dataSource.getAttribute("data-field-name");const filterValueLabel=document.createElement("label");filterValueLabel.setAttribute("for",dataSource.id),filterValueLabel.classList.add("sr-only"),filterValueLabel.innerText=dataSource.getAttribute("data-field-title"),filterValueNode.appendChild(filterValueLabel),initialValues.forEach((filterValue=>{let selectedOption=dataSource.querySelector('option[value="'.concat(filterValue,'"]'));selectedOption?selectedOption.selected=!0:this.showSuggestions||(selectedOption=document.createElement("option"),selectedOption.value=filterValue,selectedOption.innerHTML=filterValue,selectedOption.selected=!0,dataSource.append(selectedOption))})),_formAutocomplete.default.enhance(dataSource,"1"==dataSource.dataset.allowCustom,null,await this.placeholder,!1,this.showSuggestions,null,!dataSource.multiple,{items:"core/datafilter/autocomplete_selection_items",layout:"core/datafilter/autocomplete_layout",selection:"core/datafilter/autocomplete_selection"})}get filterRoot(){return this.rootNode.querySelector(_selectors.default.filter.byName(this.filterType))}getSourceDataForFilter(){return this.rootNode.querySelector(_selectors.default.filterset.regions.datasource).querySelector(_selectors.default.data.fields.byName(this.filterType))}getFilterValueNode(){return this.filterRoot.querySelector(_selectors.default.filter.regions.values)}get name(){return this.filterType}get jointype(){return parseInt(this.filterRoot.querySelector(_selectors.default.filter.fields.join).value,10)}get rawValues(){const filterValueSelect=this.getFilterValueNode().querySelector("select");return Object.values((select=filterValueSelect,select.querySelectorAll(":checked"))).map((option=>option.value));var select}get values(){return this.rawValues.map((option=>parseInt(option,10)))}get filterValue(){return{name:this.name,jointype:this.jointype,values:this.values}}},_exports.default})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_formAutocomplete=_interopRequireDefault(_formAutocomplete),_selectors=_interopRequireDefault(_selectors),_notification=_interopRequireDefault(_notification);return _exports.default=class{constructor(filterType,rootNode,initialValues){this.filterType=filterType,this.rootNode=rootNode,this.addValueSelector(initialValues).then((()=>{const filterRoot=this.filterRoot;return filterRoot&&filterRoot.querySelector(_selectors.default.data.required)&&filterRoot.querySelector(_selectors.default.filter.actions.remove).remove(),filterRoot})).catch(_notification.default.exception)}tearDown(){}get placeholder(){return(0,_str.getString)("placeholdertypeorselect","core")}get showSuggestions(){return!0}async addValueSelector(){let initialValues=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];const filterValueNode=this.getFilterValueNode(),sourceDataNode=this.getSourceDataForFilter();if(!sourceDataNode)throw new Error("No source data for filter.");filterValueNode.innerHTML=sourceDataNode.outerHTML;const dataSource=filterValueNode.querySelector("select");dataSource.id="filter-value-"+dataSource.getAttribute("data-field-name");const filterValueLabel=document.createElement("label");return filterValueLabel.setAttribute("for",dataSource.id),filterValueLabel.classList.add("sr-only"),filterValueLabel.innerText=dataSource.getAttribute("data-field-title"),filterValueNode.appendChild(filterValueLabel),initialValues.forEach((filterValue=>{let selectedOption=dataSource.querySelector('option[value="'.concat(filterValue,'"]'));selectedOption?selectedOption.selected=!0:this.showSuggestions||(selectedOption=document.createElement("option"),selectedOption.value=filterValue,selectedOption.innerHTML=filterValue,selectedOption.selected=!0,dataSource.append(selectedOption))})),_formAutocomplete.default.enhance(dataSource,"1"==dataSource.dataset.allowCustom,null,await this.placeholder,!1,this.showSuggestions,null,!dataSource.multiple,{items:"core/datafilter/autocomplete_selection_items",layout:"core/datafilter/autocomplete_layout",selection:"core/datafilter/autocomplete_selection"})}get filterRoot(){return this.rootNode.querySelector(_selectors.default.filter.byName(this.filterType))}getSourceDataForFilter(){return this.rootNode.querySelector(_selectors.default.filterset.regions.datasource).querySelector(_selectors.default.data.fields.byName(this.filterType))}getFilterValueNode(){return this.filterRoot.querySelector(_selectors.default.filter.regions.values)}get name(){return this.filterType}get jointype(){return parseInt(this.filterRoot.querySelector(_selectors.default.filter.fields.join).value,10)}get rawValues(){const filterValueSelect=this.getFilterValueNode().querySelector("select");return Object.values((select=filterValueSelect,select.querySelectorAll(":checked"))).map((option=>option.value));var select}get values(){return this.rawValues.map((option=>parseInt(option,10)))}get filterOptions(){return[]}get filterValue(){return{name:this.name,jointype:this.jointype,values:this.values,filteroptions:this.filterOptions}}},_exports.default})); //# sourceMappingURL=filtertype.min.js.map \ No newline at end of file diff --git a/lib/amd/build/datafilter/filtertype.min.js.map b/lib/amd/build/datafilter/filtertype.min.js.map index a5cb0a32f6c..5a187666490 100644 --- a/lib/amd/build/datafilter/filtertype.min.js.map +++ b/lib/amd/build/datafilter/filtertype.min.js.map @@ -1 +1 @@ -{"version":3,"file":"filtertype.min.js","sources":["../../src/datafilter/filtertype.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 .\n\n/**\n * Base Filter class for a filter type in the filter UI.\n *\n * @module core/datafilter/filtertype\n * @copyright 2020 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport Autocomplete from 'core/form-autocomplete';\nimport Selectors from 'core/datafilter/selectors';\nimport {getString} from 'core/str';\n\n/**\n * Fetch all checked options in the select.\n *\n * This is a poor-man's polyfill for select.selectedOptions, which is not available in IE11.\n *\n * @param {HTMLSelectElement} select\n * @returns {HTMLOptionElement[]} All selected options\n */\nconst getOptionsForSelect = select => {\n return select.querySelectorAll(':checked');\n};\n\nexport default class {\n\n /**\n * Constructor for a new filter.\n *\n * @param {String} filterType The type of filter that this relates to\n * @param {HTMLElement} rootNode The root node for the participants filterset\n * @param {Array} initialValues The initial values for the selector\n */\n constructor(filterType, rootNode, initialValues) {\n this.filterType = filterType;\n this.rootNode = rootNode;\n\n this.addValueSelector(initialValues);\n }\n\n /**\n * Perform any tear-down for this filter type.\n */\n tearDown() {\n // eslint-disable-line no-empty-function\n }\n\n /**\n * Get the placeholder to use when showing the value selector.\n *\n * @return {Promise} Resolving to a String\n */\n get placeholder() {\n return getString('placeholdertypeorselect', 'core');\n }\n\n /**\n * Whether to show suggestions in the autocomplete.\n *\n * @return {Boolean}\n */\n get showSuggestions() {\n return true;\n }\n\n /**\n * Add the value selector to the filter row.\n *\n * @param {Array} initialValues\n */\n async addValueSelector(initialValues = []) {\n const filterValueNode = this.getFilterValueNode();\n\n // Copy the data in place.\n const sourceDataNode = this.getSourceDataForFilter();\n if (!sourceDataNode) {\n return;\n }\n filterValueNode.innerHTML = sourceDataNode.outerHTML;\n\n const dataSource = filterValueNode.querySelector('select');\n\n // Set an ID for this filter value element.\n dataSource.id = 'filter-value-' + dataSource.getAttribute('data-field-name');\n\n // Create a hidden label for the filter value.\n const filterValueLabel = document.createElement('label');\n filterValueLabel.setAttribute('for', dataSource.id);\n filterValueLabel.classList.add('sr-only');\n filterValueLabel.innerText = dataSource.getAttribute('data-field-title');\n\n // Append this label to the filter value container.\n filterValueNode.appendChild(filterValueLabel);\n\n // If there are any initial values then attempt to apply them.\n initialValues.forEach(filterValue => {\n let selectedOption = dataSource.querySelector(`option[value=\"${filterValue}\"]`);\n if (selectedOption) {\n selectedOption.selected = true;\n } else if (!this.showSuggestions) {\n selectedOption = document.createElement('option');\n selectedOption.value = filterValue;\n selectedOption.innerHTML = filterValue;\n selectedOption.selected = true;\n\n dataSource.append(selectedOption);\n }\n });\n\n Autocomplete.enhance(\n // The source select element.\n dataSource,\n\n // Whether to allow 'tags' (custom entries).\n dataSource.dataset.allowCustom == \"1\",\n\n // We do not require AJAX at all as standard.\n null,\n\n // The string to use as a placeholder.\n await this.placeholder,\n\n // Disable case sensitivity on searches.\n false,\n\n // Show suggestions.\n this.showSuggestions,\n\n // Do not override the 'no suggestions' string.\n null,\n\n // Close the suggestions if this is not a multi-select.\n !dataSource.multiple,\n\n // Template overrides.\n {\n items: 'core/datafilter/autocomplete_selection_items',\n layout: 'core/datafilter/autocomplete_layout',\n selection: 'core/datafilter/autocomplete_selection',\n }\n );\n }\n\n /**\n * Get the root node for this filter.\n *\n * @returns {HTMLElement}\n */\n get filterRoot() {\n return this.rootNode.querySelector(Selectors.filter.byName(this.filterType));\n }\n\n /**\n * Get the possible data for this filter type.\n *\n * @returns {Array}\n */\n getSourceDataForFilter() {\n const filterDataNode = this.rootNode.querySelector(Selectors.filterset.regions.datasource);\n\n return filterDataNode.querySelector(Selectors.data.fields.byName(this.filterType));\n }\n\n /**\n * Get the HTMLElement which contains the value selector.\n *\n * @returns {HTMLElement}\n */\n getFilterValueNode() {\n return this.filterRoot.querySelector(Selectors.filter.regions.values);\n }\n\n /**\n * Get the name of this filter.\n *\n * @returns {String}\n */\n get name() {\n return this.filterType;\n }\n\n /**\n * Get the type of join specified.\n *\n * @returns {Number}\n */\n get jointype() {\n return parseInt(this.filterRoot.querySelector(Selectors.filter.fields.join).value, 10);\n }\n\n /**\n * Get the list of raw values for this filter type.\n *\n * @returns {Array}\n */\n get rawValues() {\n const filterValueNode = this.getFilterValueNode();\n const filterValueSelect = filterValueNode.querySelector('select');\n\n return Object.values(getOptionsForSelect(filterValueSelect)).map(option => option.value);\n }\n\n /**\n * Get the list of values for this filter type.\n *\n * @returns {Array}\n */\n get values() {\n return this.rawValues.map(option => parseInt(option, 10));\n }\n\n /**\n * Get the composed value for this filter.\n *\n * @returns {Object}\n */\n get filterValue() {\n return {\n name: this.name,\n jointype: this.jointype,\n values: this.values,\n };\n }\n}\n"],"names":["constructor","filterType","rootNode","initialValues","addValueSelector","tearDown","placeholder","showSuggestions","filterValueNode","this","getFilterValueNode","sourceDataNode","getSourceDataForFilter","innerHTML","outerHTML","dataSource","querySelector","id","getAttribute","filterValueLabel","document","createElement","setAttribute","classList","add","innerText","appendChild","forEach","filterValue","selectedOption","selected","value","append","enhance","dataset","allowCustom","multiple","items","layout","selection","filterRoot","Selectors","filter","byName","filterset","regions","datasource","data","fields","values","name","jointype","parseInt","join","rawValues","filterValueSelect","Object","select","querySelectorAll","map","option"],"mappings":";;;;;;;6NA+CIA,YAAYC,WAAYC,SAAUC,oBACzBF,WAAaA,gBACbC,SAAWA,cAEXE,iBAAiBD,eAM1BE,YASIC,yBACO,kBAAU,0BAA2B,QAQ5CC,6BACO,+BAQYJ,qEAAgB,SAC7BK,gBAAkBC,KAAKC,qBAGvBC,eAAiBF,KAAKG,6BACvBD,sBAGLH,gBAAgBK,UAAYF,eAAeG,gBAErCC,WAAaP,gBAAgBQ,cAAc,UAGjDD,WAAWE,GAAK,gBAAkBF,WAAWG,aAAa,yBAGpDC,iBAAmBC,SAASC,cAAc,SAChDF,iBAAiBG,aAAa,MAAOP,WAAWE,IAChDE,iBAAiBI,UAAUC,IAAI,WAC/BL,iBAAiBM,UAAYV,WAAWG,aAAa,oBAGrDV,gBAAgBkB,YAAYP,kBAG5BhB,cAAcwB,SAAQC,kBACdC,eAAiBd,WAAWC,sCAA+BY,mBAC3DC,eACAA,eAAeC,UAAW,EAClBrB,KAAKF,kBACbsB,eAAiBT,SAASC,cAAc,UACxCQ,eAAeE,MAAQH,YACvBC,eAAehB,UAAYe,YAC3BC,eAAeC,UAAW,EAE1Bf,WAAWiB,OAAOH,8CAIbI,QAETlB,WAGkC,KAAlCA,WAAWmB,QAAQC,YAGnB,WAGM1B,KAAKH,aAGX,EAGAG,KAAKF,gBAGL,MAGCQ,WAAWqB,SAGZ,CACIC,MAAO,+CACPC,OAAQ,sCACRC,UAAW,2CAUnBC,wBACO/B,KAAKP,SAASc,cAAcyB,mBAAUC,OAAOC,OAAOlC,KAAKR,aAQpEW,gCAC2BH,KAAKP,SAASc,cAAcyB,mBAAUG,UAAUC,QAAQC,YAEzD9B,cAAcyB,mBAAUM,KAAKC,OAAOL,OAAOlC,KAAKR,aAQ1ES,4BACWD,KAAK+B,WAAWxB,cAAcyB,mBAAUC,OAAOG,QAAQI,QAQ9DC,kBACOzC,KAAKR,WAQZkD,sBACOC,SAAS3C,KAAK+B,WAAWxB,cAAcyB,mBAAUC,OAAOM,OAAOK,MAAMtB,MAAO,IAQnFuB,sBAEMC,kBADkB9C,KAAKC,qBACaM,cAAc,iBAEjDwC,OAAOP,QAnLMQ,OAmLqBF,kBAlLtCE,OAAOC,iBAAiB,cAkLkCC,KAAIC,QAAUA,OAAO7B,QAnL9D0B,IAAAA,OA2LpBR,oBACOxC,KAAK6C,UAAUK,KAAIC,QAAUR,SAASQ,OAAQ,MAQrDhC,wBACO,CACHsB,KAAMzC,KAAKyC,KACXC,SAAU1C,KAAK0C,SACfF,OAAQxC,KAAKwC"} \ No newline at end of file +{"version":3,"file":"filtertype.min.js","sources":["../../src/datafilter/filtertype.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 .\n\n/**\n * Base Filter class for a filter type in the filter UI.\n *\n * @module core/datafilter/filtertype\n * @copyright 2020 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport Autocomplete from 'core/form-autocomplete';\nimport Selectors from 'core/datafilter/selectors';\nimport {getString} from 'core/str';\nimport Notification from 'core/notification';\n\n/**\n * Fetch all checked options in the select.\n *\n * This is a poor-man's polyfill for select.selectedOptions, which is not available in IE11.\n *\n * @param {HTMLSelectElement} select\n * @returns {HTMLOptionElement[]} All selected options\n */\nconst getOptionsForSelect = select => {\n return select.querySelectorAll(':checked');\n};\n\nexport default class {\n\n /**\n * Constructor for a new filter.\n *\n * @param {String} filterType The type of filter that this relates to\n * @param {HTMLElement} rootNode The root node for the participants filterset\n * @param {Array} initialValues The initial values for the selector\n */\n constructor(filterType, rootNode, initialValues) {\n this.filterType = filterType;\n this.rootNode = rootNode;\n\n this.addValueSelector(initialValues).then(() => {\n const filterRoot = this.filterRoot;\n if (filterRoot && filterRoot.querySelector(Selectors.data.required)) {\n filterRoot.querySelector(Selectors.filter.actions.remove).remove();\n }\n return filterRoot;\n }).catch(Notification.exception);\n\n }\n\n /**\n * Perform any tear-down for this filter type.\n */\n tearDown() {\n // eslint-disable-line no-empty-function\n }\n\n /**\n * Get the placeholder to use when showing the value selector.\n *\n * @return {Promise} Resolving to a String\n */\n get placeholder() {\n return getString('placeholdertypeorselect', 'core');\n }\n\n /**\n * Whether to show suggestions in the autocomplete.\n *\n * @return {Boolean}\n */\n get showSuggestions() {\n return true;\n }\n\n /**\n * Add the value selector to the filter row.\n *\n * @param {Array} initialValues\n * @return {Promise}\n */\n async addValueSelector(initialValues = []) {\n const filterValueNode = this.getFilterValueNode();\n\n // Copy the data in place.\n const sourceDataNode = this.getSourceDataForFilter();\n if (!sourceDataNode) {\n throw new Error('No source data for filter.');\n }\n filterValueNode.innerHTML = sourceDataNode.outerHTML;\n\n const dataSource = filterValueNode.querySelector('select');\n\n // Set an ID for this filter value element.\n dataSource.id = 'filter-value-' + dataSource.getAttribute('data-field-name');\n\n // Create a hidden label for the filter value.\n const filterValueLabel = document.createElement('label');\n filterValueLabel.setAttribute('for', dataSource.id);\n filterValueLabel.classList.add('sr-only');\n filterValueLabel.innerText = dataSource.getAttribute('data-field-title');\n\n // Append this label to the filter value container.\n filterValueNode.appendChild(filterValueLabel);\n\n // If there are any initial values then attempt to apply them.\n initialValues.forEach(filterValue => {\n let selectedOption = dataSource.querySelector(`option[value=\"${filterValue}\"]`);\n if (selectedOption) {\n selectedOption.selected = true;\n } else if (!this.showSuggestions) {\n selectedOption = document.createElement('option');\n selectedOption.value = filterValue;\n selectedOption.innerHTML = filterValue;\n selectedOption.selected = true;\n\n dataSource.append(selectedOption);\n }\n });\n\n return Autocomplete.enhance(\n // The source select element.\n dataSource,\n\n // Whether to allow 'tags' (custom entries).\n dataSource.dataset.allowCustom == \"1\",\n\n // We do not require AJAX at all as standard.\n null,\n\n // The string to use as a placeholder.\n await this.placeholder,\n\n // Disable case sensitivity on searches.\n false,\n\n // Show suggestions.\n this.showSuggestions,\n\n // Do not override the 'no suggestions' string.\n null,\n\n // Close the suggestions if this is not a multi-select.\n !dataSource.multiple,\n\n // Template overrides.\n {\n items: 'core/datafilter/autocomplete_selection_items',\n layout: 'core/datafilter/autocomplete_layout',\n selection: 'core/datafilter/autocomplete_selection',\n }\n );\n }\n\n /**\n * Get the root node for this filter.\n *\n * @returns {HTMLElement}\n */\n get filterRoot() {\n return this.rootNode.querySelector(Selectors.filter.byName(this.filterType));\n }\n\n /**\n * Get the possible data for this filter type.\n *\n * @returns {Array}\n */\n getSourceDataForFilter() {\n const filterDataNode = this.rootNode.querySelector(Selectors.filterset.regions.datasource);\n\n return filterDataNode.querySelector(Selectors.data.fields.byName(this.filterType));\n }\n\n /**\n * Get the HTMLElement which contains the value selector.\n *\n * @returns {HTMLElement}\n */\n getFilterValueNode() {\n return this.filterRoot.querySelector(Selectors.filter.regions.values);\n }\n\n /**\n * Get the name of this filter.\n *\n * @returns {String}\n */\n get name() {\n return this.filterType;\n }\n\n /**\n * Get the type of join specified.\n *\n * @returns {Number}\n */\n get jointype() {\n return parseInt(this.filterRoot.querySelector(Selectors.filter.fields.join).value, 10);\n }\n\n /**\n * Get the list of raw values for this filter type.\n *\n * @returns {Array}\n */\n get rawValues() {\n const filterValueNode = this.getFilterValueNode();\n const filterValueSelect = filterValueNode.querySelector('select');\n\n return Object.values(getOptionsForSelect(filterValueSelect)).map(option => option.value);\n }\n\n /**\n * Get the list of values for this filter type.\n *\n * @returns {Array}\n */\n get values() {\n return this.rawValues.map(option => parseInt(option, 10));\n }\n\n /**\n * Get options specific to this filter type.\n *\n * @returns {Array} of {name:, value:} objects\n */\n get filterOptions() {\n return [];\n }\n\n /**\n * Get the composed value for this filter.\n *\n * @returns {Object}\n */\n get filterValue() {\n return {\n name: this.name,\n jointype: this.jointype,\n values: this.values,\n filteroptions: this.filterOptions,\n };\n }\n}\n"],"names":["constructor","filterType","rootNode","initialValues","addValueSelector","then","filterRoot","this","querySelector","Selectors","data","required","filter","actions","remove","catch","Notification","exception","tearDown","placeholder","showSuggestions","filterValueNode","getFilterValueNode","sourceDataNode","getSourceDataForFilter","Error","innerHTML","outerHTML","dataSource","id","getAttribute","filterValueLabel","document","createElement","setAttribute","classList","add","innerText","appendChild","forEach","filterValue","selectedOption","selected","value","append","Autocomplete","enhance","dataset","allowCustom","multiple","items","layout","selection","byName","filterset","regions","datasource","fields","values","name","jointype","parseInt","join","rawValues","filterValueSelect","Object","select","querySelectorAll","map","option","filterOptions","filteroptions"],"mappings":";;;;;;;iRAgDIA,YAAYC,WAAYC,SAAUC,oBACzBF,WAAaA,gBACbC,SAAWA,cAEXE,iBAAiBD,eAAeE,MAAK,WAChCC,WAAaC,KAAKD,kBACpBA,YAAcA,WAAWE,cAAcC,mBAAUC,KAAKC,WACtDL,WAAWE,cAAcC,mBAAUG,OAAOC,QAAQC,QAAQA,SAEvDR,cACRS,MAAMC,sBAAaC,WAO1BC,YASIC,yBACO,kBAAU,0BAA2B,QAQ5CC,6BACO,+BASYjB,qEAAgB,SAC7BkB,gBAAkBd,KAAKe,qBAGvBC,eAAiBhB,KAAKiB,6BACvBD,qBACK,IAAIE,MAAM,8BAEpBJ,gBAAgBK,UAAYH,eAAeI,gBAErCC,WAAaP,gBAAgBb,cAAc,UAGjDoB,WAAWC,GAAK,gBAAkBD,WAAWE,aAAa,yBAGpDC,iBAAmBC,SAASC,cAAc,gBAChDF,iBAAiBG,aAAa,MAAON,WAAWC,IAChDE,iBAAiBI,UAAUC,IAAI,WAC/BL,iBAAiBM,UAAYT,WAAWE,aAAa,oBAGrDT,gBAAgBiB,YAAYP,kBAG5B5B,cAAcoC,SAAQC,kBACdC,eAAiBb,WAAWpB,sCAA+BgC,mBAC3DC,eACAA,eAAeC,UAAW,EAClBnC,KAAKa,kBACbqB,eAAiBT,SAASC,cAAc,UACxCQ,eAAeE,MAAQH,YACvBC,eAAef,UAAYc,YAC3BC,eAAeC,UAAW,EAE1Bd,WAAWgB,OAAOH,oBAInBI,0BAAaC,QAEhBlB,WAGkC,KAAlCA,WAAWmB,QAAQC,YAGnB,WAGMzC,KAAKY,aAGX,EAGAZ,KAAKa,gBAGL,MAGCQ,WAAWqB,SAGZ,CACIC,MAAO,+CACPC,OAAQ,sCACRC,UAAW,2CAUnB9C,wBACOC,KAAKL,SAASM,cAAcC,mBAAUG,OAAOyC,OAAO9C,KAAKN,aAQpEuB,gCAC2BjB,KAAKL,SAASM,cAAcC,mBAAU6C,UAAUC,QAAQC,YAEzDhD,cAAcC,mBAAUC,KAAK+C,OAAOJ,OAAO9C,KAAKN,aAQ1EqB,4BACWf,KAAKD,WAAWE,cAAcC,mBAAUG,OAAO2C,QAAQG,QAQ9DC,kBACOpD,KAAKN,WAQZ2D,sBACOC,SAAStD,KAAKD,WAAWE,cAAcC,mBAAUG,OAAO6C,OAAOK,MAAMnB,MAAO,IAQnFoB,sBAEMC,kBADkBzD,KAAKe,qBACad,cAAc,iBAEjDyD,OAAOP,QA3LMQ,OA2LqBF,kBA1LtCE,OAAOC,iBAAiB,cA0LkCC,KAAIC,QAAUA,OAAO1B,QA3L9DuB,IAAAA,OAmMpBR,oBACOnD,KAAKwD,UAAUK,KAAIC,QAAUR,SAASQ,OAAQ,MAQrDC,0BACO,GAQP9B,wBACO,CACHmB,KAAMpD,KAAKoD,KACXC,SAAUrD,KAAKqD,SACfF,OAAQnD,KAAKmD,OACba,cAAehE,KAAK+D"} \ No newline at end of file diff --git a/lib/amd/build/datafilter/filtertypes/binary.min.js b/lib/amd/build/datafilter/filtertypes/binary.min.js new file mode 100644 index 00000000000..98fc1526147 --- /dev/null +++ b/lib/amd/build/datafilter/filtertypes/binary.min.js @@ -0,0 +1,3 @@ +define("core/datafilter/filtertypes/binary",["exports","core/datafilter/filtertype","core/datafilter/selectors","core/templates","core/str"],(function(_exports,_filtertype,_selectors,_templates,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_filtertype=_interopRequireDefault(_filtertype),_selectors=_interopRequireDefault(_selectors),_templates=_interopRequireDefault(_templates);class _default extends _filtertype.default{constructor(){super(...arguments),_defineProperty(this,"optionOne",void 0),_defineProperty(this,"optionTwo",void 0)}async addValueSelector(initialValues){return[this.optionOne,this.optionTwo]=await this.getTextValues(),this.displayBinarySelection(initialValues)}getTextValues(){return(0,_str.get_strings)([{key:"no"},{key:"yes"}])}async displayBinarySelection(){let initialValues=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];const specificFilterSet=this.rootNode.querySelector(_selectors.default.filter.byName(this.filterType)),sourceDataNode=this.getSourceDataForFilter(),context={filtertype:this.filterType,title:sourceDataNode.getAttribute("data-field-title"),required:sourceDataNode.dataset.required,options:[{text:this.optionOne,value:0,selected:0===initialValues[0]},{text:this.optionTwo,value:1,selected:1===initialValues[0]}]};return _templates.default.render("core/datafilter/filtertypes/binary_selector",context).then(((binaryUi,js)=>_templates.default.replaceNodeContents(specificFilterSet.querySelector(_selectors.default.filter.regions.values),binaryUi,js)))}get values(){return this.filterRoot.querySelector('[data-filterfield="'.concat(this.name,'"]')).value}}return _exports.default=_default,_exports.default})); + +//# sourceMappingURL=binary.min.js.map \ No newline at end of file diff --git a/lib/amd/build/datafilter/filtertypes/binary.min.js.map b/lib/amd/build/datafilter/filtertypes/binary.min.js.map new file mode 100644 index 00000000000..b41d8295796 --- /dev/null +++ b/lib/amd/build/datafilter/filtertypes/binary.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"binary.min.js","sources":["../../../src/datafilter/filtertypes/binary.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 .\n\n/**\n * Base filter for binary selector ie: (Yes / No).\n *\n * @module core/datafilter/filtertypes/binary\n * @author 2022 Ghaly Marc-Alexandre \n * @copyright 2022 Catalyst IT Australia Pty Ltd\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Filter from 'core/datafilter/filtertype';\nimport Selectors from 'core/datafilter/selectors';\nimport Templates from 'core/templates';\nimport {get_strings as getStrings} from 'core/str';\n\nexport default class extends Filter {\n\n /**\n * Text string for the first binary option.\n *\n * This option (and {@see optionTwo}) are set by {@see getTextValues()}. The base class will set default values,\n * a subclass can override the method to define its own option.\n *\n * @type {String}\n */\n optionOne;\n\n /**\n * Text string for the second binary option.\n *\n * @type {String}\n */\n optionTwo;\n\n /**\n * Add the value selector to the filter row.\n *\n * @param {Array} initialValues The default value for the filter.\n */\n async addValueSelector(initialValues) {\n [this.optionOne, this.optionTwo] = await this.getTextValues();\n return this.displayBinarySelection(initialValues);\n }\n\n /**\n * Fetch text values for select options.\n *\n * Subclasses should override this method to set their own options.\n *\n * @returns {Promise}\n */\n getTextValues() {\n return getStrings([{key: 'no'}, {key: 'yes'}]);\n }\n\n /**\n * Renders yes/no select input with proper selection.\n *\n * @param {Array} initialValues The default value for the filter.\n */\n async displayBinarySelection(initialValues = []) {\n // We specify a specific filterset in case there are multiple filtering condition - avoiding glitches.\n const specificFilterSet = this.rootNode.querySelector(Selectors.filter.byName(this.filterType));\n const sourceDataNode = this.getSourceDataForFilter();\n const context = {\n filtertype: this.filterType,\n title: sourceDataNode.getAttribute('data-field-title'),\n required: sourceDataNode.dataset.required,\n options: [\n {\n text: this.optionOne,\n value: 0,\n selected: initialValues[0] === 0,\n },\n {\n text: this.optionTwo,\n value: 1,\n selected: initialValues[0] === 1,\n },\n ]\n };\n return Templates.render('core/datafilter/filtertypes/binary_selector', context)\n .then((binaryUi, js) => {\n return Templates.replaceNodeContents(specificFilterSet.querySelector(Selectors.filter.regions.values), binaryUi, js);\n });\n }\n\n /**\n * Get the list of raw values for this filter type.\n *\n * @returns {Array}\n */\n get values() {\n return this.filterRoot.querySelector(`[data-filterfield=\"${this.name}\"]`).value;\n }\n\n}\n"],"names":["Filter","initialValues","this","optionOne","optionTwo","getTextValues","displayBinarySelection","key","specificFilterSet","rootNode","querySelector","Selectors","filter","byName","filterType","sourceDataNode","getSourceDataForFilter","context","filtertype","title","getAttribute","required","dataset","options","text","value","selected","Templates","render","then","binaryUi","js","replaceNodeContents","regions","values","filterRoot","name"],"mappings":"irBA6B6BA,+JAwBFC,sBAClBC,KAAKC,UAAWD,KAAKE,iBAAmBF,KAAKG,gBACvCH,KAAKI,uBAAuBL,eAUvCI,uBACW,oBAAW,CAAC,CAACE,IAAK,MAAO,CAACA,IAAK,4CAQbN,qEAAgB,SAEnCO,kBAAoBN,KAAKO,SAASC,cAAcC,mBAAUC,OAAOC,OAAOX,KAAKY,aAC7EC,eAAiBb,KAAKc,yBACtBC,QAAU,CACZC,WAAYhB,KAAKY,WACjBK,MAAOJ,eAAeK,aAAa,oBACnCC,SAAUN,eAAeO,QAAQD,SACjCE,QAAS,CACL,CACIC,KAAMtB,KAAKC,UACXsB,MAAO,EACPC,SAA+B,IAArBzB,cAAc,IAE5B,CACIuB,KAAMtB,KAAKE,UACXqB,MAAO,EACPC,SAA+B,IAArBzB,cAAc,aAI7B0B,mBAAUC,OAAO,8CAA+CX,SACtEY,MAAK,CAACC,SAAUC,KACNJ,mBAAUK,oBAAoBxB,kBAAkBE,cAAcC,mBAAUC,OAAOqB,QAAQC,QAASJ,SAAUC,MASrHG,oBACOhC,KAAKiC,WAAWzB,2CAAoCR,KAAKkC,YAAUX"} \ No newline at end of file diff --git a/lib/amd/build/datafilter/selectors.min.js b/lib/amd/build/datafilter/selectors.min.js index 335229b97a2..7e318337318 100644 --- a/lib/amd/build/datafilter/selectors.min.js +++ b/lib/amd/build/datafilter/selectors.min.js @@ -6,6 +6,6 @@ define("core/datafilter/selectors",["exports"],(function(_exports){Object.define * @copyright 2020 Michael Hawkins * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -const getFilterRegion=region=>'[data-filterregion="'.concat(region,'"]'),getFilterAction=action=>'[data-filteraction="'.concat(action,'"]'),getFilterField=field=>'[data-filterfield="'.concat(field,'"]');var _default={filter:{region:getFilterRegion("filter"),actions:{remove:getFilterAction("remove")},fields:{join:getFilterField("join"),type:getFilterField("type")},regions:{values:getFilterRegion("value")},byName:name=>"".concat(getFilterRegion("filter"),'[data-filter-type="').concat(name,'"]')},filterset:{region:getFilterRegion("actions"),actions:{addRow:getFilterAction("add"),applyFilters:getFilterAction("apply"),resetFilters:getFilterAction("reset")},regions:{filtermatch:getFilterRegion("filtermatch"),filterlist:getFilterRegion("filters"),datasource:getFilterRegion("filtertypedata")},fields:{join:"".concat(getFilterRegion("filtermatch")," ").concat(getFilterField("join"))}},data:{fields:{byName:name=>'[data-field-name="'.concat(name,'"]'),all:"".concat(getFilterRegion("filtertypedata")," [data-field-name]")},typeList:getFilterRegion("filtertypelist"),typeListSelect:"select".concat(getFilterRegion("filtertypelist"))}};return _exports.default=_default,_exports.default})); +const getFilterRegion=region=>'[data-filterregion="'.concat(region,'"]'),getFilterAction=action=>'[data-filteraction="'.concat(action,'"]'),getFilterField=field=>'[data-filterfield="'.concat(field,'"]');var _default={filter:{region:getFilterRegion("filter"),actions:{remove:getFilterAction("remove")},fields:{join:getFilterField("join"),type:getFilterField("type")},regions:{values:getFilterRegion("value")},byName:name=>"".concat(getFilterRegion("filter"),'[data-filter-type="').concat(name,'"]')},filterset:{region:getFilterRegion("actions"),actions:{addRow:getFilterAction("add"),applyFilters:getFilterAction("apply"),resetFilters:getFilterAction("reset")},regions:{filtermatch:getFilterRegion("filtermatch"),filterlist:getFilterRegion("filters"),datasource:getFilterRegion("filtertypedata"),emptyFilterRow:"".concat(getFilterRegion("filter"),'[data-filter-type=""]')},fields:{join:"".concat(getFilterRegion("filtermatch")," ").concat(getFilterField("join"))}},data:{fields:{byName:name=>'[data-field-name="'.concat(name,'"]'),all:"".concat(getFilterRegion("filtertypedata")," [data-field-name]")},typeList:getFilterRegion("filtertypelist"),typeListSelect:"select".concat(getFilterRegion("filtertypelist")),required:"".concat(getFilterRegion("value"),' > [data-required="1"]')}};return _exports.default=_default,_exports.default})); //# sourceMappingURL=selectors.min.js.map \ No newline at end of file diff --git a/lib/amd/build/datafilter/selectors.min.js.map b/lib/amd/build/datafilter/selectors.min.js.map index 1cb34ad6cf8..6a51d33dfd8 100644 --- a/lib/amd/build/datafilter/selectors.min.js.map +++ b/lib/amd/build/datafilter/selectors.min.js.map @@ -1 +1 @@ -{"version":3,"file":"selectors.min.js","sources":["../../src/datafilter/selectors.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 .\n\n/**\n * Module containing the selectors for user filters.\n *\n * @module core/datafilter/selectors\n * @copyright 2020 Michael Hawkins \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst getFilterRegion = region => `[data-filterregion=\"${region}\"]`;\nconst getFilterAction = action => `[data-filteraction=\"${action}\"]`;\nconst getFilterField = field => `[data-filterfield=\"${field}\"]`;\n\nexport default {\n filter: {\n region: getFilterRegion('filter'),\n actions: {\n remove: getFilterAction('remove'),\n },\n fields: {\n join: getFilterField('join'),\n type: getFilterField('type'),\n },\n regions: {\n values: getFilterRegion('value'),\n },\n byName: name => `${getFilterRegion('filter')}[data-filter-type=\"${name}\"]`,\n },\n filterset: {\n region: getFilterRegion('actions'),\n actions: {\n addRow: getFilterAction('add'),\n applyFilters: getFilterAction('apply'),\n resetFilters: getFilterAction('reset'),\n },\n regions: {\n filtermatch: getFilterRegion('filtermatch'),\n filterlist: getFilterRegion('filters'),\n datasource: getFilterRegion('filtertypedata'),\n },\n fields: {\n join: `${getFilterRegion('filtermatch')} ${getFilterField('join')}`,\n },\n },\n data: {\n fields: {\n byName: name => `[data-field-name=\"${name}\"]`,\n all: `${getFilterRegion('filtertypedata')} [data-field-name]`,\n },\n typeList: getFilterRegion('filtertypelist'),\n typeListSelect: `select${getFilterRegion('filtertypelist')}`,\n },\n};\n"],"names":["getFilterRegion","region","getFilterAction","action","getFilterField","field","filter","actions","remove","fields","join","type","regions","values","byName","name","filterset","addRow","applyFilters","resetFilters","filtermatch","filterlist","datasource","data","all","typeList","typeListSelect"],"mappings":";;;;;;;;MAuBMA,gBAAkBC,sCAAiCA,aACnDC,gBAAkBC,sCAAiCA,aACnDC,eAAiBC,oCAA+BA,yBAEvC,CACXC,OAAQ,CACJL,OAAQD,gBAAgB,UACxBO,QAAS,CACLC,OAAQN,gBAAgB,WAE5BO,OAAQ,CACJC,KAAMN,eAAe,QACrBO,KAAMP,eAAe,SAEzBQ,QAAS,CACLC,OAAQb,gBAAgB,UAE5Bc,OAAQC,gBAAWf,gBAAgB,wCAA+Be,YAEtEC,UAAW,CACPf,OAAQD,gBAAgB,WACxBO,QAAS,CACLU,OAAQf,gBAAgB,OACxBgB,aAAchB,gBAAgB,SAC9BiB,aAAcjB,gBAAgB,UAElCU,QAAS,CACLQ,YAAapB,gBAAgB,eAC7BqB,WAAYrB,gBAAgB,WAC5BsB,WAAYtB,gBAAgB,mBAEhCS,OAAQ,CACJC,eAASV,gBAAgB,2BAAkBI,eAAe,WAGlEmB,KAAM,CACFd,OAAQ,CACJK,OAAQC,kCAA6BA,WACrCS,cAAQxB,gBAAgB,yCAE5ByB,SAAUzB,gBAAgB,kBAC1B0B,+BAAyB1B,gBAAgB"} \ No newline at end of file +{"version":3,"file":"selectors.min.js","sources":["../../src/datafilter/selectors.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 .\n\n/**\n * Module containing the selectors for user filters.\n *\n * @module core/datafilter/selectors\n * @copyright 2020 Michael Hawkins \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst getFilterRegion = region => `[data-filterregion=\"${region}\"]`;\nconst getFilterAction = action => `[data-filteraction=\"${action}\"]`;\nconst getFilterField = field => `[data-filterfield=\"${field}\"]`;\n\nexport default {\n filter: {\n region: getFilterRegion('filter'),\n actions: {\n remove: getFilterAction('remove'),\n },\n fields: {\n join: getFilterField('join'),\n type: getFilterField('type'),\n },\n regions: {\n values: getFilterRegion('value'),\n },\n byName: name => `${getFilterRegion('filter')}[data-filter-type=\"${name}\"]`,\n },\n filterset: {\n region: getFilterRegion('actions'),\n actions: {\n addRow: getFilterAction('add'),\n applyFilters: getFilterAction('apply'),\n resetFilters: getFilterAction('reset'),\n },\n regions: {\n filtermatch: getFilterRegion('filtermatch'),\n filterlist: getFilterRegion('filters'),\n datasource: getFilterRegion('filtertypedata'),\n emptyFilterRow: `${getFilterRegion('filter')}[data-filter-type=\"\"]`,\n },\n fields: {\n join: `${getFilterRegion('filtermatch')} ${getFilterField('join')}`,\n },\n },\n data: {\n fields: {\n byName: name => `[data-field-name=\"${name}\"]`,\n all: `${getFilterRegion('filtertypedata')} [data-field-name]`,\n },\n typeList: getFilterRegion('filtertypelist'),\n typeListSelect: `select${getFilterRegion('filtertypelist')}`,\n required: `${getFilterRegion('value')} > [data-required=\"1\"]`,\n },\n};\n"],"names":["getFilterRegion","region","getFilterAction","action","getFilterField","field","filter","actions","remove","fields","join","type","regions","values","byName","name","filterset","addRow","applyFilters","resetFilters","filtermatch","filterlist","datasource","emptyFilterRow","data","all","typeList","typeListSelect","required"],"mappings":";;;;;;;;MAuBMA,gBAAkBC,sCAAiCA,aACnDC,gBAAkBC,sCAAiCA,aACnDC,eAAiBC,oCAA+BA,yBAEvC,CACXC,OAAQ,CACJL,OAAQD,gBAAgB,UACxBO,QAAS,CACLC,OAAQN,gBAAgB,WAE5BO,OAAQ,CACJC,KAAMN,eAAe,QACrBO,KAAMP,eAAe,SAEzBQ,QAAS,CACLC,OAAQb,gBAAgB,UAE5Bc,OAAQC,gBAAWf,gBAAgB,wCAA+Be,YAEtEC,UAAW,CACPf,OAAQD,gBAAgB,WACxBO,QAAS,CACLU,OAAQf,gBAAgB,OACxBgB,aAAchB,gBAAgB,SAC9BiB,aAAcjB,gBAAgB,UAElCU,QAAS,CACLQ,YAAapB,gBAAgB,eAC7BqB,WAAYrB,gBAAgB,WAC5BsB,WAAYtB,gBAAgB,kBAC5BuB,yBAAmBvB,gBAAgB,oCAEvCS,OAAQ,CACJC,eAASV,gBAAgB,2BAAkBI,eAAe,WAGlEoB,KAAM,CACFf,OAAQ,CACJK,OAAQC,kCAA6BA,WACrCU,cAAQzB,gBAAgB,yCAE5B0B,SAAU1B,gBAAgB,kBAC1B2B,+BAAyB3B,gBAAgB,mBACzC4B,mBAAa5B,gBAAgB"} \ No newline at end of file diff --git a/lib/amd/build/form-autocomplete.min.js b/lib/amd/build/form-autocomplete.min.js index 895a40ee988..920ad6e55f5 100644 --- a/lib/amd/build/form-autocomplete.min.js +++ b/lib/amd/build/form-autocomplete.min.js @@ -6,6 +6,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since 3.0 */ -define("core/form-autocomplete",["jquery","core/log","core/str","core/templates","core/notification","core/loadingicon","core/aria","core_form/changechecker"],(function($,log,str,templates,notification,LoadingIcon,Aria,FormChangeChecker){var KEYS_DOWN=40,KEYS_ENTER=13,KEYS_SPACE=32,KEYS_ESCAPE=27,KEYS_COMMA=44,KEYS_UP=38,KEYS_LEFT=37,KEYS_RIGHT=39,uniqueId=Date.now(),activateSelection=function(index,state){var selectionElement=$(document.getElementById(state.selectionId)),length=selectionElement.children("[aria-selected=true]").length;for(index%=length;index<0;)index+=length;var element=$(selectionElement.children("[aria-selected=true]").get(index)),itemId=state.selectionId+"-"+index;return selectionElement.children().attr("data-active-selection",null).attr("id",""),element.attr("data-active-selection",!0).attr("id",itemId),selectionElement.attr("aria-activedescendant",itemId),selectionElement.attr("data-active-value",element.attr("data-value")),$.Deferred().resolve()},updateActiveSelectionFromState=function(state){var activeElement=function(state){var _selectionRegion$attr,selectionRegion=$(document.getElementById(state.selectionId)),activeId=selectionRegion.attr("aria-activedescendant");if(activeId){var activeElement=$(document.getElementById(activeId));if(activeElement.length)return activeElement}var activeValue=null===(_selectionRegion$attr=selectionRegion.attr("data-active-value"))||void 0===_selectionRegion$attr?void 0:_selectionRegion$attr.replace(/"/g,'\\"');return selectionRegion.find('[data-value="'+activeValue+'"]')}(state),activeValue=activeElement.attr("data-value"),selectionRegion=$(document.getElementById(state.selectionId));if(activeValue){var activeIndex=selectionRegion.find("[aria-selected=true]").index(activeElement);if(-1!==activeIndex)return void activateSelection(activeIndex,state)}activateSelection(0,state)},updateSelectionList=function(options,state,originalSelect){var pendingKey="form-autocomplete-updateSelectionList-"+state.inputId;M.util.js_pending(pendingKey);var items=[],newSelection=$(document.getElementById(state.selectionId));if(originalSelect.children("option").each((function(index,ele){var label;$(ele).prop("selected")&&(""!==(label=$(ele).data("html")?$(ele).data("html"):$(ele).html())&&items.push({label:label,value:$(ele).attr("value")}))})),!hasItemListChanged(state,items))return M.util.js_complete(pendingKey),Promise.resolve();state.items=items;var context=$.extend(options,state);return templates.render(options.templates.items,context).then((function(html,js){templates.replaceNodeContents(newSelection,html,js),updateActiveSelectionFromState(state)})).then((function(){return M.util.js_complete(pendingKey)})).catch(notification.exception)},hasItemListChanged=function(state,items){return state.items.length!==items.length||state.items.filter((item=>-1===items.indexOf(item))).length>0},notifyChange=function(originalSelect){FormChangeChecker.markFormChangedFromNode(originalSelect[0]),originalSelect[0].dispatchEvent(new Event("change"))},deselectItem=function(options,state,item,originalSelect){var selectedItemValue=$(item).attr("data-value");return originalSelect.prepend($("