navigation MDL-14632 Very significant navigation commit

This patch introduces two new blocks global_navigation_tree and settings_navigation_tree
both of which have been designed to make full use of the new navigation objects available through
the $PAGE object.
Bulk of this code is within lib/navigationlib.php
This commit is contained in:
samhemelryk
2009-08-28 08:47:31 +00:00
parent 4460e25d2b
commit 7d2a049292
55 changed files with 6787 additions and 712 deletions
@@ -0,0 +1,354 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains classes used to manage the navigation structures in Moodle
* and was introduced as part of the changes occuring in Moodle 2.0
*
* @since 2.0
* @package blocks
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* The global navigation tree block class
*
* Used to produce the global navigation block new to Moodle 2.0
*
* @package blocks
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class block_global_navigation_tree extends block_tree {
/** @var int */
public static $navcount;
/** @var string */
public $blockname = null;
protected $contentgenerated = false;
/**
* Set the initial properties for the block
*/
function init() {
global $CFG;
$this->blockname = get_class($this);
$this->title = get_string('blockname', $this->blockname);
$this->version = 2009082800;
}
/**
* All multiple instances of this block
* @return bool Returns true
*/
function instance_allow_multiple() {
return false;
}
/**
* Set the applicable formats for this block to all
* @return array
*/
function applicable_formats() {
return array('all' => true);
}
/**
* Allow the user to configure a block instance
* @return bool Returns true
*/
function instance_allow_config() {
return true;
}
/**
* Gets the content for this block by grabbing it from $this->page
*/
function get_content() {
global $CFG, $OUTPUT;
// First check if we have already generated, don't waste cycles
if ($this->contentgenerated === true) {
return true;
}
$this->page->requires->js('lib/javascript-navigation.js');
// Navcount is used to allow us to have multiple trees although I dont' know why
// you would want to trees the same
block_global_navigation_tree::$navcount++;
// Set the expansionlimit if one has been set in block config
if (!empty($this->config->expansionlimit) && $this->config->expansionlimit!='0') {
$this->page->navigation->expansionlimit = $this->config->expansionlimit;
}
// Initialise (only actually happens if it hasn't already been done yet
$this->page->navigation->initialise();
// Remove empty branches if the user has selected to
if (empty($this->config->showemptybranches) || $this->config->showemptybranches=='no') {
$this->remove_empty_section_branches();
}
// Load the my courses branch if the user has selected to
if (!empty($this->config->showmycourses) && $this->config->showmycourses=='yes') {
$this->showmycourses();
}
if (!empty($this->config->showmyhistory) && $this->config->showmyhistory=='yes') {
$this->showmyhistory();
}
$tooglesidetabdisplay = get_string('tooglesidetabdisplay', $this->blockname);
$toogleblockdisplay = get_string('toogleblockdisplay', $this->blockname);
// Get the expandable items so we can pass them to JS
$expandable = array();
$this->page->navigation->find_expandable($expandable);
$args = array('expansions'=>$expandable,'instance'=>$this->instance->id);
$args['tooglesidetabdisplay'] = $tooglesidetabdisplay;
$args['toogleblockdisplay'] = $toogleblockdisplay;
// Give JS some information we will use within the JS tree object
$this->page->requires->data_for_js('globalnav'.block_global_navigation_tree::$navcount, $args);
// Initialise the JS tree object
$this->id = 'globalnav'.block_global_navigation_tree::$navcount;
$this->page->requires->js_function_call('setup_new_navtree', array($this->id))->on_dom_ready();
// Grab the items to display
$this->content->items = array($this->page->navigation);
$url = $this->page->url;
$url->param('regenerate','navigation');
$reloadstr = get_string('reload');
$this->content->footer .= '<a href="'.$url->out().'" class="customcommand"><img src="'.$OUTPUT->old_icon_url('t/reload').'" alt="'.$reloadstr.'" title="'.$reloadstr.'" /></a>';
if (empty($this->config->enablesidebarpopout) || $this->config->enablesidebarpopout == 'yes') {
user_preference_allow_ajax_update('nav_in_tab_panel_globalnav'.block_global_navigation_tree::$navcount, PARAM_INT);
if (get_user_preferences('nav_in_tab_panel_globalnav'.block_global_navigation_tree::$navcount, 0)) {
$icon = $OUTPUT->old_icon_url('t/movetoblock');
$string = $toogleblockdisplay;
} else {
$icon = $OUTPUT->old_icon_url('t/movetosidetab');
$string = $tooglesidetabdisplay;
}
$this->content->footer .= '<a class="moveto customcommand requiresjs"><img src="'.$icon.'" alt="'.$string.'" title="'.$string.'"></a>';
}
// Set content generated to true so that we know it has been done
$this->contentgenerated = true;
return true;
}
/**
* Returns the attributes to set for this block
*
* This function returns an array of HTML attributes for this block including
* the defaults
* {@link block_tree->html_attributes()} is used to get the default arguments
* and then we check whether the user has enabled hover expansion and add the
* appropriate hover class if it has
*
* @return array An array of HTML attributes
*/
public function html_attributes() {
$attributes = parent::html_attributes();
if (!empty($this->config->enablehoverexpansion) && $this->config->enablehoverexpansion == 'yes') {
$attributes['class'] .= ' sideblock_js_expansion';
}
if (get_user_preferences('nav_in_tab_panel_globalnav'.block_global_navigation_tree::$navcount, 0)) {
$attributes['class'] .= ' sideblock_js_sidebarpopout';
}
return $attributes;
}
/**
* This function maintains a history of the active pages that a user has visited
* and displays it back to the user as part of the navigation structure
*
* @return bool
*/
protected function showmyhistory() {
global $USER, $PAGE, $ME;
// Create a navigation cache so that we can store the history
$cache = new navigation_cache('navigationhistory', 60*60);
// If the user isn't logged in or is a guest we don't want to display anything
if (!isloggedin() || isguest()) {
return false;
}
// Check the cache to see if we have loaded my courses already
// there is a very good chance that we have
if (!$cache->cached('history')) {
$cache->history = array();
}
$history = $cache->history;
$historycount = count($history);
// Find the initial active node
$child = false;
if ($PAGE->navigation->contains_active_node()) {
$child = $PAGE->navigation->find_active_node();
} else if ($PAGE->settingsnav->contains_active_node()) {
$child = $PAGE->settingsnav->find_active_node();
}
// Check that we found an active child node
if ($child!==false) {
$properties = array();
// Check whether this child contains another active child node
// this can happen if we are looking at a module
if ($child->contains_active_node()) {
$titlebits = array();
// Loop while the child contains active nodes and in each iteration
// find the next node in the correct direction
while ($child!==null && $child->contains_active_node()) {
if (!empty($child->shorttext)) {
$titlebits[] = $child->shorttext;
} else {
$titlebits[] = $child->text;
}
foreach ($child->children as $child) {
if ($child->contains_active_node() || $child->isactive) {
// We have found the active child or one of its parents
// so break the foreach so we can proceed in the while
break;
}
}
}
if (!empty($child->shorttext)) {
$titlebits[] = $child->shorttext;
} else {
$titlebits[] = $child->text;
}
$properties['text'] = join(' - ', $titlebits);
$properties['shorttext'] = join(' - ', $titlebits);
} else {
$properties['text'] = $child->text;
$properties['shorttext'] = $child->shorttext;
}
$properties['action'] = $child->action;
$properties['key'] = $child->key;
$properties['type'] = $child->type;
$properties['icon'] = $child->icon;
// Create a new navigation node object free of the main structure
// so that it is easily storeable and customised
$child = new navigation_node($properties);
// Check that this page isn't already in the history array. If it is
// we will remove it so that it gets added at the top and we dont get
// duplicate entries
foreach ($history as $key=>$node) {
if ($node->key == $child->key && $node->type == $child->type) {
if ($node->action instanceof moodle_url && $child->action instanceof moodle_url && $node->action->compare($child->action)) {
unset($history[$key]);
} else if ($child->action instanceof moodle_url && $child->action->out(true) == $node->action) {
unset($history[$key]);
} else if ($child->action == $node->action) {
unset($history[$key]);
}
}
}
// If there is more than 5 elements in the array remove the first one
// We want a fifo array
if (count($history) > 5) {
array_shift($history);
}
$child->nodetype = navigation_node::NODETYPE_LEAF;
$child->children = array();
// Add the child to the history array
array_push($history,$child);
}
// If we have `more than nothing` in the history display it :D
if ($historycount > 0) {
// Add a branch to hold the users history
$myhistorybranch = $PAGE->navigation->add(get_string('showmyhistorytitle', $this->blockname), null, 'myhistory',navigation_node::TYPE_CATEGORY);
$PAGE->navigation->get($myhistorybranch)->children = array_reverse($history);
}
// Cache the history (or update the cached history as it is)
$cache->history = $history;
return true;
}
/**
* This function loads the users my courses array into the navigation
*
* @return bool
*/
protected function showmycourses() {
global $USER, $PAGE;
// Create a navigation cache to point at the same node as the main navigation
// cache
$cache = new navigation_cache('navigation');
// If the user isn't logged in or is a guest we don't want to display anything
if (!isloggedin() || isguest()) {
return false;
}
// Check the cache to see if we have loaded my courses already
// there is a very good chance that we have
if (!$cache->cached('mycourses')) {
$cache->mycourses = get_my_courses($USER->id);
}
$courses = $cache->mycourses;
// If no courses to display here, return before adding anything
if (!is_array($courses) || count($courses)==0) {
return false;
}
// Add a branch labelled something like My Courses
$mycoursesbranch = $PAGE->navigation->add(get_string('mycourses'), null, 'mycourses',navigation_node::TYPE_CATEGORY);
$PAGE->navigation->add_courses($courses, $mycoursesbranch);
return true;
}
/**
* This function searches all branches and removes any empty section branches
* for the global navigation structure. This is usually called by the global
* navigation block based on a block setting
*/
protected function remove_empty_section_branches() {
global $PAGE;
$cache = new navigation_cache('navigation');
$course = &$PAGE->navigation->find_active_node(navigation_node::TYPE_COURSE);
if ($course===false || !$cache->cached('modinfo'.$course->key) || !$cache->cached('coursesections'.$course->key)) {
return 0;
}
$sectionstoremove = array();
$coursesections = $cache->{'coursesections'.$course->key};
$modinfosections = $cache->{'modinfo'.$course->key}->sections;
foreach ($coursesections as $id=>$section) {
if (!array_key_exists($id, $modinfosections)) {
$sectionstoremove[] = $section->id;
}
}
foreach ($course->children as $key=>$node) {
if ($node->type == navigation_node::TYPE_SECTION && in_array($node->key, $sectionstoremove)) {
$course->remove_child($key);
}
}
}
}
@@ -0,0 +1,57 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file keeps track of upgrades to the global_navigation_tree block
*
* Sometimes, changes between versions involve alterations to database structures
* and other major things that may break installations.
*
* The upgrade function in this file will attempt to perform all the necessary
* actions to upgrade your older installtion to the current version.
*
* If there's something it cannot do itself, it will tell you what you need to do.
*
* The commands in here will all be database-neutral, using the methods of
* database_manager class
*
* Please do not forget to use upgrade_set_timeout()
* before any action that may take longer time to finish.
*
* @since 2.0
* @package blocks
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* As of the implementation of this block and the general navigation code
* in Moodle 2.0 the body of immediate upgrade work for this block and
* settings_navigation_tree is done in core upgrade {@see lib/db/upgrade.php}
*
* There were several reasons that they were put there and not here, both becuase
* the process for the two blocks was very similar and because the upgrade process
* was complex due to us wanting to remvoe the outmoded blocks that this
* block was going to replace.
*
* @param int $oldversion
* @param object $block
*/
function xmldb_block_global_navigation_tree_upgrade($oldversion, $block) {
// Implemented at 2009082800
return true;
}
@@ -0,0 +1,67 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Form for editing global navigation instances.
*
* @since 2.0
* @package blocks
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Form for editing global navigation instances.
*
* @package blocks
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class block_global_navigation_tree_edit_form extends block_edit_form {
protected function specific_definition($mform) {
global $CFG;
$mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
$options = array();
$options['0'] = get_string('everything', $this->block->blockname);
$options[global_navigation::TYPE_COURSE] = get_string('courses', $this->block->blockname);
$options[global_navigation::TYPE_SECTION] = get_string('coursestructures', $this->block->blockname);
$options[global_navigation::TYPE_ACTIVITY] = get_string('courseactivities', $this->block->blockname);
$mform->addElement('select', 'config_expansionlimit', get_string('expansionlimit', $this->block->blockname), $options);
if (isset($this->block->config->expansionlimit) && $this->block->config->expansionlimit!='0') {
$mform->getElement('config_expansionlimit')->setSelected($this->block->config->expansionlimit);
} else {
$mform->getElement('config_expansionlimit')->setSelected('0');
}
$mform->setType('expansionlimit', PARAM_MULTILANG);
$mods = array('showemptybranches'=>'no','enablesidebarpopout'=>'yes', 'enablehoverexpansion'=>'no', 'showmycourses'=>'yes', 'showmyhistory'=>'no');
$yesnooptions = array('yes'=>get_string('yes'), 'no'=>get_string('no'));
foreach ($mods as $modname=>$default) {
$mform->addElement('select', 'config_'.$modname, get_string($modname.'desc', $this->block->blockname), $yesnooptions);
if (isset($this->block->config->{$modname}) && $this->block->config->{$modname}!=$default) {
if ($default=='no') {
$mform->getElement('config_'.$modname)->setSelected('yes');
} else {
$mform->getElement('config_'.$modname)->setSelected('no');
}
} else {
$mform->getElement('config_'.$modname)->setSelected($default);
}
}
}
}
+71 -2
View File
@@ -33,6 +33,10 @@ define('BLOCK_TYPE_LIST', 1);
* Block type of text. Contents of block should be set to standard html text in the content object as items ($this->content->text). Optionally include footer text in $this->content->footer.
*/
define('BLOCK_TYPE_TEXT', 2);
/**
* Block type of tree. $this->content->items is a list of tree_item objects and $this->content->footer is a string.
*/
define('BLOCK_TYPE_TREE', 3);
/**
* Class for describing a moodle block, all Moodle blocks derive from this class
@@ -440,7 +444,7 @@ class block_base {
$errors[] = 'title_not_set';
$correct = false;
}
if (!in_array($this->get_content_type(), array(BLOCK_TYPE_LIST, BLOCK_TYPE_TEXT))) {
if (!in_array($this->get_content_type(), array(BLOCK_TYPE_LIST, BLOCK_TYPE_TEXT, BLOCK_TYPE_TREE))) {
$errors[] = 'invalid_content_type';
$correct = false;
}
@@ -520,6 +524,20 @@ class block_base {
/**
* Return any HTML attributes that you want added to the outer <div> that
* of the block when it is output.
*
* Because of the way certain JS events are wired it is a good idea to ensure
* that the default values here still get set.
* I found the easiest way to do this and still set anything you want is to
* override it within your block in the following way
*
* <code php>
* function html_attributes() {
* $attributes = parent::html_attributes();
* $attributes['class'] .= ' mynewclass';
* return $attributes;
* }
* </code>
*
* @return array attribute name => value.
*/
function html_attributes() {
@@ -767,4 +785,55 @@ class block_list extends block_base {
}
}
?>
/**
* Specialized class for displaying a tree menu.
*
* The {@link get_content()} method involves setting the content of
* <code>$this->content->items</code> with an array of {@link tree_item}
* objects (these are the top-level nodes). The {@link tree_item::children}
* property may contain more tree_item objects, and so on. The tree_item class
* itself is abstract and not intended for use, use one of it's subclasses.
*
* Unlike {@link block_list}, the icons are specified as part of the items,
* not in a separate array.
*
* @author Alan Trick
* @package blocks
* @internal this extends block_list so we get is_empty() for free
*/
class block_tree extends block_list {
/**
* @var int specifies the manner in which contents should be added to this
* block type. In this case <code>$this->content->items</code> is used with
* {@link tree_item}s.
*/
public $content_type = BLOCK_TYPE_TREE;
/**
* Make the formatted HTML ouput.
*
* Also adds the required javascript call to the page output.
*
* @param moodle_core_renderer $output
* @return string HTML
*/
protected function formatted_contents($output) {
// based of code in admin_tree
global $PAGE; // TODO change this when there is a proper way for blocks to get stuff into head.
static $eventattached;
if ($eventattached===null) {
$eventattached = true;
}
if (!$this->content) {
$this->content = new stdClass;
$this->content->items = array();
}
$this->get_content();
$content = $output->tree_block_contents($this->content->items,array('class'=>'block_tree'));
if (isset($this->id) && !is_numeric($this->id)) {
$content = $output->box($content, 'block_tree_box', $this->id);
}
return $content;
}
}
+10 -20
View File
@@ -166,20 +166,14 @@ if (!$managesharedfeeds) {
}
$urlparams = array('rssid' => $rssid);
$manageparams = array();
if ($courseid) {
$urlparams['courseid'] = $courseid;
$manageparams[] = 'courseid=' . $courseid;
}
if ($returnurl) {
$urlparams['returnurl'] = $returnurl;
$manageparams = 'returnurl=' . $returnurl;
}
if ($manageparams) {
$manageparams = '?' . implode('&', $manageparams);
} else {
$manageparams = '';
}
$managefeeds = new moodle_url($CFG->wwwroot . '/blocks/rss_client/managefeeds.php', $urlparams);
$PAGE->set_url('blocks/rss_client/editfeed.php', $urlparams);
$PAGE->set_generaltype('form');
@@ -195,7 +189,7 @@ $mform = new feed_edit_form($PAGE->url, $isadding, $managesharedfeeds);
$mform->set_data($rssrecord);
if ($mform->is_cancelled()) {
redirect($CFG->wwwroot . '/blocks/rss_client/managefeeds.php' . $manageparams);
redirect($managefeeds);
} else if ($data = $mform->get_data()) {
$data->userid = $USER->id;
@@ -210,7 +204,7 @@ if ($mform->is_cancelled()) {
$DB->update_record('block_rss_client', $data);
}
redirect($CFG->wwwroot . '/blocks/rss_client/managefeeds.php' . $manageparams);
redirect($managefeeds);
} else {
if ($isadding) {
@@ -222,17 +216,13 @@ if ($mform->is_cancelled()) {
$PAGE->set_title($strtitle);
$PAGE->set_heading($strtitle);
$navlinks = array(
array('name' => get_string('administration'), 'link' => "$CFG->wwwroot/$CFG->admin/index.php", 'type' => 'misc'),
array('name' => get_string('managemodules'), 'link' => null, 'type' => 'misc'),
array('name' => get_string('blocks'), 'link' => null, 'type' => 'misc'),
array('name' => get_string('feedstitle', 'block_rss_client'), 'link' => "$CFG->wwwroot/$CFG->admin/settings.php?section=blocksettingrss_client", 'type' => 'misc'),
array('name' => get_string('managefeeds', 'block_rss_client'), 'link' => $CFG->wwwroot . '/blocks/rss_client/managefeeds.php' . $manageparams, 'type' => 'misc'),
array('name' => $strtitle, 'link' => null, 'type' => 'misc'),
);
$navigation = build_navigation($navlinks);
$settingsurl = new moodle_url($CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section=blocksettingrss_client');
$PAGE->navbar->add(get_string('blocks'));
$PAGE->navbar->add(get_string('feedstitle', 'block_rss_client'), null, null, navbar::TYPE_SETTING, $settingsurl);
$PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'));
$PAGE->navbar->add($strtitle);
echo $OUTPUT->header($navigation);
echo $OUTPUT->header();
echo $OUTPUT->heading($strtitle, 2);
$mform->display();
+6 -10
View File
@@ -82,16 +82,12 @@ $PAGE->set_generaltype('form');
$PAGE->set_title($strmanage);
$PAGE->set_heading($strmanage);
$navlinks = array(
array('name' => get_string('administration'), 'link' => "$CFG->wwwroot/$CFG->admin/index.php", 'type' => 'misc'),
array('name' => get_string('managemodules'), 'link' => null, 'type' => 'misc'),
array('name' => get_string('blocks'), 'link' => null, 'type' => 'misc'),
array('name' => get_string('feedstitle', 'block_rss_client'), 'link' => "$CFG->wwwroot/$CFG->admin/settings.php?section=blocksettingrss_client", 'type' => 'misc'),
array('name' => get_string('managefeeds', 'block_rss_client'), 'link' => null, 'type' => 'misc'),
);
$navigation = build_navigation($navlinks);
echo $OUTPUT->header($navigation);
$settingsurl = new moodle_url($CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section=blocksettingrss_client');
$managefeeds = new moodle_url($CFG->wwwroot . '/blocks/rss_client/managefeeds.php', $urlparams);
$PAGE->navbar->add(get_string('blocks'));
$PAGE->navbar->add(get_string('feedstitle', 'block_rss_client'), null, null, navbar::TYPE_SETTING, $settingsurl);
$PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'), null, null, navbar::TYPE_SETTING, $managefeeds);
echo $OUTPUT->header();
$table = new flexible_table('rss-display-feeds');
+7 -20
View File
@@ -48,19 +48,11 @@ if ($courseid) {
}
$urlparams = array('rssid' => $rssid);
$manageparams = array();
if ($courseid) {
$urlparams['courseid'] = $courseid;
$manageparams[] = 'courseid=$courseid';
}
if ($returnurl) {
$urlparams['returnurl'] = $returnurl;
$manageparams = 'returnurl=' . $returnurl;
}
if ($manageparams) {
$manageparams = '?' . implode('&', $manageparams);
} else {
$manageparams = '';
}
$PAGE->set_url('blocks/rss_client/viewfeed.php', $urlparams);
$PAGE->set_generaltype('popup');
@@ -79,18 +71,13 @@ $strviewfeed = get_string('viewfeed', 'block_rss_client');
$PAGE->set_title($strviewfeed);
$PAGE->set_heading($strviewfeed);
$navlinks = array(
array('name' => get_string('administration'), 'link' => "$CFG->wwwroot/$CFG->admin/index.php", 'type' => 'misc'),
array('name' => get_string('managemodules'), 'link' => null, 'type' => 'misc'),
array('name' => get_string('blocks'), 'link' => null, 'type' => 'misc'),
array('name' => get_string('feedstitle', 'block_rss_client'), 'link' => "$CFG->wwwroot/$CFG->admin/settings.php?section=blocksettingrss_client", 'type' => 'misc'),
array('name' => get_string('managefeeds', 'block_rss_client'), 'link' => $CFG->wwwroot . '/blocks/rss_client/managefeeds.php' . $manageparams, 'type' => 'misc'),
array('name' => $strviewfeed, 'link' => null, 'type' => 'misc'),
);
$navigation = build_navigation($navlinks);
echo $OUTPUT->header($navigation);
$settingsurl = new moodle_url($CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section=blocksettingrss_client');
$managefeeds = new moodle_url($CFG->wwwroot . '/blocks/rss_client/managefeeds.php', $urlparams);
$PAGE->navbar->add(get_string('blocks'));
$PAGE->navbar->add(get_string('feedstitle', 'block_rss_client'), null, null, navbar::TYPE_SETTING, $settingsurl);
$PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'));
$PAGE->navbar->add($strviewfeed);
echo $OUTPUT->header();
if (!empty($rssrecord->preferredtitle)) {
$feedtitle = $rssrecord->preferredtitle;
@@ -0,0 +1,149 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains classes used to manage the navigation structures in Moodle
* and was introduced as part of the changes occuring in Moodle 2.0
*
* @since 2.0
* @package blocks
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* The settings navigation tree block class
*
* Used to produce the settings navigation block new to Moodle 2.0
*
* @package blocks
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class block_settings_navigation_tree extends block_tree {
/** @var string */
public static $navcount;
public $blockname = null;
protected $contentgenerated = false;
public $id = null;
/**
* Set the initial properties for the block
*/
function init() {
$this->blockname = get_class($this);
$this->title = get_string('blockname', $this->blockname);
$this->version = 2009082800;
}
/**
* All multiple instances of this block
* @return bool Returns true
*/
function instance_allow_multiple() {
return false;
}
/**
* Set the applicable formats for this block to all
* @return array
*/
function applicable_formats() {
return array('all' => true);
}
/**
* Allow the user to configure a block instance
* @return bool Returns true
*/
function instance_allow_config() {
return true;
}
/**
* Gets the content for this block by grabbing it from $this->page
*/
function get_content() {
global $CFG, $OUTPUT;
// First check if we have already generated, don't waste cycles
if ($this->contentgenerated === true) {
return true;
}
$this->page->requires->js('lib/javascript-navigation.js');
block_settings_navigation_tree::$navcount++;
$tooglesidetabdisplay = get_string('tooglesidetabdisplay', $this->blockname);
$toogleblockdisplay = get_string('toogleblockdisplay', $this->blockname);
$args = array('instance'=>$this->instance->id);
$args['tooglesidetabdisplay'] = $tooglesidetabdisplay;
$args['toogleblockdisplay'] = $toogleblockdisplay;
// Give JS some information we will use within the JS tree object
$this->page->requires->data_for_js('settingsnav'.block_settings_navigation_tree::$navcount, $args);
$this->id = 'settingsnav'.block_settings_navigation_tree::$navcount;
$this->page->requires->js_function_call('setup_new_navtree', array($this->id))->on_dom_ready();
// Grab the children from settings nav, we have more than one root node
// and we dont want to show the site node
$this->content->items = $this->page->settingsnav->children;
// only do search if you have moodle/site:config
if (count($this->content->items)>0) {
if (has_capability('moodle/site:config',get_context_instance(CONTEXT_SYSTEM)) ) {
$this->content->footer =
'<div class="adminsearchform">'.
'<form action="'.$CFG->wwwroot.'/'.$CFG->admin.'/search.php" method="get"><div>'.
'<label for="query" class="accesshide">'.get_string('searchinsettings', 'admin').'</label>'.
'<input type="text" name="query" id="query" size="8" value="'.s(optional_param('query', '')).'" />'.
'<input type="submit" value="'.get_string('search').'" /></div>'.
'</form></div>';
} else {
$this->content->footer = '';
}
$url = $this->page->url;
$url->param('regenerate','navigation');
$reloadstr = get_string('reload');
$this->content->footer .= '<a href="'.$url->out().'" class="customcommand"><img src="'.$OUTPUT->old_icon_url('t/reload').'" alt="'.$reloadstr.'" title="'.$reloadstr.'" /></a>';
if (!empty($this->config->enablesidebarpopout) && $this->config->enablesidebarpopout == 'yes') {
user_preference_allow_ajax_update('nav_in_tab_panel_settingsnav'.block_settings_navigation_tree::$navcount, PARAM_INT);
if (get_user_preferences('nav_in_tab_panel_settingsnav'.block_settings_navigation_tree::$navcount, 0)) {
$icon = $OUTPUT->old_icon_url('t/movetoblock');
$string = $toogleblockdisplay;
} else {
$icon = $OUTPUT->old_icon_url('t/movetosidetab');
$string = $tooglesidetabdisplay;
}
$this->content->footer .= '<a class="moveto customcommand requiresjs"><img src="'.$icon.'" alt="'.$string.'" title="'.$string.'"></a>';
}
}
$this->contentgenerated = true;
return true;
}
function html_attributes() {
$attributes = parent::html_attributes();
if (!empty($this->config->enablehoverexpansion) && $this->config->enablehoverexpansion == 'yes') {
$attributes['class'] .= ' sideblock_js_expansion';
}
if (get_user_preferences('nav_in_tab_panel_settingsnav'.block_settings_navigation_tree::$navcount, 0)) {
$attributes['class'] .= ' sideblock_js_sidebarpopout';
}
return $attributes;
}
}
@@ -0,0 +1,54 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Form for editing settings navigation instances.
*
* @since 2.0
* @package blocks
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Form for setting navigation instances.
*
* @package blocks
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class block_settings_navigation_tree_edit_form extends block_edit_form {
protected function specific_definition($mform) {
$mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
$yesnooptions = array('yes'=>get_string('yes'), 'no'=>get_string('no'));
$mform->addElement('select', 'config_enablehoverexpansion', get_string('enablehoverexpansion', $this->block->blockname), $yesnooptions);
if (empty($this->block->config->enablehoverexpansion) || $this->block->config->enablehoverexpansion=='no') {
$mform->getElement('config_enablehoverexpansion')->setSelected('no');
} else {
$mform->getElement('config_enablehoverexpansion')->setSelected('yes');
}
$mform->addElement('select', 'config_enablesidebarpopout', get_string('enablesidebarpopout', $this->block->blockname), $yesnooptions);
if (empty($this->block->config->enablesidebarpopout) || $this->block->config->enablesidebarpopout=='no') {
$mform->getElement('config_enablesidebarpopout')->setSelected('no');
} else {
$mform->getElement('config_enablesidebarpopout')->setSelected('yes');
}
}
}
+1 -6
View File
@@ -142,11 +142,6 @@
$strcategory = get_string('category');
$strcourses = get_string('courses');
$navlinks = array();
$navlinks[] = array('name' => $strcategories, 'link' => 'index.php', 'type' => 'misc');
$navlinks[] = array('name' => format_string($category->name), 'link' => null, 'type' => 'misc');
$navigation = build_navigation($navlinks);
if ($editingon && can_edit_in_category()) {
// Integrate into the admin tree only if the user can edit categories at the top level,
// otherwise the admin block does not appear to this user, and you get an error.
@@ -156,7 +151,7 @@
admin_externalpage_print_header();
} else {
$navbaritem = print_course_search('', true, 'navbar');
print_header("$site->shortname: $category->name", "$site->fullname: $strcourses", $navigation, '', '', true, $navbaritem);
print_header("$site->shortname: $category->name", "$site->fullname: $strcourses", array(), '', '', true, $navbaritem);
}
/// Print link to roles
+1 -2
View File
@@ -6,7 +6,6 @@
// social format.
//
// The default blocks layout for this course format:
$format['defaultblocks'] = 'participants,social_activities,admin,course_list:'.
'news_items,recent_activity,calendar_upcoming';
$format['defaultblocks'] = ':news_items,recent_activity,calendar_upcoming';
?>
+55
View File
@@ -0,0 +1,55 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains general functions for the course format SCORM
*
* @since 2.0
* @package moodlecore
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* The string that is used to describe a section of the course
* e.g. Topic, Week...
*
* @return string
*/
function callback_scorm_definition() {
return get_string('scorm');
}
/**
* The GET argument variable that is used to identify the section being
* viewed by the user (if there is one)
*
* @return string
*/
function callback_scorm_request_keyscorm() {
return 'scorm';
}
/**
* Toogle display of course contents (sections, activities)
*
* @return bool
*/
function callback_scorm_display_content() {
return false;
}
?>
+1 -2
View File
@@ -6,7 +6,6 @@
// social format.
//
// The default blocks layout for this course format:
$format['defaultblocks'] = 'participants,search_forums,calendar_upcoming,'.
'social_activities,recent_activity,admin,course_list';
$format['defaultblocks'] = ':search_forums,calendar_upcoming,social_activities,recent_activity,admin,course_list';
?>
+83
View File
@@ -0,0 +1,83 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains general functions for the course format Social
*
* @since 2.0
* @package moodlecore
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Used to display the course structure for a course where format=social
*
* This is called automatically by {@link load_course()} if the current course
* format = weeks.
*
* @param array $path An array of keys to the course node in the navigation
* @param stdClass $modinfo The mod info object for the current course
* @return bool Returns true
*/
function load_course_format_social(&$navigation, $keys, $course) {
$navigation->add_course_section_generic($keys, $course, get_string('social'), 'social');
}
/**
* Used to display the course structure for a course where format=social
*
* This is called automatically by {@link load_course()} if the current course
* format = weeks and the navigation was requested via AJAX
*
* @param array $path An array of keys to the course node in the navigation
* @param stdClass $modinfo The mod info object for the current course
* @return bool Returns true
*/
function limited_load_section_social(&$navigation, $keys, $course, $section) {
$navigation->limited_load_section_generic($keys, $course, $section, get_string('social'), 'social');
}
/**
* The string that is used to describe a section of the course
* e.g. Topic, Week...
*
* @return string
*/
function callback_social_definition() {
return get_string('social');
}
/**
* The GET argument variable that is used to identify the section being
* viewed by the user (if there is one)
*
* @return string
*/
function callback_social_request_key() {
return 'social';
}
/**
* Toogle display of course contents (sections, activities)
*
* @return bool
*/
function callback_social_display_content() {
return false;
}
?>
+1 -3
View File
@@ -6,8 +6,6 @@
// format.
//
// The default blocks layout for this course format:
$format['defaultblocks'] = 'participants,activity_modules,search_forums,'.
'admin,course_list:news_items,calendar_upcoming,'.
'recent_activity';
$format['defaultblocks'] = ':search_forums,news_items,calendar_upcoming,recent_activity';
//
?>
+73
View File
@@ -0,0 +1,73 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains general functions for the course format Topic
*
* @since 2.0
* @package moodlecore
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Used to display the course structure for a course where format=topic
*
* This is called automatically by {@link load_course()} if the current course
* format = weeks.
*
* @param array $path An array of keys to the course node in the navigation
* @param stdClass $modinfo The mod info object for the current course
* @return bool Returns true
*/
function callback_topics_load_content(&$navigation, $keys, $course) {
$navigation->add_course_section_generic($keys, $course, get_string('topic'), 'topic');
}
/**
* Used to display the course structure for a course where format=topic
*
* This is called automatically by {@link load_course()} if the current course
* format = weeks and the navigation was requested via AJAX
*
* @param array $path An array of keys to the course node in the navigation
* @param stdClass $modinfo The mod info object for the current course
* @return bool Returns true
*/
function callback_topics_load_limited_section(&$navigation, $keys, $course, $section) {
$navigation->limited_load_section_generic($keys, $course, $section, get_string('topic'), 'topic');
}
/**
* The string that is used to describe a section of the course
* e.g. Topic, Week...
*
* @return string
*/
function callback_topics_definition() {
return get_string('topic');
}
/**
* The GET argument variable that is used to identify the section being
* viewed by the user (if there is one)
*
* @return string
*/
function callback_topics_request_key() {
return 'topic';
}
?>
+1 -3
View File
@@ -6,8 +6,6 @@
// format.
//
// The default blocks layout for this course format:
$format['defaultblocks'] = 'participants,activity_modules,search_forums,'.
'admin,course_list:news_items,calendar_upcoming,'.
'recent_activity';
$format['defaultblocks'] = ':search_forums,news_items,calendar_upcoming,recent_activity';
//
?>
+73
View File
@@ -0,0 +1,73 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains general functions for the course format Week
*
* @since 2.0
* @package moodlecore
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Used to display the course structure for a course where format=weeks
*
* This is called automatically by {@link load_course()} if the current course
* format = weeks.
*
* @param array $path An array of keys to the course node in the navigation
* @param stdClass $modinfo The mod info object for the current course
* @return bool Returns true
*/
function callback_weeks_load_content(&$navigation, $keys, $course) {
$navigation->add_course_section_generic($keys, $course, get_string('week'), 'week');
}
/**
* Used to display the course structure for a course where format=weeks
*
* This is called automatically by {@link load_course()} if the current course
* format = weeks and the navigation was requested via AJAX
*
* @param array $path An array of keys to the course node in the navigation
* @param stdClass $modinfo The mod info object for the current course
* @return bool Returns true
*/
function callback_weeks_load_limited_section(&$navigation, $keys, $course, $section) {
$navigation->limited_load_section_generic($keys, $course, $section, get_string('week'), 'week');
}
/**
* The string that is used to describe a section of the course
* e.g. Topic, Week...
*
* @return string
*/
function callback_weeks_definition() {
return get_string('week');
}
/**
* The GET argument variable that is used to identify the section being
* viewed by the user (if there is one)
*
* @return string
*/
function callback_weeks_request_key() {
return 'week';
}
?>
+3 -1
View File
@@ -204,7 +204,9 @@
$navlinks = array();
$navlinks[] = array('name' => $strcourses, 'link' => 'index.php', 'type' => 'misc');
$navlinks[] = array('name' => $strsearch, 'link' => 'search.php', 'type' => 'misc');
$navlinks[] = array('name' => "'".s($search)."'", 'link' => null, 'type' => 'misc');
if (!empty($search)) {
$navlinks[] = array('name' => "'".s($search)."'", 'link' => null, 'type' => 'misc');
}
$navigation = build_navigation($navlinks);
print_header("$site->fullname : $strsearchresults", $site->fullname, $navigation, "", "", "", $searchform);
+84
View File
@@ -0,0 +1,84 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* The purpose of this file is to allow the user to switch roles and be redirected
* back to the page that they were on.
*
* This functionality is also supported in {@link /course/view.php} in order to comply
* with backwards compatibility
* The reason that we created this file was so that user didn't get redirected back
* to the course view page only to be redirected again.
*
* @since 2.0
* @package moodlecore
* @subpackage navigation
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once('../config.php');
require_once($CFG->dirroot.'/course/lib.php');
$id = required_param('id', PARAM_INT);
$switchrole = optional_param('switchrole',-1, PARAM_INT);
$returnurlkey = optional_param('returnurl', false, PARAM_INT);
if (!confirm_sesskey()) {
print_error('confirmsesskeybad', 'error');
}
if (! ($course = $DB->get_record('course', array('id'=>$id)))) {
print_error('invalidcourseid', 'error');
}
if (!$context = get_context_instance(CONTEXT_COURSE, $course->id)) {
print_error('nocontext');
}
// Remove any switched roles before checking login
if ($switchrole == 0) {
role_switch($switchrole, $context);
}
require_login($course);
// Switchrole - sanity check in cost-order...
if ($switchrole > 0 && has_capability('moodle/role:switchroles', $context)) {
// is this role assignable in this context?
// inquiring minds want to know...
$aroles = get_switchable_roles($context);
if (is_array($aroles) && isset($aroles[$switchrole])) {
role_switch($switchrole, $context);
// Double check that this role is allowed here
require_login($course);
}
}
$returnurl = false;
if ($returnurlkey && !empty($SESSION->returnurl) && strpos($SESSION->returnurl, 'moodle_url')!==false) {
$returnurl = @unserialize($SESSION->returnurl);
if (!($returnurl instanceof moodle_url)) {
$returnurl = false;
}
unset($SESSION->returnurl);
}
if ($returnurl===false) {
$returnurl = new moodle_url('/course/view.php', array('id'=>$course->id));
}
redirect($returnurl);
?>
+1 -1
View File
@@ -87,7 +87,7 @@
$editing = $PAGE->user_is_editing();
$PAGE->set_title($SITE->fullname);
$PAGE->set_heading($SITE->fullname);
echo $OUTPUT->header('', user_login_string($SITE) . $langmenu);
echo $OUTPUT->header(user_login_string($SITE) . $langmenu);
/// Print Section
if ($SITE->numsections > 0) {
+3
View File
@@ -614,6 +614,9 @@ $string['mymoodle'] = 'My Moodle';
$string['mymoodleredirect'] = 'Force users to use My Moodle';
$string['mysql416bypassed'] = 'However, if your site is using iso-8859-1 (latin) languages ONLY, you may continue using your currently installed MySQL 4.1.12 (or higher).';
$string['mysql416required'] = 'MySQL 4.1.16 is the minimum version required for Moodle 1.6 in order to guarantee that all data can be converted to UTF-8 in the future.';
$string['navigationupgrade'] = 'This upgrade introduces two new navigation blocks that will replace these blocks: Administration, Courses, Activities and Participants. If you had set any special permissions on those blocks you should check to make sure everything
is behaving as you want it.<br /><br />
You should also "Shift-Refresh" your browser to load the new styles, otherwise the new blocks will not work correctly.';
$string['nobookmarksforuser'] = 'You do not have any bookmarks.';
$string['nochanges'] = 'No changes';
$string['nodatabase'] = 'No database';
@@ -0,0 +1,40 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains language strings used in the global navigation block
*
* @since 2.0
* @package blocks
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['blockname'] = 'Navigation';
$string['expansionlimit'] = 'Generate navigation for the following';
$string['everything'] = 'Everything';
$string['courses'] = 'Categories and courses';
$string['coursestructures'] = 'Categories, courses, and course structures';
$string['courseactivities'] = 'Categories, courses, and course Activities';
$string['showemptybranchesdesc'] = 'Show empty course section branches';
$string['showmycoursesdesc'] = 'Show my courses in the navigation';
$string['enablehoverexpansiondesc'] = 'Enable mouseover expansion of this block';
$string['enablesidebarpopoutdesc'] = 'Allow the user to switch the block to a sidbar popout';
$string['showmyhistorydesc'] = 'Show my history as a branch in the navigation';
$string['showmyhistorytitle'] = 'My history';
$string['toogleblockdisplay'] = 'Move to block position';
$string['tooglesidetabdisplay'] = 'Move to side panel tab';
@@ -0,0 +1,31 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains language strings used in the settings navigation block
*
* @since 2.0
* @package blocks
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['blockname'] = 'Settings';
$string['enablehoverexpansion'] = 'Enable mouseover expansion of this block';
$string['enablesidebarpopout'] = 'Allow the user to switch the block to a sidbar popout';
$string['toogleblockdisplay'] = 'Move to block position';
$string['tooglesidetabdisplay'] = 'Move to side panel tab';
+3 -1
View File
@@ -126,6 +126,7 @@ $string['forcessubscribe'] = 'This forum forces everyone to be subscribed';
$string['forcesubscribe'] = 'Force everyone to be subscribed';
$string['forcesubscribeq'] = 'Force everyone to be subscribed?';
$string['forum'] = 'Forum';
$string['forumadministration'] = 'Forum Administration';
$string['forum:addnews'] = 'Add news';
$string['forumauthorhidden'] = 'Author (hidden)';
$string['forumblockingalmosttoomanyposts'] = 'You are approaching the posting threshold. You have posted $a->numposts times in the last $a->blockperiod and the limit is $a->blockafter posts.';
@@ -350,6 +351,7 @@ $string['unsubscribeallempty'] = 'Sorry, you are not subscribed to any forums. I
$string['unsubscribed'] = 'Unsubscribed';
$string['unsubscribeshort'] = 'Unsubscribe';
$string['usermarksread'] = 'Manual message read marking';
$string['viewalldiscussions'] = 'View all discussions';
$string['warnafter'] = 'Post threshold for warning';
$string['yesforever'] = 'Yes, forever';
$string['yesinitially'] = 'Yes, initially';
@@ -357,4 +359,4 @@ $string['youratedthis'] = 'You rated this';
$string['yournewquestion'] = 'Your new question';
$string['yournewtopic'] = 'Your new discussion topic';
$string['yourreply'] = 'Your reply';
?>
?>
+7
View File
@@ -275,6 +275,7 @@ $string['costdefault'] = 'Default cost';
$string['counteditems'] = '$a->count $a->items';
$string['country'] = 'Country';
$string['course'] = 'Course';
$string['courseadministration'] = 'Course Administration';
$string['courseapprovedemail'] = 'Your requested course, $a->name, has been approved and you have been made a $a->teacher. To access your new course, go to $a->url';
$string['courseapprovedemail2'] = 'Your requested course, $a->name, has been approved. To access your new course, go to $a->url';
$string['courseapprovedfailed'] = 'Failed to save the course as approved!';
@@ -731,6 +732,7 @@ $string['frontpagedescriptionhelp'] = 'This description of the site will be disp
$string['frontpageformat'] = 'Front page format';
$string['frontpageformatloggedin'] = 'Front page format when logged in';
$string['frontpagenews'] = 'News items';
$string['frontpagesettings'] = 'Front Page Settings';
$string['frontpagetopiconly'] = 'Topic section';
$string['fulllistofcourses'] = 'All courses';
$string['fullname'] = 'Full name';
@@ -1034,6 +1036,7 @@ $string['moreinformation'] = 'More information about this error';
$string['moreprofileinfoneeded'] = 'Please tell us more about yourself';
$string['mostrecently'] = 'most recently';
$string['move'] = 'Move';
$string['moveallsidetabstoblock'] = 'Move all tabs back to their block position';
$string['movecategoryto'] = 'Move category to:';
$string['movecategorycontentto'] = 'Move into';
$string['movecontentstoanothercategory'] = 'Move contents to another category';
@@ -1355,6 +1358,7 @@ $string['restoretositeadding'] = 'Warning: You are about to restore to the site
$string['restoretositedeleting'] = 'Warning: You are about to restore to the site front page, deleting data from it first!';
$string['restricted'] = 'Restricted';
$string['restrictmodules'] = 'Restrict activity modules?';
$string['returntooriginaluser'] = 'Return to $a';
$string['returningtosite'] = 'Returning to this web site?';
$string['revert'] = 'Revert';
$string['role'] = 'Role';
@@ -1657,6 +1661,8 @@ $string['used'] = 'Used';
$string['usedinnplaces'] = 'Used in $a places';
$string['usemessageform'] = 'or use the form below to send a message to the selected students';
$string['user'] = 'User';
$string['usercurrentsettings'] = 'My profile settings';
$string['userviewingsettings'] = 'Profile for $a';
$string['userconfirmed'] = 'Confirmed $a';
$string['userdata'] = 'User Data';
$string['userdeleted'] = 'This user account has been deleted';
@@ -1687,6 +1693,7 @@ $string['valuealreadyused'] = 'This value has already been used.';
$string['version'] = 'Version';
$string['view'] = 'View';
$string['viewfileinpopup'] = 'View file in a popup window';
$string['viewmyprofile'] = 'View my profile';
$string['views'] = 'Views';
$string['viewsolution'] = 'view solution';
$string['virusfound'] = 'Attention administrator! Clam AV has found a virus in a file uploaded by $a->user for the course $a->course. Here is the output of clamscan:';
+3 -7
View File
@@ -5082,13 +5082,7 @@ function admin_externalpage_print_header($focus='') {
$buttons = $OUTPUT->button(html_form::make_button($PAGE->url->out(false), $options, $caption, 'get'));
}
$navlinks = array();
foreach ($visiblepathtosection as $element) {
$navlinks[] = array('name' => $element, 'link' => null, 'type' => 'misc');
}
$navigation = build_navigation($navlinks);
print_header("$SITE->shortname: " . implode(": ",$visiblepathtosection), $SITE->fullname, $navigation, $focus, '', true, $buttons, '');
print_header("$SITE->shortname: " . implode(": ",$visiblepathtosection), $SITE->fullname, array(), $focus, '', true, $buttons, '');
}
/**
@@ -5551,6 +5545,7 @@ function print_plugin_tables() {
'comments',
'course_list',
'course_summary',
'global_navigation_tree',
'glossary_random',
'html',
'loancalc',
@@ -5567,6 +5562,7 @@ function print_plugin_tables() {
'search',
'search_forums',
'section_links',
'settings_navigation_tree',
'site_main_menu',
'social_activities',
'tag_flickr',
+96
View File
@@ -0,0 +1,96 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file is used to deliver a branch from the navigation structure
* in XML format back to a page from an AJAX call
*
* @since 2.0
* @package moodlecore
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/** Include config */
require_once(dirname(__FILE__) . '/../../config.php');
/** Include course lib for its functions */
require_once($CFG->dirroot.'/course/lib.php');
// Start buffer capture so that we can `remove` any errors
ob_start();
// Require elementid (this identifies which HTML element it is being expanded
$elementid = optional_param('elementid', null, PARAM_INT);
// Require id This is the key for whatever branch we want to get
$branchid = optional_param('id', null, PARAM_INT);
// This identifies the type of the branch we want to get
$branchtype = optional_param('type', null, PARAM_INT);
// This identifies the block instance requesting AJAX extension
$instanceid = optional_param('instance', null, PARAM_INT);
// Create a global nav object
$navigation = new limited_global_navigation();
// If set to true then we need to call toggle display
$toggledisplay = false;
if ($instanceid!==null) {
// Get the db record for the block instance
$blockrecords = $DB->get_record('block_instances', array('id'=>$instanceid,'blockname'=>'global_navigation_tree'));
if ($blockrecords!=false) {
// Instantiate a block_instance object so we can access congif
$block = block_instance('global_navigation_tree', $blockrecords);
// Check if the expansion limit config option has been set and isn't the default [everything]
if (!empty($block->config->expansionlimit) && $block->config->expansionlimit > '0') {
// Set the expansion limit
$navigation->expansionlimit = $block->config->expansionlimit;
$toggledisplay = true;
}
if (empty($block->config->showemptybranches) || $block->config->showemptybranches=='no') {
$navigation->showemptybranches = false;
}
}
}
// Create a navigation object to use, we can't guarantee PAGE will be complete
$expandable = $navigation->initialise($branchtype, $branchid);
if ($toggledisplay) {
// Toggle display of item types we dont' want to display
$navigation->toggle_type_display($navigation->expansionlimit);
}
// Find the actuall branch we are looking for
$branch = $navigation->find_child($branchid, $branchtype);
// Stop buffering errors at this point
$html = ob_get_contents();
ob_end_clean();
// Check if the buffer contianed anything if it did ERROR!
if (trim($html)!=='') {
die('Errors were encountered while producing the navigation branch'."\n\n\n".$html);
}
// Check that branch isn't empty... if it is ERROR!
if (empty($branch) || $branch->nodetype !== navigation_node::NODETYPE_BRANCH) {
die('No further information available for this branch');
}
// Prepare an XML converter for the branch
$converter = new navigation_xml();
$converter->set_expandable($expandable);
// Set XML headers
header('Content-type: text/xml');
echo '<?xml version="1.0" encoding="utf-8"?>';
// Convert and output the branch as XML
echo $converter->convert($branch);
-3
View File
@@ -35,9 +35,6 @@
require_once(dirname(__FILE__) . '/../../config.php');
// Check access.
if (!isloggedin()) {;
print_error('mustbeloggedin');
}
if (!confirm_sesskey()) {
print_error('invalidsesskey');
}
+15 -8
View File
@@ -585,12 +585,12 @@ class block_manager {
* @param string $pagetypepattern optional. Passed to @see add_block()
* @param string $subpagepattern optional. Passed to @see add_block()
*/
public function add_blocks($blocks, $pagetypepattern = NULL, $subpagepattern = NULL) {
public function add_blocks($blocks, $pagetypepattern = NULL, $subpagepattern = NULL, $showinsubcontexts=false, $weight=0) {
$this->add_regions(array_keys($blocks));
foreach ($blocks as $region => $regionblocks) {
$weight = 0;
foreach ($regionblocks as $blockname) {
$this->add_block($blockname, $region, $weight, false, $pagetypepattern, $subpagepattern);
$this->add_block($blockname, $region, $weight, $showinsubcontexts, $pagetypepattern, $subpagepattern);
$weight += 1;
}
}
@@ -1626,10 +1626,16 @@ function blocks_parse_default_blocks_list($blocksstr) {
$blocks = array();
$bits = explode(':', $blocksstr);
if (!empty($bits)) {
$blocks[BLOCK_POS_LEFT] = explode(',', array_shift($bits));
$leftbits = trim(array_shift($bits));
if ($leftbits != '') {
$blocks[BLOCK_POS_LEFT] = explode(',', $leftbits);
}
}
if (!empty($bits)) {
$blocks[BLOCK_POS_RIGHT] = explode(',', array_shift($bits));
$rightbits =trim(array_shift($bits));
if ($rightbits != '') {
$blocks[BLOCK_POS_RIGHT] = explode(',', $rightbits);
}
}
return $blocks;
}
@@ -1644,7 +1650,7 @@ function blocks_get_default_site_course_blocks() {
return blocks_parse_default_blocks_list($CFG->defaultblocks_site);
} else {
return array(
BLOCK_POS_LEFT => array('site_main_menu', 'admin_tree'),
BLOCK_POS_LEFT => array('site_main_menu'),
BLOCK_POS_RIGHT => array('course_summary', 'calendar_month')
);
}
@@ -1682,8 +1688,8 @@ function blocks_add_default_course_blocks($course) {
} else {
$blocknames = array(
BLOCK_POS_LEFT => array('participants', 'activity_modules', 'search_forums', 'admin', 'course_list'),
BLOCK_POS_RIGHT => array('news_items', 'calendar_upcoming', 'recent_activity')
BLOCK_POS_LEFT => array(),
BLOCK_POS_RIGHT => array('search_forums', 'news_items', 'calendar_upcoming', 'recent_activity')
);
}
}
@@ -1706,5 +1712,6 @@ function blocks_add_default_course_blocks($course) {
function blocks_add_default_system_blocks() {
$page = new moodle_page();
$page->set_context(get_context_instance(CONTEXT_SYSTEM));
$page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('admin_tree', 'admin_bookmarks')), 'admin-*');
$page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('global_navigation_tree', 'settings_navigation_tree')), '*', null, true);
$page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('admin_bookmarks')), 'admin-*', null, null, 2);
}
+104
View File
@@ -2370,6 +2370,110 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL");
upgrade_main_savepoint($result, 2009072400);
}
/**
* This upgrade is to set up the new navigation blocks that have been developed
* as part of Moodle 2.0
* Now I [Sam Hemelryk] hit a conundrum while exploring how to go about this
* as not only do we want to install the new blocks but we also want to set up
* default instances of them, and at the same time remove instances of the blocks
* that were/will-be outmoded by the two new navigation blocks.
* After talking it through with Tim Hunt {@link http://moodle.org/mod/cvsadmin/view.php?conversationid=3112}
* we decided that the best way to go about this was to put the bulk of the
* upgrade operation into core upgrade `here` but to let the plugins block
* still install the blocks.
* This leaves one hairy end in that we will create block_instances within the
* DB before the blocks themselves are created within the DB
*/
if ($result && $oldversion < 2009082800) {
echo $OUTPUT->notification(get_string('navigationupgrade', 'admin'));
// Get the system context so we can set the block instances to it
$syscontext = get_context_instance(CONTEXT_SYSTEM);
// An array to contain the new block instances we will create
$newblockinstances = array('globalnavigation'=>new stdClass,'settingsnavigation'=>new stdClass);
// The new global navigation block instance as a stdClass
$newblockinstances['globalnavigation']->blockname = 'global_navigation_tree';
$newblockinstances['globalnavigation']->parentcontextid = $syscontext->id; // System context
$newblockinstances['globalnavigation']->showinsubcontexts = true; // Show absolutly everywhere
$newblockinstances['globalnavigation']->pagetypepattern = '*'; // Thats right everywhere
$newblockinstances['globalnavigation']->subpagetypepattern = null;
$newblockinstances['globalnavigation']->defaultregion = BLOCK_POS_LEFT;
$newblockinstances['globalnavigation']->defaultweight = -10; // Try make this first
$newblockinstances['globalnavigation']->configdata = '';
// The new settings navigation block instance as a stdClass
$newblockinstances['settingsnavigation']->blockname = 'settings_navigation_tree';
$newblockinstances['settingsnavigation']->parentcontextid = $syscontext->id;
$newblockinstances['settingsnavigation']->showinsubcontexts = true;
$newblockinstances['settingsnavigation']->pagetypepattern = '*';
$newblockinstances['settingsnavigation']->subpagetypepattern = null;
$newblockinstances['settingsnavigation']->defaultregion = BLOCK_POS_LEFT;
$newblockinstances['settingsnavigation']->defaultweight = -9; // Try make this second
$newblockinstances['settingsnavigation']->configdata = '';
// Blocks that are outmoded and for whom the bells will toll... by which I
// mean we will delete all instances of
$outmodedblocks = array('participants','admin_tree','activity_modules','admin','course_list');
$outmodedblocksstring = '\''.join('\',\'',$outmodedblocks).'\'';
unset($outmodedblocks);
// Retrieve the block instance id's and parent contexts, so we can join them an GREATLY
// cut down the number of delete queries we will need to run
$allblockinstances = $DB->get_recordset_select('block_instances', 'blockname IN ('.$outmodedblocksstring.')', array(), '', 'id, parentcontextid');
$contextids = array();
$instanceids = array();
// Iterate through all block instances
foreach ($allblockinstances as $blockinstance) {
if (!in_array($blockinstance->parentcontextid, $contextids)) {
$contextids[] = $blockinstance->parentcontextid;
// If we have over 1000 contexts clean them up and reset the array
// this ensures we don't hit any nasty memory limits or such
if (count($contextids) > 1000) {
$result = $result && upgrade_cleanup_unwanted_block_contexts($contextids);
$contextids = array();
}
}
if (!in_array($blockinstance->id, $instanceids)) {
$instanceids[] = $blockinstance->id;
// If we have more than 1000 block instances now remove all block positions
// and empty the array
if (count($contextids) > 1000) {
$instanceidstring = join(',',$instanceids);
$result = $result && $DB->delete_records_select('block_positions', 'blockinstanceid IN ('.$instanceidstring.')');
$instanceids = array();
}
}
}
$result = $result && upgrade_cleanup_unwanted_block_contexts($contextids);
$instanceidstring = join(',',$instanceids);
$outcome1 = $result && $DB->delete_records_select('block_positions', 'blockinstanceid IN ('.$instanceidstring.')');
unset($allblockinstances);
unset($contextids);
unset($instanceids);
unset($instanceidstring);
// Now remove the actual block instance
$result = $result && $DB->delete_records_select('block_instances', 'blockname IN ('.$outmodedblocksstring.')');
unset($outmodedblocksstring);
// Insert the new block instances. Remember they have not been installed yet
// however this should not be a problem
foreach ($newblockinstances as $blockinstance) {
$blockinstance->id= $DB->insert_record('block_instances', $blockinstance);
// Ensure the block context is created.
get_context_instance(CONTEXT_BLOCK, $blockinstance->id);
}
unset($newblockinstances);
upgrade_main_savepoint($result, 2009082800);
// The end of the navigation upgrade
}
return $result;
}
+49
View File
@@ -331,4 +331,53 @@ function upgrade_fix_incorrect_mnethostids() {
}
}
/**
* This function is used as part of the great navigation upgrade of 20090828
* It is used to clean up contexts that are unique to a blocks that are about
* to be removed.
*
*
* Look at {@link blocklib.php::blocks_delete_instance()} the function from
* which I based this code. It is important to mention one very important fact
* before doing this I checked that the blocks did not override the
* {@link block_base::instance_delete()} method. Should this function ever
* be repeated check this again
*
* @link lib/db/upgrade.php
*
* @since navigation upgrade 20090828
* @param array $contextidarray An array of block instance context ids
* @return bool
*/
function upgrade_cleanup_unwanted_block_contexts($contextidarray) {
global $DB;
if (!is_array($contextidarray) || count($contextidarray)===0) {
// Ummmm no instances?
return true;
}
$contextidstring = join(',', $contextidarray);
$blockcontexts = $DB->get_recordset_select('context', 'contextlevel = '.CONTEXT_BLOCK.' AND id IN ('.$contextidstring.')', array(), '', 'id, contextlevel');
$blockcontextids = array();
foreach ($blockcontexts as $blockcontext) {
$blockcontextids[] = $blockcontext->id;
}
if (count($blockcontextids)===0) {
// None of the instances have unique contexts
return true;
}
$blockcontextidsstring = join(',', $blockcontextids);
$outcome1 = $DB->delete_records_select('role_assignments', 'contextid IN ('.$blockcontextidsstring.')');
$outcome2 = $DB->delete_records_select('role_capabilities', 'contextid IN ('.$blockcontextidsstring.')');
$outcome3 = $DB->delete_records_select('role_names', 'contextid IN ('.$blockcontextidsstring.')');
$outcome4 = $DB->delete_records_select('context', 'id IN ('.$blockcontextidsstring.')');
return ($outcome1 && $outcome2 && $outcome4 && $outcome4);
}
?>
+116 -10
View File
@@ -2133,15 +2133,6 @@ function print_header($title='', $heading='', $navigation='', $focus='',
}
$PAGE->set_button($button);
if ($navigation == 'home') {
$navigation = '';
}
if (gettype($navigation) == 'string' && strlen($navigation) != 0 && $navigation != 'home') {
debugging("print_header() was sent a string as 3rd ($navigation) parameter. "
. "This is deprecated in favour of an array built by build_navigation(). Please upgrade your code.", DEBUG_DEVELOPER);
}
// TODO $navigation
// TODO $menu
if ($meta) {
@@ -2155,7 +2146,7 @@ function print_header($title='', $heading='', $navigation='', $focus='',
throw new coding_exception('The $bodytags parameter to print_header is no longer supported.');
}
$output = $OUTPUT->header($navigation, $menu);
$output = $OUTPUT->header($menu);
if ($return) {
return $output;
@@ -3564,3 +3555,118 @@ function update_course_icon($courseid) {
return $OUTPUT->edit_button(new moodle_url($CFG->wwwroot.'/course/view.php', array('id' => $courseid)));
}
/**
* Prints breadcrumb trail of links, called in theme/-/header.html
*
* This function has now been deprecated please use output's navbar method instead
* as shown below
*
* <code php>
* echo $OUTPUT->navbar();
* </code>
*
* @deprecated since 2.0
* @param mixed $navigation deprecated
* @param string $separator OBSOLETE, and now deprecated
* @param boolean $return False to echo the breadcrumb string (default), true to return it.
* @return string|void String or null, depending on $return.
*/
function print_navigation ($navigation, $separator=0, $return=false) {
global $OUTPUT,$PAGE;
# debugging('print_navigation has been deprecated please update your theme to use $OUTPUT->navbar() instead', DEBUG_DEVELOPER);
$output = $OUTPUT->navbar();
if ($return) {
return $output;
} else {
echo $output;
}
}
/**
* This function will build the navigation string to be used by print_header
* and others.
*
* It automatically generates the site and course level (if appropriate) links.
*
* If you pass in a $cm object, the method will also generate the activity (e.g. 'Forums')
* and activityinstances (e.g. 'General Developer Forum') navigation levels.
*
* If you want to add any further navigation links after the ones this function generates,
* the pass an array of extra link arrays like this:
* array(
* array('name' => $linktext1, 'link' => $url1, 'type' => $linktype1),
* array('name' => $linktext2, 'link' => $url2, 'type' => $linktype2)
* )
* The normal case is to just add one further link, for example 'Editing forum' after
* 'General Developer Forum', with no link.
* To do that, you need to pass
* array(array('name' => $linktext, 'link' => '', 'type' => 'title'))
* However, becuase this is a very common case, you can use a shortcut syntax, and just
* pass the string 'Editing forum', instead of an array as $extranavlinks.
*
* At the moment, the link types only have limited significance. Type 'activity' is
* recognised in order to implement the $CFG->hideactivitytypenavlink feature. Types
* that are known to appear are 'home', 'course', 'activity', 'activityinstance' and 'title'.
* This really needs to be documented better. In the mean time, try to be consistent, it will
* enable people to customise the navigation more in future.
*
* When passing a $cm object, the fields used are $cm->modname, $cm->name and $cm->course.
* If you get the $cm object using the function get_coursemodule_from_instance or
* get_coursemodule_from_id (as recommended) then this will be done for you automatically.
* If you don't have $cm->modname or $cm->name, this fuction will attempt to find them using
* the $cm->module and $cm->instance fields, but this takes extra database queries, so a
* warning is printed in developer debug mode.
*
* @deprecated since 2.0
* @param mixed $extranavlinks - Normally an array of arrays, keys: name, link, type. If you
* only want one extra item with no link, you can pass a string instead. If you don't want
* any extra links, pass an empty string.
* @param mixed $cm deprecated
* @return array Navigation array
*/
function build_navigation($extranavlinks, $cm = null) {
global $CFG, $COURSE, $DB, $SITE, $PAGE;
if (is_array($extranavlinks) && count($extranavlinks)>0) {
# debugging('build_navigation() has been deprecated, please replace with $PAGE->navbar methods', DEBUG_DEVELOPER);
foreach ($extranavlinks as $nav) {
if (array_key_exists('name', $nav)) {
$link = (array_key_exists('link', $nav))?$nav['link']:null;
$PAGE->navbar->add($nav['name'],null, null, navbar::TYPE_CUSTOM, $link);
}
}
}
return(array('newnav' => true, 'navlinks' => array()));
}
/**
* Returns a small popup menu of course activity modules
*
* Given a course and a (current) coursemodule
* his function returns a small popup menu with all the
* course activity modules in it, as a navigation menu
* The data is taken from the serialised array stored in
* the course record
*
* @global object
* @global object
* @global object
* @global object
* @uses CONTEXT_COURSE
* @param object $course A {@link $COURSE} object.
* @param object $cm A {@link $COURSE} object.
* @param string $targetwindow The target window attribute to us
* @return string
*/
function navmenu($course, $cm=NULL, $targetwindow='self') {
global $CFG, $THEME, $USER, $DB, $OUTPUT;
// This function has been deprecated with the creation of the global nav in
// moodle 2.0
return '';
}
+836
View File
@@ -0,0 +1,836 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains classes used to manage the navigation structures in Moodle
* and was introduced as part of the changes occuring in Moodle 2.0
*
* @since 2.0
* @package javascript
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Some very important general namespaces to act as containers for the general
* objects required to manage the navigation.
*
* For anyone looking to improve this javascript taking a little time to turn
* the classes into namespaced classes, and giving the class structure in this file
* a similar structure to YUI on a moodle namespace would be AWESOME
*/
YAHOO.namespace('moodle.navigation');
YAHOO.namespace('moodle.navigation.sideblockwidth');
YAHOO.namespace('moodle.navigation.tabpanel');
YAHOO.namespace('moodle.navigation.treecollection');
/**
* Instatiate some very important variables that allow us to manage the navigaiton
* objects without having to hit my arch enemy `undefined`
*/
YAHOO.moodle.navigation.sideblockwidth = null;
YAHOO.moodle.navigation.tabpanel = null;
YAHOO.moodle.navigation.treecollection = Array();
/**
* Navigation Tree object (function) used to control a global navigation tree
* handling things such as collapse, expand, and AJAX requests for more branches
*
* You should never call this directly.. you should use {@link start_new_navtree()}
* which will create the class and make it accessible in a smart way
*
* @class navigation_tree
* @constructor
* @param {string} treename
* @param {string} key
*/
function navigation_tree (treename, key) {
this.name = treename;
this.key = key;
this.errorlog = '';
this.ajaxbranches = 0;
this.expansions = Array();
this.instance = null
this.cachedcontent = null;
this.cachedfooter = null;
this.position = 'block';
this.tooglesidetabdisplay = '[[tooglesidetabdisplay]]';
this.toogleblockdisplay = '[[toogleblockdisplay]]';
this.sideblockwidth = null;
if (window[this.name]) {
if (window[this.name].expansions) {
this.expansions = window[this.name].expansions;
}
if (window[this.name].instance) {
this.instance = window[this.name].instance;
}
if (window[this.name].tooglesidetabdisplay) {
this.tooglesidetabdisplay = window[this.name].tooglesidetabdisplay;
}
if (window[this.name].toogleblockdisplay) {
this.toogleblockdisplay = window[this.name].toogleblockdisplay;
}
}
}
/**
* Initialise function used to attach the initial events to the navigation tree
* This function attachs toogles and ajax calls
*/
navigation_tree.prototype.initialise = function() {
if (!document.getElementById(this.name)) {
return;
}
var e = document.getElementById(this.name);
var i = 0;
while (!YAHOO.util.Dom.hasClass(e, 'sideblock') && e.nodeName.toUpperCase()!='BODY') {
e = e.parentNode;
}
var movetos = YAHOO.util.Dom.getElementsByClassName('moveto', 'a', e);
if (movetos !== null && movetos.length > 0) {
for (i = 0;i<movetos.length;i++) {
YAHOO.util.Event.addListener(movetos[i], 'click', this.toggle_block_display, this, true);
}
}
for (i = 0; i<this.expansions.length; i++) {
try {
YAHOO.util.Event.addListener(this.expansions[i].id, 'click', this.init_load_ajax, this.expansions[i], this);
} catch (err) {
this.errorlog += "attaching ajax load events: \t"+err+"\n";
}
}
var items = YAHOO.util.Dom.getElementsByClassName('tree_item branch', '', document.getElementById(this.name));
if (items != null && items.length>0) {
for (i = 0; i<items.length; i++) {
try {
YAHOO.util.Event.addListener(items[i], 'click', this.toggleexpansion, this, true);
} catch (err) {
this.errorlog += "attaching toggleexpansion events: \t"+err+"\n";
}
}
}
var customcommands = YAHOO.util.Dom.getElementsByClassName('customcommand', 'a', e);
var commands = YAHOO.util.Dom.getElementsByClassName('commands', 'div', e);
if (commands.length === 1 && customcommands.length > 0) {
for (i = 0; i < customcommands.length; i++) {
customcommands[i].parentNode.removeChild(customcommands[i]);
commands[0].appendChild(customcommands[i]);
}
}
if (YAHOO.util.Dom.hasClass(e, 'sideblock_js_sidebarpopout')) {
YAHOO.util.Dom.removeClass(e, 'sideblock_js_sidebarpopout');
this.toggle_block_display(e, this);
} else if (YAHOO.util.Dom.hasClass(e, 'sideblock_js_expansion')) {
YAHOO.util.Event.addListener(e, 'mouseover', this.togglesize, e, this);
YAHOO.util.Event.addListener(e, 'mouseout', this.togglesize, e, this);
}
}
/**
* Toogle a branch either collapsed or expanded... CSS styled
* @param {object} e Event object
*/
navigation_tree.prototype.toggleexpansion = function(e) {
YAHOO.util.Event.stopPropagation(e);
var target = YAHOO.util.Event.getTarget(e);
var parent = target.parentNode;
if (YAHOO.util.Dom.hasClass(parent, 'collapsed')) {
YAHOO.util.Dom.removeClass(parent, 'collapsed');
} else {
YAHOO.util.Dom.addClass(parent, 'collapsed');
}
if (this.position === 'sidebar') {
YAHOO.moodle.navigation.tabpanel.resize_tab();
}
}
/**
* Toggles the size on an element by adding/removing the mouseover class
* @param {object} e Event object
* @param {element} element The element to add/remove the class from
*/
navigation_tree.prototype.togglesize = function(e, element) {
if (e.type == 'mouseout') {
var mp = YAHOO.util.Event.getXY(e);
if (mp[0] == -1) {
return true;
}
var ep = YAHOO.util.Dom.getXY(element);
ep[2] = ep[0]+element.offsetWidth;
ep[3] = ep[1]+element.offsetHeight;
var withinrealm = (mp[0] > ep[0] && mp[0] < ep[2] && mp[1] > ep[1] && mp[1] < ep[3]);
if (!withinrealm) {
YAHOO.util.Event.stopEvent(e);
YAHOO.util.Dom.removeClass(element, 'mouseover');
}
} else {
YAHOO.util.Event.stopEvent(e);
element.style.width = element.offsetWidth +'px';
YAHOO.util.Dom.addClass(element, 'mouseover');
}
return true;
}
/**
* This function makes the initial call to load a branch of the navigation
* tree by AJAX
* @param {object} e Event object
* @param {object} branch The branch object from navigation_tree::expansions
* @return {bool}
*/
navigation_tree.prototype.init_load_ajax = function(e, branch) {
YAHOO.util.Event.stopPropagation(e);
if (YAHOO.util.Event.getTarget(e).nodeName.toUpperCase() != 'P') {
return true;
}
var postargs = 'elementid='+branch.id+'&id='+branch.branchid+'&type='+branch.type+'&sesskey='+moodle_cfg.sesskey;
if (this.instance != null) {
postargs += '&instance='+this.instance;
}
YAHOO.util.Connect.asyncRequest('POST', moodle_cfg.wwwroot+'/lib/ajax/getnavbranch.php', callback={
success:function(o) {this.load_ajax(o);},
failure:function(o) {this.load_ajax(o);},
argument: {gntinstance:this,branch:branch,event:e, target:YAHOO.util.Event.getTarget(e)},
scope: this
}, postargs);
return true;
}
/**
* This function loads a branch returned by AJAX into the XHTML tree structure
* @param {object} outcome The AJAX response
* @return {bool}
*/
navigation_tree.prototype.load_ajax = function(outcome) {
// Check the status
if (outcome.status!=0 && outcome.responseXML!=null) {
var branch = outcome.responseXML.documentElement;
if (branch!=null && this.add_branch(branch,outcome.argument.target ,1)) {
// If we get here everything worked perfectly
YAHOO.util.Event.removeListener(outcome.argument.branch.id, 'click', this.init_load_ajax);
if (this.position === 'sidebar') {
YAHOO.moodle.navigation.tabpanel.resize_tab();
}
return true;
}
}
// Something went wrong or there simply wasn't anything more to display
// add the emptybranch css class so we can flag it
YAHOO.util.Dom.replaceClass(outcome.argument.target, 'branch', 'emptybranch');
return false;
}
/**
* This recursive function takes an XML branch and includes it in the tree
* @param {xmlnode} branchxml The XML node for the branch
* @param {element} target The target node to add to
* @param {int} depth The depth we have delved (recusive counter)
* @return {bool}
*/
navigation_tree.prototype.add_branch = function(branchxml, target, depth) {
var branch = new navigation_tree_branch();
branch.load_from_xml_node(branchxml);
if (depth>1) {
target = branch.inject_into_dom(target,this);
}
var dropcount = 5;
while (target.nodeName.toUpperCase() !== 'LI') {
target = target.parentNode;
if (dropcount==0 && moodle_cfg.developerdebug) {
return alert("dropped because of exceeding dropcount");
}
dropcount--;
}
if (branch.haschildren && branch.mychildren && branch.mychildren.childNodes) {
for (var i=0;i<branch.mychildren.childNodes.length;i++) {
if (branch.haschildren) {
var ul = document.createElement('ul');
target.appendChild(ul);
}
var child = branch.mychildren.childNodes[i];
this.add_branch(child, ul, depth+1);
}
} else if(depth==1) {
// If we are here then we got a valid response however there are no children
// to display for the branch that we are expanding, thus we will return false
// so we can add the emptybranch class
return false;
}
return true;
}
/**
* This switches a navigation block between its block position and the sidebar
*
* @param {element} e Event object
*/
navigation_tree.prototype.toggle_block_display = function(e) {
if (e !== null) {
YAHOO.util.Event.stopPropagation(e);
}
if (this.position === 'block') {
this.move_to_sidebar_popout(e);
this.position = 'sidebar';
} else {
this.move_to_block_position(e);
this.position = 'block';
}
}
/**
* This function gets called from {@link navigation_tree.toggle_block_display()}
* and is responsible for moving the block from the block position to the sidebar
* @return {bool}
*/
navigation_tree.prototype.move_to_sidebar_popout = function(e) {
var element = document.getElementById(this.name).parentNode;
if (element == null) {
return false;
}
var tabcontent = document.getElementById(this.name).parentNode;
while (!YAHOO.util.Dom.hasClass(element, 'sideblock')) {
element = element.parentNode;
}
this.cachedcontent = element;
var sideblocknode = element;
while (sideblocknode && !YAHOO.util.Dom.hasClass(sideblocknode, 'block-region')) {
sideblocknode = sideblocknode.parentNode;
}
var moveto = YAHOO.util.Dom.getElementsByClassName('moveto customcommand', 'a', this.cachedcontent);
if (moveto.length > 0) {
for (var i=0;i<moveto.length;i++) {
var moveicon = moveto[i].getElementsByTagName('img');
if (moveicon.length>0) {
for (var j=0;j<moveicon.length;j++) {
moveicon[j].src = moveicon[j].src.replace(/movetosidetab/, 'movetoblock');
moveicon[j].setAttribute('alt', this.toogleblockdisplay);
moveicon[j].setAttribute('title', this.toogleblockdisplay);
}
}
}
}
var placeholder = document.createElement('div');
placeholder.setAttribute('id', this.name+'_content_placeholder');
element.parentNode.replaceChild(placeholder, element);
element = null;
var tabtitle = this.cachedcontent.getElementsByTagName('h2')[0].cloneNode(true);
tabtitle.innerHTML = tabtitle.innerHTML.replace(/([a-zA-Z0-9])/g, "$1<br />");
var commands = YAHOO.util.Dom.getElementsByClassName('commands', 'div', this.cachedcontent);
var tabcommands = null;
if (commands.length > 0) {
tabcommands = commands[0];
} else {
tabcommands = document.createElement('div');
YAHOO.util.Dom.addClass(tabcommands, 'commands');
}
if (YAHOO.util.Dom.hasClass(sideblocknode, 'block-region')) {
var blocks = YAHOO.util.Dom.getElementsByClassName('sideblock', 'div', sideblocknode);
if (blocks.length === 0) {
YAHOO.moodle.navigation.sideblockwidth = YAHOO.util.Dom.getStyle(sideblocknode, 'width');
YAHOO.util.Dom.setStyle(sideblocknode, 'width', '0px');
}
}
if (YAHOO.moodle.navigation.tabpanel === null) {
YAHOO.moodle.navigation.tabpanel = new navigation_tab_panel();
}
YAHOO.moodle.navigation.tabpanel.add_to_tab_panel(this.name, tabtitle, tabcontent, tabcommands);
return true;
}
/**
* This function gets called from {@link navigation_tree.toggle_block_display()}
* and is responsible for moving the block from the sidebar to the block position
* @return {bool}
*/
navigation_tree.prototype.move_to_block_position = function(e) {
if (this.sideblockwidth !== null) {
YAHOO.util.Dom.setStyle(sideblocknode, 'width', this.sideblockwidth);
this.sideblockwidth = null;
}
var placeholder = document.getElementById(this.name+'_content_placeholder');
if (!placeholder || YAHOO.moodle.navigation.tabpanel == null) {
return false;
}
if (YAHOO.moodle.navigation.tabpanel.showntab !== null) {
YAHOO.moodle.navigation.tabpanel.hide_tab(e, YAHOO.moodle.navigation.tabpanel.showntab.tabname);
}
var tabcontent = YAHOO.moodle.navigation.tabpanel.get_tab_panel_contents(this.name);
this.cachedcontent.appendChild(tabcontent);
placeholder.parentNode.replaceChild(this.cachedcontent, placeholder);
if (YAHOO.moodle.navigation.sideblockwidth !== null) {
var sideblocknode = this.cachedcontent;
while (sideblocknode && !YAHOO.util.Dom.hasClass(sideblocknode, 'block-region')) {
sideblocknode = sideblocknode.parentNode;
}
if (YAHOO.util.Dom.hasClass(sideblocknode, 'block-region')) {
YAHOO.util.Dom.setStyle(sideblocknode, 'width', YAHOO.moodle.navigation.sideblockwidth);
}
}
var moveto = YAHOO.util.Dom.getElementsByClassName('moveto customcommand', 'a', this.cachedcontent);
if (moveto.length > 0) {
for (var i=0;i<moveto.length;i++) {
var moveicon = moveto[i].getElementsByTagName('img');
if (moveicon.length>0) {
for (var j=0;j<moveicon.length;j++) {
moveicon[j].src = moveicon[j].src.replace(/movetoblock/, 'movetosidetab');
moveicon[j].setAttribute('alt', this.tooglesidetabdisplay);
moveicon[j].setAttribute('title', this.tooglesidetabdisplay);
}
}
}
}
var commands = YAHOO.util.Dom.getElementsByClassName('commands', 'div', this.cachedcontent);
var blocktitle = YAHOO.util.Dom.getElementsByClassName('title', 'div', this.cachedcontent);
if (commands.length === 1 && blocktitle.length === 1) {
commands[0].parentNode.removeChild(commands[0]);
blocktitle[0].appendChild(commands[0]);
}
YAHOO.moodle.navigation.tabpanel.remove_from_tab_panel(this.name);
var block = this.cachedcontent;
while (!YAHOO.util.Dom.hasClass(block, 'sideblock')) {
block = block.parentNode;
}
return true;
}
/**
* This class is used to manage the navigation tab panel
*
* Through this class you can add, remove, and manage items from the navigation
* tab panel.
* Note you only EVER need one of these
* @constructor
* @class navigation_tab_panel
*/
function navigation_tab_panel() {
this.tabpanelexists = false;
this.tabpanelelementnames = Array();
this.tabpanelelementcontents = Array();
this.navigationpanel = null;
this.tabpanel = null;
this.tabpanels = Array();
this.tabcount = 0;
this.showntab = null;
}
/**
* This creates a tab panel element and injects it into the DOM
* @method create_tab_panel
* @return {bool}
*/
navigation_tab_panel.prototype.create_tab_panel = function () {
var navbar = document.createElement('div');
navbar.style.display = 'none';
navbar.setAttribute('id', 'sidebarpopup');
YAHOO.util.Dom.addClass(navbar, 'navigation_bar');
if (YAHOO.env.ua.ie > 0 && YAHOO.env.ua.ie < 7) {
YAHOO.util.Dom.setStyle(navbar, 'height', YAHOO.util.Dom.getViewportHeight()+'px');
}
var navbarcontrol = document.createElement('div');
YAHOO.util.Dom.addClass(navbarcontrol, 'controls');
var removeall = document.createElement('img');
removeall.setAttribute('src', moodle_cfg.wwwroot+'/pix/t/movetoblock.png');
removeall.setAttribute('title', mstr.moodle.moveallsidetabstoblock);
removeall.setAttribute('alt', mstr.moodle.moveallsidetabstoblock);
navbarcontrol.appendChild(removeall);
navbar.appendChild(navbarcontrol);
document.getElementsByTagName('body')[0].appendChild(navbar);
navbar.appendChild(create_shadow(false, true, true, false));
YAHOO.util.Dom.addClass(document.getElementsByTagName('body')[0], 'has_navigation_bar');
this.navigationpanel = navbar;
this.tabpanelexists = true;
navbar.style.display = 'block';
YAHOO.util.Event.addListener(removeall, 'click', move_all_sidetabs_to_block_position);
return true;
}
/**
* This removes the tab panel element from the page
* @method remove_tab_panel
* @return {bool}
*/
navigation_tab_panel.prototype.remove_tab_panel = function () {
var panel = document.getElementById('sidebarpopup');
if (!panel) {
return false;
}
this.tabpanel = null;
panel.parentNode.removeChild(panel);
this.tabpanelexists = false;
this.navigationpanel = null;
if (YAHOO.util.Dom.hasClass(document.getElementsByTagName('body')[0], 'has_navigation_bar')) {
YAHOO.util.Dom.removeClass(document.getElementsByTagName('body')[0], 'has_navigation_bar')
}
return true;
}
/**
* This function retrieves the content of a tab in the navigation tab panel
* @method get_tab_panel_contents
* @param {string} tabname The name of the tab
* @return {element} The content element
*/
navigation_tab_panel.prototype.get_tab_panel_contents = function(tabname) {
remove_shadow(this.tabpanelelementcontents[tabname]);
return this.tabpanelelementcontents[tabname];
}
/**
* This function adds a tab to the navigation tab panel
*
* If you find that it takes a long time to make the initial transaction then I
* would first check the time that set_user_preference is taking, during development
* the code needed to be re-jigged because it was taking a very long time to execute
*
* @method add_to_tab_panel
* @param {string} tabname The string name of the tab
* @param {element} tabtitle The title of the tab
* @param {element} tabcontent The content for the tab
* @param {element} tabcommands The commands for the tab
*/
navigation_tab_panel.prototype.add_to_tab_panel = function (tabname, tabtitle, tabcontent, tabcommands) {
if (!this.tabpanelexists) {
this.create_tab_panel();
}
var firsttab = (this.tabcount==0);
var sidetab = document.createElement('div');
sidetab.setAttribute('id', tabname+'_sidebarpopup');
YAHOO.util.Dom.addClass(sidetab, 'sideblock_tab');
if (firsttab) {
YAHOO.util.Dom.addClass(sidetab, 'firsttab');
}
var sidetabtitle = document.createElement('div');
sidetabtitle.appendChild(tabtitle);
sidetabtitle.setAttribute('id', tabname+'_title');
YAHOO.util.Dom.addClass(sidetabtitle, 'title');
tabcontent.appendChild(create_shadow(true, true, true, false));
sidetab.appendChild(sidetabtitle);
if (tabcommands.childNodes.length>0) {
tabcontent.appendChild(tabcommands);
}
this.navigationpanel.appendChild(sidetab);
var position = YAHOO.util.Dom.getXY(sidetabtitle);
position[0] += sidetabtitle.offsetWidth;
if (YAHOO.env.ua.ie > 0 && YAHOO.env.ua.ie < 8) {
position[0] -= 2;
}
this.tabpanels[tabname] = new YAHOO.widget.Panel('navigation_tab_panel_'+tabname, {
close:false,
draggable:false,
constraintoviewport: false,
underlay:"none",
visible:false,
monitorresize:false,
/*context:[tabname+'_title','tl','tr',['configChanged','beforeShow','changeBody']],*/
xy:position,
autofillheight:'body'});
this.tabpanels[tabname].showEvent.subscribe(this.resize_tab, this, true);
this.tabpanels[tabname].setBody(tabcontent);
this.tabpanels[tabname].render(this.navigationpanel);
this.tabpanelelementnames[this.tabpanelelementnames.length] = tabname;
this.tabpanelelementcontents[tabname] = tabcontent;
this.tabcount++;
YAHOO.util.Event.addListener(sidetab, "mouseover", this.show_tab, tabname, this);
set_user_preference('nav_in_tab_panel_'+tabname, 1);
}
/**
* This function handles checking the size, and positioning of the navigaiton
* panel when expansion events occur, or when the panel is shown, or if the window
* is resized
*
* There are undoubtably some bugs in this little bit of code. For one it relies
* on the padding set in CSS by the YUI:sam skin, if you are hitting a problem
* whereby the navigation extends beyond its border, or doesn't fill to its own
* border check the value assigned to padding for the panel body `.yui_panel .bd`
*
* @return {bool}
*/
navigation_tab_panel.prototype.resize_tab = function () {
var screenheight = YAHOO.util.Dom.getViewportHeight();
var tabheight = parseInt(this.tabpanels[this.showntab.tabname].body.offsetHeight);
var tabtop = parseInt(this.tabpanels[this.showntab.tabname].cfg.getProperty('y'));
var titletop = YAHOO.util.Dom.getY(this.showntab.tabname+'_title');
// This makes sure that the panel is the same height as the tab title to
// begin with
if (tabtop > 10 && tabtop > titletop) {
this.tabpanels[this.showntab.tabname].cfg.setProperty('y', titletop);
}
// This makes sure that if the panel is big it is moved up to ensure we don't
// have wasted space above the panel
if ((tabtop+tabheight)>screenheight && tabtop > 10) {
tabtop = (screenheight-tabheight-10);
if (tabtop<10) {
tabtop = 10;
}
this.tabpanels[this.showntab.tabname].cfg.setProperty('y', tabtop);
}
// This makes the panel constrain to the screen's height if the panel is big
if (tabtop <= 10 && ((tabheight+tabtop*2) > screenheight || YAHOO.util.Dom.hasClass(this.tabpanels[this.showntab.tabname].body, 'oversized_content'))) {
this.tabpanels[this.showntab.tabname].cfg.setProperty('height', (screenheight-39));
YAHOO.util.Dom.setStyle(this.tabpanels[this.showntab.tabname].body, 'height', (screenheight-59)+'px');
YAHOO.util.Dom.addClass(this.tabpanels[this.showntab.tabname].body, 'oversized_content');
}
return true;
}
/**
* This function sets everything up for the show even and then calls the panel's
* show event once we are happy.
*
* This function is responsible for closing any open panels, removing show events
* so we don't refresh unnessecarily and adding events to trap closing, and resizing
* events
*
* @param {event} e The event that fired to get us here
* @param {string} tabname The tabname to open
* @return {bool}
*/
navigation_tab_panel.prototype.show_tab = function (e, tabname) {
if (this.showntab !== null) {
this.hide_tab(e, this.showntab.tabname);
}
this.showntab = {event:e, tabname:tabname};
this.tabpanels[tabname].show(e, this.tabpanel);
YAHOO.util.Dom.addClass(tabname+'_title', 'active_tab');
YAHOO.util.Event.removeListener(tabname+'_sidebarpopup', "mouseover", this.show_tab);
YAHOO.util.Event.addListener(tabname+'_sidebarpopup', "click", this.hide_tab, tabname, this);
YAHOO.util.Event.addListener(window, 'resize', this.resize_tab, this, true);
YAHOO.util.Event.addListener(document.body, "click", this.hide_tab, tabname, this);
return true;
}
/**
* This function closes the open tab and sets the listeners up to handle the show
* event again
*
* @param {event} e The event that fired to get us here
* @param {string} tabname The tabname to close
* @return {bool}
*/
navigation_tab_panel.prototype.hide_tab = function(e, tabname) {
this.showntab = null;
YAHOO.util.Event.addListener(tabname+'_sidebarpopup', "mouseover", this.show_tab, tabname, this);
YAHOO.util.Event.removeListener(window, 'resize', this.resize_tab);
YAHOO.util.Event.removeListener(document.body, "click", this.hide_tab);
YAHOO.util.Dom.removeClass(tabname+'_title', 'active_tab');
this.tabpanels[tabname].hide(e, this.tabpanel);
return true;
}
/**
* This function removes a tab from the navigation tab panel
* @param {string} tabname
* @return {bool}
*/
navigation_tab_panel.prototype.remove_from_tab_panel = function(tabname) {
set_user_preference('nav_in_tab_panel_'+tabname, 0);
var tab = document.getElementById(tabname+'_sidebarpopup');
if (!tab) {
return false;
}
tab.parentNode.removeChild(tab);
this.tabpanels[tabname].destroy();
this.tabpanels[tabname] = null;
this.tabcount--;
if (this.tabcount === 0) {
this.remove_tab_panel();
}
return true;
}
/**
* Global navigation tree branch object used to parse an XML branch
* into a usable object, and then to inject it into the DOM
* @class navigation_tree_branch
* @constructor
*/
function navigation_tree_branch() {
this.myname = null;
this.mytitle = null;
this.myclass = null;
this.myid = null;
this.mykey = null;
this.mytype = null;
this.mylink = null;
this.myicon = null;
this.myexpandable = null;
this.myhidden = false;
this.haschildren = false;
this.mychildren = false;
}
/**
* This function populates the object from an XML branch
* @param {xmlnode} branch The XML branch to turn into an object
*/
navigation_tree_branch.prototype.load_from_xml_node = function (branch) {
this.myname = null;
this.mytitle = branch.getAttribute('title');
this.myclass = branch.getAttribute('class');
this.myid = branch.getAttribute('id');
this.mylink = branch.getAttribute('link');
this.myicon = branch.getAttribute('icon');
this.mykey = branch.getAttribute('key');
this.mytype = branch.getAttribute('type');
this.myexpandable = branch.getAttribute('expandable');
this.myhidden = (branch.getAttribute('hidden')=='true');
this.haschildren = (branch.getAttribute('haschildren')=='true');
for (var i=0; i<branch.childNodes.length;i++) {
var node = branch.childNodes[i];
switch (node.nodeName.toLowerCase()) {
case 'name':
this.myname = node.firstChild.nodeValue;
break;
case 'children':
this.mychildren = node;
}
}
}
/**
* This function injects the node into the navigation tree
* @param {element} element The branch to inject into {element}
* @param {navigation_tree} gntinstance The instance of the navigaiton_tree that this branch
* is associated with
* @return {element} The now added node
*/
navigation_tree_branch.prototype.inject_into_dom = function (element, gntinstance) {
var branchli = document.createElement('li');
var branchp = document.createElement('p');
YAHOO.util.Dom.addClass(branchp, 'tree_item');
if (this.myexpandable !==null || this.haschildren) {
YAHOO.util.Dom.addClass(branchp, 'branch');
YAHOO.util.Dom.addClass(branchli, 'collapsed');
YAHOO.util.Event.addListener(branchp, 'click', gntinstance.toggleexpansion, this, gntinstance);
if (this.myexpandable) {
YAHOO.util.Event.addListener(branchp, 'click', gntinstance.init_load_ajax, {branchid:this.mykey,id:this.myid,type:this.mytype}, gntinstance);
}
}
if (this.myclass != null) {
YAHOO.util.Dom.addClass(branchp, this.myclass);
}
if (this.myid != null) {
branchp.setAttribute('id',this.myid);
}
if (this.myicon != null) {
var branchicon = document.createElement('img');
branchicon.setAttribute('src',this.myicon);
branchicon.setAttribute('alt','');
branchp.appendChild(branchicon);
this.myname = ' '+this.myname;
}
if (this.mylink === null) {
branchp.innerHTML = this.myname.replace(/\n/g, '<br />');
} else {
var branchlink = document.createElement('a');
branchlink.setAttribute('title', this.mytitle);
branchlink.setAttribute('href', this.mylink);
branchlink.innerHTML = this.myname.replace(/\n/g, '<br />');
if (this.myhidden) {
YAHOO.util.Dom.addClass(branchlink, 'dimmed');
}
branchp.appendChild(branchlink);
}
branchli.appendChild(branchp);
element.appendChild(branchli);
return branchli;
}
/**
* Creates a new JS instance of a global navigation tree and kicks it into gear
* @param {string} treename The name of the tree
*/
function setup_new_navtree(treename) {
var key = YAHOO.moodle.navigation.treecollection.length;
YAHOO.moodle.navigation.treecollection[key] = new navigation_tree(treename, key);
YAHOO.moodle.navigation.treecollection[key].initialise();
}
/**
* This function moves all navigation tree instances that are currently
* displayed in the sidebar back into their block positions
*/
function move_all_sidetabs_to_block_position(e) {
for (var i=0; i<YAHOO.moodle.navigation.treecollection.length;i++) {
var navtree = YAHOO.moodle.navigation.treecollection[i];
if (navtree.position != 'block') {
navtree.move_to_block_position(e);
}
}
}
/**
* This function create a series of DIV's appended to an element to give it a
* shadow
* @param {bool} top Displays a top shadow if true
* @param {bool} right Displays a right shadow if true
* @param {bool} bottom Displays a bottom shadow if true
* @param {bool} left Displays a left shadow if true
* @return {element}
*/
function create_shadow(top, right, bottom, left) {
var shadow = document.createElement('div');
YAHOO.util.Dom.addClass(shadow, 'divshadow');
if (YAHOO.env.ua.ie > 0 && YAHOO.env.ua.ie < 7) {
// IE6 just doest like my shadow...
return shadow;
}
var createShadowDiv = function(cname) {
var shadowdiv = document.createElement('div');
YAHOO.util.Dom.addClass(shadowdiv, cname);
if (YAHOO.env.ua.ie > 0 && YAHOO.env.ua.ie < 7) {
// IE version less than 7 doesnt support alpha
YAHOO.util.Dom.setStyle(shadowdiv, 'opacity', 0.3);
}
return shadowdiv;
}
if (top) shadow.appendChild(createShadowDiv('shadow_top'));
if (right) shadow.appendChild(createShadowDiv('shadow_right'));
if (bottom) shadow.appendChild(createShadowDiv('shadow_bottom'));
if (left) shadow.appendChild(createShadowDiv('shadow_left'));
if (top && left) shadow.appendChild(createShadowDiv('shadow_top_left'));
if (bottom && left) shadow.appendChild(createShadowDiv('shadow_bottom_left'));
if (top && right) shadow.appendChild(createShadowDiv('shadow_top_right'));
if (bottom && right) shadow.appendChild(createShadowDiv('shadow_bottom_right'));
return shadow;
}
/**
* This function removes any shadows that a node and its children may have
* @param {element} el The element to remove the shadow from
* @return {bool}
*/
function remove_shadow(el) {
var shadows = YAHOO.util.Dom.getElementsByClassName('divshadow', 'div', el);
if (shadows == null || shadows.length == 0) return true;
for (var i=0;i<shadows.length;i++) {
shadows[i].parentNode.removeChild(shadows[i]);
}
return true;
}
+36 -9
View File
@@ -721,18 +721,45 @@ function addonload(fn) {
fn();
}
}
function getElementsByClassName(oElm, strTagName, oClassNames) {
/**
* Replacement for getElementsByClassName in browsers that aren't cool enough
*
* Relying on the built-in getElementsByClassName is far, far faster than
* using YUI.
*
* Note: the third argument used to be an object with odd behaviour. It now
* acts like the 'name' in the HTML5 spec, though the old behaviour is still
* mimicked if you pass an object.
*
* @param {Node} oElm The top-level node for searching. To search a whole
* document, use `document`.
* @param {String} strTagName filter by tag names
* @param {String} name same as HTML5 spec
*/
function getElementsByClassName(oElm, strTagName, name) {
// for backwards compatibility
if(typeof name == "object") {
var names = new Array();
for(var i=0; i<name.length; i++) names.push(names[i]);
name = names.join('');
}
// use native implementation if possible
if (oElm.getElementsByClassName && Array.filter) {
if (strTagName == '*') {
return oElm.getElementsByClassName(name);
} else {
return Array.filter(oElm.getElementsByClassName(name), function(el) {
return el.nodeName.toLowerCase() == strTagName.toLowerCase();
});
}
}
// native implementation unavailable, fall back to slow method
var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
var arrRegExpClassNames = new Array();
if(typeof oClassNames == "object") {
for(var i=0; i<oClassNames.length; i++) {
arrRegExpClassNames.push(new RegExp("(^|\\s)" + oClassNames[i].replace(/\-/g, "\\-") + "(\\s|$)"));
}
}
else{
arrRegExpClassNames.push(new RegExp("(^|\\s)" + oClassNames.replace(/\-/g, "\\-") + "(\\s|$)"));
var names = name.split(' ');
for(var i=0; i<names.length; i++) {
arrRegExpClassNames.push(new RegExp("(^|\\s)" + names[i].replace(/\-/g, "\\-") + "(\\s|$)"));
}
var oElement;
var bMatchesAll;
File diff suppressed because it is too large Load Diff
+91 -8
View File
@@ -495,21 +495,21 @@ class moodle_core_renderer extends moodle_renderer_base {
$this->page->requires->js('lib/overlib/overlib.js')->in_head();
$this->page->requires->js('lib/overlib/overlib_cssstyle.js')->in_head();
$this->page->requires->js('lib/cookies.js')->in_head();
$this->page->requires->js_function_call('setTimeout', Array('fix_column_widths()', 20));
$this->page->requires->js_function_call('setTimeout', array('fix_column_widths()', 20));
$focus = $this->page->focuscontrol;
if (!empty($focus)) {
if (preg_match("#forms\['([a-zA-Z0-9]+)'\].elements\['([a-zA-Z0-9]+)'\]#", $focus, $matches)) {
// This is a horrifically bad way to handle focus but it is passed in
// through messy formslib::moodleform
$this->page->requires->js_function_call('old_onload_focus', Array($matches[1], $matches[2]));
$this->page->requires->js_function_call('old_onload_focus', array($matches[1], $matches[2]));
} else if (strpos($focus, '.')!==false) {
// Old style of focus, bad way to do it
debugging('This code is using the old style focus event, Please update this code to focus on an element id or the moodleform focus method.', DEBUG_DEVELOPER);
$this->page->requires->js_function_call('old_onload_focus', explode('.', $focus, 2));
} else {
// Focus element with given id
$this->page->requires->js_function_call('focuscontrol', Array($focus));
$this->page->requires->js_function_call('focuscontrol', array($focus));
}
}
@@ -691,7 +691,7 @@ class moodle_core_renderer extends moodle_renderer_base {
* removed when there is a $PAGE->... replacement.
* @return string HTML that you must output this, preferably immediately.
*/
public function header($navigation = '', $menu='') {
public function header($menu='') {
// TODO remove $navigation and $menu arguments - replace with $PAGE->navigation
global $USER, $CFG;
@@ -701,10 +701,10 @@ class moodle_core_renderer extends moodle_renderer_base {
$templatefile = $this->page->theme->template_for_page($this->page->generaltype);
if ($templatefile) {
// Render the template.
$template = $this->render_page_template($templatefile, $menu, $navigation);
$template = $this->render_page_template($templatefile, $menu);
} else {
// New style template not found, fall back to using header.html and footer.html.
$template = $this->handle_legacy_theme($navigation, $menu);
$template = $this->handle_legacy_theme($menu);
}
// Slice the template output into header and footer.
@@ -734,7 +734,7 @@ class moodle_core_renderer extends moodle_renderer_base {
* @param array $navigation The navigation that will be used in the included file
* @return string HTML code
*/
protected function render_page_template($templatefile, $menu, $navigation) {
protected function render_page_template($templatefile, $menu) {
global $CFG, $SITE, $THEME, $USER;
// The next lines are a bit tricky. The point is, here we are in a method
// of a renderer class, and this object may, or may not, be the same as
@@ -746,6 +746,9 @@ class moodle_core_renderer extends moodle_renderer_base {
$PAGE = $this->page;
$COURSE = $this->page->course;
// Required for legacy template uses
$navigation = $this->has_navbar();
ob_start();
include($templatefile);
$template = ob_get_contents();
@@ -759,12 +762,13 @@ class moodle_core_renderer extends moodle_renderer_base {
* @param array $menu The menu that will be used in the included file
* @return string HTML code
*/
protected function handle_legacy_theme($navigation, $menu) {
protected function handle_legacy_theme($menu) {
global $CFG, $SITE, $USER;
// Set a pretend global from the properties of this class.
// See the comment in render_page_template for a fuller explanation.
$COURSE = $this->page->course;
$THEME = $this->page->theme;
$OUTPUT = $this;
// Set up local variables that header.html expects.
$direction = $this->htmlattributes();
@@ -789,6 +793,7 @@ class moodle_core_renderer extends moodle_renderer_base {
$course = $this->page->course;
$performanceinfo = self::PERFORMANCE_INFO_TOKEN;
$navigation = $this->has_navbar();
if (!$menu && $navigation) {
$menu = $loggedinas;
}
@@ -2259,6 +2264,84 @@ class moodle_core_renderer extends moodle_renderer_base {
public function container_end() {
return $this->opencontainers->pop('container');
}
/**
* Make nested HTML lists out of the items
*
* The resulting list will look something like this:
*
* <pre>
* <<ul>>
* <<li>><div class='tree_item parent'>(item contents)</div>
* <<ul>
* <<li>><div class='tree_item'>(item contents)</div><</li>>
* <</ul>>
* <</li>>
* <</ul>>
* </pre>
*
* @param array[]tree_item $items
* @param array[string]string $attrs html attributes passed to the top of
* the list
* @return string HTML
*/
function tree_block_contents($items, $attrs=array()) {
// exit if empty, we don't want an empty ul element
if (empty($items)) {
return '';
}
// array of nested li elements
$lis = array();
foreach ($items as $item) {
// this applies to the li item which contains all child lists too
$content = $item->content($this);
$liclasses = array($item->get_css_type());
if (!$item->forceopen || (!$item->forceopen && $item->collapse) || (count($item->children)==0 && $item->nodetype==navigation_node::NODETYPE_BRANCH)) {
$liclasses[] = 'collapsed';
}
if ($item->isactive === true) {
$liclasses[] = 'current_branch';
}
$liattr = array('class'=>join(' ',$liclasses));
// class attribute on the div item which only contains the item content
$divclasses = array('tree_item');
if (!empty($item->children) || $item->nodetype==navigation_node::NODETYPE_BRANCH) {
$divclasses[] = 'branch';
} else {
$divclasses[] = 'leaf';
}
if (!empty($item->classes) && count($item->classes)>0) {
$divclasses[] = join(' ', $item->classes);
}
$divattr = array('class'=>join(' ', $divclasses));
if (!empty($item->id)) {
$divattr['id'] = $item->id;
}
$content = $this->output_tag('p', $divattr, $content) . $this->tree_block_contents($item->children);
if (!empty($item->preceedwithhr) && $item->preceedwithhr===true) {
$content = $this->output_tag('hr', array(), null).$content;
}
$content = $this->output_tag('li', $liattr, $content);
$lis[] = $content;
}
return $this->output_tag('ul', $attrs, implode("\n", $lis));
}
/**
* Return the navbar content so that it can be echoed out by the layout
* @return string XHTML navbar
*/
public function navbar() {
return $this->page->navbar->content();
}
/**
* Checks to see if there are any items on the navbar object
* @return bool true if there are, false if not
*/
public function has_navbar() {
return $this->page->navbar->has_items();
}
}
+40
View File
@@ -126,6 +126,12 @@ class moodle_page {
protected $_button = '';
protected $_theme = null;
/** @var null|global_navigation Contains the global navigation structure*/
protected $_navigation = null;
/** @var null|settings_navigation Contains the settings navigation structure*/
protected $_settingsnav = null;
/** @var null|navbar Contains the navbar structure*/
protected $_navbar = null;
/**
* Then the theme is initialsed, we save the stack trace, for use in error messages.
@@ -437,6 +443,40 @@ class moodle_page {
return $this->_opencontainers;
}
/**
* Return the navigation object
* @return global_navigation
*/
public function get_navigation() {
if ($this->_navigation === null) {
$this->_navigation = new global_navigation();
}
return $this->_navigation;
}
/**
* Return a navbar object
* @return navbar
*/
public function get_navbar() {
if ($this->_navbar === null) {
$this->_navbar = new navbar($this);
}
return $this->_navbar;
}
/**
* Returns the settings navigation object
* @return settings_navigation
*/
public function get_settingsnav() {
if ($this->_settingsnav === null) {
$this->_settingsnav = new settings_navigation($this);
$this->_settingsnav->initialise();
}
return $this->_settingsnav;
}
/**
* PHP overloading magic to make the $PAGE->course syntax work by redirecting
* it to the corresponding $PAGE->get_course() method if there is one, and
+1
View File
@@ -241,6 +241,7 @@ global $SCRIPT;
require_once($CFG->libdir .'/ajax/ajaxlib.php'); // Functions for managing our use of JavaScript and YUI
require_once($CFG->libdir .'/weblib.php'); // Functions relating to HTTP and content
require_once($CFG->libdir .'/outputlib.php'); // Functions for generating output
require_once($CFG->libdir .'/navigationlib.php'); // Class for generating Navigation structure
require_once($CFG->libdir .'/dmllib.php'); // Database access
require_once($CFG->libdir .'/datalib.php'); // Legacy lib with a big-mix of functions.
require_once($CFG->libdir .'/accesslib.php'); // Access control functions
+694
View File
@@ -0,0 +1,694 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for lib/navigationlib.php
*
* @package moodlecore
* @copyright 2009 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later (5)
*/
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
}
require_once($CFG->libdir . '/navigationlib.php');
class navigation_node_test extends UnitTestCase {
protected $tree;
public static $includecoverage = array('./lib/navigationlib.php');
public static $excludecoverage = array();
public function setUp() {
global $CFG, $FULLME;
parent::setUp();
$oldfullme = $FULLME;
$FULLME = 'http://www.moodle.org/test.php';
$this->node = new navigation_node('Test Node');
$this->node->type = navigation_node::TYPE_SYSTEM;
$this->node->add('demo1', null, 'demo1', navigation_node::TYPE_COURSE, 'http://www.moodle.org/',$CFG->httpswwwroot . '/pix/i/course.gif');
$this->node->add('demo2', null, 'demo2', navigation_node::TYPE_COURSE, 'http://www.moodle.com/',$CFG->httpswwwroot . '/pix/i/course.gif');
$this->node->add('demo3', null, 'demo3', navigation_node::TYPE_CATEGORY, 'http://www.moodle.org/',$CFG->httpswwwroot . '/pix/i/course.gif');
$this->node->get('demo3')->add('demo4', null, 'demo4', navigation_node::TYPE_COURSE, new moodle_url('http://www.moodle.org/'),$CFG->httpswwwroot . '/pix/i/course.gif');
$this->node->get('demo3')->add('demo5', null, 'demo5', navigation_node::TYPE_COURSE, 'http://www.moodle.org/test.php',$CFG->httpswwwroot . '/pix/i/course.gif');
$this->node->get('demo3')->get('demo5')->make_active();
$this->node->get('demo3')->get('demo5')->add('activity1', null, 'activity1',navigation_node::TYPE_ACTIVITY);
$this->node->get('demo3')->get('demo5')->get('activity1')->make_active();
$this->node->add('hiddendemo1', null, 'hiddendemo1', navigation_node::TYPE_CATEGORY, 'http://www.moodle.org/',$CFG->httpswwwroot . '/pix/i/course.gif');
$this->node->get('hiddendemo1')->hidden = true;
$this->node->get('hiddendemo1')->add('hiddendemo2', null, 'hiddendemo2', navigation_node::TYPE_COURSE, new moodle_url('http://www.moodle.org/'),$CFG->httpswwwroot . '/pix/i/course.gif');
$this->node->get('hiddendemo1')->add('hiddendemo3', null, 'hiddendemo3', navigation_node::TYPE_COURSE, new moodle_url('http://www.moodle.org/'),$CFG->httpswwwroot . '/pix/i/course.gif');
$this->node->get('hiddendemo1')->get('hiddendemo2')->helpbutton = 'Here is a help button';
$this->node->get('hiddendemo1')->get('hiddendemo3')->display = false;
$FULLME = $oldfullme;
}
public function test___construct() {
global $CFG;
$properties = array();
$properties['text'] = 'text';
$properties['shorttext'] = 'shorttext';
$properties['key'] = 'key';
$properties['type'] = 'navigation_node::TYPE_COURSE';
$properties['action'] = 'http://www.moodle.org/';
$properties['icon'] = $CFG->httpswwwroot . '/pix/i/course.gif';
$node = new navigation_node($properties);
$this->assertEqual($node->text, $properties['text']);
$this->assertEqual($node->title, $properties['text']);
$this->assertEqual($node->shorttext, $properties['shorttext']);
$this->assertEqual($node->key, $properties['key']);
$this->assertEqual($node->type, $properties['type']);
$this->assertEqual($node->action, $properties['action']);
$this->assertEqual($node->icon, $properties['icon']);
}
public function test_add() {
global $CFG;
// Add a node with all args set
$key1 = $this->node->add('test_add_1','testadd1','key',navigation_node::TYPE_COURSE,'http://www.moodle.org/',$CFG->httpswwwroot . '/pix/i/course.gif');
// Add a node with the minimum args required
$key2 = $this->node->add('test_add_2','testadd2');
$key3 = $this->node->add(str_repeat('moodle ', 15),str_repeat('moodle', 15));
$this->assertEqual('key',$key1);
$this->assertEqual($key2, $this->node->get($key2)->key);
$this->assertEqual($key3, $this->node->get($key3)->key);
$this->assertIsA($this->node->get('key'), 'navigation_node');
$this->assertIsA($this->node->get($key2), 'navigation_node');
$this->assertIsA($this->node->get($key3), 'navigation_node');
}
public function test_add_class() {
$node = $this->node->get('demo1');
$this->assertIsA($node, 'navigation_node');
if ($node !== false) {
$node->add_class('myclass');
$classes = $node->classes;
$this->assertTrue(in_array('myclass', $classes));
}
}
public function test_add_to_path() {
global $CFG;
$path = array('demo3','demo5');
$key1 = $this->node->add_to_path($path, 'testatp1', 'Test add to path 1', 'testatp1', navigation_node::TYPE_COURSE, 'http://www.moodle.org/',$CFG->httpswwwroot . '/pix/i/course.gif');
$this->assertEqual($key1, 'testatp1');
// This should generate an exception as we have not provided any text for
// the node
$this->expectException();
$key3 = $this->node->add_to_path(array('demo3','dud1','dud2'), 'text', 'shorttext');
$this->assertFalse($key3);
// This should generate an exception as we have not provided any text for
// the node
$this->expectException(new coding_exception('You must set the text for the node when you create it.'));
$key2 = $this->node->add_to_path($path);
}
public function test_check_if_active() {
global $FULLME;
$oldfullme = $FULLME;
// First test the string urls
$FULLME = 'http://www.moodle.org/';
// demo1 -> action is http://www.moodle.org/, thus should be true
$this->assertTrue($this->node->get('demo1')->check_if_active());
// demo2 -> action is http://www.moodle.com/, thus should be false
$this->assertFalse($this->node->get('demo2')->check_if_active());
$FULLME = $oldfullme;
}
public function test_contains_active_node() {
// demo5, and activity1 were set to active during setup
// Should be true as it contains all nodes
$this->assertTrue($this->node->contains_active_node());
// Should be true as demo5 is a child of demo3
$this->assertTrue($this->node->get('demo3')->contains_active_node());
// Obviously duff
$this->assertFalse($this->node->get('demo1')->contains_active_node());
// Should be true as demo5 contains activity1
$this->assertTrue($this->node->get('demo3')->get('demo5')->contains_active_node());
// Should be false activity1 doesnt contain the active node... it is the active node
$this->assertFalse($this->node->get('demo3')->get('demo5')->get('activity1')->contains_active_node());
// Obviously duff
$this->assertFalse($this->node->get('demo3')->get('demo4')->contains_active_node());
}
public function test_content() {
$content1 = $this->node->get('demo1')->content();
$content2 = $this->node->get('demo3')->content();
$content3 = $this->node->get('demo3')->get('demo5')->content();
$content4 = $this->node->get('hiddendemo1')->get('hiddendemo2')->content();
$content5 = $this->node->get('hiddendemo1')->get('hiddendemo3')->content();
$this->assert(new ContainsTagWithAttribute('a','href',$this->node->get('demo1')->action), $content1);
$this->assert(new ContainsTagWithAttribute('a','href',$this->node->get('demo3')->action), $content2);
$this->assert(new ContainsTagWithAttribute('a','href',$this->node->get('demo3')->get('demo5')->action), $content3);
$this->assert(new ContainsTagWithAttribute('a','href',$this->node->get('hiddendemo1')->get('hiddendemo2')->action->out()), $content4);
$this->assertTrue(empty($content5));
}
public function test_find_active_node() {
$activenode1 = $this->node->find_active_node();
$activenode2 = $this->node->find_active_node(navigation_node::TYPE_COURSE);
$activenode3 = $this->node->find_active_node(navigation_node::TYPE_CATEGORY);
$activenode4 = $this->node->get('demo1')->find_active_node(navigation_node::TYPE_COURSE);
$this->assertIsA($activenode1, 'navigation_node');
if ($activenode1 instanceof navigation_node) {
$this->assertEqual($activenode1, $this->node->get('demo3')->get('demo5'));
}
$this->assertIsA($activenode2, 'navigation_node');
if ($activenode1 instanceof navigation_node) {
$this->assertEqual($activenode2, $this->node->get('demo3')->get('demo5'));
}
$this->assertIsA($activenode3, 'navigation_node');
if ($activenode1 instanceof navigation_node) {
$this->assertEqual($activenode3, $this->node->get('demo3'));
}
$this->assertNotA($activenode4, 'navigation_node');
}
public function test_find_child() {
$node1 = $this->node->find_child('demo1', navigation_node::TYPE_COURSE);
$node2 = $this->node->find_child('demo5', navigation_node::TYPE_COURSE);
$node3 = $this->node->find_child('demo5', navigation_node::TYPE_CATEGORY);
$node4 = $this->node->find_child('demo0', navigation_node::TYPE_COURSE);
$this->assertIsA($node1, 'navigation_node');
$this->assertIsA($node2, 'navigation_node');
$this->assertNotA($node3, 'navigation_node');
$this->assertNotA($node4, 'navigation_node');
}
public function test_find_child_depth() {
$depth1 = $this->node->find_child_depth('demo1',navigation_node::TYPE_COURSE);
$depth2 = $this->node->find_child_depth('demo5',navigation_node::TYPE_COURSE);
$depth3 = $this->node->find_child_depth('demo5',navigation_node::TYPE_CATEGORY);
$depth4 = $this->node->find_child_depth('demo0',navigation_node::TYPE_COURSE);
$this->assertEqual(1, $depth1);
$this->assertEqual(1, $depth2);
$this->assertFalse($depth3);
$this->assertFalse($depth4);
}
public function test_find_expandable() {
$expandable = array();
$this->node->find_expandable($expandable);
$this->assertEqual(count($expandable), 5);
if (count($expandable) === 5) {
$name = $expandable[0]['branchid'];
$name .= $expandable[1]['branchid'];
$name .= $expandable[2]['branchid'];
$name .= $expandable[3]['branchid'];
$name .= $expandable[4]['branchid'];
$this->assertEqual($name, 'demo1demo2demo4hiddendemo2hiddendemo3');
}
}
public function test_get() {
$node1 = $this->node->get('demo1'); // Exists
$node2 = $this->node->get('demo4'); // Doesn't exist for this node
$node3 = $this->node->get('demo0'); // Doesn't exist at all
$node4 = $this->node->get(false); // Sometimes occurs in nature code
$this->assertIsA($node1, 'navigation_node');
$this->assertFalse($node2);
$this->assertFalse($node3);
$this->assertFalse($node4);
}
public function test_get_by_path() {
$node1 = $this->node->get_by_path(array('demo3', 'demo4')); // This path exists and should return a node
$node2 = $this->node->get_by_path(array('demo1', 'demo2')); // Both elements exist but demo2 is not a child of demo1
$node3 = $this->node->get_by_path(array('demo0', 'demo6')); // This path is totally bogus
$this->assertIsA($node1, 'navigation_node');
$this->assertFalse($node2);
$this->assertFalse($node3);
}
public function test_get_css_type() {
$csstype1 = $this->node->get('demo3')->get_css_type();
$csstype2 = $this->node->get('demo3')->get('demo5')->get_css_type();
$this->node->get('demo3')->get('demo5')->type = 1000;
$csstype3 = $this->node->get('demo3')->get('demo5')->get_css_type();
$this->assertEqual($csstype1, 'type_category');
$this->assertEqual($csstype2, 'type_course');
$this->assertEqual($csstype3, 'type_unknown');
}
public function test_make_active() {
global $CFG;
$key1 = $this->node->add('active node 1', null, 'anode1');
$key2 = $this->node->add('active node 2', null, 'anode2', navigation_node::TYPE_COURSE, new moodle_url($CFG->wwwroot));
$this->node->get($key1)->make_active();
$this->node->get($key2)->make_active();
$this->assertTrue($this->node->get($key1)->isactive);
$this->assertTrue($this->node->get($key2)->isactive);
}
public function test_reiterate_active_nodes() {
global $FULLME;
$oldfullme = $FULLME;
$FULLME = 'http://www.moodle.org/test.php';
$cachenode = serialize($this->node);
$cachenode = unserialize($cachenode);
$this->assertFalse($cachenode->get('demo3')->get('demo5')->isactive);
$this->assertTrue($cachenode->reiterate_active_nodes());
$this->assertTrue($cachenode->get('demo3')->get('demo5')->isactive);
$FULLME = $oldfullme;
}
public function test_remove_child() {
$this->node->add('child to remove 1', null, 'remove1');
$this->node->add('child to remove 2', null, 'remove2');
$this->node->get('remove2')->add('child to remove 3', null, 'remove3');
$this->assertIsA($this->node->get('remove1'), 'navigation_node');
$this->assertTrue($this->node->remove_child('remove1'));
$this->assertFalse($this->node->remove_child('remove3'));
$this->assertFalse($this->node->remove_child('remove0'));
$this->assertTrue($this->node->remove_child('remove2'));
}
public function test_remove_class() {
$this->node->add_class('testclass');
$this->assertTrue($this->node->remove_class('testclass'));
$this->assertFalse(in_array('testclass', $this->node->classes));
}
public function test_respect_forced_open() {
$this->node->respect_forced_open();
$this->assertTrue($this->node->forceopen);
}
public function test_toggle_type_display() {
$this->node->toggle_type_display(navigation_node::TYPE_CATEGORY);
$this->assertFalse($this->node->get('demo1')->display);
$this->assertFalse($this->node->get('demo3')->get('demo5')->display);
$this->assertTrue($this->node->get('demo3')->display);
$this->node->toggle_type_display(navigation_node::TYPE_CATEGORY, true);
}
}
/**
* This is a dummy object that allows us to call protected methods within the
* global navigation class by prefixing the methods with `exposed_`
*/
class exposed_global_navigation extends global_navigation {
protected $exposedkey = 'exposed_';
function __construct() {
parent::__construct();
$this->cache = new navigation_cache('simpletest_nav');
}
function __call($method, $arguments) {
if (strpos($method,$this->exposedkey) !== false) {
$method = substr($method, strlen($this->exposedkey));
}
if (method_exists($this, $method)) {
return call_user_func_array(array($this, $method), $arguments);
}
throw new coding_exception('You have attempted to access a method that does not exist for the given object '.$method, DEBUG_DEVELOPER);
}
}
class global_navigation_test extends UnitTestCase {
/**
* @var global_navigation
*/
public $node;
protected $cache;
public static $includecoverage = array('./lib/navigationlib.php');
public static $excludecoverage = array();
public function setUp() {
$this->cache = new navigation_cache('simpletest_nav');
$this->node = new exposed_global_navigation();
// Create an initial tree structure to work with
$this->node->add('category 1', null, 'cat1', navigation_node::TYPE_CATEGORY);
$this->node->add('category 2', null, 'cat2', navigation_node::TYPE_CATEGORY);
$this->node->add('category 3', null, 'cat3', navigation_node::TYPE_CATEGORY);
$this->node->get('cat2')->add('sub category 1', null, 'sub1', navigation_node::TYPE_CATEGORY);
$this->node->get('cat2')->add('sub category 2', null, 'sub2', navigation_node::TYPE_CATEGORY);
$this->node->get('cat2')->add('sub category 3', null, 'sub3', navigation_node::TYPE_CATEGORY);
$this->node->get('cat2')->get('sub2')->add('course 1', null, 'course1', navigation_node::TYPE_COURSE);
$this->node->get('cat2')->get('sub2')->add('course 2', null, 'course2', navigation_node::TYPE_COURSE);
$this->node->get('cat2')->get('sub2')->add('course 3', null, 'course3', navigation_node::TYPE_COURSE);
$this->node->get('cat2')->get('sub2')->get('course2')->add('section 1', null, 'sec1', navigation_node::TYPE_COURSE);
$this->node->get('cat2')->get('sub2')->get('course2')->add('section 2', null, 'sec2', navigation_node::TYPE_COURSE);
$this->node->get('cat2')->get('sub2')->get('course2')->add('section 3', null, 'sec3', navigation_node::TYPE_COURSE);
$this->node->get('cat2')->get('sub2')->get('course2')->get('sec2')->add('activity 1', null, 'act1', navigation_node::TYPE_ACTIVITY);
$this->node->get('cat2')->get('sub2')->get('course2')->get('sec2')->add('activity 2', null, 'act2', navigation_node::TYPE_ACTIVITY);
$this->node->get('cat2')->get('sub2')->get('course2')->get('sec2')->add('activity 3', null, 'act3', navigation_node::TYPE_ACTIVITY);
$this->node->get('cat2')->get('sub2')->get('course2')->get('sec2')->add('resource 1', null, 'res1', navigation_node::TYPE_RESOURCE);
$this->node->get('cat2')->get('sub2')->get('course2')->get('sec2')->add('resource 2', null, 'res2', navigation_node::TYPE_RESOURCE);
$this->node->get('cat2')->get('sub2')->get('course2')->get('sec2')->add('resource 3', null, 'res3', navigation_node::TYPE_RESOURCE);
$this->cache->clear();
$this->cache->modinfo5 = unserialize('O:6:"object":6:{s:8:"courseid";s:1:"5";s:6:"userid";s:1:"2";s:8:"sections";a:1:{i:0;a:1:{i:0;s:3:"288";}}s:3:"cms";a:1:{i:288;O:6:"object":17:{s:2:"id";s:3:"288";s:8:"instance";s:2:"19";s:6:"course";s:1:"5";s:7:"modname";s:5:"forum";s:4:"name";s:10:"News forum";s:7:"visible";s:1:"1";s:10:"sectionnum";s:1:"0";s:9:"groupmode";s:1:"0";s:10:"groupingid";s:1:"0";s:16:"groupmembersonly";s:1:"0";s:6:"indent";s:1:"0";s:10:"completion";s:1:"0";s:5:"extra";s:0:"";s:4:"icon";s:0:"";s:11:"uservisible";b:1;s:9:"modplural";s:6:"Forums";s:9:"available";b:1;}}s:9:"instances";a:1:{s:5:"forum";a:1:{i:19;R:8;}}s:6:"groups";N;}');
$this->cache->coursesections5 = unserialize('a:5:{i:0;O:8:"stdClass":6:{s:7:"section";s:1:"0";s:2:"id";s:2:"14";s:6:"course";s:1:"5";s:7:"summary";N;s:8:"sequence";s:3:"288";s:7:"visible";s:1:"1";}i:1;O:8:"stdClass":6:{s:7:"section";s:1:"1";s:2:"id";s:2:"97";s:6:"course";s:1:"5";s:7:"summary";s:0:"";s:8:"sequence";N;s:7:"visible";s:1:"1";}i:2;O:8:"stdClass":6:{s:7:"section";s:1:"2";s:2:"id";s:2:"98";s:6:"course";s:1:"5";s:7:"summary";s:0:"";s:8:"sequence";N;s:7:"visible";s:1:"1";}i:3;O:8:"stdClass":6:{s:7:"section";s:1:"3";s:2:"id";s:2:"99";s:6:"course";s:1:"5";s:7:"summary";s:0:"";s:8:"sequence";N;s:7:"visible";s:1:"1";}i:4;O:8:"stdClass":6:{s:7:"section";s:1:"4";s:2:"id";s:3:"100";s:6:"course";s:1:"5";s:7:"summary";s:0:"";s:8:"sequence";N;s:7:"visible";s:1:"1";}}');
$this->cache->canviewhiddenactivities = true;
$this->cache->canviewhiddensections = true;
$this->cache->canviewhiddencourses = true;
$this->node->get('cat2')->get('sub2')->add('Test Course 5',null,'5',navigation_node::TYPE_COURSE, new moodle_url('http://moodle.org'));
}
public function test_add_categories() {
$categories = array();
for ($i=0;$i<3;$i++) {
$categories[$i] = new stdClass;
$categories[$i]->id = 'sub4_'.$i;
$categories[$i]->name = 'add_categories '.$i;
}
$this->node->exposed_add_categories(array('cat3'), $categories);
$this->assertEqual(count($this->node->get('cat3')->children), 3);
$this->assertIsA($this->node->get('cat3')->get('sub4_1'), 'navigation_node');
$this->node->get('cat3')->children = array();
}
public function test_add_course_section_generic() {
$keys = array('cat2', 'sub2', '5');
$course = new stdClass;
$course->id = '5';
$this->node->add_course_section_generic($keys, $course, 'topic', 'topic');
$this->assertEqual(count($this->node->get_by_path($keys)->children),4);
}
public function test_add_category_by_path() {
$category = new stdClass;
$category->id = 'sub3';
$category->name = 'Sub category 3';
$category->path = '/cat2/sub3';
$this->node->exposed_add_category_by_path($category);
$this->assertIsA($this->node->get('cat2')->get('sub3'), 'navigation_node');
}
public function test_add_courses() {
$courses = array();
for ($i=0;$i<5;$i++) {
$course = new stdClass;
$course->id = $i;
$course->visible = true;
$course->category = 'cat3';
$course->fullname = "Test Course $i";
$course->shortname = "tcourse$i";
$courses[$i] = $course;
}
$this->node->add_courses($courses);
$this->assertIsA($this->node->get('cat3')->get(0), 'navigation_node');
$this->assertIsA($this->node->get('cat3')->get(1), 'navigation_node');
$this->assertIsA($this->node->get('cat3')->get(2), 'navigation_node');
$this->assertIsA($this->node->get('cat3')->get(3), 'navigation_node');
$this->assertIsA($this->node->get('cat3')->get(4), 'navigation_node');
$this->node->get('cat3')->children = array();
}
public function test_can_display_type() {
$this->node->expansionlimit = navigation_node::TYPE_COURSE;
$this->assertTrue($this->node->exposed_can_display_type(navigation_node::TYPE_CATEGORY));
$this->assertTrue($this->node->exposed_can_display_type(navigation_node::TYPE_COURSE));
$this->assertFalse($this->node->exposed_can_display_type(navigation_node::TYPE_SECTION));
$this->node->expansionlimit = null;
}
public function test_content() {
$html1 = $this->node->content();
$this->node->expansionlimit = navigation_node::TYPE_CATEGORY;
$html2 = $this->node->content();
$this->node->expansionlimit = null;
$this->assert(new ContainsTagWithAttribute('a','href',$this->node->action->out()), $html1);
$this->assert(new ContainsTagWithAttribute('a','href',$this->node->action->out()), $html2);
}
public function test_format_display_course_content() {
$this->assertTrue($this->node->exposed_format_display_course_content('topic'));
$this->assertFalse($this->node->exposed_format_display_course_content('scorm'));
$this->assertTrue($this->node->exposed_format_display_course_content('dummy'));
}
public function test_load_course() {
$course = new stdClass;
$course->id = 'tcourse10';
$course->fullname = 'Test Course 10';
$course->shortname = 'tcourse10';
$course->visible = true;
$this->node->exposed_load_course(array('cat2','sub3'), $course);
$this->assertIsA($this->node->get('cat2')->get('sub3')->get('tcourse10'), 'navigation_node');
}
public function test_load_course_activities() {
$keys = array('cat2', 'sub2', '5');
$course = new stdClass;
$course->id = '5';
$modinfo = $this->cache->modinfo5;
$modinfo->cms[290] = clone($modinfo->cms[288]);
$modinfo->cms[290]->id = 290;
$modinfo->cms[290]->modname = 'resource';
$modinfo->cms[290]->instance = 21;
$modinfo->instances['resource'] = array();
$modinfo->instances['resource'][21] = clone($modinfo->instances['forum'][19]);
$modinfo->instances['resource'][21]->id = 21;
$this->cache->modinfo5 = $modinfo;
$this->node->exposed_load_course_activities($keys, $course);
$this->assertIsA($this->node->get_by_path(array_merge($keys, array(288))), 'navigation_node');
$this->assertEqual($this->node->get_by_path(array_merge($keys, array(288)))->type, navigation_node::TYPE_ACTIVITY);
$this->assertIsA($this->node->get_by_path(array_merge($keys, array(290))), 'navigation_node');
$this->assertEqual($this->node->get_by_path(array_merge($keys, array(290)))->type, navigation_node::TYPE_RESOURCE);
}
public function test_load_course_sections() {
$keys = array('cat2', 'sub2', '5');
$course = new stdClass;
$course->id = '5';
$course->format = 'topics';
$coursechildren = $this->node->get_by_path($keys)->children;
$this->node->get_by_path(array('cat2', 'sub2', '5'))->children = array();
$this->node->exposed_load_course_sections($keys, $course);
$course->format = 'topics';
$this->node->get_by_path(array('cat2', 'sub2', '5'))->children = array();
$this->node->exposed_load_course_sections($keys, $course);
$course->format = 'scorm';
$this->node->get_by_path(array('cat2', 'sub2', '5'))->children = array();
$this->node->exposed_load_course_sections($keys, $course);
$course->format = 'sillywilly';
$this->node->get_by_path(array('cat2', 'sub2', '5'))->children = array();
$this->node->exposed_load_course_sections($keys, $course);
$this->node->get_by_path($keys)->children = $coursechildren;
}
public function test_load_for_user() {
$this->node->exposed_load_for_user();
}
public function test_load_section_activities() {
$keys = array('cat2', 'sub2', '5');
$course = new stdClass;
$course->id = '5';
$this->node->get_by_path($keys)->add('Test Section 1', null, $this->cache->coursesections5[1]->id, navigation_node::TYPE_SECTION);
$modinfo = $this->cache->modinfo5;
$modinfo->sections[1] = array(289, 290);
$modinfo->cms[289] = clone($modinfo->cms[288]);
$modinfo->cms[289]->id = 289;
$modinfo->cms[289]->sectionnum = 1;
$modinfo->cms[290]->modname = 'forum';
$modinfo->cms[289]->instance = 20;
$modinfo->cms[290] = clone($modinfo->cms[288]);
$modinfo->cms[290]->id = 290;
$modinfo->cms[290]->modname = 'resource';
$modinfo->cms[290]->sectionnum = 1;
$modinfo->cms[290]->instance = 21;
$modinfo->instances['forum'][20] = clone($modinfo->instances['forum'][19]);
$modinfo->instances['forum'][20]->id = 20;
$modinfo->instances['resource'] = array();
$modinfo->instances['resource'][21] = clone($modinfo->instances['forum'][19]);
$modinfo->instances['resource'][21]->id = 21;
$this->cache->modinfo5 = $modinfo;
$this->node->exposed_load_section_activities($keys, 1, $course);
$keys[] = 97;
$this->assertIsA($this->node->get_by_path(array_merge($keys, array(289))),'navigation_node');
$this->assertEqual($this->node->get_by_path(array_merge($keys, array(289)))->type, navigation_node::TYPE_ACTIVITY);
$this->assertIsA($this->node->get_by_path(array_merge($keys, array(290))),'navigation_node');
$this->assertEqual($this->node->get_by_path(array_merge($keys, array(290)))->type, navigation_node::TYPE_RESOURCE);
}
public function test_module_extends_navigation() {
$this->cache->test1_extends_navigation = true;
$this->cache->test2_extends_navigation = false;
$this->assertTrue($this->node->exposed_module_extends_navigation('forum'));
$this->assertTrue($this->node->exposed_module_extends_navigation('test1'));
$this->assertFalse($this->node->exposed_module_extends_navigation('test2'));
$this->assertFalse($this->node->exposed_module_extends_navigation('test3'));
}
}
/**
* This is a dummy object that allows us to call protected methods within the
* global navigation class by prefixing the methods with `exposed_`
*/
class exposed_navbar extends navbar {
protected $exposedkey = 'exposed_';
function __construct() {
global $PAGE;
parent::__construct($PAGE);
$this->cache = new navigation_cache('simpletest_nav');
}
function __call($method, $arguments) {
if (strpos($method,$this->exposedkey) !== false) {
$method = substr($method, strlen($this->exposedkey));
}
if (method_exists($this, $method)) {
return call_user_func_array(array($this, $method), $arguments);
}
throw new coding_exception('You have attempted to access a method that does not exist for the given object '.$method, DEBUG_DEVELOPER);
}
}
class navbar_test extends UnitTestCase {
protected $node;
protected $oldnav;
public static $includecoverage = array('./lib/navigationlib.php');
public static $excludecoverage = array();
public function setUp() {
global $PAGE;
$this->oldnav = $PAGE->navigation;
$this->cache = new navigation_cache('simpletest_nav');
$this->node = new exposed_navbar();
$temptree = new global_navigation_test();
$temptree->setUp();
$temptree->node->get_by_path(array('cat2','sub2', 'course2'))->make_active();
$PAGE->navigation = $temptree->node;
}
public function tearDown() {
global $PAGE;
$PAGE->navigation = $this->oldnav;
}
public function test_add() {
global $CFG;
// Add a node with all args set
$this->node->add('test_add_1','testadd1','testadd1',navigation_node::TYPE_COURSE,'http://www.moodle.org/',$CFG->httpswwwroot . '/pix/i/course.gif');
// Add a node with the minimum args required
$key2 = $this->node->add('test_add_2');
$this->assertIsA($this->node->get('testadd1'), 'navigation_node');
$this->assertIsA($this->node->get('testadd1')->get($key2), 'navigation_node');
}
public function test_content() {
$html = $this->node->content();
$this->assert(new ContainsTagWithAttribute('a','href',$this->node->action->out()), $html);
}
public function test_has_items() {
global $PAGE;
$this->assertTrue($this->node->has_items());
$PAGE->navigation->get_by_path(array('cat2','sub2', 'course2'))->remove_class('active_tree_node');
$PAGE->navigation->get_by_path(array('cat2','sub2', 'course2'))->isactive = false;
$this->assertFalse($this->node->has_items());
$PAGE->navigation->get_by_path(array('cat2','sub2', 'course2'))->make_active();
}
public function test_parse_branch_to_html() {
global $CFG;
$key = $this->node->add('test_add_1','testadd1','testadd1',navigation_node::TYPE_COURSE,'http://www.moodle.org/',$CFG->httpswwwroot . '/pix/i/course.gif');
$this->node->get($key)->make_active();
$html = $this->node->exposed_parse_branch_to_html($this->node->children, true);
$this->assert(new ContainsTagWithAttribute('a','href',$this->node->action->out()), $html);
}
}
class navigation_cache_test extends UnitTestCase {
protected $cache;
public static $includecoverage = array('./lib/navigationlib.php');
public static $excludecoverage = array();
public function setUp() {
$this->cache = new navigation_cache('simpletest_nav');
$this->cache->anysetvariable = true;
}
public function test___get() {
$this->assertTrue($this->cache->anysetvariable);
$this->assertEqual($this->cache->notasetvariable, null);
}
public function test___set() {
$this->cache->myname = 'Sam Hemelryk';
$this->assertTrue($this->cache->cached('myname'));
$this->assertEqual($this->cache->myname, 'Sam Hemelryk');
}
public function test_cached() {
$this->assertTrue($this->cache->cached('anysetvariable'));
$this->assertFalse($this->cache->cached('notasetvariable'));
}
public function test_clear() {
$cache = clone($this->cache);
$this->assertTrue($cache->cached('anysetvariable'));
$cache->clear();
$this->assertFalse($cache->cached('anysetvariable'));
}
public function test_set() {
$this->cache->set('software', 'Moodle');
$this->assertTrue($this->cache->cached('software'));
$this->assertEqual($this->cache->software, 'Moodle');
}
}
/**
* This is a dummy object that allows us to call protected methods within the
* global navigation class by prefixing the methods with `exposed_`
*/
class exposed_settings_navigation extends settings_navigation {
protected $exposedkey = 'exposed_';
function __construct() {
global $PAGE;
parent::__construct($PAGE);
$this->cache = new navigation_cache('simpletest_nav');
}
function __call($method, $arguments) {
if (strpos($method,$this->exposedkey) !== false) {
$method = substr($method, strlen($this->exposedkey));
}
if (method_exists($this, $method)) {
return call_user_func_array(array($this, $method), $arguments);
}
throw new coding_exception('You have attempted to access a method that does not exist for the given object '.$method, DEBUG_DEVELOPER);
}
}
class settings_navigation_test extends UnitTestCase {
protected $node;
protected $cache;
public static $includecoverage = array('./lib/navigationlib.php');
public static $excludecoverage = array();
public function setUp() {
global $PAGE;
$this->cache = new navigation_cache('simpletest_nav');
$this->node = new exposed_settings_navigation();
}
public function test___construct() {
$this->node = new exposed_settings_navigation();
}
public function test___initialise() {
$this->node->initialise();
$this->assertEqual($this->node->id, 'settingsnav');
}
public function test_load_front_page_settings() {
$this->node->exposed_load_front_page_settings();
$settings = false;
foreach ($this->node->children as $child) {
if ($child->id === 'frontpagesettings') {
$settings = $child;
}
}
$this->assertIsA($settings, 'navigation_node');
}
public function test_in_alternative_role() {
$this->assertFalse($this->node->exposed_in_alternative_role());
}
public function test_remove_empty_root_branches() {
$this->node->add('rootbranch1', null, 'rootbranch1');
$this->node->add('rootbranch2', null, 'rootbranch2');
$this->node->add('rootbranch3', null, 'rootbranch3');
$this->node->get('rootbranch2')->add('something', null, null, navigation_node::TYPE_SETTING);
$this->node->remove_empty_root_branches();
$this->assertFalse($this->node->get('rootbranch1'));
$this->assertIsA($this->node->get('rootbranch2'), 'navigation_node');
$this->assertFalse($this->node->get('rootbranch3'));
}
}
-415
View File
@@ -2082,262 +2082,6 @@ function get_separator() {
return ' '.link_arrow_right($text='/', $url='', $accesshide=true, 'sep').' ';
}
/**
* Prints breadcrumb trail of links, called in theme/-/header.html
*
* @global object
* @global object
* @global object
* @uses CONTEXT_SYSTEM
* @param mixed $navigation The breadcrumb navigation string to be printed
* @param string $separator OBSOLETE, mostly not used any more. See build_navigation instead.
* @param boolean $return False to echo the breadcrumb string (default), true to return it.
* @return string|void String or null, depending on $return.
*/
function print_navigation ($navigation, $separator=0, $return=false) {
global $CFG, $THEME, $SITE;
$output = '';
if (0 === $separator) {
$separator = get_separator();
}
else {
$separator = '<span class="sep">'. $separator .'</span>';
}
if ($navigation) {
if (is_newnav($navigation)) {
if ($return) {
return($navigation['navlinks']);
} else {
echo $navigation['navlinks'];
return;
}
} else {
debugging('Navigation needs to be updated to use build_navigation()', DEBUG_DEVELOPER);
}
if (!is_array($navigation)) {
$ar = explode('->', $navigation);
$navigation = array();
foreach ($ar as $a) {
if (strpos($a, '</a>') === false) {
$navigation[] = array('title' => $a, 'url' => '');
} else {
if (preg_match('/<a.*href="([^"]*)">(.*)<\/a>/', $a, $matches)) {
$navigation[] = array('title' => $matches[2], 'url' => $matches[1]);
}
}
}
}
if (!$SITE) {
$site = new object();
$site->shortname = get_string('home');
} else {
$site = $SITE;
}
//Accessibility: breadcrumb links now in a list, &raquo; replaced with a 'silent' character.
$output .= get_accesshide(get_string('youarehere','access'), 'h2')."<ul>\n";
$output .= '<li class="first">'."\n".'<a '.$CFG->frametarget.' onclick="this.target=\''.$CFG->framename.'\'" href="'
.$CFG->wwwroot.((!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))
&& !empty($USER->id) && !empty($CFG->mymoodleredirect) && !isguest())
? '/my' : '') .'/">'. format_string($site->shortname) ."</a>\n</li>\n";
foreach ($navigation as $navitem) {
$title = trim(strip_tags(format_string($navitem['title'], false)));
$url = $navitem['url'];
if (empty($url)) {
$output .= '<li>'."$separator $title</li>\n";
} else {
$output .= '<li>'."$separator\n<a ".$CFG->frametarget.' onclick="this.target=\''.$CFG->framename.'\'" href="'
.$url.'">'."$title</a>\n</li>\n";
}
}
$output .= "</ul>\n";
}
if ($return) {
return $output;
} else {
echo $output;
}
}
/**
* This function will build the navigation string to be used by print_header
* and others.
*
* It automatically generates the site and course level (if appropriate) links.
*
* If you pass in a $cm object, the method will also generate the activity (e.g. 'Forums')
* and activityinstances (e.g. 'General Developer Forum') navigation levels.
*
* If you want to add any further navigation links after the ones this function generates,
* the pass an array of extra link arrays like this:
* array(
* array('name' => $linktext1, 'link' => $url1, 'type' => $linktype1),
* array('name' => $linktext2, 'link' => $url2, 'type' => $linktype2)
* )
* The normal case is to just add one further link, for example 'Editing forum' after
* 'General Developer Forum', with no link.
* To do that, you need to pass
* array(array('name' => $linktext, 'link' => '', 'type' => 'title'))
* However, becuase this is a very common case, you can use a shortcut syntax, and just
* pass the string 'Editing forum', instead of an array as $extranavlinks.
*
* At the moment, the link types only have limited significance. Type 'activity' is
* recognised in order to implement the $CFG->hideactivitytypenavlink feature. Types
* that are known to appear are 'home', 'course', 'activity', 'activityinstance' and 'title'.
* This really needs to be documented better. In the mean time, try to be consistent, it will
* enable people to customise the navigation more in future.
*
* When passing a $cm object, the fields used are $cm->modname, $cm->name and $cm->course.
* If you get the $cm object using the function get_coursemodule_from_instance or
* get_coursemodule_from_id (as recommended) then this will be done for you automatically.
* If you don't have $cm->modname or $cm->name, this fuction will attempt to find them using
* the $cm->module and $cm->instance fields, but this takes extra database queries, so a
* warning is printed in developer debug mode.
*
* @global object
* @global object
* @global object
* @global object
* @uses SITEID
* @uses DEBUG_DEVELOPER
* @uses CONTEXT_SYSTEM
* @param mixed $extranavlinks - Normally an array of arrays, keys: name, link, type. If you
* only want one extra item with no link, you can pass a string instead. If you don't want
* any extra links, pass an empty string.
* @param mixed $cm - optionally the $cm object, if you want this function to generate the
* activity and activityinstance levels of navigation too.
* @return array Navigation array
*/
function build_navigation($extranavlinks, $cm = null) {
global $CFG, $COURSE, $DB, $SITE;
if (is_string($extranavlinks)) {
if ($extranavlinks == '') {
$extranavlinks = array();
} else {
$extranavlinks = array(array('name' => $extranavlinks, 'link' => '', 'type' => 'title'));
}
}
$navlinks = array();
//Site name
if (!empty($SITE->shortname)) {
$navlinks[] = array(
'name' => format_string($SITE->shortname),
'link' => "$CFG->wwwroot/",
'type' => 'home');
}
// Course name, if appropriate.
if (isset($COURSE) && $COURSE->id != SITEID) {
$navlinks[] = array(
'name' => format_string($COURSE->shortname),
'link' => "$CFG->wwwroot/course/view.php?id=$COURSE->id",
'type' => 'course');
}
// Activity type and instance, if appropriate.
if (is_object($cm)) {
if (!isset($cm->modname)) {
debugging('The field $cm->modname should be set if you call build_navigation with '.
'a $cm parameter. If you get $cm using get_coursemodule_from_instance or '.
'get_coursemodule_from_id, this will be done automatically.', DEBUG_DEVELOPER);
if (!$cm->modname = $DB->get_field('modules', 'name', array('id'=>$cm->module))) {
print_error('cannotmoduletype');
}
}
if (!isset($cm->name)) {
debugging('The field $cm->name should be set if you call build_navigation with '.
'a $cm parameter. If you get $cm using get_coursemodule_from_instance or '.
'get_coursemodule_from_id, this will be done automatically.', DEBUG_DEVELOPER);
if (!$cm->name = $DB->get_field($cm->modname, 'name', array('id'=>$cm->instance))) {
print_error('cannotmodulename');
}
}
$navlinks[] = array(
'name' => get_string('modulenameplural', $cm->modname),
'link' => $CFG->wwwroot . '/mod/' . $cm->modname . '/index.php?id=' . $cm->course,
'type' => 'activity');
$navlinks[] = array(
'name' => format_string($cm->name),
'link' => $CFG->wwwroot . '/mod/' . $cm->modname . '/view.php?id=' . $cm->id,
'type' => 'activityinstance');
}
//Merge in extra navigation links
$navlinks = array_merge($navlinks, $extranavlinks);
// Work out whether we should be showing the activity (e.g. Forums) link.
// Note: build_navigation() is called from many places --
// install & upgrade for example -- where we cannot count on the
// roles infrastructure to be defined. Hence the during_initial_install() check.
if (!isset($CFG->hideactivitytypenavlink)) {
$CFG->hideactivitytypenavlink = 0;
}
if ($CFG->hideactivitytypenavlink == 2) {
$hideactivitylink = true;
} else if ($CFG->hideactivitytypenavlink == 1 && !during_initial_install() &&
!empty($COURSE->id) && $COURSE->id != SITEID) {
if (!isset($COURSE->context)) {
$COURSE->context = get_context_instance(CONTEXT_COURSE, $COURSE->id);
}
$hideactivitylink = !has_capability('moodle/course:manageactivities', $COURSE->context);
} else {
$hideactivitylink = false;
}
//Construct an unordered list from $navlinks
//Accessibility: heading hidden from visual browsers by default.
$navigation = get_accesshide(get_string('youarehere','access'), 'h2')." <ul>\n";
$lastindex = count($navlinks) - 1;
$i = -1; // Used to count the times, so we know when we get to the last item.
$first = true;
foreach ($navlinks as $navlink) {
$i++;
$last = ($i == $lastindex);
if (!is_array($navlink)) {
continue;
}
if (!empty($navlink['type']) && $navlink['type'] == 'activity' && !$last && $hideactivitylink) {
continue;
}
if ($first) {
$navigation .= '<li class="first">';
} else {
$navigation .= '<li>';
}
if (!$first) {
$navigation .= get_separator();
}
if ((!empty($navlink['link'])) && !$last) {
$navigation .= "<a onclick=\"this.target='$CFG->framename'\" href=\"{$navlink['link']}\">";
}
$navigation .= "{$navlink['name']}";
if ((!empty($navlink['link'])) && !$last) {
$navigation .= "</a>";
}
$navigation .= "</li>";
$first = false;
}
$navigation .= "</ul>";
return(array('newnav' => true, 'navlinks' => $navigation));
}
/**
* Print (or return) a collapisble region, that has a caption that can
* be clicked to expand or collapse the region.
@@ -2676,165 +2420,6 @@ function switchroles_form($courseid) {
return '';
}
/**
* Returns a small popup menu of course activity modules
*
* Given a course and a (current) coursemodule
* his function returns a small popup menu with all the
* course activity modules in it, as a navigation menu
* The data is taken from the serialised array stored in
* the course record
*
* @global object
* @global object
* @global object
* @global object
* @uses CONTEXT_COURSE
* @param object $course A {@link $COURSE} object.
* @param object $cm A {@link $COURSE} object.
* @param string $targetwindow The target window attribute to us
* @return string
*/
function navmenu($course, $cm=NULL, $targetwindow='self') {
global $CFG, $THEME, $USER, $DB, $OUTPUT;
require_once($CFG->dirroot . '/course/lib.php'); // Required for get_fast_modinfo
if (empty($THEME->navmenuwidth)) {
$width = 50;
} else {
$width = $THEME->navmenuwidth;
}
if ($cm) {
$cm = $cm->id;
}
if ($course->format == 'weeks') {
$strsection = get_string('week');
} else {
$strsection = get_string('topic');
}
$strjumpto = get_string('jumpto');
$modinfo = get_fast_modinfo($course);
$context = get_context_instance(CONTEXT_COURSE, $course->id);
$section = -1;
$selected = '';
$url = '';
$previousmod = NULL;
$backmod = NULL;
$nextmod = NULL;
$selectmod = NULL;
$logslink = NULL;
$flag = false;
$menu = array();
$menustyle = array();
$sections = $DB->get_records('course_sections', array('course'=>$course->id), 'section', 'section,visible,summary');
if (!empty($THEME->makenavmenulist)) { /// A hack to produce an XHTML navmenu list for use in themes
$THEME->navmenulist = navmenulist($course, $sections, $modinfo, $strsection, $strjumpto, $width, $cm);
}
foreach ($modinfo->cms as $mod) {
if ($mod->modname == 'label') {
continue;
}
if ($mod->sectionnum > $course->numsections) { /// Don't show excess hidden sections
break;
}
if (!$mod->uservisible) { // do not icnlude empty sections at all
continue;
}
if ($mod->sectionnum > 0 and $section != $mod->sectionnum) {
$thissection = $sections[$mod->sectionnum];
if ($thissection->visible or !$course->hiddensections or
has_capability('moodle/course:viewhiddensections', $context)) {
$thissection->summary = strip_tags(format_string($thissection->summary,true));
if ($course->format == 'weeks' or empty($thissection->summary)) {
$menu[] = '--'.$strsection ." ". $mod->sectionnum;
} else {
if (strlen($thissection->summary) < ($width-3)) {
$menu[] = '--'.$thissection->summary;
} else {
$menu[] = '--'.substr($thissection->summary, 0, $width).'...';
}
}
$section = $mod->sectionnum;
} else {
// no activities from this hidden section shown
continue;
}
}
$url = $mod->modname.'/view.php?id='. $mod->id;
if ($flag) { // the current mod is the "next" mod
$nextmod = $mod;
$flag = false;
}
$localname = $mod->name;
if ($cm == $mod->id) {
$selected = $url;
$selectmod = $mod;
$backmod = $previousmod;
$flag = true; // set flag so we know to use next mod for "next"
$localname = $strjumpto;
$strjumpto = '';
} else {
$localname = strip_tags(format_string($localname,true));
$tl=textlib_get_instance();
if ($tl->strlen($localname) > ($width+5)) {
$localname = $tl->substr($localname, 0, $width).'...';
}
if (!$mod->visible) {
$localname = '('.$localname.')';
}
}
$menu[$url] = $localname;
if (empty($THEME->navmenuiconshide)) {
$menustyle[$url] = 'style="background-image: url('.$OUTPUT->mod_icon_url('icon', $mod->modname) . ');"'; // Unfortunately necessary to do this here
}
$previousmod = $mod;
}
//Accessibility: added Alt text, replaced &gt; &lt; with 'silent' character and 'accesshide' text.
if ($selectmod and has_capability('coursereport/log:view', $context)) {
$logstext = get_string('alllogs');
$logslink = '<li>'."\n".'<a title="'.$logstext.'" '.
$CFG->frametarget.'onclick="this.target=\''.$CFG->framename.'\';"'.' href="'.
$CFG->wwwroot.'/course/report/log/index.php?chooselog=1&amp;user=0&amp;date=0&amp;id='.
$course->id.'&amp;modid='.$selectmod->id.'">'.
'<img class="icon log" src="'.$OUTPUT->old_icon_url('i/log') . '" alt="'.$logstext.'" /></a>'."\n".'</li>';
}
if ($backmod) {
$backtext= get_string('activityprev', 'access');
$backmod = '<li><form action="'.$CFG->wwwroot.'/mod/'.$backmod->modname.'/view.php" '.
'onclick="this.target=\''.$CFG->framename.'\';"'.'><fieldset class="invisiblefieldset">'.
'<input type="hidden" name="id" value="'.$backmod->id.'" />'.
'<button type="submit" title="'.$backtext.'">'.link_arrow_left($backtext, $url='', $accesshide=true).
'</button></fieldset></form></li>';
}
if ($nextmod) {
$nexttext= get_string('activitynext', 'access');
$nextmod = '<li><form action="'.$CFG->wwwroot.'/mod/'.$nextmod->modname.'/view.php" '.
'onclick="this.target=\''.$CFG->framename.'\';"'.'><fieldset class="invisiblefieldset">'.
'<input type="hidden" name="id" value="'.$nextmod->id.'" />'.
'<button type="submit" title="'.$nexttext.'">'.link_arrow_right($nexttext, $url='', $accesshide=true).
'</button></fieldset></form></li>';
}
return '<div class="navigation">'."\n".'<ul>'.$logslink . $backmod .
'<li>'.popup_form($CFG->wwwroot .'/mod/', $menu, 'navmenupopup', $selected, $strjumpto,
'', '', true, $targetwindow, '', $menustyle).'</li>'.
$nextmod . '</ul>'."\n".'</div>';
}
/**
* Returns a popup menu with course activity modules
*
+177
View File
@@ -8177,3 +8177,180 @@ class forum_portfolio_caller extends portfolio_module_caller_base {
return get_string('modulename', 'forum');
}
}
/**
* This function is used to extend the global navigation by add forum nodes if there
* is relevant content.
*
* @param navigation_node $navref
* @param stdClass $course
* @param stdClass $module
* @param stdClass $cm
*/
function forum_extend_navigation($navref, $course, $module, $cm) {
global $CFG, $OUTPUT, $USER;
$limit = 5;
$discussions = forum_get_discussions($cm,"d.timemodified DESC", false, -1, $limit);
$discussioncount = forum_get_discussions_count($cm);
if (!is_array($discussions) || count($discussions)==0) {
return;
}
$discussionkey = $navref->add(get_string('discussions', 'forum').' ('.$discussioncount.')');
$navref->get($discussionkey)->mainnavonly = true;
foreach ($discussions as $discussion) {
$icon = $OUTPUT->old_icon_url('i/feedback');
$url = new moodle_url($CFG->wwwroot.'/mod/forum/discuss.php', array('d'=>$discussion->discussion));
$navref->get($discussionkey)->add($discussion->subject, null, null, null, $url, $icon);
}
if ($discussioncount > count($discussions)) {
if (!empty($navref->action)) {
$url = $navref->action;
} else {
$url = new moodle_url($CFG->wwwroot.'/mod/forum/view.php', array('id'=>$cm->id));
}
$childkey = $navref->get($discussionkey)->add(get_string('viewalldiscussions', 'forum'), null, null, null, $url, $icon);
}
$index = 0;
$recentposts = array();
$lastlogin = time() - COURSE_MAX_RECENT_PERIOD;
if (!isguestuser() and !empty($USER->lastcourseaccess[$course->id])) {
if ($USER->lastcourseaccess[$course->id] > $lastlogin) {
$lastlogin = $USER->lastcourseaccess[$course->id];
}
}
forum_get_recent_mod_activity($recentposts, $index, $lastlogin, $course->id, $cm->id);
if (is_array($recentposts) && count($recentposts)>0) {
$recentkey = $navref->add(get_string('recentactivity').' ('.count($recentposts).')');
$navref->get($recentkey)->mainnavonly = true;
foreach ($recentposts as $post) {
$icon = $OUTPUT->old_icon_url('i/feedback');
$url = new moodle_url($CFG->wwwroot.'/mod/forum/discuss.php', array('d'=>$post->content->discussion));
$title = $post->content->subject."\n".userdate($post->timestamp, get_string('strftimerecent', 'langconfig'))."\n".$post->user->firstname.' '.$post->user->lastname;
$navref->get($recentkey)->add($title, null, null, null, $url, $icon);
}
}
}
/**
* This function is used to extend the settings navigation with settings for the module
* It is called when the context for the page is a forum module
*
* @param settings_navigation $settingsnav {@link settings_navigation}
* @param stdClass $module
* @return void|mixed The key to the modules branch
*/
function forum_extend_settings_navigation($settingsnav, $module=null) {
global $USER, $PAGE, $FULLME, $CFG, $DB, $OUTPUT;
$forumkey = $settingsnav->add(get_string('forumadministration', 'forum'));
$forum = $settingsnav->get($forumkey);
$forum->forceopen = true;
$forumobject = $DB->get_record("forum", array("id" => $PAGE->cm->instance));
if (!empty($USER->id) && !has_capability('moodle/legacy:guest', $PAGE->cm->context, NULL, false)) {
$notekey = false;
$helpbutton = false;
if (forum_is_forcesubscribed($forumobject)) {
$notekey = $forum->add(get_string("forcessubscribe", 'forum'));
$string = get_string('allowchoice', 'forum');
$helpbutton = new moodle_help_icon();
$helpbutton->page = "subscription";
$helpbutton->text = $string;
$helpbutton->module = "forum";
if (has_capability('mod/forum:managesubscriptions', $PAGE->cm->context)) {
$url = new moodle_url($CFG->wwwroot.'/mod/forum/subscribe.php', array('id'=>$forumobject->id, 'force'=>'no'));
$forum->add($string, null, null, settings_navigation::TYPE_SETTING, $url);
} else {
$forum->add(get_string('everyoneisnowsubscribed', 'forum'));
}
} else if ($forumobject->forcesubscribe == FORUM_DISALLOWSUBSCRIBE) {
$string = get_string('disallowsubscribe', 'forum');
$notekey = $forum->add($string);
$helpbutton = new moodle_help_icon();
$helpbutton->page = "subscription";
$helpbutton->text = $string;
$helpbutton->module = "forum";
} else {
$string = get_string("forcesubscribe", "forum");
$notekey = $forum->add(get_string("allowsallsubscribe", 'forum'));
$helpbutton = new moodle_help_icon();
$helpbutton->page = "subscription";
$helpbutton->text = $string;
$helpbutton->module = "forum";
if (has_capability('mod/forum:managesubscriptions', $PAGE->cm->context)) {
$url = new moodle_url($CFG->wwwroot.'/mod/forum/subscribe.php', array('id'=>$forumobject->id, 'force'=>'yes'));
$forum->add($string, null, null, settings_navigation::TYPE_SETTING, $url);
} else {
$forum->add(get_string('everyonecannowchoose', 'forum'));
}
if(has_capability('mod/forum:viewsubscribers', $PAGE->cm->context)){
$url = new moodle_url($CFG->wwwroot.'/mod/forum/subscribers.php', array('id'=>$forumobject->id));
$forum->add(get_string('showsubscribers', 'forum'), null, null, settings_navigation::TYPE_SETTING, $url);
}
if (forum_is_forcesubscribed($forumobject) || ($forumobject->forcesubscribe == FORUM_DISALLOWSUBSCRIBE && !has_capability('mod/forum:managesubscriptions', $PAGE->cm->context))) {
// Do nothing
} else {
if (forum_is_subscribed($USER->id, $forumobject)) {
$linktext = get_string('unsubscribe', 'forum');
} else {
$linktext = get_string('subscribe', 'forum');
}
$url = new moodle_url($CFG->wwwroot . '/mod/forum/subscribe.php', array('id'=>$forumobject->id));
$forum->add($linktext, null, null, settings_navigation::TYPE_SETTING, $url);
}
}
if (forum_tp_can_track_forums($forumobject)) {
if (forum_tp_is_tracked($forumobject)) {
$linktext = get_string('notrackforum', 'forum');
} else {
$linktext = get_string('trackforum', 'forum');
}
$url = new moodle_url($CFG->wwwroot . '/mod/forum/settracking.php', array('id'=>$forumobject->id));
$forum->add($linktext, null, null, settings_navigation::TYPE_SETTING, $url);
}
if ($notekey!==false) {
$forum->get($notekey)->add_class('note');
if ($helpbutton!==false) {
$forum->get($notekey)->helpbutton = $OUTPUT->help_icon($helpbutton);
}
}
if (has_capability('moodle/course:manageactivities', $PAGE->cm->context)) {
$modulename = get_string('modulename', 'forum');
$string = get_string('updatethis', '', $modulename);
$url = new moodle_url("$CFG->wwwroot/course/mod.php", array('update' => $PAGE->cm->id, 'return' => true, 'sesskey' => sesskey()));
$forum->add($string, null, null, settings_navigation::TYPE_SETTING, $url);
}
}
if (!empty($CFG->enablerssfeeds) && !empty($CFG->forum_enablerssfeeds) && $forumobject->rsstype && $forumobject->rssarticles) {
if (!function_exists('rss_get_url')) {
require_once("$CFG->libdir/rsslib.php");
}
if ($forumobject->rsstype == 1) {
$string = get_string("rsssubscriberssdiscussions","forum",format_string($forumobject->name));
} else {
$string = get_string("rsssubscriberssposts","forum",format_string($forumobject->name));
}
if (empty($USER->id)) {
$userid = 0;
} else {
$userid = $USER->id;
}
$url = new moodle_url(rss_get_url($PAGE->course->id, $userid, "forum", $forumobject->id));
$forum->add($string, null, null, settings_navigation::TYPE_SETTING, $url, $OUTPUT->old_icon_url('i/rss'));
}
return $forumkey;
}
+1 -89
View File
@@ -42,8 +42,6 @@
require_course_login($course, true, $cm);
$strforums = get_string("modulenameplural", "forum");
$strforum = get_string("modulename", "forum");
$PAGE->set_button(update_module_button($cm->id, $course->id, $strforum));
} else if ($f) {
if (! $forum = $DB->get_record("forum", array("id" => $f))) {
@@ -61,8 +59,6 @@
require_course_login($course, true, $cm);
$strforums = get_string("modulenameplural", "forum");
$strforum = get_string("modulename", "forum");
$PAGE->set_button(update_module_button($cm->id, $course->id, $strforum));
} else {
print_error('missingparameter');
}
@@ -76,10 +72,9 @@
/// Print header.
$navigation = build_navigation('', $cm);
$PAGE->set_title(format_string($forum->name));
$PAGE->set_heading(format_string($course->fullname));
echo $OUTPUT->header($navigation, navmenu($course, $cm));
echo $OUTPUT->header(navmenu($course, $cm));
/// Some capability checks.
if (empty($cm->visible) and !has_capability('moodle/course:viewhiddenactivities', $context)) {
@@ -123,89 +118,6 @@
}
}
// print_box_start('forumcontrol clearfix');
// print_box_start('subscription clearfix');
echo '<div class="subscription">';
if (!empty($USER->id) && !has_capability('moodle/legacy:guest', $context, NULL, false)) {
$SESSION->fromdiscussion = "$FULLME";
if (forum_is_forcesubscribed($forum)) {
$streveryoneisnowsubscribed = get_string('everyoneisnowsubscribed', 'forum');
$strallowchoice = get_string('allowchoice', 'forum');
echo '<span class="helplink">' . get_string("forcessubscribe", 'forum') . '</span><br />';
echo $OUTPUT->help_icon(moodle_help_icon::make("subscription", $strallowchoice, "forum"));
echo '&nbsp;<span class="helplink">';
if (has_capability('mod/forum:managesubscriptions', $context)) {
echo "<a title=\"$strallowchoice\" href=\"subscribe.php?id=$forum->id&amp;force=no\">$strallowchoice</a>";
} else {
echo $streveryoneisnowsubscribed;
}
echo '</span><br />';
} else if ($forum->forcesubscribe == FORUM_DISALLOWSUBSCRIBE) {
$strsubscriptionsoff = get_string('disallowsubscribe','forum');
echo $strsubscriptionsoff;
echo $OUTPUT->help_icon(moodle_help_icon::make("subscription", $strsubscriptionsoff, "forum"));
} else {
$streveryonecannowchoose = get_string("everyonecannowchoose", "forum");
$strforcesubscribe = get_string("forcesubscribe", "forum");
$strshowsubscribers = get_string("showsubscribers", "forum");
echo '<span class="helplink">' . get_string("allowsallsubscribe", 'forum') . '</span><br />';
echo $OUTPUT->help_icon(moodle_help_icon::make("subscription", $strforcesubscribe, "forum"));
echo '&nbsp;';
if (has_capability('mod/forum:managesubscriptions', $context)) {
echo "<span class=\"helplink\"><a title=\"$strforcesubscribe\" href=\"subscribe.php?id=$forum->id&amp;force=yes\">$strforcesubscribe</a></span>";
} else {
echo '<span class="helplink">'.$streveryonecannowchoose.'</span>';
}
if(has_capability('mod/forum:viewsubscribers', $context)){
echo "<br />";
echo "<span class=\"helplink\"><a href=\"subscribers.php?id=$forum->id\">$strshowsubscribers</a></span>";
}
echo '<div class="helplink" id="subscriptionlink">', forum_get_subscribe_link($forum, $context,
array('forcesubscribed' => '', 'cantsubscribe' => '')), '</div>';
}
if (forum_tp_can_track_forums($forum)) {
echo '<div class="helplink" id="trackinglink">'. forum_get_tracking_link($forum). '</div>';
}
}
/// If rss are activated at site and forum level and this forum has rss defined, show link
if (isset($CFG->enablerssfeeds) && isset($CFG->forum_enablerssfeeds) &&
$CFG->enablerssfeeds && $CFG->forum_enablerssfeeds && $forum->rsstype and $forum->rssarticles) {
if ($forum->rsstype == 1) {
$tooltiptext = get_string("rsssubscriberssdiscussions","forum",format_string($forum->name));
} else {
$tooltiptext = get_string("rsssubscriberssposts","forum",format_string($forum->name));
}
if (empty($USER->id)) {
$userid = 0;
} else {
$userid = $USER->id;
}
// print_box_start('rsslink');
echo '<span class="wrap rsslink">';
rss_print_link($course->id, $userid, "forum", $forum->id, $tooltiptext);
echo '</span>';
// print_box_end(); // subscription
}
// print_box_end(); // subscription
echo '</div>';
// print_box_end(); // forumcontrol
// print_box('&nbsp;', 'clearer');
if (!empty($forum->blockafter) && !empty($forum->blockperiod)) {
$a->blockafter = $forum->blockafter;
$a->blockperiod = get_string('secondstotime'.$forum->blockperiod);
Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

+2 -2
View File
@@ -17,9 +17,9 @@
</div>
<?php } ?>
<?php if ($navigation) { // This is the navigation bar with breadcrumbs ?>
<?php if ($OUTPUT->has_navbar()) { // This is the navigation bar with breadcrumbs ?>
<div class="navbar clearfix">
<div class="breadcrumb"><?php print_navigation($navigation); ?></div>
<div class="breadcrumb"><?php echo $OUTPUT->navbar(); ?></div>
<div class="navbutton"><?php echo $PAGE->button; ?></div>
</div>
<?php } else if ($PAGE->heading) { // If no navigation, but a heading, then print a line ?>
Binary file not shown.

After

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

+234
View File
@@ -1792,6 +1792,180 @@ a.skip:focus, a.skip:active {
padding:3px;
}
/* Navigation and settings block */
.sideblock .block_tree_box {
margin:2px;
}
.sideblock .block_tree {
width:180px;
overflow-x:auto;
overflow-y:visible;
}
.ie6 .sideblock .block_tree,
.ie7 .sideblock .block_tree {
overflow-x:scroll;
}
.block_tree {
list-style: none;
padding-left:0px;
margin:3px;
}
.block_tree ul {
margin-left: 0px;
padding-left:16px;
list-style: none;
}
.block_tree .current_branch {
background-color:#eee;
}
.block_tree .tree_item {
white-space:nowrap;
margin:2px 0px;
padding-left: 16px;
margin:3px 0px;
white-space:nowrap;
}
.ie6 .block_tree .tree_item {
width:100%;
}
.block_tree .tree_item.note {
white-space:normal;
font-size:90%;
}
.block_tree .tree_item.branch {
background-image: url(../../pix/t/expanded.png);
background-position: center left;
background-repeat: no-repeat;
}
.block_tree .root_node.leaf {
padding-left:0px;
}
.jsenabled .sideblock_js_sidebarpopout,
.jsenabled .block_tree .collapsed ul {
display: none;
}
.jsenabled .block_tree .tree_item.branch {
cursor:pointer;
}
.jsenabled .block_tree .collapsed .tree_item.branch {
background-image: url(../../pix/t/collapsed.png);
}
.jsenabled .block_tree .tree_item.emptybranch {
background-image: url(../../pix/t/collapsed_empty.png);
background-position: center left;
background-repeat: no-repeat;
}
.block_tree_box .requiresjs {
display:none;
}
.jsenabled .block_tree_box .requiresjs {
display:inline;
}
/* Navigation and settings block */
/* This CSS is for the side panel */
body.has_navigation_bar {
margin-left:3em;
}
.navigation_bar {
width:30px;
position:fixed;
top:0px;
left:0px;
height:100%;
border-right:1px solid #bbb;
border-bottom:1px solid #bbb;
background-image:url(gradient_vertical.jpg);
background-position:100% 0%;
background-repeat:repeat-y;
}
.ie6 .navigation_bar {
position:absolute;
}
.ie6 .navigation_bar hr {
display:none;
margin:0px;
height:0px;
padding:0px;
}
.ie6 .navigation_bar li p {
background-color:inherit;
}
.navigation_bar .sideblock_tab {
}
.navigation_bar .sideblock_tab .firsttab {
margin-top:1em;
}
.navigation_bar .sideblock_tab .title {
border-bottom:1px solid #eee;
border-top:1px solid #ddd;
cursor:pointer;
}
.navigation_bar .bd.oversized_content {
background-color:red;
margin:3px;
overflow-y:auto;
overflow-x:visible;
height:inherit;
}
.navigation_bar .block_tree .current_branch {
background-color:#ddd;
}
.ie6 .navigation_bar .bd.oversized_content {
width:100%;
}
.ie7 .navigation_bar .bd.oversized_content {
width:400px;
}
.navigation_bar .bd.oversized_content .content {
margin:6px 6px 6px 0px;
padding-bottom:6px;
}
.ie6 .navigation_bar .bd.oversized_content .content,
.ie7 .navigation_bar .bd.oversized_content .content {
padding-bottom:0px;
}
.navigation_bar .sideblock_tab .title.active_tab {
background-color:#e9e9e9;
border-bottom-color:#ccc;
border-top-color:#ddd;
}
.navigation_bar .sideblock_tab .title h2 {
font-size:0.8em;
line-height:100%;
text-transform:uppercase;
text-align:center;
}
.navigation_bar .controls {
position:absolute;
bottom:1em;
width:100%;
text-align:center;
}
.navigation_bar .controls img {
cursor:pointer;
}
/* Navigation and settings block */
/* Sideblock expansion code */
.sideblock_js_expansion .block_tree {
overflow-x:scroll;
}
.sideblock_js_expansion.mouseover .content {
width:200%;
z-index:1000;
position:relative;
}
.sideblock_js_expansion.mouseover .content .block_tree {
width:100%;
background-color:#fcfcfc;
padding-bottom:0px;
}
.ie6 .sideblock_js_expansion.mouseover .content,
.ie7 .sideblock_js_expansion.mouseover .content{
padding-bottom:2px;
}
/***
*** Blogs
***/
@@ -5595,3 +5769,63 @@ wikiadminactions {
margin: 4px;
}
/* CSS for shadows */
.divshadow div {
position:absolute;
width:10px;
height:10px;
background-image:url(shadow_corners.png);
background-repeat:no-repeat;
}
.divshadow .shadow_top {
top:-10px;
right:0px;
width:100%;
background-image:url(shadow_top_bottom.png);
background-position:0px 0px;
background-repeat:repeat-x;
}
.divshadow .shadow_bottom {
bottom:-10px;
right:0px;
width:100%;
background-image:url(shadow_top_bottom.png);
background-position:0px 100%;
background-repeat:repeat-x;
}
.divshadow .shadow_left {
top:0px;
left:-10px;
height:100%;
background-image:url(shadow_left_right.png);
background-position:0px 0px;
background-repeat:repeat-y;
}
.divshadow .shadow_right {
bottom:0px;
right:-10px;
height:100%;
background-image:url(shadow_left_right.png);
background-position:100% 0px;
background-repeat:repeat-y;
}
.divshadow .shadow_top_right {
top:-10px;
right:-10px;
background-position:100% 0px;
}
.divshadow .shadow_bottom_right {
bottom:-10px;
right:-10px;
background-position:100% 100%;
}
.divshadow .shadow_top_left {
top:-10px;
left:-10px;
background-position:0px 0px;
}
.divshadow .shadow_bottom_left {
bottom:-10px;
left:-10px;
background-position:0px 100%;
}
-89
View File
@@ -108,38 +108,6 @@
$wwwroot = str_replace('http:','https:',$CFG->wwwroot);
}
$edittype = 'none';
if (isguestuser($user)) {
// guest account can not be edited
} else if (is_mnet_remote_user($user)) {
// cannot edit remote users
} else if (isguestuser() or !isloggedin()) {
// guests and not logged in can not edit own profile
} else if ($USER->id == $user->id) {
if (has_capability('moodle/user:update', $systemcontext)) {
$edittype = 'advanced';
} else if (has_capability('moodle/user:editownprofile', $systemcontext)) {
$edittype = 'normal';
}
} else {
if (has_capability('moodle/user:update', $systemcontext) and !is_primary_admin($user->id)){
$edittype = 'advanced';
} else if (has_capability('moodle/user:editprofile', $personalcontext) and !is_primary_admin($user->id)){
//teachers, parents, etc.
$edittype = 'normal';
}
}
if ($edittype == 'advanced') {
$toprow[] = new tabobject('editprofile', $wwwroot.'/user/editadvanced.php?id='.$user->id.'&amp;course='.$course->id, get_string('editmyprofile'));
} else if ($edittype == 'normal') {
$toprow[] = new tabobject('editprofile', $wwwroot.'/user/edit.php?id='.$user->id.'&amp;course='.$course->id, get_string('editmyprofile'));
}
/// Everyone can see posts for this user
/// add logic to see course read posts permission
@@ -247,57 +215,6 @@
}
} //close last bracket (individual tags)
/// this needs permission checkings
if (!empty($showroles) and !empty($user)) { // this variable controls whether this roles is showed, or not, so only user/view page should set this flag
$usercontext = get_context_instance(CONTEXT_USER, $user->id);
if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride',
'moodle/role:override', 'moodle/role:manage'), $usercontext)) {
$toprow[] = new tabobject('roles', $CFG->wwwroot.'/'.$CFG->admin.'/roles/usersroles.php?userid='.$user->id.'&amp;courseid='.$course->id
,get_string('roles'));
if (in_array($currenttab, array('usersroles', 'assign', 'override', 'check'))) {
$inactive = array('roles');
$activetwo = array('roles');
$secondrow = array();
$secondrow[] = new tabobject('usersroles', $CFG->wwwroot.'/'.$CFG->admin.'/roles/usersroles.php?userid='.$user->id.'&amp;courseid='.$course->id
,get_string('thisusersroles', 'role'));
if (!empty($assignableroles) || $currenttab=='assign') {
$secondrow[] = new tabobject('assign', $CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$usercontext->id.'&amp;userid='.$user->id.'&amp;courseid='.$course->id
,get_string('assignrolesrelativetothisuser', 'role'), '', true);
}
if (!empty($overridableroles) || $currenttab=='override') {
$secondrow[] = new tabobject('override', $CFG->wwwroot.'/'.$CFG->admin.'/roles/override.php?contextid='.$usercontext->id.'&amp;userid='.$user->id.'&amp;courseid='.$course->id
,get_string('overridepermissions', 'role'), '', true);
}
if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride',
'moodle/role:override', 'moodle/role:assign'), $usercontext)) {
$secondrow[] = new tabobject('check',
$CFG->wwwroot.'/'.$CFG->admin.'/roles/check.php?contextid='.$usercontext->id.'&amp;userid='.$user->id.'&amp;courseid='.$course->id,
get_string('checkpermissions', 'role'));
}
}
}
}
if (!empty($user) and empty($userindexpage) && $user->id == $USER->id && !empty($CFG->enableportfolios) && has_capability('moodle/portfolio:export', get_system_context())) {
/// Portfolio tab
if (portfolio_instances(true, false)) {
$toprow[] = new tabobject('portfolios', $CFG->wwwroot .'/user/portfolio.php', get_string('portfolios', 'portfolio'));
if (in_array($currenttab, array('portfolioconf', 'portfoliologs'))) {
$inactive = array('portfolios');
$activetwo = array('portfolios');
$secondrow = array();
$secondrow[] = new tabobject('portfolioconf', $CFG->wwwroot . '/user/portfolio.php', get_string('configure', 'portfolio'));
$secondrow[] = new tabobject('portfoliologs', $CFG->wwwroot . '/user/portfoliologs.php', get_string('logs', 'portfolio'));
}
}
}
// Repository Tab
if (!empty($user) and $user->id == $USER->id) {
require_once($CFG->dirroot . '/repository/lib.php');
@@ -309,12 +226,6 @@
}
/// Messaging tab
if (!empty($user) and empty($userindexpage) and has_capability('moodle/user:editownmessageprofile', $systemcontext)) {
$toprow[] = new tabobject('editmessage', $CFG->wwwroot.'/message/edit.php?id='.$user->id.'&amp;course='.$course->id, get_string('editmymessage', 'message'));
}
/// Add second row to display if there is one
if (!empty($secondrow)) {
+1 -1
View File
@@ -6,7 +6,7 @@
// This is compared against the values stored in the database to determine
// whether upgrades should be performed (see lib/db/*.php)
$version = 2009080700; // YYYYMMDD = date of the last version bump
$version = 2009082800; // YYYYMMDD = date of the last version bump
// XX = daily increments
$release = '2.0 dev (Build: 20090828)'; // Human-friendly version name