Index: lib/listlib.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/listlib.php,v retrieving revision 1.14.2.1 diff -u -r1.14.2.1 listlib.php --- lib/listlib.php 27 Nov 2008 10:53:40 -0000 1.14.2.1 +++ lib/listlib.php 20 Mar 2010 16:14:13 -0000 @@ -74,10 +74,21 @@ var $editable; /** - * Key is child id, value is parent. - * @var array + * Cache of all items contained in list + * Presents only in top-level list + * @var array that contains from: + * [id]['sortorder'] => sortorder + * [id]['parent'] => parentid + * [id]['item'] => reference to item object */ - var $childparent; + var $itemscache = null; + + /** + * Used to get $itemscache + * @var reference to top-level list + */ + var $toplevellist = null; + //------------------------------------------------------ //vars used for pagination. @@ -101,9 +112,10 @@ * @param integer $page if 0 no pagination. (These three params only used in top level list.) * @param string $pageparamname name of url param that is used for passing page no * @param integer $itemsperpage no of top level items. + * @param reference to the top-level list that contained $itemscache * @return moodle_list */ - function moodle_list($type='ul', $attributes='', $editable = false, $pageurl=null, $page = 0, $pageparamname = 'page', $itemsperpage = 20) { + function moodle_list($type='ul', $attributes='', $editable = false, $pageurl=null, $page = 0, $pageparamname = 'page', $itemsperpage = 20, $toplevellist=null) { $this->editable = $editable; $this->attributes = $attributes; $this->type = $type; @@ -116,6 +128,51 @@ } else { $this->pageurl = $pageurl; } + + if ($toplevellist==null) { + $this->toplevellist = $this; + $this->toplevellist->itemscache = array(); + } else { + $this->toplevellist = $toplevellist; + } + } + + /** + * Change move state + * @param ineger $mode id of item to move or 0 to stop moving + */ + function set_moving_item($mode) { + global $USER; + $paramname = get_class($this).'moving'; + if ($mode>0) { + $USER->$paramname = $mode; + } else { + unset($USER->$paramname); + } + } + + /** + * Returns id of item to move + * @return integer id of item to move or 0 + */ + function get_moving_item() { + global $USER; + if ($this->is_moving_active()) { + $paramname = get_class($this).'moving'; + return $USER->$paramname; + } else { + return 0; + } + } + + /** + * Returns state of list: moving or not + * @return bool state + */ + function is_moving_active() { + global $USER; + $paramname = get_class($this).'moving'; + return isset($USER->$paramname); } /** @@ -124,6 +181,7 @@ * @param integer $indent depth of indentation. */ function to_html($indent=0, $extraargs=array()) { + global $CFG; if (count($this->items)) { $tabs = str_repeat("\t", $indent); $first = true; @@ -132,15 +190,39 @@ $html = ''; foreach ($this->items as $item) { + // ignoring item which ig going to be moved + if ($this->get_moving_item() == $item->id) continue; + $last = (count($this->items) == $itemiter); if ($this->editable) { $item->set_icon_html($first, $last, $lastitem); } + + // inserting "movebefore" action in the beginnig of the top-level list + if ($this->is_moving_active() && $first && !isset($this->parentitem)) { + $action = array('actionname'=>'movebefore','actionargs'=>$item->id); + $html .= "attributes))?(' '.$item->attributes):'').">"; + $html .= ""; + $html .= ""; + $html .= "\n"; + } + + // generating HTML-code of an item if ($itemhtml = $item->to_html($indent+1, $extraargs)) { $html .= "$tabs\tattributes))?(' '.$item->attributes):'').">"; $html .= $itemhtml; $html .= "\n"; } + + // inserting "moveafter" action after every list item + if ($this->is_moving_active()) { + $action = array('actionname'=>'moveafter','actionargs'=>$item->id); + $html .= "attributes))?(' '.$item->attributes):'').">"; + $html .= ""; + $html .= ""; + $html .= "\n"; + } + $first = false; $lastitem = $item; $itemiter++; @@ -217,14 +299,15 @@ $this->lastitem = $this->firstitem + $this->itemsperpage - 1; } $itemiter = $offset; - //make a simple array which is easier to search - $this->childparent = array(); foreach ($records as $record) { - $this->childparent[$record->id] = $record->parent; + // Caching items to prevent a lot of database queries in future + $this->toplevellist->itemscache[$record->id] = array(); + $this->toplevellist->itemscache[$record->id]['sortorder'] = $record->sortorder; + $this->toplevellist->itemscache[$record->id]['parent'] = $record->parent; } //create top level list items and they're responsible for creating their children foreach ($records as $record) { - if (!array_key_exists($record->parent, $this->childparent)) { + if (!array_key_exists($record->parent, $this->toplevellist->itemscache)) { //if this record is not a child of another record then $inpage = ($itemiter >= $this->firstitem && $itemiter <= $this->lastitem); @@ -234,11 +317,10 @@ $newattributes = $this->parentitem->attributes; } else { $newattributes = ''; - } $this->items[$itemiter] =& new $this->listitemclassname($record, $this, $newattributes, $inpage); if ($inpage) { - $this->items[$itemiter]->create_children($records, $this->childparent, $record->id); + $this->items[$itemiter]->create_children($records, $this->toplevellist->itemscache, $record->id); } else { //don't recurse down the tree for items that are not on this page $this->paged = true; @@ -278,10 +360,10 @@ } return $html; } - /** * Returns an array of ids of peers of an item. * + * @deprecated should be deleted with process_actions * @param int itemid - if given, restrict records to those with this parent id. * @return array peer ids */ @@ -307,6 +389,7 @@ /** * Move a record up or down * + * @deprecated should be deleted with process_actions * @param string $direction up / down * @param integer $id */ @@ -337,6 +420,9 @@ $this->reorder_peers($peers); } + /** + * @deprecated should be deleted with process_actions + */ function reorder_peers($peers) { foreach ($peers as $key => $peer) { if (!set_field("{$this->table}", "sortorder", $key, "id", $peer)) { @@ -346,6 +432,7 @@ } /** + * @deprecated should be deleted with process_actions * @param integer $id an item index. * @return object the item that used to be the parent of the item moved. */ @@ -374,6 +461,7 @@ /** * Make item with id $id the child of the peer that is just above it in the sort order. * + * @deprecated should be deleted with process_actions * @param integer $id */ function move_item_right($id) { @@ -405,6 +493,7 @@ * @param integer $moveup id of item to move up * @param integer $movedown id of item to move down * @return unknown + * @deprecated use process_action instead */ function process_actions($left, $right, $moveup, $movedown) { //should this action be processed by this list object? @@ -447,6 +536,90 @@ } /** + * Process any action + * @param string $action name of action. Can be: startmove, cancelmove, + * movebefore, moveafter, movefirstchild + * @param integer $value id of item + */ + function process_action($action,$value) { + global $CFG; + + if ($action=='movebefore' || $action=='moveafter' || $action=='movefirstchild') { + $itemtomove = $this->toplevellist->itemscache[$this->get_moving_item()]; + $itemtomove['id'] = $this->get_moving_item(); + $anchor = $this->toplevellist->itemscache[$value]; + $anchor['id'] = $value; + } + + switch ($action){ + case 'startmove': // pushed "Move" button + $this->set_moving_item($value); + break; + case 'cancelmove': // pushed "Cancel" button + $this->set_moving_item(0); + break; + case 'movebefore': // use this to move in the beginning of the group + $extendsortorders = "UPDATE ".$CFG->prefix.$this->table." + SET sortorder = sortorder + 1 + WHERE parent = ".$anchor['parent']; + $move = "UPDATE ".$CFG->prefix.$this->table." + SET + parent = ".$anchor['parent'].", + sortorder = 0 + WHERE id = ".$itemtomove['id']; + $reducesortorders = "UPDATE ".$CFG->prefix.$this->table." + SET sortorder = sortorder - 1 + WHERE parent = ".$itemtomove['parent']. + " AND sortorder > ".$itemtomove['sortorder']; + execute_sql($extendsortorders,false); + execute_sql($move,false); + execute_sql($reducesortorders,false); + $this->set_moving_item(0); + break; + case 'moveafter': // move item after selected item + $extendsortorders = "UPDATE ".$CFG->prefix.$this->table." + SET sortorder = sortorder + 1 + WHERE parent = ".$anchor['parent']." AND sortorder >".$anchor['sortorder']; + $move = "UPDATE ".$CFG->prefix.$this->table." + SET + parent = ".$anchor['parent'].", + sortorder = ".$anchor['sortorder']." + 1 + WHERE id = ".$itemtomove['id']; + $reducesortorders = "UPDATE ".$CFG->prefix.$this->table." + SET sortorder = sortorder - 1 + WHERE parent = ".$itemtomove['parent']. + " AND sortorder > ".$itemtomove['sortorder']; + execute_sql($extendsortorders,false); + execute_sql($move,false); + execute_sql($reducesortorders,false); + $this->set_moving_item(0); + break; + case 'movefirstchild': // insert list item as subitem + $extendsortorders = "UPDATE ".$CFG->prefix.$this->table." + SET sortorder = sortorder + 1 + WHERE parent = ".$anchor['id']; + $move = "UPDATE ".$CFG->prefix.$this->table." + SET + parent = ".$anchor['id'].", + sortorder = 0 + WHERE id = ".$itemtomove['id']; + $reducesortorders = "UPDATE ".$CFG->prefix.$this->table." + SET sortorder = sortorder - 1 + WHERE parent = ".$itemtomove['parent']. + " AND sortorder > ".$itemtomove['sortorder']; + execute_sql($extendsortorders,false); + execute_sql($move,false); + execute_sql($reducesortorders,false); + $this->set_moving_item(0); + break; + default: + return false; + } + + redirect($this->pageurl->out()); + } + + /** * @param integer $itemid an item id. * @return boolean Is the item with the given id the first top-level item on * the current page? @@ -544,55 +717,42 @@ * @return string html */ function to_html($indent=0, $extraargs = array()) { + global $CFG; if (!$this->display) { return ''; } $tabs = str_repeat("\t", $indent); + // inserting "movefirstchild" action in the beginning of every list + if ($this->parentlist->is_moving_active()) { + $action = array('actionname'=>'movefirstchild','actionargs'=>$this->id); + $childrenhtml .= "\n"; + } if (isset($this->children)) { - $childrenhtml = $this->children->to_html($indent+1, $extraargs); + $childrenhtml .= $this->children->to_html($indent+1, $extraargs); } else { - $childrenhtml = ''; + $childrenhtml .= ''; } return $this->item_html($extraargs).' '.(join($this->icons, '')).(($childrenhtml !='')?("\n".$childrenhtml):''); } function set_icon_html($first, $last, &$lastitem) { global $CFG; - $strmoveup = get_string('moveup'); - $strmovedown = get_string('movedown'); - $strmoveleft = get_string('maketoplevelitem', 'question'); + $strmove = get_string('move'); $pixpath = $CFG->pixpath; - if (isset($this->parentlist->parentitem)) { - $parentitem =& $this->parentlist->parentitem; - if (isset($parentitem->parentlist->parentitem)) { - $action = get_string('makechildof', 'question', $parentitem->parentlist->parentitem->name); + if (!$this->parentlist->is_moving_active()) { + // "Move"-icon must be drawn in all list-items except alone item in list + if (!isset($this->parentlist->parentitem)) { + if (count($this->parentlist->items)>1) { + $this->icons['move'] = $this->image_icon($strmove, $this->parentlist->pageurl->out_action(array('actionname'=>'startmove','actionargs'=>$this->id)), 'move'); + } } else { - $action = $strmoveleft; + $this->icons['move'] = $this->image_icon($strmove, $this->parentlist->pageurl->out_action(array('actionname'=>'startmove','actionargs'=>$this->id)), 'move'); } - $this->icons['left'] = $this->image_icon($action, $this->parentlist->pageurl->out_action(array('left'=>$this->id)), 'left'); - } else { - $this->icons['left'] = $this->image_spacer(); - } - - if (!$first) { - $this->icons['up'] = $this->image_icon($strmoveup, $this->parentlist->pageurl->out_action(array('moveup'=>$this->id)), 'up'); - } else { - $this->icons['up'] = $this->image_spacer(); - } - - if (!$last) { - $this->icons['down'] = $this->image_icon($strmovedown, $this->parentlist->pageurl->out_action(array('movedown'=>$this->id)), 'down'); - } else { - $this->icons['down'] = $this->image_spacer(); - } - - if (!empty($lastitem)) { - $makechildof = get_string('makechildof', 'question', $lastitem->name); - $this->icons['right'] = $this->image_icon($makechildof, $this->parentlist->pageurl->out_action(array('right'=>$this->id)), 'right'); - } else { - $this->icons['right'] = $this->image_spacer(); } } @@ -617,8 +777,13 @@ * @param integer $thisrecordid */ function create_children(&$records, &$children, $thisrecordid) { - //keys where value is $thisrecordid - $thischildren = array_keys($children, $thisrecordid); + //keys where parent is $thisrecordid + $children[$thisrecordid]['item'] = $this; + $thischildren = array(); + foreach($children as $id => $item) { + if ($item['parent']==$thisrecordid) + $thischildren[]=$id; + } if (count($thischildren)) { foreach ($thischildren as $child) { $thisclass = get_class($this); Index: question/category.php =================================================================== RCS file: /cvsroot/moodle/moodle/question/category.php,v retrieving revision 1.24.2.5 diff -u -r1.24.2.5 category.php --- question/category.php 2 Nov 2009 17:15:19 -0000 1.24.2.5 +++ question/category.php 20 Mar 2010 16:52:29 -0000 @@ -7,45 +7,28 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License * @package questionbank */ - require_once("../config.php"); require_once($CFG->dirroot."/question/editlib.php"); require_once($CFG->dirroot."/question/category_class.php"); - list($thispageurl, $contexts, $cmid, $cm, $module, $pagevars) = question_edit_setup('categories'); // get values from form for actions on this page $param = new stdClass(); - $param->moveup = optional_param('moveup', 0, PARAM_INT); - $param->movedown = optional_param('movedown', 0, PARAM_INT); - $param->moveupcontext = optional_param('moveupcontext', 0, PARAM_INT); - $param->movedowncontext = optional_param('movedowncontext', 0, PARAM_INT); - $param->tocontext = optional_param('tocontext', 0, PARAM_INT); - $param->left = optional_param('left', 0, PARAM_INT); - $param->right = optional_param('right', 0, PARAM_INT); $param->delete = optional_param('delete', 0, PARAM_INT); $param->confirm = optional_param('confirm', 0, PARAM_INT); - $param->cancel = optional_param('cancel', '', PARAM_ALPHA); - $param->move = optional_param('move', 0, PARAM_INT); - $param->moveto = optional_param('moveto', 0, PARAM_INT); + $param->actionname = optional_param('actionname', 'noaction', PARAM_ALPHA); + $param->actionargs = optional_param('actionargs', 0, PARAM_INT); $param->edit = optional_param('edit', 0, PARAM_INT); - $qcobject = new question_category_object($pagevars['cpage'], $thispageurl, $contexts->having_one_edit_tab_cap('categories'), $param->edit, $pagevars['cat'], $param->delete, $contexts->having_cap('moodle/question:add')); - $streditingcategories = get_string('editcategories', 'quiz'); - if ($param->left || $param->right || $param->moveup || $param->movedown|| $param->moveupcontext || $param->movedowncontext){ - require_sesskey(); - foreach ($qcobject->editlists as $list){ - //processing of these actions is handled in the method where appropriate and page redirects. - $list->process_actions($param->left, $param->right, $param->moveup, $param->movedown, - $param->moveupcontext, $param->movedowncontext, $param->tocontext); - } - } + + $qcobject->process_action($param->actionname, $param->actionargs); + if ($param->delete && ($questionstomove = count_records("question", "category", $param->delete))){ if (!$category = get_record("question_categories", "id", $param->delete)) { // security error("No such category {$param->delete}!", $thispageurl->out()); Index: question/category_class.php =================================================================== RCS file: /cvsroot/moodle/moodle/question/category_class.php,v retrieving revision 1.32.2.10 diff -u -r1.32.2.10 category_class.php --- question/category_class.php 19 Nov 2009 17:46:17 -0000 1.32.2.10 +++ question/category_class.php 28 Mar 2010 14:53:20 -0000 @@ -28,14 +28,43 @@ var $context = null; - function question_category_list($type='ul', $attributes='', $editable = false, $pageurl=null, $page = 0, $pageparamname = 'page', $itemsperpage = 20, $context = null){ - parent::moodle_list('ul', '', $editable, $pageurl, $page, 'cpage', $itemsperpage); + function question_category_list($type='ul', $attributes='', $editable = false, $pageurl=null, $page = 0, $pageparamname = 'page', $itemsperpage = 20, $context = null, $toplevellist=null){ + parent::moodle_list('ul', '', $editable, $pageurl, $page, 'cpage', $itemsperpage, $toplevellist); $this->context = $context; } + function list_from_records($paged = false, $offset = 0) { + $result = parent::list_from_records($paged, $offset); + foreach ($this->records as $record) { + // context will used for moving items between contexts + $this->toplevellist->itemscache[$record->id]['context'] = $this->context->id; + } + return $result; + } + function get_records() { $this->records = get_categories_for_contexts($this->context->id, $this->sortby); } + + /** + * Returns array that contains id's of all element which ares childs of this list + * @return array which contains id's if all child elements + */ + function get_child_ids_recursive() { + $childs = array(); + if (isset($this->items)) { + foreach ($this->items as $child) { + $childs[] = $child->id; + $recurs = $child->children->get_child_ids_recursive(); + $childs = array_merge($childs,$recurs); + } + } + return $childs; + } + + /** + * @deprecated use process_action instead + */ function process_actions($left, $right, $moveup, $movedown, $moveupcontext, $movedowncontext, $tocontext){ global $CFG; //parent::procces_actions redirects after any action @@ -54,27 +83,44 @@ $this->pageurl->get_query_string(compact('cattomove', 'totop', 'toparent'))); } } + + function process_action($action, $value) { + if (($action=='movefirstchild' || $action=='moveafter' || $action=='movebefore') + // Changing context if item to move and anchor item are in defferent contexts + && $this->toplevellist->itemscache[$this->get_moving_item()]['context']!=$this->toplevellist->itemscache[$value]['context']) { + global $CFG; + $itemstorecontext = $this->toplevellist->itemscache[$this->get_moving_item()]['item']->children->get_child_ids_recursive(); + $itemstorecontext[] = $this->get_moving_item(); + + $changecontext = 'UPDATE '.$CFG->prefix.$this->table.' + SET contextid = '.$this->toplevellist->itemscache[$value]['context'].' + WHERE id IN ('.implode(',',$itemstorecontext).')'; + execute_sql($changecontext,false); + } + + // parent::process_action redirects after any action + parent::process_action($action, $value); + } } + class question_category_list_item extends list_item { + function question_category_list_item($item, &$parent, $attributes='', $display = true) { + parent::list_item($item, $parent, $attributes, $display); + } function set_icon_html($first, $last, &$lastitem){ global $CFG; - $category = $this->item; - $this->icons['edit']= $this->image_icon(get_string('editthiscategory', 'question'), - "{$CFG->wwwroot}/question/category.php?".$this->parentlist->pageurl->get_query_string(array('edit'=>$category->id)), 'edit'); - parent::set_icon_html($first, $last, $lastitem); - $toplevel = ($this->parentlist->parentitem === null);//this is a top level item - if (($this->parentlist->nextlist !== null) && $last && $toplevel && (count($this->parentlist->items)>1)){ - $this->icons['down'] = $this->image_icon(get_string('shareincontext', 'question', print_context_name($this->parentlist->nextlist->context)), - $this->parentlist->pageurl->out_action(array('movedowncontext'=>$this->id, 'tocontext'=>$this->parentlist->nextlist->context->id)), 'down'); - } - if (($this->parentlist->lastlist !== null) && $first && $toplevel && (count($this->parentlist->items)>1)){ - $this->icons['up'] = $this->image_icon(get_string('shareincontext', 'question', print_context_name($this->parentlist->lastlist->context)), - $this->parentlist->pageurl->out_action(array('moveupcontext'=>$this->id, 'tocontext'=>$this->parentlist->lastlist->context->id)), 'up'); + + if (!$this->parentlist->is_moving_active()) { + $category = $this->item; + $this->icons['edit']= $this->image_icon(get_string('editthiscategory'), + "{$CFG->wwwroot}/question/category.php?".$this->parentlist->pageurl->get_query_string(array('edit'=>$category->id)), 'edit'); } + parent::set_icon_html($first, $last, $lastitem); } + function item_html($extraargs = array()){ global $CFG; $pixpath = $CFG->pixpath; @@ -91,14 +137,14 @@ $item .= ' '. $category->info; - if (count($this->parentlist->records)!=1){ // don't allow delete if this is the last category in this context. + // don't allow delete if there is only 1 category in this context. + if (count($this->parentlist->records)!=1 && !$this->parentlist->is_moving_active()){ $item .= ' ' .$str->delete. ''; } return $item; } - } @@ -131,6 +177,18 @@ var $catform; /** + * Cache of all items contained in list + * Presents only in top-level list. + * For question category list top-level list is question_category_object + * @var array that contains from: + * [id]['sortorder'] => sortorder + * [id]['parent'] => parentid + * [id]['item'] => reference to item object + * [id]['context'] => question category context + */ + var $itemscache = null; + + /** * Constructor * * Gets necessary strings and sets relevant path information @@ -146,8 +204,6 @@ $this->str->questions = get_string('questions', 'quiz'); $this->str->add = get_string('add'); $this->str->delete = get_string('delete'); - $this->str->moveup = get_string('moveup'); - $this->str->movedown = get_string('movedown'); $this->str->edit = get_string('editthiscategory', 'question'); $this->str->hide = get_string('hide'); $this->str->publish = get_string('publish', 'quiz'); @@ -176,8 +232,9 @@ */ function initialize($page, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts) { $lastlist = null; + $this->itemscache = array(); foreach ($contexts as $context){ - $this->editlists[$context->id] = new question_category_list('ul', '', true, $this->pageurl, $page, 'cpage', QUESTION_PAGE_LENGTH, $context); + $this->editlists[$context->id] = new question_category_list('ul', '', true, $this->pageurl, $page, 'cpage', QUESTION_PAGE_LENGTH, $context, $this); $this->editlists[$context->id]->lastlist =& $lastlist; if ($lastlist!== null){ $lastlist->nextlist =& $this->editlists[$context->id]; @@ -195,6 +252,21 @@ $this->catform->set_data(array('parent'=>$defaultcategory)); } } + + /** + * Handles question category list actions + * @param string $action action name + * @param string $value action argument + */ + function process_action($action, $value) { + if ($action != 'noaction') { + global $USER; + confirm_sesskey(); + $context = $this->itemscache[$value]['context']; + $this->editlists[$context]->process_action($action, $value); + } + } + /** * Displays the user interface * @@ -219,6 +291,25 @@ $this->catform->display(); } + /** + * Outputs a link to cancel moving category + */ + function print_cancel_moving_link() { + global $COURSE,$USER; + $itemtomove = 0; + if (count($this->editlists)>0){ + reset($this->editlists); + $itemtomove = current($this->editlists)->get_moving_item(); + } + + if ($itemtomove != 0) { + $itemname = $this->itemscache[$itemtomove]['item']->name; + echo "

".get_string('movingcategory','question'). + ": ".$itemname." (".get_string('cancel').")

"; + } + } /** * Outputs a list to allow editing/rearranging of existing categories @@ -228,6 +319,7 @@ */ function output_edit_lists() { print_heading_with_help(get_string('editcategories', 'quiz'), 'categories', 'question'); + $this->print_cancel_moving_link(); foreach ($this->editlists as $context => $list){ $listhtml = $list->to_html(0, array('str'=>$this->str)); if ($listhtml){ @@ -240,8 +332,6 @@ echo $list->display_page_numbers(); } - - /** * gets all the courseids for the given categories * @@ -378,7 +468,15 @@ $cat->contextid = $contextid; $cat->name = $newcategory; $cat->info = $newinfo; - $cat->sortorder = 999; + + // There are shouldn't be two items in one list with the same sortorder + $cat->sortorder = 0; + $neighbors = $this->itemscache[$cat->parent]['item']->children->items; + foreach ($neighbors as $item) { + if ($item->item->sortorder>=$cat->sortorder) + $cat->sortorder = $item->item->sortorder + 1; + } + $cat->stamp = make_unique_id_code(); if (!insert_record("question_categories", $cat)) { error("Could not insert the new question category '$newcategory'"); @@ -402,6 +500,14 @@ if (!empty($newparent) && !$lastcategoryinthiscontext) { list($parentid, $tocontextid) = explode(',', $newparent); + + // If parent changed category will moved in the end of list + $newsortorder = 0; + $neighbors = $this->itemscache[$parentid]['item']->children->items; + foreach ($neighbors as $item) { + if ($item->item->sortorder>=$newsortorder) + $newsortorder = $item->item->sortorder + 1; + } } else { $parentid = $oldcat->parent; $tocontextid = $oldcat->contextid; @@ -423,6 +529,7 @@ $cat->name = $newname; $cat->info = $newinfo; $cat->parent = $parentid; + $cat->sortorder = $newsortorder; // We don't change $cat->contextid here, if necessary we redirect to contextmove.php later. if (!update_record("question_categories", $cat)) { error("Could not update the category '$newname'", $this->pageurl->out());