libdir.'/pagelib.php'); // Returns the case-sensitive name of the class' constructor function. This includes both // PHP5- and PHP4-style constructors. If no appropriate constructor can be found, returns NULL. // If there is no such class, returns boolean false. function get_class_constructor($classname) { // Caching static $constructors = array(); if(!class_exists($classname)) { return false; } // Tests indicate this doesn't hurt even in PHP5. $classname = strtolower($classname); // Return cached value, if exists if(isset($constructors[$classname])) { return $constructors[$classname]; } // Get a list of methods. After examining several different ways of // doing the check, (is_callable, method_exists, function_exists etc) // it seems that this is the most reliable one. $methods = get_class_methods($classname); // PHP5 constructor? if(phpversion() >= '5') { if(in_array('__construct', $methods)) { return $constructors[$classname] = '__construct'; } } // If we have PHP5 but no magic constructor, we have to lowercase the methods $methods = array_map('strtolower', $methods); if(in_array($classname, $methods)) { return $constructors[$classname] = $classname; } return $constructors[$classname] = NULL; } //This function retrieves a method-defined property of a class WITHOUT instantiating an object //It seems that the only way to use the :: operator with variable class names is eval() :( //For caveats with this technique, see the PHP docs on operator :: function block_method_result($blockname, $method) { if(!block_load_class($blockname)) { return NULL; } return eval('return block_'.$blockname.'::'.$method.'();'); } //This function creates a new object of the specified block class function block_instance($blockname, $instance = NULL) { if(!block_load_class($blockname)) { return false; } $classname = 'block_'.$blockname; $retval = new $classname; if($instance !== NULL) { $retval->load_instance($instance); } return $retval; } //This function loads the necessary class files for a block //Whenever you want to load a block, use this first function block_load_class($blockname) { global $CFG; @include_once($CFG->dirroot.'/blocks/moodleblock.class.php'); $classname = 'block_'.$blockname; @include_once($CFG->dirroot.'/blocks/'.$blockname.'/block_'.$blockname.'.php'); // After all this, return value indicating success or failure return class_exists($classname); } // This function returns an array with the IDs of any blocks that you can add to your page. // Parameters are passed by reference for speed; they are not modified at all. function blocks_get_missing(&$page, &$pageblocks) { $missingblocks = array(); $allblocks = blocks_get_record(); $pageformat = $page->get_format_name(); if(!empty($allblocks)) { foreach($allblocks as $block) { if($block->visible && (!blocks_find_block($block->id, $pageblocks) || $block->multiple)) { // And if it's applicable for display in this format... $formats = block_method_result($block->name, 'applicable_formats'); if(isset($formats[$pageformat]) ? $formats[$pageformat] : !empty($formats['all'])) { // Add it to the missing blocks $missingblocks[] = $block->id; } } } } return $missingblocks; } function blocks_remove_inappropriate($page) { $pageblocks = blocks_get_by_page($page); if(empty($pageblocks)) { return; } if(($pageformat = $page->get_format_name()) == NULL) { return; } foreach($pageblocks as $position) { foreach($position as $instance) { $block = blocks_get_record($instance->blockid); $formats = block_method_result($block->name, 'applicable_formats'); if(! (isset($formats[$pageformat]) ? $formats[$pageformat] : !empty($formats['all']))) { // Translation: if the course format is explicitly accepted/rejected, use // that setting. Otherwise, fallback to the 'all' format. The empty() test // uses the trick that empty() fails if 'all' is either !isset() or false. blocks_delete_instance($instance); } } } } function blocks_delete_instance($instance) { global $CFG; delete_records('block_instance', 'id', $instance->id); // And now, decrement the weight of all blocks after this one execute_sql('UPDATE '.$CFG->prefix.'block_instance SET weight = weight - 1 WHERE pagetype = \''.$instance->pagetype. '\' AND pageid = '.$instance->pageid.' AND position = \''.$instance->position. '\' AND weight > '.$instance->weight, false); } // Accepts an array of block instances and checks to see if any of them have content to display // (causing them to calculate their content in the process). Returns true or false. Parameter passed // by reference for speed; the array is actually not modified. function blocks_have_content(&$instances) { foreach($instances as $instance) { if(!$instance->visible) { continue; } $record = blocks_get_record($instance->blockid); $obj = block_instance($record->name, $instance); $content = $obj->get_content(); $type = $obj->get_content_type(); switch($type) { case BLOCK_TYPE_LIST: if(!empty($content->items) || !empty($content->footer)) { return true; } break; case BLOCK_TYPE_TEXT: case BLOCK_TYPE_NUKE: if(!empty($content->text) || !empty($content->footer)) { return true; } break; } } return false; } // This function prints one group of blocks in a page // Parameters passed by reference for speed; they are not modified. function blocks_print_group(&$page, &$instances) { if(empty($instances)) { return; } $isediting = $page->user_is_editing(); $maxweight = max(array_keys($instances)); foreach($instances as $instance) { $block = blocks_get_record($instance->blockid); if(!$block->visible) { // Disabled by the admin continue; } if (!$obj = block_instance($block->name, $instance)) { // Invalid block continue; } if ($isediting) { $options = 0; // The block can be moved up if it's NOT the first one in its position. If it is, we look at the OR clause: // the first block might still be able to move up if the page says so (i.e., it will change position) $options |= BLOCK_MOVE_UP * ($instance->weight != 0 || ($page->blocks_move_position($instance, BLOCK_MOVE_UP) != $instance->position)); // Same thing for downward movement $options |= BLOCK_MOVE_DOWN * ($instance->weight != $maxweight || ($page->blocks_move_position($instance, BLOCK_MOVE_DOWN) != $instance->position)); // For left and right movements, it's up to the page to tell us whether they are allowed $options |= BLOCK_MOVE_RIGHT * ($page->blocks_move_position($instance, BLOCK_MOVE_RIGHT) != $instance->position); $options |= BLOCK_MOVE_LEFT * ($page->blocks_move_position($instance, BLOCK_MOVE_LEFT ) != $instance->position); // Finally, the block can be configured if the block class either allows multiple instances, or if it specifically // allows instance configuration (multiple instances override that one). It doesn't have anything to do with what the // administrator has allowed for this block in the site admin options. $options |= BLOCK_CONFIGURE * ( $obj->instance_allow_multiple() || $obj->instance_allow_config() ); $obj->add_edit_controls($options); } if(!$instance->visible) { if($isediting) { $obj->print_shadow(); } } else { $obj->print_block(); } } } // This iterates over an array of blocks and calculates the preferred width // Parameter passed by reference for speed; it's not modified. function blocks_preferred_width(&$instances) { $width = 0; if(empty($instances) || !is_array($instances)) { return 0; } foreach($instances as $instance) { if(!$instance->visible) { continue; } $block = blocks_get_record($instance->blockid); $pref = block_method_result($block->name, 'preferred_width'); if($pref === NULL) { continue; } if($pref > $width) { $width = $pref; } } return $width; } function blocks_get_record($blockid = NULL, $invalidate = false) { static $cache = NULL; if($invalidate || empty($cache)) { $cache = get_records('block'); } if($blockid === NULL) { return $cache; } return (isset($cache[$blockid])? $cache[$blockid] : false); } function blocks_find_block($blockid, $blocksarray) { foreach($blocksarray as $blockgroup) { foreach($blockgroup as $instance) { if($instance->blockid == $blockid) { return $instance; } } } return false; } function blocks_find_instance($instanceid, $blocksarray) { foreach($blocksarray as $subarray) { foreach($subarray as $instance) { if($instance->id == $instanceid) { return $instance; } } } return false; } function blocks_execute_action($page, &$pageblocks, $blockaction, $instanceorid) { global $CFG; if (is_int($instanceorid)) { $blockid = $instanceorid; } else if (is_object($instanceorid)) { $instance = $instanceorid; } switch($blockaction) { case 'config': global $USER; $block = blocks_get_record($instance->blockid); $blockobject = block_instance($block->name, $instance); if ($blockobject === false) { continue; } optional_param('submitted', 0, PARAM_INT); // Define the data we're going to silently include in the instance config form here, // so we can strip them from the submitted data BEFORE serializing it. $hiddendata = array( 'sesskey' => $USER->sesskey, 'instanceid' => $instance->id, 'blockaction' => 'config' ); // To this data, add anything the page itself needs to display $hiddendata = array_merge($hiddendata, $page->url_get_parameters()); if($data = data_submitted()) { $remove = array_keys($hiddendata); foreach($remove as $item) { unset($data->$item); } if(!$blockobject->instance_config_save($data)) { error('Error saving block configuration'); } // And nothing more, continue with displaying the page } else { // We need to show the config screen, so we highjack the display logic and then die $strheading = get_string('blockconfiga', 'moodle', $block->name); $page->print_header(get_string('pageheaderconfigablock', 'moodle'), array($strheading => '')); print_heading($strheading); echo '
'; print_footer(); die(); // Do not go on with the other page-related stuff } break; case 'toggle': if(empty($instance)) { error('Invalid block instance for '.$blockaction); } $instance->visible = ($instance->visible) ? 0 : 1; update_record('block_instance', $instance); break; case 'delete': if(empty($instance)) { error('Invalid block instance for '. $blockaction); } blocks_delete_instance($instance); break; case 'moveup': if(empty($instance)) { error('Invalid block instance for '. $blockaction); } if($instance->weight == 0) { // The block is the first one, so a move "up" probably means it changes position // Where is the instance going to be moved? $newpos = $page->blocks_move_position($instance, BLOCK_MOVE_UP); $newweight = (empty($pageblocks[$newpos]) ? 0 : max(array_keys($pageblocks[$newpos])) + 1); blocks_execute_repositioning($instance, $newpos, $newweight); } else { // The block is just moving upwards in the same position. // This configuration will make sure that even if somehow the weights // become not continuous, block move operations will eventually bring // the situation back to normal without printing any warnings. if(!empty($pageblocks[$instance->position][$instance->weight - 1])) { $other = $pageblocks[$instance->position][$instance->weight - 1]; } if(!empty($other)) { ++$other->weight; update_record('block_instance', $other); } --$instance->weight; update_record('block_instance', $instance); } break; case 'movedown': if(empty($instance)) { error('Invalid block instance for '. $blockaction); } if($instance->weight == max(array_keys($pageblocks[$instance->position]))) { // The block is the last one, so a move "down" probably means it changes position // Where is the instance going to be moved? $newpos = $page->blocks_move_position($instance, BLOCK_MOVE_DOWN); $newweight = (empty($pageblocks[$newpos]) ? 0 : max(array_keys($pageblocks[$newpos])) + 1); blocks_execute_repositioning($instance, $newpos, $newweight); } else { // The block is just moving downwards in the same position. // This configuration will make sure that even if somehow the weights // become not continuous, block move operations will eventually bring // the situation back to normal without printing any warnings. if(!empty($pageblocks[$instance->position][$instance->weight + 1])) { $other = $pageblocks[$instance->position][$instance->weight + 1]; } if(!empty($other)) { --$other->weight; update_record('block_instance', $other); } ++$instance->weight; update_record('block_instance', $instance); } break; case 'moveleft': if(empty($instance)) { error('Invalid block instance for '. $blockaction); } // Where is the instance going to be moved? $newpos = $page->blocks_move_position($instance, BLOCK_MOVE_LEFT); $newweight = (empty($pageblocks[$newpos]) ? 0 : max(array_keys($pageblocks[$newpos])) + 1); blocks_execute_repositioning($instance, $newpos, $newweight); break; case 'moveright': if(empty($instance)) { error('Invalid block instance for '. $blockaction); } // Where is the instance going to be moved? $newpos = $page->blocks_move_position($instance, BLOCK_MOVE_RIGHT); $newweight = (empty($pageblocks[$newpos]) ? 0 : max(array_keys($pageblocks[$newpos])) + 1); blocks_execute_repositioning($instance, $newpos, $newweight); break; case 'add': // Add a new instance of this block, if allowed $block = blocks_get_record($blockid); if(!$block->visible) { // Only allow adding if the block is enabled return false; } if(!$block->multiple && blocks_find_block($blockid, $pageblocks) !== false) { // If no multiples are allowed and we already have one, return now return false; } $newpos = $page->blocks_default_position(); $weight = get_record_sql('SELECT 1, max(weight) + 1 AS nextfree FROM '. $CFG->prefix .'block_instance WHERE pageid = '. $page->get_id() .' AND pagetype = \''. $page->get_type() .'\' AND position = \''. $newpos .'\''); $newinstance = new stdClass; $newinstance->blockid = $blockid; $newinstance->pageid = $page->get_id(); $newinstance->pagetype = $page->get_type(); $newinstance->position = $newpos; $newinstance->weight = $weight->nextfree; $newinstance->visible = 1; $newinstance->configdata = ''; insert_record('block_instance', $newinstance); break; } // In order to prevent accidental duplicate actions, redirect to a page with a clean url redirect($page->url_get_full()); } // 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) { global $CFG; // If it's staying where it is, don't do anything if($newpos == $instance->position) { return; } // Close the weight gap we 'll leave behind execute_sql('UPDATE '. $CFG->prefix .'block_instance SET weight = weight - 1 WHERE pagetype = \''. $instance->pagetype. '\' AND pageid = '. $instance->pageid .' AND position = \'' .$instance->position. '\' AND weight > '. $instance->weight, false); $instance->position = $newpos; $instance->weight = $newweight; update_record('block_instance', $instance); } function blocks_get_by_page($page) { $blocks = get_records_select('block_instance', 'pageid = '. $page->get_id() .' AND pagetype = \''. $page->get_type() .'\'', 'position, weight'); $positions = $page->blocks_get_positions(); $arr = array(); foreach($positions as $key => $position) { $arr[$position] = array(); } if(empty($blocks)) { return $arr; } foreach($blocks as $block) { $arr[$block->position][$block->weight] = $block; } return $arr; } //This function prints the block to admin blocks as necessary function blocks_print_adminblock($page, $missingblocks) { global $USER; $strblocks = get_string('blocks'); $stradd = get_string('add'); if (!empty($missingblocks)) { foreach ($missingblocks as $blockid) { $block = blocks_get_record($blockid); $blockobject = block_instance($block->name); if ($blockobject === false) { continue; } $menu[$block->id] = $blockobject->get_title(); } $target = $page->url_get_full(array('sesskey' => $USER->sesskey, 'blockaction' => 'add')); $content = popup_form($target.'&blockid=', $menu, 'add_block', '', $stradd .'...', '', '', true); $content = '