From 8c355f1f1c895739a4c404bcc2d500d166344bfc Mon Sep 17 00:00:00 2001 From: Katie Ransom Date: Wed, 5 Feb 2025 16:05:58 +0000 Subject: [PATCH] MDL-83840 course: add warning when hiding category --- course/classes/management_renderer.php | 4 +- .../behat/category_change_visibility.feature | 59 +++++++++++++++++++ .../behat/course_change_visibility.feature | 2 + .../moodle-course-management-debug.js | 23 +++++++- .../moodle-course-management-min.js | 6 +- .../moodle-course-management.js | 23 +++++++- course/yui/src/management/js/category.js | 23 +++++++- lang/en/moodle.php | 5 ++ 8 files changed, 138 insertions(+), 7 deletions(-) diff --git a/course/classes/management_renderer.php b/course/classes/management_renderer.php index 99aa1bde6ed..baeadef6572 100644 --- a/course/classes/management_renderer.php +++ b/course/classes/management_renderer.php @@ -178,7 +178,9 @@ class core_course_management_renderer extends plugin_renderer_base { 'data-selected' => $activecategory ? '1' : '0', 'data-visible' => $category->visible ? '1' : '0', 'role' => 'treeitem', - 'aria-expanded' => $isexpanded ? 'true' : 'false' + 'aria-expanded' => $isexpanded ? 'true' : 'false', + 'data-course-count' => $category->get_courses_count(['recursive' => 1]), + 'data-category-name' => $category->get_formatted_name(), ); $text = $category->get_formatted_name(); if (($parent = $category->get_parent_coursecat()) && $parent->id) { diff --git a/course/tests/behat/category_change_visibility.feature b/course/tests/behat/category_change_visibility.feature index ab9364ec8f3..2ec80749a92 100644 --- a/course/tests/behat/category_change_visibility.feature +++ b/course/tests/behat/category_change_visibility.feature @@ -227,6 +227,7 @@ Feature: We can change the visibility of categories in the management interface. And course in management listing should be dimmed "C2" And course in management listing should be visible "C3" And I toggle visibility of category "CAT1" in management listing + And I click on "Hide" "button" in the "Hide category?" "dialogue" And a new page should not have loaded since I started watching And category in management listing should be dimmed "CAT1" And category in management listing should be visible "CAT2" @@ -277,6 +278,7 @@ Feature: We can change the visibility of categories in the management interface. And category in management listing should be visible "CAT3" And course in management listing should be visible "C1" And I toggle visibility of category "CAT1" in management listing + And I click on "Hide" "button" in the "Hide category?" "dialogue" And a new page should not have loaded since I started watching And category in management listing should be dimmed "CAT1" And category in management listing should be dimmed "CAT2" @@ -295,6 +297,7 @@ Feature: We can change the visibility of categories in the management interface. And category in management listing should be visible "CAT3" And course in management listing should be dimmed "C1" And I toggle visibility of category "CAT1" in management listing + And I click on "Hide" "button" in the "Hide category?" "dialogue" And a new page should not have loaded since I started watching And category in management listing should be dimmed "CAT1" And category in management listing should be dimmed "CAT2" @@ -306,3 +309,59 @@ Feature: We can change the visibility of categories in the management interface. And category in management listing should be visible "CAT2" And category in management listing should be visible "CAT3" And course in management listing should be dimmed "C1" + + @javascript + Scenario: Test confirm popup when hiding a category + Given the following "categories" exist: + | name | category | idnumber | + | Cat 1 | 0 | CAT1 | + | Cat 1b | CAT1 | CAT1B | + | Cat 1c | CAT1 | CAT1C | + | Cat 2 | 0 | CAT2 | + And the following "courses" exist: + | category | fullname | shortname | idnumber | + | CAT1B | Course 1 | Course 1 | C1 | + | CAT1B | Course 2 | Course 2 | C2 | + | CAT1C | Course 3 | Course 3 | C3 | + And I log in as "admin" + And I go to the courses management page + And I should see the "Course categories and courses" management page + And I click on category "Cat 1" in the management interface + And category in management listing should be visible "CAT1" + And category in management listing should be visible "CAT1B" + And category in management listing should be visible "CAT1C" + And category in management listing should be visible "CAT2" + + # Category should not be hidden if the dialogue is cancelled. + And I toggle visibility of category "CAT1C" in management listing + And I should see "The category Cat 1c contains 1 course" in the "Hide category?" "dialogue" + And I click on "Cancel" "button" in the "Hide category?" "dialogue" + And category in management listing should be visible "CAT1" + And category in management listing should be visible "CAT1B" + And category in management listing should be visible "CAT1C" + And category in management listing should be visible "CAT2" + + # Hide CAT1 - course count should include courses all subcategories. + And I toggle visibility of category "CAT1" in management listing + And I should see "The category Cat 1 contains 3 courses" in the "Hide category?" "dialogue" + And I click on "Hide" "button" in the "Hide category?" "dialogue" + And category in management listing should be dimmed "CAT1" + And category in management listing should be dimmed "CAT1B" + And category in management listing should be dimmed "CAT1C" + And category in management listing should be visible "CAT2" + + # Dialogue should not show when showing a category. + And I toggle visibility of category "CAT1" in management listing + And "Hide category?" "dialogue" should not exist + And category in management listing should be visible "CAT1" + And category in management listing should be visible "CAT1B" + And category in management listing should be visible "CAT1C" + And category in management listing should be visible "CAT2" + + # Dialogue should not show when hiding a category that contains no courses. + And I toggle visibility of category "CAT2" in management listing + And "Hide category?" "dialogue" should not exist + And category in management listing should be visible "CAT1" + And category in management listing should be visible "CAT1B" + And category in management listing should be visible "CAT1C" + And category in management listing should be dimmed "CAT2" diff --git a/course/tests/behat/course_change_visibility.feature b/course/tests/behat/course_change_visibility.feature index fd175fac1c4..e11c3256304 100644 --- a/course/tests/behat/course_change_visibility.feature +++ b/course/tests/behat/course_change_visibility.feature @@ -85,6 +85,7 @@ Feature: We can change the visibility of courses in the management interface. And category in management listing should be visible "CAT1" And course in management listing should be dimmed "C1" And I toggle visibility of category "CAT1" in management listing + And I click on "Hide" "button" in the "Hide category?" "dialogue" And a new page should not have loaded since I started watching And category in management listing should be dimmed "CAT1" And course in management listing should be dimmed "C1" @@ -93,6 +94,7 @@ Feature: We can change the visibility of courses in the management interface. And category in management listing should be visible "CAT1" And course in management listing should be dimmed "C1" And I toggle visibility of category "CAT1" in management listing + And I click on "Hide" "button" in the "Hide category?" "dialogue" And I toggle visibility of course "C1" in management listing And I select "Courses" from the "Viewing" singleselect And a new page should have loaded since I started watching diff --git a/course/yui/build/moodle-course-management/moodle-course-management-debug.js b/course/yui/build/moodle-course-management/moodle-course-management-debug.js index f73764d4c90..3ce015d201d 100644 --- a/course/yui/build/moodle-course-management/moodle-course-management-debug.js +++ b/course/yui/build/moodle-course-management/moodle-course-management-debug.js @@ -1306,7 +1306,28 @@ Category.prototype = { break; case 'hide': e.preventDefault(); - this.get('console').performAjaxAction('hidecategory', catarg, this.hide, this); + var courseCount = this.get('node').getData('course-count'); + if (courseCount === '0') { + this.get('console').performAjaxAction('hidecategory', catarg, this.hide, this); + break; + } + var warningStr = courseCount === '1' ? 'hidecategoryone' : 'hidecategorymany'; + var warningParams = { + category: this.get('node').getData('category-name'), + coursecount: courseCount, + }; + require(['core/notification', 'core/str'], function(Notification, Str) { + Notification.saveCancelPromise( + Str.get_string('hidecategory'), + Str.get_string(warningStr, 'core', warningParams), + Str.get_string('hide') + ).then(function() { + this.get('console').performAjaxAction('hidecategory', catarg, this.hide, this); + }.bind(this) + ).catch(function() { + // User cancelled, no action needed. + }); + }.bind(this)); break; case 'expand': e.preventDefault(); diff --git a/course/yui/build/moodle-course-management/moodle-course-management-min.js b/course/yui/build/moodle-course-management/moodle-course-management-min.js index efd6c3b7a37..72cd5c32e68 100644 --- a/course/yui/build/moodle-course-management/moodle-course-management-min.js +++ b/course/yui/build/moodle-course-management/moodle-course-management-min.js @@ -1,4 +1,4 @@ YUI.add("moodle-course-management",function(s,e){var i,o,r,t,n=function(){n.superclass.constructor.apply(this,arguments)};n.NAME="moodle-course-management",n.CSS_PREFIX="management",n.ATTRS={element:{setter:function(e){return e="string"==typeof e?s.one("#"+e):e}},categorylisting:{value:null},courselisting:{value:null},coursedetails:{value:null},activecategoryid:{value:null},activecourseid:{value:null},categories:{setter:function(e,t){if(s.Lang.isArray(e))return e;t=this.get(t);return t.push(e),t},value:[]},courses:{validator:function(e){return s.Lang.isArray(e)},value:[]},page:{getter:function(e,t){return null===e&&(e=this.get("element").getData(t),this.set(t,e)),e},value:null},totalpages:{getter:function(e,t){return null===e&&(e=this.get("element").getData(t),this.set(t,e)),e},value:null},totalcourses:{getter:function(e,t){return null===e&&(e=this.get("element").getData(t),this.set(t,e)),e},value:null},ajaxurl:{getter:function(e){return e=null===e?M.cfg.wwwroot+"/course/ajax/management.php":e},value:null},dragdrop:{value:null}},s.extend(n,s.Base,n.prototype={categoriesinit:!1,initializer:function(){this.set("element","coursecat-management");var e=this.get("element"),t=e.one("#category-listing"),i=e.one("#course-listing"),o=null,n=null;t&&(o=t.one('.listitem[data-selected="1"]')),i&&(n=i.one('.listitem[data-selected="1"]')),this.set("categorylisting",t),this.set("courselisting",i),this.set("coursedetails",e.one("#course-detail")),o&&this.set("activecategoryid",o.getData("id")),n&&this.set("activecourseid",n.getData("id")),this.initialiseCategories(t),this.initialiseCourses(),i&&this.set("dragdrop",new r({console:this}))},initialiseCategories:function(e){var t;if(!e)return!1;(t=e.one("#menumovecategoriesto"))&&t.setAttribute("disabled",!0),(t=e.one("#menuresortcategoriesby"))&&t.setAttribute("disabled",!0),(t=e.one("#menuresortcoursesby"))&&t.setAttribute("disabled",!0),e.all(".listitem[data-id]").each(function(e){this.set("categories",new i({node:e,console:this})),0},this),this.categoriesinit||(this.get("categorylisting").delegate("click",this.handleCategoryDelegation,"a[data-action]",this),this.get("categorylisting").delegate("click",this.handleCategoryDelegation,'input[name="bcat[]"]',this),this.get("categorylisting").delegate("change",this.handleBulkSortByaction,"#menuselectsortby",this),this.categoriesinit=!0)},initialiseCourses:function(){var e,t=this.getCategoryById(this.get("activecategoryid")),i=this.get("courselisting");if(!i)return!1;(e=i.one("#menumovecoursesto"))&&e.setAttribute("disabled",!0),i.all(".listitem[data-id]").each(function(e){this.registerCourse(new o({node:e,console:this,category:t})),0},this),i.delegate("click",this.handleCourseDelegation,"a[data-action]",this),i.delegate("click",this.handleCourseDelegation,'input[name="bc[]"]',this)},registerCourse:function(e){var t=this.get("courses");t.push(e),this.set("courses",t)},handleCourseDelegation:function(e){var t=e.currentTarget,i=t.getData("action"),t=t.ancestor(".listitem").getData("id"),t=this.getCourseById(t);t&&t.handle(i,e)},handleCategoryDelegation:function(e){var t=e.currentTarget,i=t.getData("action"),t=t.ancestor(".listitem").getData("id"),t=this.getCategoryById(t);t&&t.handle(i,e)},isCourseSelected:function(e){var t,i,o,n=!1;if(e&&e.get("checked"))n=!0;else for(o=(i=this.get("courses")).length,t=0;t .course-listing"),t=t?t.one("ul.category-list"):null,o=i?i.one("ul.course-list"):null,i=!!i&&i.getData("canmoveoutof"),n=i?e:o;if(!o)return!1;for(;0===n.get("scrollHeight")&&!n.compareTo(window.document.body);)n=n.get("parentNode");o.all("> li").each(function(e){this.initCourseListing(e,n)},this),o.setData("dd",new s.DD.Drop({node:o})),i&&t&&t.all("li > div").each(function(e){this.initCategoryListitem(e)},this),s.DD.DDM.on("drag:start",this.dragStart, -this),s.DD.DDM.on("drag:end",this.dragEnd,this),s.DD.DDM.on("drag:drag",this.dragDrag,this),s.DD.DDM.on("drop:over",this.dropOver,this),s.DD.DDM.on("drop:enter",this.dropEnter,this),s.DD.DDM.on("drop:exit",this.dropExit,this),s.DD.DDM.on("drop:hit",this.dropHit,this)},initCourseListing:function(e,t){e.setData("dd",new s.DD.Drag({node:e,target:{padding:"0 0 0 20"}}).addHandle(".drag-handle").plug(s.Plugin.DDProxy,{moveOnEnd:!1,borderStyle:!1}).plug(s.Plugin.DDConstrained,{constrain2node:t}))},initCategoryListitem:function(e){e.setData("dd",new s.DD.Drop({node:e}))},dragStart:function(e){var e=e.target,t=e.get("node"),e=e.get("dragNode");t.addClass("course-being-dragged"),e.addClass("course-being-dragged-proxy").set("innerHTML",t.one("a.coursename").get("innerHTML")),this.previoussibling=t.get("previousSibling")},dragEnd:function(e){e.target.get("node").removeClass("course-being-dragged"),this.get("console").get("element").all("#category-listing li.highlight").removeClass("highlight")},dragDrag:function(e){e=e.target.lastXY[1];e div a.action-moveup"),n=e.one(" > div a.action-movedown"),i&&n||(o=e.one(" > div a.action-moveup"),t=t.one(" > div a.action-movedown"),i||n?n||o.insert(t,"after"):(i=s.Node.create(' '),t.replace(i),o.replace(t),i.replace(o),i.destroy())),(o=e.one(" > div a.action-moveup"))?o.focus():(n=e.one(" > div a.action-movedown"))&&n.focus(),this.updated(!0)):window.location.reload()},movedown:function(e,t,i){var o,n;if(!1===this.checkAjaxResponse(e,t,i))return!1;(t=(e=this.get("node")).next(".listitem"))?(e.insert(t,"before"),i=t.one(" > div a.action-movedown"),o=e.one(" > div a.action-moveup"),i&&o||(t=t.one(" > div a.action-moveup"),n=e.one(" > div a.action-movedown"),i||o?o||n.insert(t,"before"):(i=s.Node.create(' '),t.replace(i),n.replace(t),i.replace(n),i.destroy())),(n=e.one(" > div a.action-movedown"))?n.focus():(o=e.one(" > div a.action-moveup"))&&o.focus(),this.updated(!0)):window.location.reload()},show:function(e,t,i){if(!1===this.checkAjaxResponse(e,t,i))return!1;this.markVisible(),(e=this.get("node").one("a[data-action=hide]"))&&e.focus(),this.updated()},markVisible:function(){return this.get("node").setAttribute("data-visible","1"),!0},hide:function(e,t,i){if(!1===this.checkAjaxResponse(e,t,i))return!1;this.markHidden(),(e=this.get("node").one("a[data-action=show]"))&&e.focus(),this.updated()},markHidden:function(){return this.get("node").setAttribute("data-visible","0"),!0},updated:function(e){e&&this.highlight()},highlight:function(){var e=this.get("node");e.siblings(".highlight").removeClass("highlight"),e.addClass("highlight"),this.highlighttimeout&&window.clearTimeout(this.highlighttimeout),this.highlighttimeout=window.setTimeout(function(){e.removeClass("highlight")},2500)}}),(i=function(){i.superclass.constructor.apply(this,arguments)}).NAME="moodle-course-management-category",i.CSS_PREFIX="management-category",i.ATTRS={categoryid:{getter:function(e,t){return null===e&&(e=this.get("node").getData("id"),this.set(t,e)),e},value:null,writeOnce:!0},selected:{getter:function(e,t){return null===e&&(e=this.get("node").getData(t),this.set(t,e=null===e?!1:e)),e},value:null},courses:{validator:function(e){return s.Lang.isArray(e)},value:[]}},i.prototype={initializer:function(){this.set("itemname","category")},getName:function(){return this.get("node").one("a.categoryname").get("innerHTML")},registerCourse:function(e){var t=this.get("courses");t.push(e),this.set("courses",t)},handle:function(e,t){var i,o,n={categoryid:this.get("categoryid")},s=this.get("console").get("activecategoryid");switch(s&&s!==n.categoryid&&(n.selectedcategory=s),e){case"moveup":t.preventDefault(),this.get("console").performAjaxAction("movecategoryup",n,this.moveup,this);break;case"movedown":t.preventDefault(),this.get("console").performAjaxAction("movecategorydown",n,this.movedown,this);break;case"show":t.preventDefault(),this.get("console").performAjaxAction("showcategory",n,this.show,this);break;case"hide":t.preventDefault(),this.get("console").performAjaxAction("hidecategory",n,this.hide,this);break;case"expand":t.preventDefault(),"0"===this.get( -"node").getData("expanded")&&(this.get("node").setAttribute("data-expanded","1").setData("expanded","true"),this.get("console").performAjaxAction("getsubcategorieshtml",n,this.loadSubcategories,this)),this.expand();break;case"collapse":t.preventDefault(),this.collapse();break;case"select":(o=(i=this.get("console")).get("categorylisting").one("#menumovecategoriesto"))&&(i.isCategorySelected(t.currentTarget)&&1 div a.action-moveup"),n=e.one(" > div a.action-movedown"),i&&n||(o=e.one(" > div a.action-moveup"),t=t.one(" > div a.action-movedown"),i||n?n||o.insert(t,"after"):(i=s.Node.create(' '),t.replace(i),o.replace(t),i.replace(o),i.destroy())),(o=e.one(" > div a.action-moveup"))?o.focus():(n=e.one(" > div a.action-movedown"))&&n.focus(),this.updated(!0)):window.location.reload()},movedown:function(e,t,i){var o,n;if(!1===this.checkAjaxResponse(e,t,i))return!1;(t=(e=this.get("node")).next(".listitem"))?(e.insert(t,"before"),i=t.one(" > div a.action-movedown"),o=e.one(" > div a.action-moveup"),i&&o||(t=t.one(" > div a.action-moveup"),n=e.one(" > div a.action-movedown"),i||o?o||n.insert(t,"before"):(i=s.Node.create(' '),t.replace(i),n.replace(t),i.replace(n),i.destroy())),(n=e.one(" > div a.action-movedown"))?n.focus():(o=e.one(" > div a.action-moveup"))&&o.focus(),this.updated(!0)):window.location.reload()},show:function(e,t,i){if(!1===this.checkAjaxResponse(e,t,i))return!1;this.markVisible(),(e=this.get("node").one("a[data-action=hide]"))&&e.focus(),this.updated()},markVisible:function(){return this.get("node").setAttribute("data-visible","1"),!0},hide:function(e,t,i){if(!1===this.checkAjaxResponse(e,t,i))return!1;this.markHidden(),(e=this.get("node").one("a[data-action=show]"))&&e.focus(),this.updated()},markHidden:function(){return this.get("node").setAttribute("data-visible","0"),!0},updated:function(e){e&&this.highlight()},highlight:function(){var e=this.get("node");e.siblings(".highlight").removeClass("highlight"),e.addClass("highlight"),this.highlighttimeout&&window.clearTimeout(this.highlighttimeout),this.highlighttimeout=window.setTimeout(function(){e.removeClass("highlight")},2500)}}),(i=function(){i.superclass.constructor.apply(this,arguments)}).NAME="moodle-course-management-category",i.CSS_PREFIX="management-category",i.ATTRS={categoryid:{getter:function(e,t){return null===e&&(e=this.get("node").getData("id"),this.set(t,e)),e},value:null,writeOnce:!0},selected:{getter:function(e,t){return null===e&&(e=this.get("node").getData(t),this.set(t,e=null===e?!1:e)),e},value:null},courses:{validator:function(e){return s.Lang.isArray(e)},value:[]}},i.prototype={initializer:function(){this.set("itemname","category")},getName:function(){return this.get("node").one("a.categoryname").get("innerHTML")},registerCourse:function(e){var t=this.get("courses");t.push(e),this.set("courses",t)},handle:function(e,t){var i,o,n,s,r={categoryid:this.get("categoryid")},a=this.get("console").get("activecategoryid");switch(a&&a!==r.categoryid&&(r.selectedcategory=a),e){case"moveup":t.preventDefault(),this.get("console").performAjaxAction("movecategoryup",r,this.moveup,this);break;case"movedown":t.preventDefault(),this.get("console").performAjaxAction("movecategorydown",r,this.movedown,this);break;case"show":t.preventDefault(),this.get("console").performAjaxAction("showcategory",r,this.show,this);break;case"hide":if(t.preventDefault(),"0"===(n=this.get("node").getData("course-count"))){this.get("console").performAjaxAction("hidecategory",r,this.hide, +this);break}i="1"===n?"hidecategoryone":"hidecategorymany",o={category:this.get("node").getData("category-name"),coursecount:n},require(["core/notification","core/str"],function(e,t){e.saveCancelPromise(t.get_string("hidecategory"),t.get_string(i,"core",o),t.get_string("hide")).then(function(){this.get("console").performAjaxAction("hidecategory",r,this.hide,this)}.bind(this))["catch"](function(){})}.bind(this));break;case"expand":t.preventDefault(),"0"===this.get("node").getData("expanded")&&(this.get("node").setAttribute("data-expanded","1").setData("expanded","true"),this.get("console").performAjaxAction("getsubcategorieshtml",r,this.loadSubcategories,this)),this.expand();break;case"collapse":t.preventDefault(),this.collapse();break;case"select":(s=(n=this.get("console")).get("categorylisting").one("#menumovecategoriesto"))&&(n.isCategorySelected(t.currentTarget)&&1