diff --git a/course/rest.php b/course/rest.php index 41fce5d17bd..ac04a75c257 100644 --- a/course/rest.php +++ b/course/rest.php @@ -6,11 +6,10 @@ require_once($CFG->dirroot.'/course/lib.php'); require_once($CFG->libdir .'/pagelib.php'); require_once($CFG->libdir .'/blocklib.php'); + // Initialise ALL the incoming parameters here, up front. - -$courseid = required_param('courseId', PARAM_INT); -$class = required_param('class', PARAM_ALPHA); - +$courseid = required_param('courseId', PARAM_INT); +$class = required_param('class', PARAM_ALPHA); $field = optional_param('field', '', PARAM_ALPHA); $instanceid = optional_param('instanceId', 0, PARAM_INT); $sectionid = optional_param('sectionId', 0, PARAM_INT); @@ -22,46 +21,51 @@ $summary = optional_param('summary', '', PARAM_RAW); $sequence = optional_param('sequence', '', PARAM_SEQUENCE); $visible = optional_param('visible', 0, PARAM_INT); -// Authorise the user and verify some incoming data +// Authorise the user and verify some incoming data if (!$course = get_record('course', 'id', $courseid)) { error_log('AJAX commands.php: Course does not exist'); die; } $PAGE = page_create_object(PAGE_COURSE_VIEW, $course->id); -$pageblocks = blocks_setup($PAGE,BLOCKS_PINNED_BOTH); +$pageblocks = blocks_setup($PAGE, BLOCKS_PINNED_BOTH); + if (!empty($instanceid)) { $blockinstance = blocks_find_instance($instanceid, $pageblocks); - if (!$blockinstance || $blockinstance->pageid != $course->id || $blockinstance->pagetype != 'course-view') { + if (!$blockinstance || $blockinstance->pageid != $course->id + || $blockinstance->pagetype != 'course-view') { error_log('AJAX commands.php: Bad block ID '.$instanceid); die; } } $context = get_context_instance(CONTEXT_COURSE, $course->id); - require_login($course->id); require_capability('moodle/course:update', $context); -// OK, now let's process the parameters and do stuff + +// OK, now let's process the parameters and do stuff switch($_SERVER['REQUEST_METHOD']) { case 'POST': + switch ($class) { - case 'block': - switch ($field) { - case 'visible': - blocks_execute_action($PAGE, $pageblocks, 'toggle', $blockinstance); - break; - - case 'position': - //while not entirely restful this will handle all the details of moving a block - blocks_execute_repositioning_atomic($blockinstance, $column, $value); - break; - } - break; - + case 'block': + + switch ($field) { + case 'visible': + blocks_execute_action($PAGE, $pageblocks, 'toggle', $blockinstance); + break; + + case 'position': // Misleading case. Should probably call it 'move'. + // We want to move the block around. This means changing + // the column (position field) and/or block sort order + // (weight field). + blocks_move_block($PAGE, $blockinstance, $column, $value); + break; + } + break; case 'section': diff --git a/lib/blocklib.php b/lib/blocklib.php index 092127f53b8..6189dc15b83 100644 --- a/lib/blocklib.php +++ b/lib/blocklib.php @@ -290,7 +290,7 @@ function blocks_print_group(&$page, &$pageblocks, $position) { // Disabled by the admin continue; } - + if (empty($instance->obj)) { if (!$obj = block_instance($block->name, $instance)) { // Invalid block @@ -709,11 +709,11 @@ function blocks_execute_url_action(&$PAGE, &$pageblocks,$pinned=false) { // This shouldn't be used externally at all, it's here for use by blocks_execute_action() // in order to reduce code repetition. -function blocks_execute_repositioning(&$instance, $newpos, $newweight, $pinned=false, $checkPos=true) { +function blocks_execute_repositioning(&$instance, $newpos, $newweight, $pinned=false) { global $CFG; // If it's staying where it is, don't do anything, unless overridden - if (($newpos == $instance->position) && $checkPos) { + if ($newpos == $instance->position) { return; } @@ -742,38 +742,82 @@ function blocks_execute_repositioning(&$instance, $newpos, $newweight, $pinned=f } } -//like blocks_execute_repositiong except completely atomic, handles all aspects of the positioning -function blocks_execute_repositioning_atomic(&$instance, $newpos, $newweight, $pinned=false){ + +/** + * Moves a block to the new position (column) and weight (sort order). + * @param $instance - The block instance to be moved. + * @param $destpos - BLOCK_POS_LEFT or BLOCK_POS_RIGHT. The destination column. + * @param $destweight - The destination sort order. If NULL, we add to the end + * of the destination column. + * @param $pinned - Are we moving pinned blocks? We can only move pinned blocks + * to a new position withing the pinned list. Likewise, we + * can only moved non-pinned blocks to a new position within + * the non-pinned list. + * @return boolean (success or failure). + */ +function blocks_move_block($page, &$instance, $destpos, $destweight=NULL, $pinned=false) { global $CFG; - if ($instance->weight == $newweight) { + if ($pinned) { + $blocklist = blocks_get_pinned($page); + } else { + $blocklist = blocks_get_by_page($page); + } + + if ($blocklist[$instance->position][$instance->weight]->id != $instance->id) { + // The source block instance is not where we think it is. return false; } - - //make room for block insert - if (!empty($pinned)) { - $sql = 'UPDATE '. $CFG->prefix .'block_instance SET weight = weight + 1 '. - 'WHERE pagetype = \''. $instance->pagetype. - '\' AND position = \'' .$newpos. - '\' AND weight >= '. $newweight; - } else { - $sql = 'UPDATE '. $CFG->prefix .'block_instance SET weight = weight + 1 '. - 'WHERE pagetype = \''. $instance->pagetype. - '\' AND pageid = '. $instance->pageid. - ' AND position = \'' .$newpos. - '\' AND weight >= '. $newweight; - } - execute_sql($sql,false); - //adjusts the wieghts for changes in the weight list - if ($newweight < $instance->weight) { - $instance->weight+=2; + // First we close the gap that will be left behind when we take out the + // block from it's current column. + if ($pinned) { + $closegapsql = "UPDATE {$CFG->prefix}block_instance + SET weight = weight - 1 + WHERE weight > '$instance->weight' + AND position = '$instance->position' + AND pagetype = '$instance->pagetype'"; } else { - $newweight--; + $closegapsql = "UPDATE {$CFG->prefix}block_instance + SET weight = weight - 1 + WHERE weight > '$instance->weight' + AND position = '$instance->position' + AND pagetype = '$instance->pagetype' + AND pageid = '$instance->pageid'"; } + if (!execute_sql($closegapsql, false)) { + return false; + } + + // Now let's make space for the block being moved. + if ($pinned) { + $opengapsql = "UPDATE {$CFG->prefix}block_instance + SET weight = weight + 1 + WHERE weight >= '$destweight' + AND position = '$destpos' + AND pagetype = '$instance->pagetype'"; + } else { + $opengapsql = "UPDATE {$CFG->prefix}block_instance + SET weight = weight + 1 + WHERE weight >= '$destweight' + AND position = '$destpos' + AND pagetype = '$instance->pagetype' + AND pageid = '$instance->pageid'"; + } + if (!execute_sql($opengapsql, false)) { + return false; + } + + // Move the block. + $instance->position = $destpos; + $instance->weight = $destweight; - //reposition blocks - blocks_execute_repositioning($instance,$newpos,$newweight,$pinned,false); + if ($pinned) { + $table = 'block_pinned'; + } else { + $table = 'block_instance'; + } + return update_record($table, $instance); }