From 290e6f4c6f54490d8b07bfa748df246c5a8094dc Mon Sep 17 00:00:00 2001 From: Amaia Anabitarte Date: Tue, 13 Jun 2023 12:00:54 +0200 Subject: [PATCH 1/4] MDL-78288 core_course: Adding filter_shown_headers option to forms --- course/editsection.php | 18 ++- course/editsection_form.php | 27 ++-- course/modedit.php | 10 ++ course/moodleform_mod.php | 3 + lib/form/amd/build/collapsesections.min.js | 2 +- .../amd/build/collapsesections.min.js.map | 2 +- lib/form/amd/src/collapsesections.js | 13 +- lib/formslib.php | 124 +++++++++++++++++- lib/upgrade.txt | 1 + 9 files changed, 177 insertions(+), 23 deletions(-) diff --git a/course/editsection.php b/course/editsection.php index 04ece14bf12..e5d10f0d1c9 100644 --- a/course/editsection.php +++ b/course/editsection.php @@ -30,8 +30,13 @@ require_once($CFG->libdir . '/formslib.php'); $id = required_param('id', PARAM_INT); // course_sections.id $sectionreturn = optional_param('sr', 0, PARAM_INT); $deletesection = optional_param('delete', 0, PARAM_BOOL); +$showonly = optional_param('showonly', 0, PARAM_TAGLIST); -$PAGE->set_url('/course/editsection.php', array('id'=>$id, 'sr'=> $sectionreturn)); +$params = ['id'=>$id, 'sr'=> $sectionreturn]; +if (!empty($showonly)) { + $params['showonly'] = $showonly; +} +$PAGE->set_url('/course/editsection.php', $params); $section = $DB->get_record('course_sections', array('id' => $id), '*', MUST_EXIST); $course = $DB->get_record('course', array('id' => $section->course), '*', MUST_EXIST); @@ -96,11 +101,13 @@ $editoroptions = array( $courseformat = course_get_format($course); $defaultsectionname = $courseformat->get_default_section_name($section); -$customdata = array( +$customdata = [ 'cs' => $sectioninfo, 'editoroptions' => $editoroptions, - 'defaultsectionname' => $defaultsectionname -); + 'defaultsectionname' => $defaultsectionname, + 'showonly' => $showonly, +]; + $mform = $courseformat->editsection_form($PAGE->url, $customdata); // set current value, make an editable copy of section_info object @@ -110,6 +117,9 @@ if (!empty($CFG->enableavailability)) { $initialdata['availabilityconditionsjson'] = $sectioninfo->availability; } $mform->set_data($initialdata); +if (!empty($showonly)) { + $mform->filter_shown_headers(explode(',', $showonly)); +} if ($mform->is_cancelled()){ // Form cancelled, return to course. diff --git a/course/editsection_form.php b/course/editsection_form.php index 264ae96ac0d..63465064e95 100644 --- a/course/editsection_form.php +++ b/course/editsection_form.php @@ -17,6 +17,7 @@ require_once($CFG->libdir.'/gradelib.php'); class editsection_form extends moodleform { function definition() { + global $CFG; $mform = $this->_form; $course = $this->_customdata['course']; @@ -47,26 +48,28 @@ class editsection_form extends moodleform { $elements = $courseformat->create_edit_form_elements($mform, true); } - $mform->_registerCancelButton('cancel'); - } - - public function definition_after_data() { - global $CFG, $DB; - - $mform = $this->_form; - $course = $this->_customdata['course']; - $context = context_course::instance($course->id); - if (!empty($CFG->enableavailability)) { $mform->addElement('header', 'availabilityconditions', - get_string('restrictaccess', 'availability')); + get_string('restrictaccess', 'availability')); $mform->setExpanded('availabilityconditions', false); // Availability field. This is just a textarea; the user interface // interaction is all implemented in JavaScript. The field is named // availabilityconditionsjson for consistency with moodleform_mod. $mform->addElement('textarea', 'availabilityconditionsjson', - get_string('accessrestrictions', 'availability')); + get_string('accessrestrictions', 'availability')); + } + + $mform->_registerCancelButton('cancel'); + } + + public function definition_after_data() { + global $CFG; + + $mform = $this->_form; + $course = $this->_customdata['course']; + + if (!empty($CFG->enableavailability)) { \core_availability\frontend::include_all_javascript($course, null, $this->_customdata['cs']); } diff --git a/course/modedit.php b/course/modedit.php index b3c9959b6b7..4cb5ee13dc3 100644 --- a/course/modedit.php +++ b/course/modedit.php @@ -37,12 +37,16 @@ $return = optional_param('return', 0, PARAM_BOOL); //return to course/view.ph $type = optional_param('type', '', PARAM_ALPHANUM); //TODO: hopefully will be removed in 2.0 $sectionreturn = optional_param('sr', null, PARAM_INT); $beforemod = optional_param('beforemod', 0, PARAM_INT); +$showonly = optional_param('showonly', '', PARAM_ALPHANUM); // Settings group to show expanded and hide the rest. $url = new moodle_url('/course/modedit.php'); $url->param('sr', $sectionreturn); if (!empty($return)) { $url->param('return', $return); } +if (!empty($showonly)) { + $url->param('showonly', $showonly); +} if (!empty($add)) { $section = required_param('section', PARAM_INT); @@ -113,6 +117,9 @@ if (!empty($add)) { $data->return = $return; $data->sr = $sectionreturn; $data->update = $update; + if (!empty($showonly)) { + $data->showonly = $showonly; + } $sectionname = get_section_name($course, $cw); $fullmodulename = get_string('modulename', $module->name); @@ -153,6 +160,9 @@ if (file_exists($modmoodleform)) { $mformclassname = 'mod_'.$module->name.'_mod_form'; $mform = new $mformclassname($data, $cw->section, $cm, $course); $mform->set_data($data); +if (!empty($showonly)) { + $mform->filter_shown_headers(explode(',', $showonly)); +} if ($mform->is_cancelled()) { if ($return && !empty($cm->id)) { diff --git a/course/moodleform_mod.php b/course/moodleform_mod.php index e11a5da2998..34c2de438c6 100644 --- a/course/moodleform_mod.php +++ b/course/moodleform_mod.php @@ -1064,6 +1064,9 @@ abstract class moodleform_mod extends moodleform { $mform->addElement('hidden', 'beforemod', 0); $mform->setType('beforemod', PARAM_INT); + + $mform->addElement('hidden', 'showonly', ''); + $mform->setType('showonly', PARAM_ALPHANUMEXT); } public function standard_grading_coursemodule_elements() { diff --git a/lib/form/amd/build/collapsesections.min.js b/lib/form/amd/build/collapsesections.min.js index c163e8553e8..ff3fd35b959 100644 --- a/lib/form/amd/build/collapsesections.min.js +++ b/lib/form/amd/build/collapsesections.min.js @@ -6,6 +6,6 @@ define("core_form/collapsesections",["exports","jquery","core/pending"],(functio * @copyright 2021 Bas Brands * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since 4.0 - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_jquery=_interopRequireDefault(_jquery),_pending=_interopRequireDefault(_pending);const SELECTORS_FORMHEADER=".fheader",SELECTORS_FORMCONTAINER=".fcontainer",CLASSES_SHOW="show",CLASSES_COLLAPSED="collapsed";_exports.init=collapsesections=>{const pendingPromise=new _pending.default("core_form/collapsesections"),collapsemenu=document.querySelector(collapsesections),formParent=collapsemenu.closest("form");collapsemenu.addEventListener("keydown",(e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),collapsemenu.click())}));let expandedcount=0;const formcontainercount=(0,_jquery.default)(SELECTORS_FORMCONTAINER).length;(0,_jquery.default)(SELECTORS_FORMCONTAINER).each(((_,collapsecontainer)=>{collapsecontainer.classList.contains(CLASSES_SHOW)&&expandedcount++})),formcontainercount===expandedcount&&(collapsemenu.classList.remove(CLASSES_COLLAPSED),collapsemenu.setAttribute("aria-expanded",!0)),collapsemenu.addEventListener("click",(()=>{let action="hide";collapsemenu.classList.contains(CLASSES_COLLAPSED)&&(action="show"),formParent.querySelectorAll(SELECTORS_FORMCONTAINER).forEach((collapsecontainer=>{(0,_jquery.default)(collapsecontainer).collapse(action)}))}));const collapseElementIds=[...(0,_jquery.default)(SELECTORS_FORMHEADER)].map(((element,index)=>(element.id=element.id||"collapseElement-".concat(index),element.id)));collapsemenu.setAttribute("aria-controls",collapseElementIds.join(" ")),(0,_jquery.default)(SELECTORS_FORMCONTAINER).on("hidden.bs.collapse",(()=>{let allCollapsed=!0;formParent.querySelectorAll(SELECTORS_FORMCONTAINER).forEach((collapsecontainer=>{collapsecontainer.classList.contains(CLASSES_SHOW)&&(allCollapsed=!1)})),allCollapsed&&(collapsemenu.classList.add(CLASSES_COLLAPSED),collapsemenu.setAttribute("aria-expanded",!1))})),(0,_jquery.default)(SELECTORS_FORMCONTAINER).on("shown.bs.collapse",(()=>{let allExpanded=!0;formParent.querySelectorAll(SELECTORS_FORMCONTAINER).forEach((collapsecontainer=>{collapsecontainer.classList.contains(CLASSES_SHOW)||(allExpanded=!1)})),allExpanded&&(collapsemenu.classList.remove(CLASSES_COLLAPSED),collapsemenu.setAttribute("aria-expanded",!0))})),pendingPromise.resolve()}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_jquery=_interopRequireDefault(_jquery),_pending=_interopRequireDefault(_pending);const SELECTORS_FORMHEADER=".fheader",SELECTORS_FORMCONTAINER=".fcontainer",CLASSES_SHOW="show",CLASSES_COLLAPSED="collapsed",CLASSES_HIDDEN="d-none";_exports.init=collapsesections=>{const pendingPromise=new _pending.default("core_form/collapsesections"),collapsemenu=document.querySelector(collapsesections),formParent=collapsemenu.closest("form");collapsemenu.addEventListener("keydown",(e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),collapsemenu.click())}));let formcontainercount=0;(0,_jquery.default)(SELECTORS_FORMCONTAINER).each(((_,container)=>{container.classList.contains(CLASSES_HIDDEN)||container.parentElement.classList.contains(CLASSES_HIDDEN)||formcontainercount++}));let expandedcount=0;(0,_jquery.default)(SELECTORS_FORMCONTAINER).each(((_,collapsecontainer)=>{collapsecontainer.classList.contains(CLASSES_SHOW)&&expandedcount++})),formcontainercount===expandedcount&&(collapsemenu.classList.remove(CLASSES_COLLAPSED),collapsemenu.setAttribute("aria-expanded",!0)),collapsemenu.addEventListener("click",(()=>{let action="hide";collapsemenu.classList.contains(CLASSES_COLLAPSED)&&(action="show"),formParent.querySelectorAll(SELECTORS_FORMCONTAINER).forEach((collapsecontainer=>{(0,_jquery.default)(collapsecontainer).collapse(action)}))}));const collapseElementIds=[...(0,_jquery.default)(SELECTORS_FORMHEADER)].map(((element,index)=>(element.id=element.id||"collapseElement-".concat(index),element.id)));collapsemenu.setAttribute("aria-controls",collapseElementIds.join(" ")),(0,_jquery.default)(SELECTORS_FORMCONTAINER).on("hidden.bs.collapse",(()=>{let allCollapsed=!0;formParent.querySelectorAll(SELECTORS_FORMCONTAINER).forEach((collapsecontainer=>{collapsecontainer.classList.contains(CLASSES_SHOW)&&(allCollapsed=!1)})),allCollapsed&&(collapsemenu.classList.add(CLASSES_COLLAPSED),collapsemenu.setAttribute("aria-expanded",!1))})),(0,_jquery.default)(SELECTORS_FORMCONTAINER).on("shown.bs.collapse",(()=>{let allExpanded=!0;formParent.querySelectorAll(SELECTORS_FORMCONTAINER).forEach((collapsecontainer=>{collapsecontainer.classList.contains(CLASSES_SHOW)||(allExpanded=!1)})),allExpanded&&(collapsemenu.classList.remove(CLASSES_COLLAPSED),collapsemenu.setAttribute("aria-expanded",!0))})),pendingPromise.resolve()}})); //# sourceMappingURL=collapsesections.min.js.map \ No newline at end of file diff --git a/lib/form/amd/build/collapsesections.min.js.map b/lib/form/amd/build/collapsesections.min.js.map index 692266169db..f2623578c63 100644 --- a/lib/form/amd/build/collapsesections.min.js.map +++ b/lib/form/amd/build/collapsesections.min.js.map @@ -1 +1 @@ -{"version":3,"file":"collapsesections.min.js","sources":["../src/collapsesections.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 * Collapse or expand all form sections on clicking the expand all / collapse al link.\n *\n * @module core_form/collapsesections\n * @copyright 2021 Bas Brands\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.0\n */\n\nimport $ from 'jquery';\nimport Pending from 'core/pending';\n\nconst SELECTORS = {\n FORMHEADER: '.fheader',\n FORMCONTAINER: '.fcontainer',\n};\n\nconst CLASSES = {\n SHOW: 'show',\n COLLAPSED: 'collapsed'\n};\n\n/**\n * Initialises the form section collapse / expand action.\n *\n * @param {string} collapsesections the collapse/expand link id.\n */\nexport const init = collapsesections => {\n // All jQuery in this code can be replaced when MDL-71979 is integrated (move to Bootstrap 5).\n const pendingPromise = new Pending('core_form/collapsesections');\n const collapsemenu = document.querySelector(collapsesections);\n const formParent = collapsemenu.closest('form');\n collapsemenu.addEventListener('keydown', e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n collapsemenu.click();\n }\n });\n\n // Override default collapse class if all containers are expanded on page load\n let expandedcount = 0;\n const formcontainercount = $(SELECTORS.FORMCONTAINER).length;\n $(SELECTORS.FORMCONTAINER).each((_, collapsecontainer) => {\n if (collapsecontainer.classList.contains(CLASSES.SHOW)) {\n expandedcount++;\n }\n });\n\n if (formcontainercount === expandedcount) {\n collapsemenu.classList.remove(CLASSES.COLLAPSED);\n collapsemenu.setAttribute('aria-expanded', true);\n }\n\n collapsemenu.addEventListener('click', () => {\n let action = 'hide';\n if (collapsemenu.classList.contains(CLASSES.COLLAPSED)) {\n action = 'show';\n }\n\n formParent.querySelectorAll(SELECTORS.FORMCONTAINER).forEach((collapsecontainer) => {\n $(collapsecontainer).collapse(action);\n });\n });\n\n // Ensure collapse menu button adds aria-controls attribute referring to each collapsible element.\n const collapseElements = $(SELECTORS.FORMHEADER);\n const collapseElementIds = [...collapseElements].map((element, index) => {\n element.id = element.id || `collapseElement-${index}`;\n return element.id;\n });\n collapsemenu.setAttribute('aria-controls', collapseElementIds.join(' '));\n\n $(SELECTORS.FORMCONTAINER).on('hidden.bs.collapse', () => {\n let allCollapsed = true;\n\n formParent.querySelectorAll(SELECTORS.FORMCONTAINER).forEach((collapsecontainer) => {\n if (collapsecontainer.classList.contains(CLASSES.SHOW)) {\n allCollapsed = false;\n }\n });\n\n if (allCollapsed) {\n collapsemenu.classList.add(CLASSES.COLLAPSED);\n collapsemenu.setAttribute('aria-expanded', false);\n }\n });\n $(SELECTORS.FORMCONTAINER).on('shown.bs.collapse', () => {\n let allExpanded = true;\n\n formParent.querySelectorAll(SELECTORS.FORMCONTAINER).forEach((collapsecontainer) => {\n if (!collapsecontainer.classList.contains(CLASSES.SHOW)) {\n allExpanded = false;\n }\n });\n\n if (allExpanded) {\n collapsemenu.classList.remove(CLASSES.COLLAPSED);\n collapsemenu.setAttribute('aria-expanded', true);\n }\n });\n pendingPromise.resolve();\n};\n"],"names":["SELECTORS","CLASSES","collapsesections","pendingPromise","Pending","collapsemenu","document","querySelector","formParent","closest","addEventListener","e","key","preventDefault","click","expandedcount","formcontainercount","length","each","_","collapsecontainer","classList","contains","remove","setAttribute","action","querySelectorAll","forEach","collapse","collapseElementIds","map","element","index","id","join","on","allCollapsed","add","allExpanded","resolve"],"mappings":";;;;;;;;0KA2BMA,qBACU,WADVA,wBAEa,cAGbC,aACI,OADJA,kBAES,0BAQKC,yBAEVC,eAAiB,IAAIC,iBAAQ,8BAC7BC,aAAeC,SAASC,cAAcL,kBACtCM,WAAaH,aAAaI,QAAQ,QACxCJ,aAAaK,iBAAiB,WAAWC,IACvB,UAAVA,EAAEC,KAA6B,MAAVD,EAAEC,MACvBD,EAAEE,iBACFR,aAAaS,gBAKjBC,cAAgB,QACdC,oBAAqB,mBAAEhB,yBAAyBiB,2BACpDjB,yBAAyBkB,MAAK,CAACC,EAAGC,qBAC5BA,kBAAkBC,UAAUC,SAASrB,eACrCc,mBAIJC,qBAAuBD,gBACvBV,aAAagB,UAAUE,OAAOtB,mBAC9BI,aAAamB,aAAa,iBAAiB,IAG/CnB,aAAaK,iBAAiB,SAAS,SAC/Be,OAAS,OACTpB,aAAagB,UAAUC,SAASrB,qBAChCwB,OAAS,QAGbjB,WAAWkB,iBAAiB1B,yBAAyB2B,SAASP,wCACxDA,mBAAmBQ,SAASH,oBAMhCI,mBAAqB,KADF,mBAAE7B,uBACsB8B,KAAI,CAACC,QAASC,SAC3DD,QAAQE,GAAKF,QAAQE,8BAAyBD,OACvCD,QAAQE,MAEnB5B,aAAamB,aAAa,gBAAiBK,mBAAmBK,KAAK,0BAEjElC,yBAAyBmC,GAAG,sBAAsB,SAC5CC,cAAe,EAEnB5B,WAAWkB,iBAAiB1B,yBAAyB2B,SAASP,oBACtDA,kBAAkBC,UAAUC,SAASrB,gBACrCmC,cAAe,MAInBA,eACA/B,aAAagB,UAAUgB,IAAIpC,mBAC3BI,aAAamB,aAAa,iBAAiB,2BAGjDxB,yBAAyBmC,GAAG,qBAAqB,SAC3CG,aAAc,EAElB9B,WAAWkB,iBAAiB1B,yBAAyB2B,SAASP,oBACrDA,kBAAkBC,UAAUC,SAASrB,gBACtCqC,aAAc,MAIlBA,cACAjC,aAAagB,UAAUE,OAAOtB,mBAC9BI,aAAamB,aAAa,iBAAiB,OAGnDrB,eAAeoC"} \ No newline at end of file +{"version":3,"file":"collapsesections.min.js","sources":["../src/collapsesections.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 * Collapse or expand all form sections on clicking the expand all / collapse al link.\n *\n * @module core_form/collapsesections\n * @copyright 2021 Bas Brands\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.0\n */\n\nimport $ from 'jquery';\nimport Pending from 'core/pending';\n\nconst SELECTORS = {\n FORMHEADER: '.fheader',\n FORMCONTAINER: '.fcontainer',\n};\n\nconst CLASSES = {\n SHOW: 'show',\n COLLAPSED: 'collapsed',\n HIDDEN: 'd-none'\n};\n\n/**\n * Initialises the form section collapse / expand action.\n *\n * @param {string} collapsesections the collapse/expand link id.\n */\nexport const init = collapsesections => {\n // All jQuery in this code can be replaced when MDL-71979 is integrated (move to Bootstrap 5).\n const pendingPromise = new Pending('core_form/collapsesections');\n const collapsemenu = document.querySelector(collapsesections);\n const formParent = collapsemenu.closest('form');\n collapsemenu.addEventListener('keydown', e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n collapsemenu.click();\n }\n });\n\n // Override default collapse class if all visible containers are expanded on page load\n let formcontainercount = 0;\n $(SELECTORS.FORMCONTAINER).each((_, container) => {\n if (!container.classList.contains(CLASSES.HIDDEN) &&\n !container.parentElement.classList.contains(CLASSES.HIDDEN)) {\n formcontainercount++;\n }\n });\n let expandedcount = 0;\n $(SELECTORS.FORMCONTAINER).each((_, collapsecontainer) => {\n if (collapsecontainer.classList.contains(CLASSES.SHOW)) {\n expandedcount++;\n }\n });\n\n if (formcontainercount === expandedcount) {\n collapsemenu.classList.remove(CLASSES.COLLAPSED);\n collapsemenu.setAttribute('aria-expanded', true);\n }\n\n collapsemenu.addEventListener('click', () => {\n let action = 'hide';\n if (collapsemenu.classList.contains(CLASSES.COLLAPSED)) {\n action = 'show';\n }\n\n formParent.querySelectorAll(SELECTORS.FORMCONTAINER).forEach((collapsecontainer) => {\n $(collapsecontainer).collapse(action);\n });\n });\n\n // Ensure collapse menu button adds aria-controls attribute referring to each collapsible element.\n const collapseElements = $(SELECTORS.FORMHEADER);\n const collapseElementIds = [...collapseElements].map((element, index) => {\n element.id = element.id || `collapseElement-${index}`;\n return element.id;\n });\n collapsemenu.setAttribute('aria-controls', collapseElementIds.join(' '));\n\n $(SELECTORS.FORMCONTAINER).on('hidden.bs.collapse', () => {\n let allCollapsed = true;\n\n formParent.querySelectorAll(SELECTORS.FORMCONTAINER).forEach((collapsecontainer) => {\n if (collapsecontainer.classList.contains(CLASSES.SHOW)) {\n allCollapsed = false;\n }\n });\n\n if (allCollapsed) {\n collapsemenu.classList.add(CLASSES.COLLAPSED);\n collapsemenu.setAttribute('aria-expanded', false);\n }\n });\n $(SELECTORS.FORMCONTAINER).on('shown.bs.collapse', () => {\n let allExpanded = true;\n\n formParent.querySelectorAll(SELECTORS.FORMCONTAINER).forEach((collapsecontainer) => {\n if (!collapsecontainer.classList.contains(CLASSES.SHOW)) {\n allExpanded = false;\n }\n });\n\n if (allExpanded) {\n collapsemenu.classList.remove(CLASSES.COLLAPSED);\n collapsemenu.setAttribute('aria-expanded', true);\n }\n });\n pendingPromise.resolve();\n};\n"],"names":["SELECTORS","CLASSES","collapsesections","pendingPromise","Pending","collapsemenu","document","querySelector","formParent","closest","addEventListener","e","key","preventDefault","click","formcontainercount","each","_","container","classList","contains","parentElement","expandedcount","collapsecontainer","remove","setAttribute","action","querySelectorAll","forEach","collapse","collapseElementIds","map","element","index","id","join","on","allCollapsed","add","allExpanded","resolve"],"mappings":";;;;;;;;0KA2BMA,qBACU,WADVA,wBAEa,cAGbC,aACI,OADJA,kBAES,YAFTA,eAGM,uBAQQC,yBAEVC,eAAiB,IAAIC,iBAAQ,8BAC7BC,aAAeC,SAASC,cAAcL,kBACtCM,WAAaH,aAAaI,QAAQ,QACxCJ,aAAaK,iBAAiB,WAAWC,IACvB,UAAVA,EAAEC,KAA6B,MAAVD,EAAEC,MACvBD,EAAEE,iBACFR,aAAaS,gBAKjBC,mBAAqB,sBACvBf,yBAAyBgB,MAAK,CAACC,EAAGC,aAC3BA,UAAUC,UAAUC,SAASnB,iBACjCiB,UAAUG,cAAcF,UAAUC,SAASnB,iBACxCc,4BAGJO,cAAgB,sBAClBtB,yBAAyBgB,MAAK,CAACC,EAAGM,qBAC5BA,kBAAkBJ,UAAUC,SAASnB,eACrCqB,mBAIJP,qBAAuBO,gBACvBjB,aAAac,UAAUK,OAAOvB,mBAC9BI,aAAaoB,aAAa,iBAAiB,IAG/CpB,aAAaK,iBAAiB,SAAS,SAC/BgB,OAAS,OACTrB,aAAac,UAAUC,SAASnB,qBAChCyB,OAAS,QAGblB,WAAWmB,iBAAiB3B,yBAAyB4B,SAASL,wCACxDA,mBAAmBM,SAASH,oBAMhCI,mBAAqB,KADF,mBAAE9B,uBACsB+B,KAAI,CAACC,QAASC,SAC3DD,QAAQE,GAAKF,QAAQE,8BAAyBD,OACvCD,QAAQE,MAEnB7B,aAAaoB,aAAa,gBAAiBK,mBAAmBK,KAAK,0BAEjEnC,yBAAyBoC,GAAG,sBAAsB,SAC5CC,cAAe,EAEnB7B,WAAWmB,iBAAiB3B,yBAAyB4B,SAASL,oBACtDA,kBAAkBJ,UAAUC,SAASnB,gBACrCoC,cAAe,MAInBA,eACAhC,aAAac,UAAUmB,IAAIrC,mBAC3BI,aAAaoB,aAAa,iBAAiB,2BAGjDzB,yBAAyBoC,GAAG,qBAAqB,SAC3CG,aAAc,EAElB/B,WAAWmB,iBAAiB3B,yBAAyB4B,SAASL,oBACrDA,kBAAkBJ,UAAUC,SAASnB,gBACtCsC,aAAc,MAIlBA,cACAlC,aAAac,UAAUK,OAAOvB,mBAC9BI,aAAaoB,aAAa,iBAAiB,OAGnDtB,eAAeqC"} \ No newline at end of file diff --git a/lib/form/amd/src/collapsesections.js b/lib/form/amd/src/collapsesections.js index 2ebfab88a08..b8f8f7e9641 100644 --- a/lib/form/amd/src/collapsesections.js +++ b/lib/form/amd/src/collapsesections.js @@ -32,7 +32,8 @@ const SELECTORS = { const CLASSES = { SHOW: 'show', - COLLAPSED: 'collapsed' + COLLAPSED: 'collapsed', + HIDDEN: 'd-none' }; /** @@ -52,9 +53,15 @@ export const init = collapsesections => { } }); - // Override default collapse class if all containers are expanded on page load + // Override default collapse class if all visible containers are expanded on page load + let formcontainercount = 0; + $(SELECTORS.FORMCONTAINER).each((_, container) => { + if (!container.classList.contains(CLASSES.HIDDEN) && + !container.parentElement.classList.contains(CLASSES.HIDDEN)) { + formcontainercount++; + } + }); let expandedcount = 0; - const formcontainercount = $(SELECTORS.FORMCONTAINER).length; $(SELECTORS.FORMCONTAINER).each((_, collapsecontainer) => { if (collapsecontainer.classList.contains(CLASSES.SHOW)) { expandedcount++; diff --git a/lib/formslib.php b/lib/formslib.php index 56270813653..bba17179d20 100644 --- a/lib/formslib.php +++ b/lib/formslib.php @@ -485,6 +485,24 @@ abstract class moodleform { $this->_form->setDefaults($default_values); } + /** + * Use this method to indicate that the fieldsets should be shown as expanded + * and all other fieldsets should be hidden. + * The method is applicable to header elements only. + * + * @param array $shownonly array of header element names + * @return void + */ + public function filter_shown_headers(array $shownonly): void { + $toshow = []; + foreach ($shownonly as $show) { + if ($this->_form->elementExists($show) && $this->_form->getElementType($show) == 'header') { + $toshow[] = $show; + } + } + $this->_form->filter_shown_headers($toshow); + } + /** * Check that form was submitted. Does not check validity of submitted data. * @@ -1636,6 +1654,14 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless { */ var $_disableShortforms = false; + /** + * Array whose keys are the only elements to be shown. + * Rest of the elements that are not in this array will be hidden. + * + * @var array + */ + protected $_shownonlyelements = []; + /** @var bool whether to automatically initialise the form change detector this form. */ protected $_use_form_change_checker = true; @@ -1830,6 +1856,45 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless { $this->_collapsibleElements[$headername] = !$expanded; } + /** + * Use this method to indicate that the fieldsets should be shown and expanded + * and all other fieldsets should be hidden. + * The method is applicable to header elements only. + * + * @param array $shownonly array of header element names + * @return void + */ + public function filter_shown_headers(array $shownonly): void { + $this->_shownonlyelements = []; + if (empty($shownonly)) { + return; + } + foreach ($shownonly as $headername) { + $element = $this->getElement($headername); + if ($element->getType() == 'header') { + $this->_shownonlyelements[] = $headername; + $this->setExpanded($headername); + } + } + } + + /** + * Use this method to check if the fieldsets could be shown. + * The method is applicable to header elements only. + * + * @param string $headername header element name to check in the shown only elements array. + * @return void + */ + public function is_shown(string $headername): bool { + if (empty($headername)) { + return true; + } + if (empty($this->_shownonlyelements)) { + return true; + } + return in_array($headername, $this->_shownonlyelements); + } + /** * Use this method to add show more/less status element required for passing * over the advanced elements visibility status on the form submission. @@ -2012,15 +2077,22 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless { } if ($element->getType() == 'header') { + if (!$this->is_shown($headername)) { + $this->setExpanded($headername, false); + continue; + } if ($headercounter === 1 && !isset($this->_collapsibleElements[$headername])) { // By default the first section is always expanded, except if a state has already been set. $this->setExpanded($headername, true); - } else if (($headercounter === 2 && $headerscount === 2) && !isset($this->_collapsibleElements[$headername])) { + } else if ( + ($headercounter === 2 && $headerscount === 2) + && !isset($this->_collapsibleElements[$headername]) + ) { // The second section is always expanded if the form only contains 2 sections), // except if a state has already been set. $this->setExpanded($headername, true); } - } else if ($anyrequiredorerror) { + } else if ($anyrequiredorerror && (empty($headername) || $this->is_shown($headername))) { // If any error or required field are present within the header, we need to expand it. $this->setExpanded($headername, true, true); } else if (!isset($this->_collapsibleElements[$headername])) { @@ -2032,12 +2104,38 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless { // Pass the array to renderer object. $renderer->setCollapsibleElements($this->_collapsibleElements); } + + $this->accept_set_nonvisible_elements($renderer); + if (method_exists($renderer, 'set_sticky_footer') && !empty($this->_stickyfooterelement)) { $renderer->set_sticky_footer($this->_stickyfooterelement); } parent::accept($renderer); } + /** + * Checking non-visible elements to set when accepting a renderer. + * @param HTML_QuickForm_Renderer $renderer + */ + private function accept_set_nonvisible_elements($renderer) { + if (!method_exists($renderer, 'set_nonvisible_elements') || $this->_disableShortforms) { + return; + } + $nonvisibles = []; + foreach (array_keys($this->_elements) as $index) { + $element =& $this->_elements[$index]; + if ($element->getType() != 'header') { + continue; + } + $headername = $element->getName(); + if (!$this->is_shown($headername)) { + $nonvisibles[] = $headername; + } + } + // Pass the array to renderer object. + $renderer->set_nonvisible_elements($nonvisibles); + } + /** * Adds one or more element names that indicate the end of a fieldset * @@ -3116,6 +3214,14 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{ /** @var string advanced class HTML. */ protected $_advancedHTML; + /** + * Array whose keys are element names should be hidden. + * If the key exists this is an invisible element. + * + * @var array + */ + protected $_nonvisibleelements = []; + /** * Constructor */ @@ -3175,6 +3281,15 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{ $this->_collapsibleElements = $elements; } + /** + * Setting non visible elements + * + * @param array $elements + */ + public function set_nonvisible_elements($elements) { + $this->_nonvisibleelements = $elements; + } + /** * What to do when starting the form * @@ -3437,6 +3552,11 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{ } } + // Hide fieldsets not included in the shown only elements. + if (in_array($header->getName(), $this->_nonvisibleelements)) { + $fieldsetclasses[] = 'd-none'; + } + if (isset($this->_advancedElements[$name])){ $fieldsetclasses[] = 'containsadvancedelements'; } diff --git a/lib/upgrade.txt b/lib/upgrade.txt index e72cff8d4d5..2d06b7c66f9 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -42,6 +42,7 @@ information provided here is intended especially for developers. * New events course_started and course_ended have been created. For now, they are triggered when courses change automatically their visibility through the new scheduled tasks to hide/show courses based on their start/end dates. * The action_menu::set_constraint() method is deprecated. Please use action_menu::set_boundary() instead. +* New method moodleform::filter_shown_headers() is created to show some expanded headers only and hide the rest. === 4.2 === From b9a840f638ea439ace6d506607cdaa54862cc85a Mon Sep 17 00:00:00 2001 From: Amaia Anabitarte Date: Tue, 27 Jun 2023 12:21:05 +0200 Subject: [PATCH 2/4] MDL-78288 behat: New availability info selectors - Create a new availability info selectors for section and activity data info regions - Replace css_element by created selectors in the existing behat tests --- .../tests/behat/conditional_bug.feature | 2 +- .../tests/behat/behat_availability.php | 51 +++++++++++++++++++ .../tests/behat/display_availability.feature | 42 +++++++-------- .../local/content/cm/availability.mustache | 2 +- .../content/section/availability.mustache | 2 +- .../behat/course_collapse_sections.feature | 26 +++++----- lib/templates/availability_info.mustache | 2 +- 7 files changed, 89 insertions(+), 38 deletions(-) create mode 100644 availability/tests/behat/behat_availability.php diff --git a/availability/condition/completion/tests/behat/conditional_bug.feature b/availability/condition/completion/tests/behat/conditional_bug.feature index 1bc44584e78..419ebd01810 100644 --- a/availability/condition/completion/tests/behat/conditional_bug.feature +++ b/availability/condition/completion/tests/behat/conditional_bug.feature @@ -44,7 +44,7 @@ Feature: Confirm that conditions on completion no longer cause a bug And I click on "Activity completion" "button" in the "Add restriction..." "dialogue" And I set the field with xpath "//div[contains(concat(' ', normalize-space(@class), ' '), ' availability-item ')][preceding-sibling::div]//select[@name='cm']" to "Page2" And I press "Save and return to course" - And I click on "Show more" "button" in the "#section-1 .availabilityinfo" "css_element" + And I click on "Show more" "button" in the "TestGlossary" "core_availability > Activity availability" Then I should see "Not available unless:" in the ".activity.glossary" "css_element" And I should see "The activity Page1 is marked complete" in the ".activity.glossary" "css_element" And I should see "The activity Page2 is marked complete" in the ".activity.glossary" "css_element" diff --git a/availability/tests/behat/behat_availability.php b/availability/tests/behat/behat_availability.php new file mode 100644 index 00000000000..0a86c4e2d0c --- /dev/null +++ b/availability/tests/behat/behat_availability.php @@ -0,0 +1,51 @@ +. + +require_once(__DIR__ . '/../../../lib/behat/behat_base.php'); + +/** + * Availability related behat steps and selectors definitions. + * + * @package core_availability + * @category test + * @copyright 2023 Amaia Anabitarte + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class behat_availability extends \behat_base { + + /** + * Return the list of partial named selectors. + * + * @return array + */ + public static function get_partial_named_selectors(): array { + return [ + new \behat_component_named_selector( + 'Activity availability', [<< Activity availability" + And I should see "2013" in the "Page 1" "core_availability > Activity availability" + And I should see "2013" in the "Page 1" "core_availability > Activity availability" + And "li" "css_element" should not exist in the "Page 1" "core_availability > Activity availability" + And "Show more" "button" should not exist in the "Page 1" "core_availability > Activity availability" # Page 2 should show in list format. - And "li" "css_element" should exist in the "#section-2 .availabilityinfo" "css_element" - And I should see "Not available unless:" in the "#section-2 .availabilityinfo" "css_element" - And I should see "It is before" in the "#section-2 .availabilityinfo" "css_element" - And I should see "hidden otherwise" in the "#section-2 .availabilityinfo" "css_element" + And "li" "css_element" should exist in the "Page 2" "core_availability > Activity availability" + And I should see "Not available unless:" in the "Page 2" "core_availability > Activity availability" + And I should see "It is before" in the "Page 2" "core_availability > Activity availability" + And I should see "hidden otherwise" in the "Page 2" "core_availability > Activity availability" And I click on "Show more" "button" in the "Page 2" "activity" - And I should see "Email address" in the "#section-2 .availabilityinfo" "css_element" - And I click on "Show less" "button" in the "#section-2 .availabilityinfo" "css_element" - And I should not see "Email address" in the "#section-2 .availabilityinfo" "css_element" + And I should see "Email address" in the "Page 2" "core_availability > Activity availability" + And I click on "Show less" "button" in the "Page 2" "core_availability > Activity availability" + And I should not see "Email address" in the "Page 2" "core_availability > Activity availability" # Page 3 should not have available info. - And "#section-3 .availabilityinfo" "css_element" should not exist + And "Page 3" "core_availability > Activity availability" should not exist # Change to student view. Given I am on the "C1" "Course" page logged in as "student1" @@ -139,9 +139,9 @@ Feature: display_availability And I am on "Course 1" course homepage # Check display - Then I should see "Not available unless" in the "#section-1 .availabilityinfo" "css_element" - And I should see "Available until" in the "#section-2 .availabilityinfo" "css_element" - And I should see "hidden otherwise" in the "#section-2 .availabilityinfo" "css_element" + Then I should see "Not available unless" in the "section-1" "core_availability > Section availability" + And I should see "Available until" in the "section-2" "core_availability > Section availability" + And I should see "hidden otherwise" in the "section-2" "core_availability > Section availability" # Change to student view. Given I am on the "Course 1" "Course" page logged in as "student1" @@ -153,11 +153,11 @@ Feature: display_availability # Section 1 should be visible and show info. And I should see "Topic 1" in the "region-main" "region" - And I should see "Not available unless" in the "#section-1 .availabilityinfo" "css_element" - And I click on "Show more" "button" in the "#section-1 .availabilityinfo" "css_element" - And I should see "Email address" in the "#section-1 .availabilityinfo" "css_element" - And I click on "Show less" "button" in the "#section-1 .availabilityinfo" "css_element" - And I should not see "Email address" in the "#section-1 .availabilityinfo" "css_element" + And I should see "Not available unless" in the "section-1" "core_availability > Section availability" + And I click on "Show more" "button" in the "section-1" "core_availability > Section availability" + And I should see "Email address" in the "section-1" "core_availability > Section availability" + And I click on "Show less" "button" in the "section-1" "core_availability > Section availability" + And I should not see "Email address" in the "section-1" "core_availability > Section availability" # Section 2 should not be available at all And I should not see "Topic 2" in the "region-main" "region" diff --git a/course/format/templates/local/content/cm/availability.mustache b/course/format/templates/local/content/cm/availability.mustache index e473f3a0b3e..633dd907c3b 100644 --- a/course/format/templates/local/content/cm/availability.mustache +++ b/course/format/templates/local/content/cm/availability.mustache @@ -36,7 +36,7 @@ }} {{#hasmodavailability}} {{#info}} -
+
{{^isrestricted}} {{{text}}} {{/isrestricted}} diff --git a/course/format/templates/local/content/section/availability.mustache b/course/format/templates/local/content/section/availability.mustache index 6b7008fe619..8779073f179 100644 --- a/course/format/templates/local/content/section/availability.mustache +++ b/course/format/templates/local/content/section/availability.mustache @@ -36,7 +36,7 @@
{{#hasavailability}} {{#info}} -
+
{{^isrestricted}} {{{text}}} {{/isrestricted}} diff --git a/course/tests/behat/course_collapse_sections.feature b/course/tests/behat/course_collapse_sections.feature index 52d4df30868..d8516568237 100644 --- a/course/tests/behat/course_collapse_sections.feature +++ b/course/tests/behat/course_collapse_sections.feature @@ -65,8 +65,8 @@ Feature: Collapse course sections And I should see "Assignment 2" in the "region-main" "region" And I should see "Book 2" in the "region-main" "region" And I should see "Book 3" in the "region-main" "region" - And I should see "Available until" in the "#section-4 .availabilityinfo" "css_element" - And I should see "2013" in the "#section-4 .availabilityinfo" "css_element" + And I should see "Available until" in the "section-4" "core_availability > Section availability" + And I should see "2013" in the "section-4" "core_availability > Section availability" And I should not see "Forum 4" And I should see "Not available" in the "#section-5" "css_element" And I should not see "Forum 5" @@ -83,7 +83,7 @@ Feature: Collapse course sections And I should not see "Assignment 2" in the "region-main" "region" And I should not see "Book 2" in the "region-main" "region" And I should not see "Book 3" in the "region-main" "region" - And I should not see "Available until" in the "#section-4 .availabilityinfo" "css_element" + And I should not see "Available until" in the "section-4" "core_availability > Section availability" And I click on "#collapssesection1" "css_element" And I click on "#collapssesection2" "css_element" And I click on "#collapssesection3" "css_element" @@ -93,7 +93,7 @@ Feature: Collapse course sections And I should see "Assignment 2" in the "region-main" "region" And I should see "Book 2" in the "region-main" "region" And I should see "Book 3" in the "region-main" "region" - And I should see "Available until" in the "#section-4 .availabilityinfo" "css_element" + And I should see "Available until" in the "section-4" "core_availability > Section availability" @javascript Scenario: Expand/collapse sections for Weeks format. @@ -107,8 +107,8 @@ Feature: Collapse course sections And I should see "Assignment 2" in the "region-main" "region" And I should see "Book 2" in the "region-main" "region" And I should see "Book 3" in the "region-main" "region" - And I should see "Available until" in the "#section-4 .availabilityinfo" "css_element" - And I should see "2013" in the "#section-4 .availabilityinfo" "css_element" + And I should see "Available until" in the "section-4" "core_availability > Section availability" + And I should see "2013" in the "section-4" "core_availability > Section availability" And I should see "Forum 4" And I should see "Hidden from students" in the "#section-5" "css_element" And I should see "Forum 5" @@ -125,7 +125,7 @@ Feature: Collapse course sections And I should not see "Assignment 2" in the "region-main" "region" And I should not see "Book 2" in the "region-main" "region" And I should not see "Book 3" in the "region-main" "region" - And I should not see "Available until" in the "#section-4 .availabilityinfo" "css_element" + And I should not see "Available until" in the "section-4" "core_availability > Section availability" And I should not see "Not available" in the "#section-5" "css_element" And I click on "#collapssesection1" "css_element" And I click on "#collapssesection2" "css_element" @@ -136,8 +136,8 @@ Feature: Collapse course sections And I should see "Assignment 2" in the "region-main" "region" And I should see "Book 2" in the "region-main" "region" And I should see "Book 3" in the "region-main" "region" - And I should see "Available until" in the "#section-4 .availabilityinfo" "css_element" - And I should see "2013" in the "#section-4 .availabilityinfo" "css_element" + And I should see "Available until" in the "section-4" "core_availability > Section availability" + And I should see "2013" in the "section-4" "core_availability > Section availability" And I should see "Forum 4" And I should see "Hidden from students" in the "#section-5" "css_element" And I should see "Forum 5" @@ -157,8 +157,8 @@ Feature: Collapse course sections Then "Topic 1" "section" should not exist And "Topic 3" "section" should not exist And I am on "Course 1" course homepage with editing mode on - And I should see "Available until" in the "#section-4 .availabilityinfo" "css_element" - And I should see "2013" in the "#section-4 .availabilityinfo" "css_element" + And I should see "Available until" in the "section-4" "core_availability > Section availability" + And I should see "2013" in the "section-4" "core_availability > Section availability" And I should see "Forum 4" And I should see "Hidden from students" in the "#section-5" "css_element" And I should see "Forum 5" @@ -179,8 +179,8 @@ Feature: Collapse course sections Then "1 May - 7 May" "section" should not exist And "15 May - 21 May" "section" should not exist And I am on the "Course 1" course page logged in as student1 - And I should see "Available until" in the "#section-4 .availabilityinfo" "css_element" - And I should see "2013" in the "#section-4 .availabilityinfo" "css_element" + And I should see "Available until" in the "section-4" "core_availability > Section availability" + And I should see "2013" in the "section-4" "core_availability > Section availability" And I should not see "Forum 4" And I should see "Not available" in the "#section-5" "css_element" And I should not see "Forum 5" diff --git a/lib/templates/availability_info.mustache b/lib/templates/availability_info.mustache index b1c15231724..a56f309c42a 100644 --- a/lib/templates/availability_info.mustache +++ b/lib/templates/availability_info.mustache @@ -52,7 +52,7 @@ } }} {{#text}} -
+
{{^isrestricted}} {{{text}}} {{/isrestricted}} From 6c1471c7552d4a2cfdd16877109e9f41bce8d3f3 Mon Sep 17 00:00:00 2001 From: Amaia Anabitarte Date: Mon, 3 Jul 2023 18:15:38 +0200 Subject: [PATCH 3/4] MDL-78288 core_course: Adding a link to edit availability settings AMOS BEGIN CPY [editsettings,moodle],[editsettings,core_availability] AMOS END --- .../tests/behat/edit_availability.feature | 40 +++++++++++++++++++ course/editsection.php | 2 +- .../output/local/content/cm/availability.php | 9 ++++- .../local/content/section/availability.php | 16 ++++---- .../local/content/availability.mustache | 11 ++++- course/modedit.php | 2 +- lang/en/availability.php | 1 + theme/boost/scss/moodle/course.scss | 15 +++++++ theme/boost/style/moodle.css | 12 ++++++ theme/classic/style/moodle.css | 12 ++++++ 10 files changed, 108 insertions(+), 12 deletions(-) diff --git a/availability/tests/behat/edit_availability.feature b/availability/tests/behat/edit_availability.feature index 61f5ca67035..1d7c6d40953 100644 --- a/availability/tests/behat/edit_availability.feature +++ b/availability/tests/behat/edit_availability.feature @@ -224,3 +224,43 @@ Feature: edit_availability # And check it's still active if I delete the condition. And I click on "Delete" "link" in the "Restrict access" "fieldset" And the "Add group/grouping access restriction" "button" should be enabled + + @javascript + Scenario: Edit section availability using course page link + # Setting a restriction up + Given I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on + And I edit the section "1" + And I expand all fieldsets + And I press "Add restriction..." + And I click on "Date" "button" in the "Add restriction..." "dialogue" + And I press "Save changes" + # Testing edit settings link + And "Edit settings" "link" should exist in the "section-1" "core_availability > Section availability" + When I click on "Edit settings" "link" in the "section-1" "core_availability > Section availability" + Then I should see "Restrict access" + And I should not see "General" + And I should see "Collapse all" + And I should not see "Expand all" + And I click on "Cancel" "button" + And I am on "Course 1" course homepage with editing mode off + And I should not see "Edit settings" + + @javascript + Scenario: Edit activity availability using course page link + # Setting a restriction up + Given I am on the "MyForum" "forum activity editing" page logged in as teacher1 + And I expand all fieldsets + And I press "Add restriction..." + And I click on "Date" "button" in the "Add restriction..." "dialogue" + When I press "Save and return to course" + # Edit settings link not displayed when editing mode is off. + Then "Edit settings" "link" should not exist in the "MyForum" "core_availability > Activity availability" + # Testing edit settings link + But I am on "Course 1" course homepage with editing mode on + And "Edit settings" "link" should exist in the "MyForum" "core_availability > Activity availability" + And I click on "Edit settings" "link" in the "MyForum" "core_availability > Activity availability" + And I should see "Restrict access" + And I should not see "Content" + And I should see "Collapse all" + And I should not see "Expand all" diff --git a/course/editsection.php b/course/editsection.php index e5d10f0d1c9..a63a0860c7e 100644 --- a/course/editsection.php +++ b/course/editsection.php @@ -32,7 +32,7 @@ $sectionreturn = optional_param('sr', 0, PARAM_INT); $deletesection = optional_param('delete', 0, PARAM_BOOL); $showonly = optional_param('showonly', 0, PARAM_TAGLIST); -$params = ['id'=>$id, 'sr'=> $sectionreturn]; +$params = ['id' => $id, 'sr' => $sectionreturn]; if (!empty($showonly)) { $params['showonly'] = $showonly; } diff --git a/course/format/classes/output/local/content/cm/availability.php b/course/format/classes/output/local/content/cm/availability.php index 9776c9eccfc..1b409d14d93 100644 --- a/course/format/classes/output/local/content/cm/availability.php +++ b/course/format/classes/output/local/content/cm/availability.php @@ -86,11 +86,16 @@ class availability extends section_avalability { // Nothing to be displayed to the user. return []; } + if (!$this->mod->uservisible) { - return $this->user_availability_info($output); + return ['info' => $this->user_availability_info($output)]; } - return $this->conditional_availability_info($output); + $editurl = new \moodle_url( + '/course/modedit.php', + ['update' => $this->mod->id, 'showonly' => 'availabilityconditionsheader'] + ); + return ['editurl' => $editurl->out(false), 'info' => $this->conditional_availability_info($output)]; } /** diff --git a/course/format/classes/output/local/content/section/availability.php b/course/format/classes/output/local/content/section/availability.php index 2d24ff1728c..c3c6bab636c 100644 --- a/course/format/classes/output/local/content/section/availability.php +++ b/course/format/classes/output/local/content/section/availability.php @@ -106,9 +106,7 @@ class availability implements named_templatable, renderable { return; } - $data = (object)[ - 'info' => $this->get_info($output), - ]; + $data = (object) $this->get_info($output); $attributename = $this->hasavailabilityname; $data->$attributename = !empty($data->info); @@ -139,21 +137,25 @@ class availability implements named_templatable, renderable { $canviewhidden = has_capability('moodle/course:viewhiddensections', $context, $USER); - $info = []; + $editurl = new \moodle_url( + '/course/editsection.php', + ['id' => $this->section->id, 'showonly' => 'availabilityconditions'] + ); + $info = ['editurl' => $editurl->out(false)]; if (!$section->visible) { - $info = []; + return []; } else if (!$section->uservisible) { if ($section->availableinfo) { // Note: We only get to this function if availableinfo is non-empty, // so there is definitely something to print. - $info[] = $this->get_availability_data($output, $section->availableinfo, 'isrestricted'); + $info['info'] = $this->get_availability_data($output, $section->availableinfo, 'isrestricted'); } } else if ($canviewhidden && !empty($CFG->enableavailability)) { // Check if there is an availability restriction. $ci = new info_section($section); $fullinfo = $ci->get_full_information(); if ($fullinfo) { - $info[] = $this->get_availability_data($output, $fullinfo, 'isrestricted isfullinfo'); + $info['info'] = $this->get_availability_data($output, $fullinfo, 'isrestricted isfullinfo'); } } diff --git a/course/format/templates/local/content/availability.mustache b/course/format/templates/local/content/availability.mustache index 1e899660226..ef88b91aef3 100644 --- a/course/format/templates/local/content/availability.mustache +++ b/course/format/templates/local/content/availability.mustache @@ -22,7 +22,9 @@ Example context (json): { "text": "Not available unless:
  • It is on or after 8 June 2012
  • You achieve higher than a certain score in Course total
", - "excerpt": "Not available unless: It is on or after 8 June 2012" + "excerpt": "Not available unless: It is on or after 8 June 2012", + "editing": true, + "editurl": "/course/editsection.php?id=81&showonly=availabilityconditions" } }} {{^excerpt}} @@ -41,3 +43,10 @@ {{$expandedextraclasses}}py-2{{/expandedextraclasses}} {{/core/showmore }} {{/excerpt}} +{{#editing}} + {{#editurl}} + + {{/editurl}} +{{/editing}} diff --git a/course/modedit.php b/course/modedit.php index 4cb5ee13dc3..82a4eed3e65 100644 --- a/course/modedit.php +++ b/course/modedit.php @@ -37,7 +37,7 @@ $return = optional_param('return', 0, PARAM_BOOL); //return to course/view.ph $type = optional_param('type', '', PARAM_ALPHANUM); //TODO: hopefully will be removed in 2.0 $sectionreturn = optional_param('sr', null, PARAM_INT); $beforemod = optional_param('beforemod', 0, PARAM_INT); -$showonly = optional_param('showonly', '', PARAM_ALPHANUM); // Settings group to show expanded and hide the rest. +$showonly = optional_param('showonly', '', PARAM_TAGLIST); // Settings group to show expanded and hide the rest. $url = new moodle_url('/course/modedit.php'); $url->param('sr', $sectionreturn); diff --git a/lang/en/availability.php b/lang/en/availability.php index 19a28288dec..40f259293ed 100644 --- a/lang/en/availability.php +++ b/lang/en/availability.php @@ -28,6 +28,7 @@ $string['and'] = 'and'; $string['condition_group'] = 'Restriction set'; $string['condition_group_info'] = 'Add a set of nested restrictions to apply complex logic.'; $string['disabled_verb'] = 'Cannot be changed as ruleset includes a rule containing private data.'; +$string['editsettings'] = 'Edit settings'; $string['enableavailability'] = 'Enable restricted access'; $string['enableavailability_desc'] = 'If enabled, conditions (based on date, grade, completion etc.) may be set to control whether an activity or resource can be accessed.'; $string['error_list_nochildren'] = 'Restriction sets should contain at least one condition.'; diff --git a/theme/boost/scss/moodle/course.scss b/theme/boost/scss/moodle/course.scss index 3fbe65b7023..eeda48b282a 100644 --- a/theme/boost/scss/moodle/course.scss +++ b/theme/boost/scss/moodle/course.scss @@ -1362,6 +1362,21 @@ $activity-add-hover: theme-color-level('primary', -10) !default; padding: map-get($spacers, 1) map-get($spacers, 3); background-color: $gray-200; @include border-radius($activity-item-border-radius); + + .editavailability { + padding: map-get($spacers, 1) map-get($spacers, 3); + @include border-radius(1rem); + + :hover { + background-color: $gray-400; + } + + a { + @include border-radius(0.5rem); + color: $body-color; + text-decoration: none; + } + } } &.section-summary { diff --git a/theme/boost/style/moodle.css b/theme/boost/style/moodle.css index 54c3f2c7a56..fc3d101159b 100644 --- a/theme/boost/style/moodle.css +++ b/theme/boost/style/moodle.css @@ -29002,6 +29002,18 @@ span.editinstructions .alert-link { background-color: #e9ecef; border-radius: 1rem; } +.course-section .availabilityinfo .editavailability { + padding: 0.25rem 1rem; + border-radius: 1rem; +} +.course-section .availabilityinfo .editavailability :hover { + background-color: #ced4da; +} +.course-section .availabilityinfo .editavailability a { + border-radius: 0.5rem; + color: #1d2125; + text-decoration: none; +} .course-section.section-summary { padding-left: 1rem; padding-right: 1rem; diff --git a/theme/classic/style/moodle.css b/theme/classic/style/moodle.css index 2c8445d995a..69cb7c284df 100644 --- a/theme/classic/style/moodle.css +++ b/theme/classic/style/moodle.css @@ -29002,6 +29002,18 @@ span.editinstructions .alert-link { background-color: #e9ecef; border-radius: 1rem; } +.course-section .availabilityinfo .editavailability { + padding: 0.25rem 1rem; + border-radius: 1rem; +} +.course-section .availabilityinfo .editavailability :hover { + background-color: #ced4da; +} +.course-section .availabilityinfo .editavailability a { + border-radius: 0.5rem; + color: #1d2125; + text-decoration: none; +} .course-section.section-summary { padding-left: 1rem; padding-right: 1rem; From 841d5529420c4b1a6ec9ce09704cbbeb6c5d996c Mon Sep 17 00:00:00 2001 From: Amaia Anabitarte Date: Mon, 3 Jul 2023 18:12:44 +0200 Subject: [PATCH 4/4] MDL-78288 core_course: Hide access restrictions textarea till ready --- .../moodle-core_availability-form-debug.js | 4 ++++ .../moodle-core_availability-form-min.js | 8 ++++---- .../moodle-core_availability-form.js | 4 ++++ availability/yui/src/form/js/form.js | 4 ++++ course/editsection_form.php | 4 +++- course/moodleform_mod.php | 5 ++++- 6 files changed, 23 insertions(+), 6 deletions(-) diff --git a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js index 617c5bcec9e..965d4a5bf50 100644 --- a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js +++ b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js @@ -145,6 +145,10 @@ M.core_availability.form = { } this.updateRestrictByGroup(); } + + // Everything is ready. Make sure the div is visible. + this.parent = Y.one('#fitem_id_availabilityconditionsjson'); + this.parent.removeClass('d-none'); }, /** diff --git a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js index df705576a3b..2a1f8006f1b 100644 --- a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js +++ b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js @@ -1,4 +1,4 @@ -YUI.add("moodle-core_availability-form",function(d,i){M.core_availability=M.core_availability||{},M.core_availability.form={plugins:{},field:null,mainDiv:null,rootList:null,idCounter:0,restrictByGroup:null,init:function(i){var t,e,a,l,n;for(t in i)e=i[t],(a=M[e[0]].form).init.apply(a,e);if(this.field=d.one("#id_availabilityconditionsjson"),this.field.setAttribute("aria-hidden","true"),this.mainDiv=d.Node.create(''),this.field.insert(this.mainDiv,"after"),n=null,""!==(l=this.field.get("value")))try{n=d.JSON.parse(l)}catch(o){this.field.set("value","")}this.rootList=new M.core_availability.List(n,!0),this.mainDiv.appendChild(this.rootList.node),this.update(),this.rootList.renumber(),this.mainDiv.setAttribute("aria-live","polite"),this.field.ancestor("form").on("submit",function(){this.mainDiv.all("input,textarea,select").set("disabled",!0)},this),this.restrictByGroup=d.one("#restrictbygroup"),this.restrictByGroup&&(this.restrictByGroup.on("click",this.addRestrictByGroup,this),l=d.one("#id_groupmode"),n=d.one("#id_groupingid"),l&&l.on("change",this.updateRestrictByGroup,this),n&&n.on("change",this.updateRestrictByGroup,this),this.updateRestrictByGroup())},update:function(){var i=this.rootList.getValue(),t=[];this.rootList.fillErrors(t),0!==t.length&&(i.errors=t),this.field.set("value",d.JSON.stringify(i)),this.updateRestrictByGroup()},updateRestrictByGroup:function(){var i,t,e,a;this.restrictByGroup&&("&"!==this.rootList.getValue().op||(this.rootList.hasItemOfType("group")||this.rootList.hasItemOfType("grouping"))?this.restrictByGroup.set("disabled",!0):(i=d.one("#id_groupmode"),t=d.one("#id_groupingid"),e=1===Number(this.restrictByGroup.getData("groupavailability")),a=1===Number(this.restrictByGroup.getData("groupingavailability")),i&&0!==Number(i.get("value"))&&e||t&&0!==Number(t.get("value"))&&a?this.restrictByGroup.set("disabled",!1):this.restrictByGroup.set("disabled",!0)))},addRestrictByGroup:function(i){var t,e,a,l;i.preventDefault(),i=d.one("#id_groupmode"),t=d.one("#id_groupingid"),e=1===Number(this.restrictByGroup.getData("groupavailability")),a=1===Number(this.restrictByGroup.getData("groupingavailability")),t&&0!==Number(t.get("value"))&&a?l=new M.core_availability.Item({type:"grouping",id:Number(t.get("value"))},!0):i&&e&&(l=new M.core_availability.Item({type:"group"},!0)),null!==l&&(this.rootList.addChild(l),this.update(),this.rootList.renumber(),this.rootList.updateHtml())}},M.core_availability.plugin={allowAdd:!1,init:function(i,t,e){i=i.replace(/^availability_/,"");this.allowAdd=t,(M.core_availability.form.plugins[i]=this).initInner.apply(this,e)},initInner:function(){},getNode:function(){throw"getNode not implemented"},fillValue:function(){throw"fillValue not implemented"},fillErrors:function(){},focusAfterAdd:function(i){i.one("input:not([disabled]),select:not([disabled])").focus()}},M.core_availability.List=function(i,t,e){var a,l,n;if(this.children=[],t!==undefined&&(this.root=t),this.node=d.Node.create('

'+M.util.get_string("listheader_sign_before","availability")+' '+M.util.get_string("listheader_single","availability")+''+M.util.get_string("listheader_multi_before","availability")+' "+M.util.get_string("listheader_multi_after","availability")+'
'+M.util.get_string("none","moodle")+'
'),t||this.node.addClass("availability-childlist d-sm-flex align-items-center"),this.inner=this.node.one("> .availability-inner"),a=!0,t?(i&&i.show!==undefined&&(a=i.show),this.eyeIcon=new M.core_availability.EyeIcon(!1,a),this.node.one(".availability-header").get("firstChild").insert(this.eyeIcon.span,"before"),this.node.one(".availability-header").get("firstChild").insert(this.eyeIcon.disabledSpan,"before"),this.on("availability:privateRuleSet",function(i){i.target.getDOMNode().dataset["private"]=!0,this.updatePrivateStatus()}),this.on("availability:privateRuleUnset",function(i){delete i.target.getDOMNode().dataset["private"],this.updatePrivateStatus()})):e&&(i&&i.showc!==undefined&&(a=i.showc),this.eyeIcon=new M.core_availability.EyeIcon(!1,a),this.inner.insert(this.eyeIcon.span,"before"),this.inner.insert(this.eyeIcon.disabledSpan,"before")),t||(e=new M.core_availability.DeleteIcon(this),(a=this.node.one(".availability-none")).appendChild(document.createTextNode(" ")),a.appendChild(e.span),a.appendChild(d.Node.create(''+M.util.get_string("invalid","availability")+""))),(t=d.Node.create('")).on("click",function(){this.clickAdd()},this),this.node.one("div.availability-button").appendChild(t),i){switch(i.op){case"&":case"|":this.node.one(".availability-neg").set("value","");break -case"!&":case"!|":this.node.one(".availability-neg").set("value","!")}switch(i.op){case"&":case"!&":this.node.one(".availability-op").set("value","&");break;case"|":case"!|":this.node.one(".availability-op").set("value","|")}for(l=0;l
')),this.children.push(i),i.addTarget(this),this.inner.one(".availability-children").appendChild(i.node)},M.core_availability.List.prototype.focusAfterAdd=function(){this.inner.one("button").focus()},M.core_availability.List.prototype.isIndividualShowIcons=function(){var i,t;if(!this.root)throw"Can only call this on root list";return i="!"===this.node.one(".availability-neg").get("value"),t="|"===this.node.one(".availability-op").get("value"),!i&&!t||i&&t},M.core_availability.List.prototype.renumber=function(i){var t,e={count:this.children.length},a=i===undefined?e.number="":(e.number=i+":",i+"."),i=M.util.get_string("setheading","availability",e);for(this.node.one("> h3").set("innerHTML",i),t=0;t .availability-children").removeAttribute("aria-hidden"),this.inner.one("> .availability-none").setAttribute("aria-hidden","true"),this.inner.one("> .availability-header").removeAttribute("aria-hidden"),1 .availability-children").setAttribute("aria-hidden","true"),this.inner.one("> .availability-none").removeAttribute("aria-hidden"),this.inner.one("> .availability-header").setAttribute("aria-hidden","true")),this.root){for(i=this.isIndividualShowIcons(),t=0;t .availability-children > .availability-connector span.label").each(function(i){i.set("innerHTML",a)})},M.core_availability.List.prototype.deleteDescendant=function(i){for(var t,e,a=0;a .availability-children").removeChild(e),M.core_availability.form.update(),this.updateHtml(),this.inner.one("> .availability-button").one("button").focus(),!0;if(t instanceof M.core_availability.List&&t.deleteDescendant(i))return!0}return!1},M.core_availability.List.prototype.clickAdd=function(){var i,t,e,a,l,n=d.Node.create('
    "),o=n.one("button"),s={dialog:null},r=n.one("ul");for(l in M.core_availability.form.plugins)M.core_availability.form.plugins[l].allowAdd&&(i=d.Node.create('
  • '),(e=d.Node.create('
    ")).on("click",this.getAddHandler(l,s),this),i.appendChild(e),a=d.Node.create('
    "),i.appendChild(a),r.appendChild(i));i=d.Node.create('
  • '),(e=d.Node.create('
    ")).on("click",this.getAddHandler(null,s),this),i.appendChild(e),a=d.Node.create('
    "),i.appendChild(a),r.appendChild(i),n={headerContent:M.util.get_string("addrestriction","availability"),bodyContent:n,additionalBaseClass:"availability-dialogue",draggable:!0,modal:!0,closeButton:!1,width:"450px"},s.dialog=new M.core.dialogue(n),s.dialog.show(),o.on("click",function(){s.dialog.destroy(),this.inner.one("> .availability-button").one("button").focus()},this)},M.core_availability.List.prototype.getAddHandler=function(t,e){return function( -){var i=t?new M.core_availability.Item({type:t,creating:!0},this.root):new M.core_availability.List({c:[],showc:!0},!1,this.root);this.addChild(i),M.core_availability.form.update(),M.core_availability.form.rootList.renumber(),this.updateHtml(),e.dialog.destroy(),i.focusAfterAdd()}},M.core_availability.List.prototype.getValue=function(){var i,t,e={};for(e.op=this.node.one(".availability-neg").get("value")+this.node.one(".availability-op").get("value"),e.c=[],i=0;i'+M.util.get_string("missingplugin","availability")+"
    ")):(this.plugin=M.core_availability.form.plugins[i.type],this.pluginNode=this.plugin.getNode(i),this.pluginNode.addClass("availability_"+i.type)),d.augment(this.pluginNode,d.EventTarget,!0,null,{emitFacade:!0}),this.pluginNode.addTarget(this),this.node=d.Node.create('

    '),t&&(t=!0,i.showc!==undefined&&(t=i.showc),this.eyeIcon=new M.core_availability.EyeIcon(!0,t),this.node.appendChild(this.eyeIcon.span),this.node.appendChild(this.eyeIcon.disabledSpan)),this.pluginNode.addClass("availability-plugincontrols"),this.node.appendChild(this.pluginNode),i=new M.core_availability.DeleteIcon(this),this.node.appendChild(i.span),this.node.appendChild(document.createTextNode(" ")),this.node.appendChild(d.Node.create(''))},d.augment(M.core_availability.Item,d.EventTarget,!0,null,{emitFacade:!0}),M.core_availability.Item.prototype.getValue=function(){var i={type:this.pluginType};return this.plugin&&this.plugin.fillValue(i,this.pluginNode),i},M.core_availability.Item.prototype.fillErrors=function(i){var t,e,a,l=i.length;this.plugin?this.plugin.fillErrors(i,this.pluginNode):i.push("core_availability:item_unknowntype"),t=this.node.one("> .badge-warning"),i.length===l||t.get("firstChild")?i.length===l&&t.get("firstChild")&&t.get("firstChild").remove():(l="",e=(i=i[i.length-1].split(":"))[0],a="[["+(i=i[1])+","+e+"]]",(l=M.util.get_string(i,e))===a&&(l=M.util.get_string("invalid","availability")),t.appendChild(document.createTextNode(l)))},M.core_availability.Item.prototype.renumber=function(i){var t={number:i};this.plugin?t.type=M.util.get_string("title","availability_"+this.pluginType):t.type="["+this.pluginType+"]",t.number=i+":",i=M.util.get_string("itemheading","availability",t),this.node.one("> h3").set("innerHTML",i)},M.core_availability.Item.prototype.focusAfterAdd=function(){this.plugin.focusAfterAdd(this.pluginNode)},M.core_availability.Item.prototype.pluginType=null,M.core_availability.Item.prototype.plugin=null,M.core_availability.Item.prototype.eyeIcon=null,M.core_availability.Item.prototype.node=null,M.core_availability.Item.prototype.pluginNode=null,M.core_availability.EyeIcon=function(i,t){var e,a,l,n;this.individual=i,this.span=d.Node.create(''),e=d.Node.create(""),this.span.appendChild(e),a=i?"_individual":"_all",l=function(){var i=M.util.get_string("hidden"+a,"availability");e.set("src",M.util.image_url("i/show","core")),e.set("alt",i),this.span.set("title",i+" • "+M.util.get_string("show_verb","availability"))},n=function(){var i=M.util.get_string("shown"+a,"availability");e.set("src",M.util.image_url("i/hide","core")),e.set("alt",i),this.span.set("title",i+" • "+M.util.get_string("hide_verb","availability"))},(t?n:l).call(this),this.span.on("click",i=function(i){i.preventDefault(),(this.isHidden()?n:l).call(this),M.core_availability.form.update()},this),this.span.on("key",i,"up:32",this),this.span.on("key",function(i){i.preventDefault()},"down:32",this),this.disabledSpan=d.Node.create(''),t=d.Node.create(""),i=M.util.get_string("hidden"+a,"availability"),t.set("src",M.util.image_url("i/show","core")),t.set("alt",i),this.disabledSpan.set("title",i+" • "+M.util.get_string("disabled_verb","availability")),this.disabledSpan.appendChild(t),this.disabledSpan.hide()},M.core_availability.EyeIcon.prototype.individual=!1,M.core_availability.EyeIcon.prototype.span=null,M.core_availability.EyeIcon.prototype.disabledSpan=null,M.core_availability.EyeIcon.prototype.isHidden=function(){var i=this.individual?"_individual":"_all", -i=M.util.get_string("hidden"+i,"availability");return this.span.one("img").get("alt")===i},M.core_availability.EyeIcon.prototype.isDisabled=function(){return this.span.hasAttribute("hidden")},M.core_availability.EyeIcon.prototype.setDisabled=function(){this.isDisabled()||(this.span.hide(),this.disabledSpan.show())},M.core_availability.EyeIcon.prototype.setEnabled=function(){this.isDisabled()&&(this.span.show(),this.disabledSpan.hide())},M.core_availability.DeleteIcon=function(t){var i;this.span=d.Node.create(''),i=d.Node.create(''+M.util.get_string('),this.span.appendChild(i),this.span.on("click",i=function(i){i.preventDefault(),M.core_availability.form.rootList.deleteDescendant(t),M.core_availability.form.rootList.renumber()},this),this.span.on("key",i,"up:32",this),this.span.on("key",function(i){i.preventDefault()},"down:32",this)},M.core_availability.DeleteIcon.prototype.span=null},"@VERSION@",{requires:["base","node","event","event-delegate","panel","moodle-core-notification-dialogue","json"]}); \ No newline at end of file +YUI.add("moodle-core_availability-form",function(d,i){M.core_availability=M.core_availability||{},M.core_availability.form={plugins:{},field:null,mainDiv:null,rootList:null,idCounter:0,restrictByGroup:null,init:function(i){var t,e,a,l,n;for(t in i)e=i[t],(a=M[e[0]].form).init.apply(a,e);if(this.field=d.one("#id_availabilityconditionsjson"),this.field.setAttribute("aria-hidden","true"),this.mainDiv=d.Node.create(''),this.field.insert(this.mainDiv,"after"),n=null,""!==(l=this.field.get("value")))try{n=d.JSON.parse(l)}catch(o){this.field.set("value","")}this.rootList=new M.core_availability.List(n,!0),this.mainDiv.appendChild(this.rootList.node),this.update(),this.rootList.renumber(),this.mainDiv.setAttribute("aria-live","polite"),this.field.ancestor("form").on("submit",function(){this.mainDiv.all("input,textarea,select").set("disabled",!0)},this),this.restrictByGroup=d.one("#restrictbygroup"),this.restrictByGroup&&(this.restrictByGroup.on("click",this.addRestrictByGroup,this),l=d.one("#id_groupmode"),n=d.one("#id_groupingid"),l&&l.on("change",this.updateRestrictByGroup,this),n&&n.on("change",this.updateRestrictByGroup,this),this.updateRestrictByGroup()),this.parent=d.one("#fitem_id_availabilityconditionsjson"),this.parent.removeClass("d-none")},update:function(){var i=this.rootList.getValue(),t=[];this.rootList.fillErrors(t),0!==t.length&&(i.errors=t),this.field.set("value",d.JSON.stringify(i)),this.updateRestrictByGroup()},updateRestrictByGroup:function(){var i,t,e,a;this.restrictByGroup&&("&"!==this.rootList.getValue().op||(this.rootList.hasItemOfType("group")||this.rootList.hasItemOfType("grouping"))?this.restrictByGroup.set("disabled",!0):(i=d.one("#id_groupmode"),t=d.one("#id_groupingid"),e=1===Number(this.restrictByGroup.getData("groupavailability")),a=1===Number(this.restrictByGroup.getData("groupingavailability")),i&&0!==Number(i.get("value"))&&e||t&&0!==Number(t.get("value"))&&a?this.restrictByGroup.set("disabled",!1):this.restrictByGroup.set("disabled",!0)))},addRestrictByGroup:function(i){var t,e,a,l;i.preventDefault(),i=d.one("#id_groupmode"),t=d.one("#id_groupingid"),e=1===Number(this.restrictByGroup.getData("groupavailability")),a=1===Number(this.restrictByGroup.getData("groupingavailability")),t&&0!==Number(t.get("value"))&&a?l=new M.core_availability.Item({type:"grouping",id:Number(t.get("value"))},!0):i&&e&&(l=new M.core_availability.Item({type:"group"},!0)),null!==l&&(this.rootList.addChild(l),this.update(),this.rootList.renumber(),this.rootList.updateHtml())}},M.core_availability.plugin={allowAdd:!1,init:function(i,t,e){i=i.replace(/^availability_/,"");this.allowAdd=t,(M.core_availability.form.plugins[i]=this).initInner.apply(this,e)},initInner:function(){},getNode:function(){throw"getNode not implemented"},fillValue:function(){throw"fillValue not implemented"},fillErrors:function(){},focusAfterAdd:function(i){i.one("input:not([disabled]),select:not([disabled])").focus()}},M.core_availability.List=function(i,t,e){var a,l,n;if(this.children=[],t!==undefined&&(this.root=t),this.node=d.Node.create('

    '+M.util.get_string("listheader_sign_before","availability")+' '+M.util.get_string("listheader_single","availability")+''+M.util.get_string("listheader_multi_before","availability")+' "+M.util.get_string("listheader_multi_after","availability")+'
    '+M.util.get_string("none","moodle")+'
    '),t||this.node.addClass("availability-childlist d-sm-flex align-items-center"),this.inner=this.node.one("> .availability-inner"),a=!0,t?(i&&i.show!==undefined&&(a=i.show),this.eyeIcon=new M.core_availability.EyeIcon(!1,a),this.node.one(".availability-header").get("firstChild").insert(this.eyeIcon.span,"before"),this.node.one(".availability-header").get("firstChild").insert(this.eyeIcon.disabledSpan,"before"),this.on("availability:privateRuleSet",function(i){i.target.getDOMNode().dataset["private"]=!0,this.updatePrivateStatus()}),this.on("availability:privateRuleUnset",function(i){delete i.target.getDOMNode().dataset["private"],this.updatePrivateStatus()})):e&&(i&&i.showc!==undefined&&(a=i.showc),this.eyeIcon=new M.core_availability.EyeIcon(!1,a),this.inner.insert(this.eyeIcon.span,"before"),this.inner.insert(this.eyeIcon.disabledSpan,"before")),t||(e=new M.core_availability.DeleteIcon(this),(a=this.node.one(".availability-none")).appendChild(document.createTextNode(" ")),a.appendChild(e.span),a.appendChild(d.Node.create(''+M.util.get_string("invalid","availability")+""))),(t=d.Node.create('")).on("click",function(){this.clickAdd()},this),this.node.one("div.availability-button" +).appendChild(t),i){switch(i.op){case"&":case"|":this.node.one(".availability-neg").set("value","");break;case"!&":case"!|":this.node.one(".availability-neg").set("value","!")}switch(i.op){case"&":case"!&":this.node.one(".availability-op").set("value","&");break;case"|":case"!|":this.node.one(".availability-op").set("value","|")}for(l=0;l
    ')),this.children.push(i),i.addTarget(this),this.inner.one(".availability-children").appendChild(i.node)},M.core_availability.List.prototype.focusAfterAdd=function(){this.inner.one("button").focus()},M.core_availability.List.prototype.isIndividualShowIcons=function(){var i,t;if(!this.root)throw"Can only call this on root list";return i="!"===this.node.one(".availability-neg").get("value"),t="|"===this.node.one(".availability-op").get("value"),!i&&!t||i&&t},M.core_availability.List.prototype.renumber=function(i){var t,e={count:this.children.length},a=i===undefined?e.number="":(e.number=i+":",i+"."),i=M.util.get_string("setheading","availability",e);for(this.node.one("> h3").set("innerHTML",i),t=0;t .availability-children").removeAttribute("aria-hidden"),this.inner.one("> .availability-none").setAttribute("aria-hidden","true"),this.inner.one("> .availability-header").removeAttribute("aria-hidden"),1 .availability-children").setAttribute("aria-hidden","true"),this.inner.one("> .availability-none").removeAttribute("aria-hidden"),this.inner.one("> .availability-header").setAttribute("aria-hidden","true")),this.root){for(i=this.isIndividualShowIcons(),t=0;t .availability-children > .availability-connector span.label").each(function(i){i.set("innerHTML",a)})},M.core_availability.List.prototype.deleteDescendant=function(i){for(var t,e,a=0;a .availability-children").removeChild(e),M.core_availability.form.update(),this.updateHtml(),this.inner.one("> .availability-button").one("button").focus(),!0;if(t instanceof M.core_availability.List&&t.deleteDescendant(i))return!0}return!1},M.core_availability.List.prototype.clickAdd=function(){var i,t,e,a,l,n=d.Node.create('
      "),o=n.one("button"),s={dialog:null},r=n.one("ul");for(l in M.core_availability.form.plugins)M.core_availability.form.plugins[l].allowAdd&&(i=d.Node.create('
    • '),(e=d.Node.create('
      ")).on("click",this.getAddHandler(l,s),this),i.appendChild(e),a=d.Node.create('
      "),i.appendChild(a),r.appendChild(i));i=d.Node.create('
    • '),(e=d.Node.create('
      ")).on("click",this.getAddHandler(null,s),this),i.appendChild(e),a=d.Node.create('
      "),i.appendChild(a),r.appendChild(i),n={headerContent:M.util.get_string("addrestriction","availability"),bodyContent:n,additionalBaseClass:"availability-dialogue",draggable:!0,modal:!0,closeButton:!1,width:"450px"},s.dialog=new M.core.dialogue(n),s.dialog.show(),o.on("click",function(){s.dialog.destroy(),this.inner.one("> .availability-button" +).one("button").focus()},this)},M.core_availability.List.prototype.getAddHandler=function(t,e){return function(){var i=t?new M.core_availability.Item({type:t,creating:!0},this.root):new M.core_availability.List({c:[],showc:!0},!1,this.root);this.addChild(i),M.core_availability.form.update(),M.core_availability.form.rootList.renumber(),this.updateHtml(),e.dialog.destroy(),i.focusAfterAdd()}},M.core_availability.List.prototype.getValue=function(){var i,t,e={};for(e.op=this.node.one(".availability-neg").get("value")+this.node.one(".availability-op").get("value"),e.c=[],i=0;i'+M.util.get_string("missingplugin","availability")+"
      ")):(this.plugin=M.core_availability.form.plugins[i.type],this.pluginNode=this.plugin.getNode(i),this.pluginNode.addClass("availability_"+i.type)),d.augment(this.pluginNode,d.EventTarget,!0,null,{emitFacade:!0}),this.pluginNode.addTarget(this),this.node=d.Node.create('

      '),t&&(t=!0,i.showc!==undefined&&(t=i.showc),this.eyeIcon=new M.core_availability.EyeIcon(!0,t),this.node.appendChild(this.eyeIcon.span),this.node.appendChild(this.eyeIcon.disabledSpan)),this.pluginNode.addClass("availability-plugincontrols"),this.node.appendChild(this.pluginNode),i=new M.core_availability.DeleteIcon(this),this.node.appendChild(i.span),this.node.appendChild(document.createTextNode(" ")),this.node.appendChild(d.Node.create(''))},d.augment(M.core_availability.Item,d.EventTarget,!0,null,{emitFacade:!0}),M.core_availability.Item.prototype.getValue=function(){var i={type:this.pluginType};return this.plugin&&this.plugin.fillValue(i,this.pluginNode),i},M.core_availability.Item.prototype.fillErrors=function(i){var t,e,a,l=i.length;this.plugin?this.plugin.fillErrors(i,this.pluginNode):i.push("core_availability:item_unknowntype"),t=this.node.one("> .badge-warning"),i.length===l||t.get("firstChild")?i.length===l&&t.get("firstChild")&&t.get("firstChild").remove():(l="",e=(i=i[i.length-1].split(":"))[0],a="[["+(i=i[1])+","+e+"]]",(l=M.util.get_string(i,e))===a&&(l=M.util.get_string("invalid","availability")),t.appendChild(document.createTextNode(l)))},M.core_availability.Item.prototype.renumber=function(i){var t={number:i};this.plugin?t.type=M.util.get_string("title","availability_"+this.pluginType):t.type="["+this.pluginType+"]",t.number=i+":",i=M.util.get_string("itemheading","availability",t),this.node.one("> h3").set("innerHTML",i)},M.core_availability.Item.prototype.focusAfterAdd=function(){this.plugin.focusAfterAdd(this.pluginNode)},M.core_availability.Item.prototype.pluginType=null,M.core_availability.Item.prototype.plugin=null,M.core_availability.Item.prototype.eyeIcon=null,M.core_availability.Item.prototype.node=null,M.core_availability.Item.prototype.pluginNode=null,M.core_availability.EyeIcon=function(i,t){var e,a,l,n;this.individual=i,this.span=d.Node.create('
      '),e=d.Node.create(""),this.span.appendChild(e),a=i?"_individual":"_all",l=function(){var i=M.util.get_string("hidden"+a,"availability");e.set("src",M.util.image_url("i/show","core")),e.set("alt",i),this.span.set("title",i+" • "+M.util.get_string("show_verb","availability"))},n=function(){var i=M.util.get_string("shown"+a,"availability");e.set("src",M.util.image_url("i/hide","core")),e.set("alt",i),this.span.set("title",i+" • "+M.util.get_string("hide_verb","availability"))},(t?n:l).call(this),this.span.on("click",i=function(i){i.preventDefault(),(this.isHidden()?n:l).call(this),M.core_availability.form.update()},this),this.span.on("key",i,"up:32",this),this.span.on("key",function(i){i.preventDefault()},"down:32",this),this.disabledSpan=d.Node.create(''),t=d.Node.create(""),i=M.util.get_string("hidden"+a,"availability"),t.set("src",M.util.image_url("i/show","core")),t.set("alt",i),this.disabledSpan.set("title",i+" • "+M.util.get_string("disabled_verb","availability")),this.disabledSpan.appendChild(t),this.disabledSpan.hide()},M.core_availability.EyeIcon.prototype.individual=!1,M.core_availability.EyeIcon.prototype.span=null,M.core_availability.EyeIcon.prototype.disabledSpan=null, +M.core_availability.EyeIcon.prototype.isHidden=function(){var i=this.individual?"_individual":"_all",i=M.util.get_string("hidden"+i,"availability");return this.span.one("img").get("alt")===i},M.core_availability.EyeIcon.prototype.isDisabled=function(){return this.span.hasAttribute("hidden")},M.core_availability.EyeIcon.prototype.setDisabled=function(){this.isDisabled()||(this.span.hide(),this.disabledSpan.show())},M.core_availability.EyeIcon.prototype.setEnabled=function(){this.isDisabled()&&(this.span.show(),this.disabledSpan.hide())},M.core_availability.DeleteIcon=function(t){var i;this.span=d.Node.create(''),i=d.Node.create(''+M.util.get_string('),this.span.appendChild(i),this.span.on("click",i=function(i){i.preventDefault(),M.core_availability.form.rootList.deleteDescendant(t),M.core_availability.form.rootList.renumber()},this),this.span.on("key",i,"up:32",this),this.span.on("key",function(i){i.preventDefault()},"down:32",this)},M.core_availability.DeleteIcon.prototype.span=null},"@VERSION@",{requires:["base","node","event","event-delegate","panel","moodle-core-notification-dialogue","json"]}); \ No newline at end of file diff --git a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js index 617c5bcec9e..965d4a5bf50 100644 --- a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js +++ b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js @@ -145,6 +145,10 @@ M.core_availability.form = { } this.updateRestrictByGroup(); } + + // Everything is ready. Make sure the div is visible. + this.parent = Y.one('#fitem_id_availabilityconditionsjson'); + this.parent.removeClass('d-none'); }, /** diff --git a/availability/yui/src/form/js/form.js b/availability/yui/src/form/js/form.js index b5a016bd481..bfef2bc09ab 100644 --- a/availability/yui/src/form/js/form.js +++ b/availability/yui/src/form/js/form.js @@ -143,6 +143,10 @@ M.core_availability.form = { } this.updateRestrictByGroup(); } + + // Everything is ready. Make sure the div is visible. + this.parent = Y.one('#fitem_id_availabilityconditionsjson'); + this.parent.removeClass('d-none'); }, /** diff --git a/course/editsection_form.php b/course/editsection_form.php index 63465064e95..5983ebac687 100644 --- a/course/editsection_form.php +++ b/course/editsection_form.php @@ -57,7 +57,9 @@ class editsection_form extends moodleform { // interaction is all implemented in JavaScript. The field is named // availabilityconditionsjson for consistency with moodleform_mod. $mform->addElement('textarea', 'availabilityconditionsjson', - get_string('accessrestrictions', 'availability')); + get_string('accessrestrictions', 'availability'), + ['class' => 'd-none'] + ); } $mform->_registerCancelButton('cancel'); diff --git a/course/moodleform_mod.php b/course/moodleform_mod.php index 34c2de438c6..b48e583445f 100644 --- a/course/moodleform_mod.php +++ b/course/moodleform_mod.php @@ -712,7 +712,10 @@ abstract class moodleform_mod extends moodleform { // conflicts with fields in existing modules (such as assign). // So it uses a long name that will not conflict. $mform->addElement('textarea', 'availabilityconditionsjson', - get_string('accessrestrictions', 'availability')); + get_string('accessrestrictions', 'availability'), + ['class' => 'd-none'] + ); + // The _cm variable may not be a proper cm_info, so get one from modinfo. if ($this->_cm) { $modinfo = get_fast_modinfo($COURSE);