MDL-87264 qbank_managecategories: Move categories between banks
This restores the ability to move an entire category to a different context, which now means a different activity module. The feature is accessed via the Move option in the category's action menu, which now has a "Switch bank" option like the "add from question bank" UI in the quiz. When a category is moved to a different context, it will disappear from the current page, and a link to the destination bank is displayed.
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
|
||||
define("qbank_managecategories/categorymanager",["exports","core/reactive","core/str","qbank_managecategories/mutations","qbank_managecategories/events","core/ajax","core/notification","core_form/modalform"],(function(_exports,_reactive,_str,_mutations,_events,_ajax,_notification,_modalform){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=_exports.categorymanager=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification),_modalform=_interopRequireDefault(_modalform);const SELECTORS_CATEGORY_LIST=".qbank_managecategories-categorylist",SELECTORS_CONTEXT=".qbank_managecategories-categorylist[data-contextid]",SELECTORS_CATEGORY_ITEM=".qbank_managecategories-item[data-categoryid]",SELECTORS_CATEGORY_ROOT="#categoryroot",SELECTORS_SHOWDESCRIPTIONS_TOGGLE="#showdescriptions-toggle",SELECTORS_ADD_EDIT_BUTTON='[data-action="addeditcategory"]',CLASSES_DRAGHANDLE="draghandle",CLASSES_DANGER="alert-danger";class CategoryManager extends _reactive.Reactive{moveCategory(categoryId,targetParentId){let precedingSiblingId=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const call={methodname:"qbank_managecategories_move_category",args:{pagecontextid:this.state.page.contextid,categoryid:categoryId,targetparentid:targetParentId,precedingsiblingid:precedingSiblingId}};_ajax.default.call([call])[0].then((stateUpdates=>(this.stateManager.processUpdates(stateUpdates),stateUpdates))).catch((error=>{var _document$getElements;_notification.default.addNotification({message:error.message,type:"error"}),null===(_document$getElements=document.getElementsByClassName(CLASSES_DANGER)[0])||void 0===_document$getElements||_document$getElements.scrollIntoView()}))}getTitle(isEdit){return(0,_str.get_string)(isEdit?"editcategory":"addcategory","question")}getSave(isEdit){return isEdit?(0,_str.get_string)("savechanges","core"):(0,_str.get_string)("addcategory","question")}showEditModal(e){const addEditButton=e.target.closest(SELECTORS_ADD_EDIT_BUTTON);if(!addEditButton)return;if(!addEditButton.dataset.actiontype)return;e.preventDefault();const title=categorymanager.getTitle("edit"===addEditButton.dataset.actiontype),save=categorymanager.getSave("edit"===addEditButton.dataset.actiontype),cmid=addEditButton.dataset.cmid,courseid=addEditButton.dataset.courseid,questioncount=addEditButton.dataset.questioncount;let contextid=addEditButton.dataset.contextid,categoryid=null,sortorder=null,parent=null;const categoryItem=e.target.closest(SELECTORS_CATEGORY_ITEM);if(categoryItem){contextid=categoryItem.dataset.contextid,categoryid=categoryItem.dataset.categoryid,sortorder=categoryItem.dataset.sortorder;const parentContext=categoryItem.closest(SELECTORS_CONTEXT);parent=categoryItem.dataset.parent+","+parentContext.dataset.contextid}const modalForm=new _modalform.default({formClass:"qbank_managecategories\\form\\question_category_edit_form",args:{cmid:cmid,courseid:courseid,questioncount:questioncount,contextid:contextid,categoryid:categoryid,sortorder:sortorder,parent:parent},modalConfig:{title:title,large:!0},saveButtonText:save,returnFocus:addEditButton});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(response=>{categorymanager.stateManager.processUpdates(response.detail)})),modalForm.show()}updateCategoryName(categoryId,newName){categorymanager.stateManager.setReadOnly(!1),categorymanager.stateManager.processUpdate("categories","put",{id:categoryId,name:newName}),categorymanager.stateManager.setReadOnly(!0)}}const categorymanager=new CategoryManager({name:"qtype_managecategories_categorymanager",eventName:_events.eventTypes.qbankManagecategoriesStateUpdated,eventDispatch:_events.notifyQbankManagecategoriesStateUpdated,mutations:_mutations.mutations});_exports.categorymanager=categorymanager;_exports.init=()=>{(async reactive=>{const stateData={page:{contextid:document.querySelector(SELECTORS_CATEGORY_ROOT).dataset.contextid,showdescriptions:document.querySelector(SELECTORS_SHOWDESCRIPTIONS_TOGGLE).checked},categories:[],categoryLists:[]};document.querySelectorAll(SELECTORS_CATEGORY_ITEM).forEach((item=>{stateData.categories.push({id:item.dataset.categoryid,name:item.dataset.categoryname,parent:item.dataset.parent,contextid:item.dataset.contextid,sortorder:item.dataset.sortorder,draghandle:item.classList.contains(CLASSES_DRAGHANDLE)})})),document.querySelectorAll(SELECTORS_CATEGORY_LIST).forEach((categoryList=>{stateData.categoryLists.push({id:categoryList.dataset.categoryid,childCount:categoryList.querySelectorAll(SELECTORS_CATEGORY_ITEM).length})})),reactive.setInitialState(stateData)})(categorymanager)}}));
|
||||
define("qbank_managecategories/categorymanager",["exports","core/reactive","core/str","qbank_managecategories/mutations","qbank_managecategories/events","core/ajax","core/notification","core_form/modalform"],(function(_exports,_reactive,_str,_mutations,_events,_ajax,_notification,_modalform){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=_exports.categorymanager=void 0,_ajax=_interopRequireDefault(_ajax),_notification=_interopRequireDefault(_notification),_modalform=_interopRequireDefault(_modalform);const SELECTORS_CATEGORY_LIST=".qbank_managecategories-categorylist",SELECTORS_CONTEXT=".qbank_managecategories-categorylist[data-contextid]",SELECTORS_CATEGORY_ITEM=".qbank_managecategories-item[data-categoryid]",SELECTORS_CATEGORY_ROOT="#categoryroot",SELECTORS_SHOWDESCRIPTIONS_TOGGLE="#showdescriptions-toggle",SELECTORS_ADD_EDIT_BUTTON='[data-action="addeditcategory"]',CLASSES_DRAGHANDLE="draghandle",CLASSES_DANGER="alert-danger";class CategoryManager extends _reactive.Reactive{moveCategory(categoryId,targetParentId){let precedingSiblingId=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const call={methodname:"qbank_managecategories_move_category",args:{pagecontextid:this.state.page.contextid,categoryid:categoryId,targetparentid:targetParentId,precedingsiblingid:precedingSiblingId}};_ajax.default.call([call])[0].then((stateUpdates=>(this.stateManager.processUpdates(stateUpdates),stateUpdates))).catch((error=>{var _document$getElements;_notification.default.addNotification({message:error.message,type:"error"}),null===(_document$getElements=document.getElementsByClassName(CLASSES_DANGER)[0])||void 0===_document$getElements||_document$getElements.scrollIntoView()}))}getTitle(isEdit){return(0,_str.get_string)(isEdit?"editcategory":"addcategory","question")}getSave(isEdit){return isEdit?(0,_str.get_string)("savechanges","core"):(0,_str.get_string)("addcategory","question")}showEditModal(e){const addEditButton=e.target.closest(SELECTORS_ADD_EDIT_BUTTON);if(!addEditButton)return;if(!addEditButton.dataset.actiontype)return;e.preventDefault();const title=categorymanager.getTitle("edit"===addEditButton.dataset.actiontype),save=categorymanager.getSave("edit"===addEditButton.dataset.actiontype),cmid=addEditButton.dataset.cmid,courseid=addEditButton.dataset.courseid,questioncount=addEditButton.dataset.questioncount;let contextid=addEditButton.dataset.contextid,categoryid=null,sortorder=null,parent=null;const categoryItem=e.target.closest(SELECTORS_CATEGORY_ITEM);if(categoryItem){contextid=categoryItem.dataset.contextid,categoryid=categoryItem.dataset.categoryid,sortorder=categoryItem.dataset.sortorder;const parentContext=categoryItem.closest(SELECTORS_CONTEXT);parent=categoryItem.dataset.parent+","+parentContext.dataset.contextid}const modalForm=new _modalform.default({formClass:"qbank_managecategories\\form\\question_category_edit_form",args:{cmid:cmid,courseid:courseid,questioncount:questioncount,contextid:contextid,categoryid:categoryid,sortorder:sortorder,parent:parent},modalConfig:{title:title,large:!0},saveButtonText:save,returnFocus:addEditButton});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(response=>{categorymanager.stateManager.processUpdates(response.detail)})),modalForm.show()}updateCategoryName(categoryId,newName){categorymanager.stateManager.setReadOnly(!1),categorymanager.stateManager.processUpdate("categories","put",{id:categoryId,name:newName}),categorymanager.stateManager.setReadOnly(!0)}}const categorymanager=new CategoryManager({name:"qtype_managecategories_categorymanager",eventName:_events.eventTypes.qbankManagecategoriesStateUpdated,eventDispatch:_events.notifyQbankManagecategoriesStateUpdated,mutations:_mutations.mutations});_exports.categorymanager=categorymanager;_exports.init=()=>{(async reactive=>{const rootElement=document.querySelector(SELECTORS_CATEGORY_ROOT),stateData={page:{contextid:rootElement.dataset.contextid,courseid:rootElement.dataset.courseid,cmid:rootElement.dataset.cmid,showdescriptions:document.querySelector(SELECTORS_SHOWDESCRIPTIONS_TOGGLE).checked},categories:[],categoryLists:[]};document.querySelectorAll(SELECTORS_CATEGORY_ITEM).forEach((item=>{stateData.categories.push({id:item.dataset.categoryid,name:item.dataset.categoryname,parent:item.dataset.parent,contextid:item.dataset.contextid,sortorder:item.dataset.sortorder,draghandle:item.classList.contains(CLASSES_DRAGHANDLE)})})),document.querySelectorAll(SELECTORS_CATEGORY_LIST).forEach((categoryList=>{stateData.categoryLists.push({id:categoryList.dataset.categoryid,childCount:categoryList.querySelectorAll(SELECTORS_CATEGORY_ITEM).length})})),reactive.setInitialState(stateData)})(categorymanager)}}));
|
||||
|
||||
//# sourceMappingURL=categorymanager.min.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -403,12 +403,24 @@ export default class extends BaseComponent {
|
||||
return categories;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recursively create a list of all valid destinations for a current category within a parent category.
|
||||
*
|
||||
* Each entry in the list represents moving the category "before" another category by default, but may also represent
|
||||
* moving "after" another category, or "as a new child of" a parent category.
|
||||
*
|
||||
* @param {Object} categoryData A list of category data from getCategoryDataFromElements() or getCategoryDataFromRecords().
|
||||
* @param {Number} movingCategoryId The ID of the category currently being moved.
|
||||
* @return {Array<Object>}
|
||||
* @return {Array<Object>} A list of objects representing valid move targets for the category. Each object has:
|
||||
* movingcategoryid - The ID of the category we are moving.
|
||||
* precedingsiblingid - The ID of the previous category under the same parent as this target. 0 if this is the first child.
|
||||
* parent - The ID of the target category's parent category. 0 if this is the top category.
|
||||
* categoryname - The name of the target category, to display as part of the destination.
|
||||
* categories - An array of child category targets. If there are no children, this must be null
|
||||
* to prevent infinite recursion in the template.
|
||||
* newchild - If true, this destination is "as a new child of the parent".
|
||||
* lastchild - If true, this destination is after the target category, rather than before.
|
||||
*/
|
||||
createMoveCategoryList(categoryData, movingCategoryId) {
|
||||
const categories = [];
|
||||
@@ -416,18 +428,16 @@ export default class extends BaseComponent {
|
||||
let precedingSibling = null;
|
||||
categoryData.forEach(category => {
|
||||
// Don't create a target for the category that's moving.
|
||||
if (category.categoryId === movingCategoryId) {
|
||||
if (parseInt(category.categoryId) === movingCategoryId) {
|
||||
return;
|
||||
}
|
||||
// Create a target to move before this child.
|
||||
let child = {
|
||||
categoryid: category.categoryId,
|
||||
movingcategoryid: movingCategoryId,
|
||||
precedingsiblingid: precedingSibling?.categoryId ?? 0,
|
||||
parent: category.parentId,
|
||||
categoryname: category.categoryName,
|
||||
categories: null,
|
||||
current: category.categoryId === movingCategoryId,
|
||||
categories: null, // Prevent infinite recursion in the template.
|
||||
};
|
||||
if (category.children) {
|
||||
// If the child has its own children, recursively make a list of those.
|
||||
@@ -440,7 +450,7 @@ export default class extends BaseComponent {
|
||||
precedingsiblingid: 0,
|
||||
parent: category.categoryId,
|
||||
categoryname: category.categoryName,
|
||||
categories: null,
|
||||
categories: null, // Prevent infinite recursion in the template.
|
||||
newchild: true,
|
||||
}
|
||||
];
|
||||
@@ -456,7 +466,7 @@ export default class extends BaseComponent {
|
||||
precedingsiblingid: precedingSibling.categoryId,
|
||||
parent: precedingSibling.parentId,
|
||||
categoryname: precedingSibling.categoryName,
|
||||
categories: null,
|
||||
categories: null, // Prevent infinite recursion in the template.
|
||||
lastchild: true,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -55,6 +55,8 @@ const loadState = async(reactive) => {
|
||||
const stateData = {
|
||||
page: {
|
||||
contextid: rootElement.dataset.contextid,
|
||||
courseid: rootElement.dataset.courseid,
|
||||
cmid: rootElement.dataset.cmid,
|
||||
showdescriptions: document.querySelector(SELECTORS.SHOWDESCRIPTIONS_TOGGLE).checked,
|
||||
},
|
||||
categories: [],
|
||||
|
||||
@@ -72,7 +72,7 @@ class move_category extends external_api {
|
||||
'id' => new external_value(PARAM_INT, 'The ID of the category that was updated.'),
|
||||
'sortorder' => new external_value(PARAM_INT, 'The new sortorder', VALUE_OPTIONAL),
|
||||
'parent' => new external_value(PARAM_INT, 'The ID of the new parent category.', VALUE_OPTIONAL),
|
||||
'context' => new external_value(PARAM_INT, 'The ID of the new context.', VALUE_OPTIONAL),
|
||||
'contextid' => new external_value(PARAM_INT, 'The ID of the new context.', VALUE_OPTIONAL),
|
||||
'draghandle' => new external_value(
|
||||
PARAM_BOOL,
|
||||
'Should this category have a drag handle?',
|
||||
@@ -151,7 +151,7 @@ class move_category extends external_api {
|
||||
) {
|
||||
$transaction->rollback(new moodle_exception('idnumberexists', 'qbank_managecategories'));
|
||||
}
|
||||
$originstateupdate->fields->context = $targetparent->contextid;
|
||||
$originstateupdate->fields->contextid = $targetparent->contextid;
|
||||
}
|
||||
|
||||
// Update sort order.
|
||||
@@ -187,7 +187,10 @@ class move_category extends external_api {
|
||||
$toupdatesortorder = $DB->get_records_select('question_categories', $select, $params, $sort);
|
||||
foreach ($toupdatesortorder as $category) {
|
||||
$DB->set_field('question_categories', 'sortorder', ++$sortorder, ['id' => $category->id]);
|
||||
$stateupdates[] = self::make_state_update($category->id, sortorder: $sortorder);
|
||||
if ($targetparent->contextid == $pagecontextid) {
|
||||
// If we're updating other categories in the current context, return state updates for those too.
|
||||
$stateupdates[] = self::make_state_update($category->id, sortorder: $sortorder);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($originstateupdate->fields->parent)) {
|
||||
|
||||
@@ -27,6 +27,7 @@ $string['after'] = 'After {$a}';
|
||||
$string['before'] = 'Before {$a}';
|
||||
$string['categoryincategory'] = 'Cannot move category in same category.';
|
||||
$string['categorymoved'] = 'The category has been moved successfully.';
|
||||
$string['categorymovedto'] = 'Category moved to <a href="{$a->url}">{$a->name}</a>.';
|
||||
$string['confirmdelete'] = 'Delete category "{$a}"?. Any child categories will be moved to this category\'s parent.';
|
||||
$string['descriptionnotdisplayed'] = 'Categories description not displayed';
|
||||
$string['displaydescription'] = 'Categories description displayed';
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
Context variables required for this template:
|
||||
* contextid - Context id for js init.
|
||||
* courseid - The course the current module context sits within.
|
||||
* cmid - The module the context belongs to.
|
||||
* categoriesrendered - Array representing categories data rendered.
|
||||
* items - Categories data.
|
||||
* heading - Category's heading for each context (ie: Course or Quiz).
|
||||
@@ -29,6 +31,8 @@
|
||||
Example context (json):
|
||||
{
|
||||
"contextid": "18",
|
||||
"courseid": "2",
|
||||
"cmid": "10",
|
||||
"categoriesrendered": [{
|
||||
"items": [{
|
||||
"categoryid": "1",
|
||||
@@ -43,14 +47,16 @@
|
||||
"iconright": "<i class=\"icon fa fa-arrow-right fa-fw \" title=\"Make child of 'category'\" role=\"img\" aria-label=\"Make child of 'category'\"></i>",
|
||||
"children": ""
|
||||
}],
|
||||
"heading": "Question categories for 'Quiz: qz'",
|
||||
"ctxlvl": "contextlevel70"
|
||||
"heading": "Question categories for 'Quiz: qz'"
|
||||
}]
|
||||
}
|
||||
}}
|
||||
<div id="categoryroot"
|
||||
class="editing col-11 col-md-12 mt-3 ps-0{{#showdescriptions}} showdescriptions{{/showdescriptions}}"
|
||||
data-contextid="{{{contextid}}}">
|
||||
data-contextid="{{{contextid}}}"
|
||||
data-courseid="{{courseid}}"
|
||||
data-cmid="{{cmid}}"
|
||||
>
|
||||
{{#categoriesrendered}}
|
||||
<h3 class="context-heading">{{heading}}</h3>
|
||||
<div class="box py-3 boxwidthwide boxaligncenter generalbox questioncategories">
|
||||
|
||||
@@ -24,56 +24,94 @@
|
||||
|
||||
Context variables required for this template:
|
||||
* categories - Array of category objects.
|
||||
* categoryname - The name of the category to move to.
|
||||
* categoryid - The ID of the category.
|
||||
* firstchild - Is this the first child of its parent? If so, a "before" option will be rendered as well as "after".
|
||||
* current - Is this the category being moved? If so, skip rendering it as a target.
|
||||
* categoryid - The ID of the category to move relative to.
|
||||
* movingcategoryid - The ID of the category we are moving.
|
||||
* categoryname - The name of the category to move relative to.
|
||||
* lastchild - Is this the last child of its parent? If true, an "after X" option will be rendered.
|
||||
* precedingsiblingid - The ID of the preceding category under the same parent.
|
||||
* parent - The ID of the parent category.
|
||||
* newchild - If true, render this as a "new child of X" option rather than "before X".
|
||||
* categories - Array containing child categories of this category.
|
||||
If there are none, this must be set null or [] to avoid infinite recursion.
|
||||
If there are none, this must be to [] to avoid infinite recursion.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"categories": [
|
||||
{
|
||||
"categoryname": "Default category for course 1",
|
||||
"categoryid": 3,
|
||||
"firstchild": true,
|
||||
"current": false,
|
||||
"hascategories": false,
|
||||
"categories": []
|
||||
},
|
||||
{
|
||||
"categoryname": "Test category 1",
|
||||
"categoryid": 4,
|
||||
"firstchild": false,
|
||||
"current": false,
|
||||
"hascategories": false,
|
||||
"categories": []
|
||||
},
|
||||
{
|
||||
"categoryname": "Test category 2",
|
||||
"categoryid": 5,
|
||||
"firstchild": false,
|
||||
"current": true,
|
||||
"hascategories": false,
|
||||
"categories": []
|
||||
},
|
||||
{
|
||||
"categoryname": "Test category 3 x < 1 && y > 2 ",
|
||||
"categoryid": 6,
|
||||
"firstchild": false,
|
||||
"current": false,
|
||||
"hascategories": true,
|
||||
"categoryid": "154001",
|
||||
"movingcategoryid": 154007,
|
||||
"precedingsiblingid": 0,
|
||||
"parent": "154000",
|
||||
"categoryname": "Default for Qbank 1",
|
||||
"categories": [
|
||||
{
|
||||
"categoryname": "Test category 4",
|
||||
"categoryid": 7,
|
||||
"firstchild": true,
|
||||
"current": false,
|
||||
"hascategories": false,
|
||||
"categories": []
|
||||
"movingcategoryid": 154007,
|
||||
"precedingsiblingid": 0,
|
||||
"parent": "154001",
|
||||
"categoryname": "Default for Qbank 1",
|
||||
"categories": [],
|
||||
"newchild": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"categoryid": "154004",
|
||||
"movingcategoryid": 154007,
|
||||
"precedingsiblingid": "154001",
|
||||
"parent": "154000",
|
||||
"categoryname": "Course category 1",
|
||||
"categories": [
|
||||
{
|
||||
"categoryid": "154006",
|
||||
"movingcategoryid": 154007,
|
||||
"precedingsiblingid": 0,
|
||||
"parent": "154004",
|
||||
"categoryname": "Course category 3",
|
||||
"categories": [
|
||||
{
|
||||
"movingcategoryid": 154007,
|
||||
"precedingsiblingid": 0,
|
||||
"parent": "154006",
|
||||
"categoryname": "Course category 3",
|
||||
"categories": [],
|
||||
"newchild": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"movingcategoryid": 154007,
|
||||
"precedingsiblingid": "154006",
|
||||
"parent": "154004",
|
||||
"categoryname": "Course category 3",
|
||||
"categories": [],
|
||||
"lastchild": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"categoryid": "154005",
|
||||
"movingcategoryid": 154007,
|
||||
"precedingsiblingid": "154004",
|
||||
"parent": "154000",
|
||||
"categoryname": "Course category 2",
|
||||
"categories": [
|
||||
{
|
||||
"movingcategoryid": 154007,
|
||||
"precedingsiblingid": 0,
|
||||
"parent": "154005",
|
||||
"categoryname": "Course category 2",
|
||||
"categories": [],
|
||||
"newchild": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"movingcategoryid": 154007,
|
||||
"precedingsiblingid": "154005",
|
||||
"parent": "154000",
|
||||
"categoryname": "Course category 2",
|
||||
"categories": [],
|
||||
"lastchild": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
Example context (json):
|
||||
{
|
||||
"contexid": 1,
|
||||
"cmid": 1,
|
||||
"contextname": "Question bank: Qbank 1",
|
||||
"categories": [
|
||||
{
|
||||
@@ -50,7 +51,7 @@
|
||||
}}
|
||||
<div role="tree">
|
||||
<div class="d-flex">
|
||||
<h3>{{{contextname}}}</h3>
|
||||
<h3 class="bank-header" data-cmid="{{cmid}}">{{{contextname}}}</h3>
|
||||
<button data-action="switch-question-bank" type="button" class="btn btn-secondary ms-auto mb-2">
|
||||
{{#str}}switchbank, core_question{{/str}}
|
||||
</button>
|
||||
|
||||
@@ -104,3 +104,34 @@ Feature: A teacher can reorder question categories
|
||||
And I should not see "+" in the "Course category 2" "list_item"
|
||||
When I drag "Course category 3" "list_item" and I drop it in "Course category 1" "text"
|
||||
Then I should see "+" in the "Course category 1" "list_item"
|
||||
|
||||
Scenario: Teacher can move a category to another bank
|
||||
Given the following "question categories" exist:
|
||||
| contextlevel | reference | name | idnumber | questioncategory |
|
||||
| Activity module | qbank1 | Course category 4 | questioncat4 | Course category 1 |
|
||||
And I reload the page
|
||||
And "Default for Qbank 1" "list_item" should exist
|
||||
And "Course category 1" "list_item" should exist
|
||||
And "Course category 2" "list_item" should exist
|
||||
And "Course category 3" "list_item" should exist
|
||||
And "Course category 4" "list_item" should exist
|
||||
And I open the action menu in "Course category 1" "list_item"
|
||||
And I choose "Move" in the open action menu
|
||||
And I should see "Question bank: Qbank 1" in the "Move Course category 1" "dialogue"
|
||||
And I should see "Before Course category 3" in the "Move Course category 1" "dialogue"
|
||||
And I press "Switch bank"
|
||||
And I click on "Qbank 2" "link" in the "Select question bank" "dialogue"
|
||||
And I should see "Question bank: Qbank 2" in the "Move Course category 1" "dialogue"
|
||||
And I should not see "Before Course category 3" in the "Move Course category 1" "dialogue"
|
||||
And I should see "As new child of Default for Qbank 2" in the "Move Course category 1" "dialogue"
|
||||
When I follow "As new child of Default for Qbank 2"
|
||||
Then "Default for Qbank 1" "list_item" should exist
|
||||
And "Course category 1" "list_item" should not exist
|
||||
And "Course category 2" "list_item" should exist
|
||||
And "Course category 3" "list_item" should exist
|
||||
And "Course category 4" "list_item" should not exist
|
||||
And I should see "Category moved to Question bank: Qbank 2"
|
||||
And I follow "Question bank: Qbank 2"
|
||||
And "Default for Qbank 2" "list_item" should exist
|
||||
And "Course category 1" "list_item" should exist
|
||||
And "Course category 4" "list_item" should exist
|
||||
|
||||
+6
-5
@@ -18,6 +18,7 @@ namespace qbank_managecategories\external;
|
||||
|
||||
use context;
|
||||
use context_module;
|
||||
use core\context\module;
|
||||
use moodle_url;
|
||||
use qbank_managecategories\question_categories;
|
||||
|
||||
@@ -39,12 +40,12 @@ final class move_category_test extends \qbank_managecategories\manage_category_t
|
||||
/**
|
||||
* Return order of categories for a given context.
|
||||
*
|
||||
* @param context $context The context to get the category order for.
|
||||
* @param module $context The context to get the category order for.
|
||||
* @return array Nested array, keyed by category IDs.
|
||||
*/
|
||||
private function get_current_order(context $context): array {
|
||||
$categories = new question_categories(new moodle_url('/'), [$context]);
|
||||
return $this->reduce_tree($categories->editlists[$context->id]->items);
|
||||
private function get_current_order(module $context): array {
|
||||
$categories = new question_categories(new moodle_url('/'), cmid: $context->instanceid);
|
||||
return $this->reduce_tree($categories->editlist->items);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,7 +128,7 @@ final class move_category_test extends \qbank_managecategories\manage_category_t
|
||||
],
|
||||
],
|
||||
];
|
||||
$this->assertEquals($stateupdates, $expectedstateupdates);
|
||||
$this->assertEquals($expectedstateupdates, $stateupdates);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,14 +25,18 @@ use core\router\parameters\query_coursemodule;
|
||||
use core\router\require_login;
|
||||
use core\router\route;
|
||||
use core\router\schema\example;
|
||||
use core\router\schema\objects\array_of_strings;
|
||||
use core\router\schema\objects\array_of_things;
|
||||
use core\router\schema\objects\schema_object;
|
||||
use core\router\schema\parameters\path_parameter;
|
||||
use core\router\schema\parameters\query_parameter;
|
||||
use core\router\schema\response\content\json_media_type;
|
||||
use core\router\schema\response\payload_response;
|
||||
use core\router\schema\response\response;
|
||||
use core_question\local\bank\formatted_bank;
|
||||
use core_question\local\bank\question_bank_helper;
|
||||
use core_question\local\bank\question_edit_contexts;
|
||||
use core_question\local\bank\question_version_status;
|
||||
use core_question\output\question_category_selector;
|
||||
use core_question\question_category;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
Reference in New Issue
Block a user