# This patch file was generated by NetBeans IDE
# This patch can be applied using context Tools: Apply Diff Patch action on respective folder.
# It uses platform neutral UTF-8 encoding.
# Above lines and this line are ignored by the patching process.
Index: moodle/blocks/dock.js
--- moodle/blocks/dock.js Base (1.13)
+++ moodle/blocks/dock.js Locally Modified (Based On 1.13)
@@ -336,7 +336,7 @@
                 }
             }
 
-            var moveto = this.Y.Node.create('<input type="image" class="moveto customcommand requiresjs" src="'+M.util.image_url('t/block_to_dock', 'moodle')+'" alt="'+M.str.block.undockitem+'" title="'+M.str.block.undockitem+'" />');
+            var moveto = this.Y.Node.create('<input type="image" class="moveto customcommand requiresjs" src="'+M.util.image_url('t/block_to_dock', 'moodle')+'" alt="'+M.str.block.addtodock+'" title="'+M.str.block.addtodock+'" />');
             moveto.on('movetodock|click', this.move_to_dock, this, commands);
 
             var blockaction = node.one('.block_action');
@@ -483,10 +483,13 @@
 
             this.resize_block_space(this.cachedcontentnode);
 
+
             var commands = this.cachedcontentnode.one('.commands');
+            if (commands) {
             commands.all('.hidepanelicon').remove();
             commands.all('.moveto').remove();
             commands.remove();
+            }
             this.cachedcontentnode.one('.title').append(commands);
             this.cachedcontentnode = null;
             M.util.set_user_preference('docked_block_instance_'+this.id, 0);
@@ -540,13 +543,6 @@
                 dockitem.addClass('firstdockitem');
             }
             dockitem.append(dockitemtitle);
-            if (this.commands.hasChildNodes) {
-                if (this.contents.ancestor().one('.footer')) {
-                    this.contents.ancestor().one('.footer').appendChild(this.commands);
-                } else {
-                    this.contents.appendChild(this.commands);
-                }
-            }
             M.core_dock.append(dockitem);
 
             var position = dockitemtitle.getXY();
@@ -573,7 +569,9 @@
             this.panel.showMaskEvent.subscribe(function(){
                 this.Y.one(this.panel.mask).setStyle('zIndex', this.cfg.panel.modalzindex);
             }, this, true);
-            this.panel.renderEvent.subscribe(this.resize_panel, this, true);
+            if (this.commands.hasChildNodes) {
+                this.panel.setHeader(this.Y.Node.getDOMNode(this.commands));
+            }
             this.panel.setBody(this.Y.Node.getDOMNode(this.contents));
             this.panel.render(M.core_dock.node);
             this.Y.one(this.panel.body).addClass(this.blockclass);
@@ -693,10 +691,14 @@
          */
         resize_panel : function() {
             this.fire('dockeditem:resizestart');
+
+            var panelheader = this.Y.one(this.panel.header);
+            panelheader = (panelheader)?panelheader.get('offsetHeight'):0;
             var panelbody = this.Y.one(this.panel.body);
+
             var buffer = this.cfg.buffer;
             var screenheight = parseInt(this.Y.get(document.body).get('winHeight'));
-            var panelheight = parseInt(panelbody.get('offsetHeight'));
+            var panelheight = parseInt(panelheader + panelbody.get('offsetHeight'));
             var paneltop = parseInt(this.panel.cfg.getProperty('y'));
             var titletop = parseInt(this.Y.one('#dock_item_'+this.id+'_title').getY());
             var scrolltop = window.pageYOffset || document.body.scrollTop || 0;
@@ -720,7 +722,7 @@
             // This makes the panel constrain to the screen's height if the panel is big
             if (paneltop <= buffer && ((panelheight+paneltop*2) > screenheight || panelbody.hasClass('oversized_content'))) {
                 this.panel.cfg.setProperty('height', screenheight-(buffer*3));
-                panelbody.setStyle('height', (screenheight-(buffer*3)-10)+'px');
+                panelbody.setStyle('height', (screenheight-panelheader-(buffer*3)-10)+'px');
                 panelbody.addClass('oversized_content');
             }
             this.fire('dockeditem:resizecomplete');
@@ -754,6 +756,7 @@
  * @param {this.Y.Node} title
  * @param {this.Y.Node} contents
  * @param {this.Y.Node} commands
+ * @param {string} blockclass
  */
 M.core_dock.item = function(Y, uid, title, contents, commands, blockclass){
     this.Y = Y;
Index: moodle/blocks/global_navigation_tree/block_global_navigation_tree.php
--- moodle/blocks/global_navigation_tree/block_global_navigation_tree.php Base (1.33)
+++ moodle/blocks/global_navigation_tree/block_global_navigation_tree.php Locally Deleted
@@ -1,372 +0,0 @@
-<?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;
-    /** @var bool */
-    protected $contentgenerated = false;
-    /** @var bool|null */
-    protected $docked = null;
-
-    /**
-     * Set the initial properties for the block
-     */
-    function init() {
-        global $CFG;
-        $this->blockname = get_class($this);
-        $this->title = get_string('pluginname', $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;
-    }
-
-    function get_required_javascript() {
-        global $CFG;
-        $this->_initialise_dock();
-        $this->page->requires->js_module(array('name'=>'core_dock', 'fullpath'=>'/blocks/dock.js', 'requires'=>array('base', 'cookie', 'dom', 'io', 'node', 'event-custom', 'event-mouseenter', 'yui2-container')));
-        $this->page->requires->js_module(array('name'=>'block_navigation', 'fullpath'=>'/blocks/global_navigation_tree/navigation.js', 'requires'=>array('core_dock', 'io', 'node', 'dom', 'event-custom', 'json-parse')));
-        user_preference_allow_ajax_update('docked_block_instance_'.$this->instance->id, PARAM_INT);
-    }
-
-    /**
-     * 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 $this->content;
-        }
-        $this->page->requires->yui2_lib('dom');
-        // JS for navigation moved to the standard theme, the code will probably have to depend on the actual page structure
-        // $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++;
-
-        // Check if this block has been docked
-        if ($this->docked === null) {
-            $this->docked = get_user_preferences('nav_in_tab_panel_globalnav'.block_global_navigation_tree::$navcount, 0);
-        }
-
-        // Check if there is a param to change the docked state
-        if ($this->docked && optional_param('undock', null, PARAM_INT)==$this->instance->id) {
-            unset_user_preference('nav_in_tab_panel_globalnav'.block_global_navigation_tree::$navcount);
-            $url = $this->page->url;
-            $url->remove_params(array('undock'));
-            redirect($url);
-        } else if (!$this->docked && optional_param('dock', null, PARAM_INT)==$this->instance->id) {
-            set_user_preferences(array('nav_in_tab_panel_globalnav'.block_global_navigation_tree::$navcount=>1));
-            $url = $this->page->url;
-            $url->remove_params(array('dock'));
-            redirect($url);
-        }
-
-        // 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 (isset($CFG->navshowcategories) && empty($CFG->navshowcategories)) {
-            $this->page->navigation->collapse_course_categories();
-        }
-
-        // 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();
-        }
-
-        // Get the expandable items so we can pass them to JS
-        $expandable = array();
-        $this->page->navigation->find_expandable($expandable);
-
-        // Initialise the JS tree object
-        $module = array('name'=>'block_navigation', 'fullpath'=>'/blocks/global_navigation_tree/navigation.js', 'requires'=>array('core_dock', 'io', 'node', 'dom', 'event-custom', 'json-parse'));
-        $arguments = array($this->instance->id, array('expansions'=>$expandable, 'instance'=>$this->instance->id, 'candock'=>$this->instance_can_be_docked()));
-        $this->page->requires->js_init_call('M.block_navigation.init_add_tree', $arguments, false, $module);
-
-        // Grab the items to display
-        $this->content->items = array($this->page->navigation);
-
-        $reloadlink = new moodle_url($this->page->url, array('regenerate'=>'navigation'));
-
-        $this->content->footer .= $OUTPUT->action_icon($reloadlink, new pix_icon('t/reload', get_string('reload')), null, array('class'=>'customcommand'));
-
-        // Set content generated to true so that we know it has been done
-        $this->contentgenerated = true;
-
-        return $this->content;
-    }
-
-    /**
-     * 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'] .= ' block_js_expansion';
-        }
-        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;
-
-        // 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() || isguestuser()) {
-            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_omit_querystring() == $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
-            $mymoodle = $PAGE->navigation->get('mymoodle', navigation_node::TYPE_CUSTOM);
-            $myhistorybranch = $mymoodle->add(get_string('showmyhistorytitle', $this->blockname), null, navigation_node::TYPE_CUSTOM, null, 'myhistory');
-            $mymoodle->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() || isguestuser()) {
-            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
-        $mymoodle = $PAGE->navigation->get('mymoodle', navigation_node::TYPE_CUSTOM);
-        $mycoursesbranch = $mymoodle->add(get_string('mycourses'), null,navigation_node::TYPE_CATEGORY, null, 'mycourses');
-        $PAGE->navigation->add_courses($courses, 'mycourses');
-        $mymoodle->get($mycoursesbranch)->type = navigation_node::TYPE_CUSTOM;
-        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);
-            }
-        }
-    }
-}
Index: moodle/blocks/global_navigation_tree/db/upgrade.php
--- moodle/blocks/global_navigation_tree/db/upgrade.php Base (1.1)
+++ moodle/blocks/global_navigation_tree/db/upgrade.php Locally Deleted
@@ -1,57 +0,0 @@
-<?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;
-}
Index: moodle/blocks/global_navigation_tree/edit_form.php
--- moodle/blocks/global_navigation_tree/edit_form.php Base (1.1)
+++ moodle/blocks/global_navigation_tree/edit_form.php Locally Deleted
@@ -1,67 +0,0 @@
-<?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);
-            }
-        }
-    }
-}
Index: moodle/blocks/global_navigation_tree/lang/en/block_global_navigation_tree.php
--- moodle/blocks/global_navigation_tree/lang/en/block_global_navigation_tree.php Base (1.3)
+++ moodle/blocks/global_navigation_tree/lang/en/block_global_navigation_tree.php Locally Deleted
@@ -1,37 +0,0 @@
-<?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/>.
-
-/**
- * Strings for component 'block_global_navigation_tree', language 'en', branch 'MOODLE_20_STABLE'
- *
- * @package   block_global_navigation_tree
- * @copyright 2009 Sam Hemelryk
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-$string['courseactivities'] = 'Categories, courses, and course Activities';
-$string['courses'] = 'Categories and courses';
-$string['coursestructures'] = 'Categories, courses, and course structures';
-$string['enablehoverexpansiondesc'] = 'Enable mouseover expansion of this block';
-$string['enablesidebarpopoutdesc'] = 'Allow the user to switch the block to a sidbar popout';
-$string['everything'] = 'Everything';
-$string['expansionlimit'] = 'Generate navigation for the following';
-$string['pluginname'] = 'Navigation';
-$string['showemptybranchesdesc'] = 'Show empty course section branches';
-$string['showmycoursesdesc'] = 'Show my courses in the navigation';
-$string['showmyhistorydesc'] = 'Show my history as a branch in the navigation';
-$string['showmyhistorytitle'] = 'My history';
Index: moodle/blocks/global_navigation_tree/navigation.js
--- moodle/blocks/global_navigation_tree/navigation.js Base (1.13)
+++ moodle/blocks/global_navigation_tree/navigation.js Locally Deleted
@@ -1,339 +0,0 @@
-// 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
- */
-
-/**
- * This namespace will contain all of the contents of the navigation blocks
- * global navigation and settings.
- * @namespace
- */
-M.block_navigation = M.block_navigation || {
-    /** The number of expandable branches in existence */
-    expandablebranchcount:0,
-    /** An array of initialised trees */
-    treecollection:[],
-    /**
-     * Will contain all of the classes for the navigation blocks
-     * @namespace
-     */
-    classes:{},
-    /**
-     * This function gets called when the module is first loaded as required by
-     * the YUI.add statement at the bottom of the page.
-     * 
-     * NOTE: This will only be executed ONCE
-     * @function
-     */
-    init:function(Y) {
-        if (M.core_dock.genericblock) {
-            // Give the tree class the dock block properties
-            Y.augment(M.block_navigation.classes.tree, M.core_dock.genericblock);
-        }
-    },
-    /**
-     * Add new instance of navigation tree to tree collection
-     */
-    init_add_tree:function(Y, id, properties) {
-    	M.block_navigation.treecollection[id] = new M.block_navigation.classes.tree(Y, id, properties);
-    }
-};
-
-/**
- * @class tree
- * @constructor
- * @base M.core_dock.abstractblock
- * @param {YUI} Y A yui instance to use with the navigation
- * @param {string} id The name of the tree
- * @param {object} properties Object containing tree properties
- */
-M.block_navigation.classes.tree = function(Y, id, properties) {
-    this.Y = Y;
-    this.id = id;
-    this.key = id;
-    this.errorlog = [];
-    this.ajaxbranches = 0;
-    this.expansions = [];
-    this.instance = id;
-    this.cachedcontentnode = null;
-    this.cachedfooter = null;
-    this.position = 'block';
-    this.skipsetposition = false;
-    this.candock = false;
-    
-    if (properties.expansions) {
-        this.expansions = properties.expansions;
-    }
-    if (properties.instance) {
-        this.instance = properties.instance;
-    }
-    if (properties.candock) {
-        this.candock = true;
-    }
-
-    var node = this.Y.one('#inst'+this.id);
-    
-    // Can't find the block instance within the page
-    if (node === null) {
-        return;
-    }
-    // Attach event to toggle expansion
-    node.all('.tree_item.branch').on('click', this.toggleexpansion , this);
-
-    // Attache events to expand by AJAX
-    for (var i in this.expansions) {
-        this.Y.one('#'+this.expansions[i].id).on('ajaxload|click', this.init_load_ajax, this, this.expansions[i]);
-        M.block_navigation.expandablebranchcount++;
-    }
-
-    if (node.hasClass('block_js_expansion')) {
-        node.on('mouseover', function(e){this.toggleClass('mouseover');}, node);
-        node.on('mouseout', function(e){this.toggleClass('mouseover');}, node);
-    }
-
-    // Call the generic blocks init method to add all the generic stuff
-    if (this.candock) {
-        this.init(Y, node);
-    }
-}
-
-/**
- * Loads a branch via AJAX
- * @param {event} e The event object
- * @param {object} branch A branch to load via ajax
- */
-M.block_navigation.classes.tree.prototype.init_load_ajax = function(e, branch) {
-    e.stopPropagation();
-    if (e.target.get('nodeName').toUpperCase() != 'P') {
-        return true;
-    }
-    var cfginstance = '';
-    if (this.instance != null) {
-        cfginstance = '&instance='+this.instance
-    }
-    this.Y.io(M.cfg.wwwroot+'/lib/ajax/getnavbranch.php', {
-        method:'POST',
-        data:'elementid='+branch.id+'&id='+branch.branchid+'&type='+branch.type+'&sesskey='+M.cfg.sesskey+cfginstance,
-        on: {
-            complete:this.load_ajax,
-            success:function() {this.Y.detach('click', this.init_load_ajax, e.target);}
-        },
-        context:this,
-        arguments:{
-            target:e.target
-        }
-    });
-    return true;
-}
-
-/**
- * Takes an branch provided through ajax and loads it into the tree
- * @param {int} tid The transaction id
- * @param {object} outcome
- * @param {mixed} args
- * @return bool
- */
-M.block_navigation.classes.tree.prototype.load_ajax = function(tid, outcome, args) {
-    try {
-        var object = this.Y.JSON.parse(outcome.responseText);
-        if (this.add_branch(object, args.target.ancestor('LI') ,1)) {
-            if (this.candock) {
-                M.core_dock.resize();
-            }
-            return true;
-        }
-    } catch (e) {
-        // If we got here then there was an error parsing the result
-    }
-    // The branch is empty so class it accordingly
-    args.target.replaceClass('branch', 'emptybranch');
-    return true;
-}
-
-/**
- * Adds a branch into the tree provided with some XML
- * @param {xmldoc} branchxml
- * @param {Y.Node} target
- * @param {int} depth
- * @return bool
- */
-M.block_navigation.classes.tree.prototype.add_branch = function(branchobj, target, depth) {
-
-    // Make the new branch into an object
-    var branch = new M.block_navigation.classes.branch(this, branchobj);
-
-    var childrenul = false;
-    if (depth === 1) {
-        if (!branch.children) {
-            return false;
-        }
-        childrenul = this.Y.Node.create('<ul></ul>');
-        target.appendChild(childrenul);
-    } else {
-        childrenul = branch.inject_into_dom(target);
-    }
-    if (childrenul) {
-        for (i in branch.children) {
-            // Add each branch to the tree
-            this.add_branch(branch.children[i], childrenul, depth+1);
-        }
-    }
-    return true;
-}
-/**
- * Toggle a branch as expanded or collapsed
- * @param {Event} e
- */
-M.block_navigation.classes.tree.prototype.toggleexpansion = function(e) {
-    // First check if they managed to click on the li iteslf, then find the closest
-    // LI ancestor and use that
-    if (e.target.get('nodeName').toUpperCase() == 'LI') {
-        e.target.toggleClass('collapsed');
-    } else if (e.target.ancestor('LI')) {
-        e.target.ancestor('LI').toggleClass('collapsed');
-    }
-    if (this.candock) {
-        M.core_dock.resize();
-    }
-}
-
-/**
- * This class represents a branch for a tree
- * @class branch
- * @constructor
- * @param {M.block_navigation.classes.tree} tree
- * @param {object|null} obj
- */
-M.block_navigation.classes.branch = function(tree, obj) {
-    this.tree = tree;
-    this.name = null;
-    this.title = null;
-    this.classname = null;
-    this.id = null;
-    this.key = null;
-    this.type = null;
-    this.link = null;
-    this.icon = null;
-    this.expandable = null;
-    this.expansionceiling = null;
-    this.hidden = false;
-    this.haschildren = false;
-    this.children = false;
-    if (obj !== null) {
-        // Construct from the provided xml
-        this.construct_from_json(obj);
-    }
-}
-M.block_navigation.classes.branch.prototype.construct_from_json = function(obj) {
-    for (var i in obj) {
-        this[i] = obj[i];
-    }
-    if (this.children) {
-        this.haschildren = true;
-    }
-    if (this.id && this.id.match(/^expandable_branch_\d+$/)) {
-        // Assign a new unique id for this new expandable branch
-        M.block_navigation.expandablebranchcount++;
-        this.id = 'expandable_branch_'+M.block_navigation.expandablebranchcount;
-    }
-}
-/**
- * Injects a branch into the tree at the given location
- * @param {element} element
- */
-M.block_navigation.classes.branch.prototype.inject_into_dom = function(element) {
-
-    var branchli = this.tree.Y.Node.create('<li></li>');
-    var branchp = this.tree.Y.Node.create('<p class="tree_item"></p>');
-
-    if ((this.expandable !== null || this.haschildren) && this.expansionceiling===null) {
-        branchli.addClass('collapsed');
-        branchp.addClass('branch');
-        branchp.on('click', this.tree.toggleexpansion, this.tree);
-        if (this.expandable) {
-            branchp.on('ajaxload|click', this.tree.init_load_ajax, this.tree, {branchid:this.key,id:this.id,type:this.type});
-        }
-    }
-
-    if (this.myclass !== null) {
-        branchp.addClass(this.myclass);
-    }
-    if (this.id !== null) {
-        branchp.setAttribute('id', this.id);
-    }
-
-    // Prepare the icon, should be an object representing a pix_icon
-    var branchicon = false;
-    if (this.icon != null) {
-        branchicon = this.tree.Y.Node.create('<img src="'+M.util.image_url(this.icon.pix, this.icon.component)+'" alt="" />');
-        if (this.icon.alt) {
-            branchicon.setAttribute('alt', this.icon.alt);
-        }
-        if (this.icon.title) {
-            branchicon.setAttribute('alt', this.icon.title);
-        }
-        if (this.icon.classes) {
-            for (var i in this.icon.classes) {
-                branchicon.addClass(this.icon.classes[i]);
-            }
-        }
-        this.name = '&nbsp;'+this.name;
-    }
-    
-    if (this.link === null) {
-        if (branchicon) {
-            branchp.appendChild(branchicon);
-        }
-        branchp.append(this.name.replace(/\n/g, '<br />'));
-    } else {
-        var branchlink = this.tree.Y.Node.create('<a title="'+this.title+'" href="'+this.link+'"></a>');
-        if (branchicon) {
-            branchlink.appendChild(branchicon);
-        }
-        branchlink.append(this.name.replace(/\n/g, '<br />'));
-        if (this.hidden) {
-            branchlink.addClass('dimmed');
-        }
-        branchp.appendChild(branchlink);
-    }
-
-    branchli.appendChild(branchp);
-    if (this.haschildren) {
-        var childrenul = this.tree.Y.Node.create('<ul></ul>');
-        branchli.appendChild(childrenul);
-        element.appendChild(branchli);
-        return childrenul
-    } else {
-        element.appendChild(branchli);
-        return false;
-    }
-}
-
-/**
- * Causes the navigation block module to initalise the first time the module
- * is used!
- *
- * NOTE: Never convert the second argument to a function reference...
- * doing so causes scoping issues
- */
-YUI.add('block_navigation', function(Y){M.block_navigation.init(Y);}, '0.0.0.1', M.yui.loader.modules.block_navigation.requires);
Index: moodle/blocks/global_navigation_tree/styles.css
--- moodle/blocks/global_navigation_tree/styles.css Base (1.1)
+++ moodle/blocks/global_navigation_tree/styles.css Locally Deleted
@@ -1,22 +0,0 @@
-/** JavaScript state rules **/
-.jsenabled .block_global_navigation_tree.dock_on_load,
-.block_global_navigation_tree .block_tree_box .requiresjs {display:none;}
-.jsenabled .block_global_navigation_tree .block_tree_box .requiresjs {display:inline;}
-
-/** General display rules **/
-.block_global_navigation_tree .block_tree {margin:5px;padding-left:0px;overflow-x:auto;overflow-y:visible;}
-.block_global_navigation_tree .block_tree li {margin:0;list-style: none;}
-.block_global_navigation_tree .block_tree li ul {padding-left:16px;margin:0;}
-.block_global_navigation_tree .block_tree .tree_item {white-space:nowrap;margin:2px 0px;padding-left: 16px;margin:3px 0px;white-space:nowrap;text-align:left;}
-.block_global_navigation_tree .block_tree .tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: center left;background-repeat: no-repeat;}
-.block_global_navigation_tree .block_tree .root_node.leaf {padding-left:0px;}
-.block_global_navigation_tree .block_tree .current_branch {font-weight:bold;}
-.jsenabled .block_global_navigation_tree .block_tree .tree_item.branch {cursor:pointer;}
-.jsenabled .block_global_navigation_tree .block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty]]);background-position: center left;background-repeat: no-repeat;}
-.jsenabled .block_global_navigation_tree .block_tree .collapsed ul {display: none;}
-.jsenabled .block_global_navigation_tree .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed]]);}
-
-/** Internet explorer specific rules **/
-.ie6 .block_global_navigation_tree .block_tree,
-.ie7 .block_global_navigation_tree .block_tree {overflow-x:scroll;}
-.ie6 .block_global_navigation_tree .block_tree .tree_item {width:100%;}
Index: moodle/blocks/moodleblock.class.php
--- moodle/blocks/moodleblock.class.php Base (1.151)
+++ moodle/blocks/moodleblock.class.php Locally Modified (Based On 1.151)
@@ -113,8 +113,6 @@
 
     var $cron          = NULL;
 
-    static $dockinitialised = false;
-
 /// Class Functions
 
     /**
@@ -562,7 +560,6 @@
     }
 
     function get_required_javascript() {
-        $this->_initialise_dock();
         if ($this->instance_can_be_docked() && !$this->hide_header()) {
             $this->page->requires->js_init_call('M.core_dock.init_genericblock', array($this->instance->id));
             user_preference_allow_ajax_update('docked_block_instance_'.$this->instance->id, PARAM_INT);
@@ -735,14 +732,6 @@
         return (!empty($CFG->allowblockstodock) && $this->page->theme->enable_dock);
     }
 
-    public function _initialise_dock() {
-        global $CFG;
-        if (!self::$dockinitialised) {
-            $this->page->requires->strings_for_js(array('addtodock','undockitem','undockall'), 'block');
-            self::$dockinitialised = true;
-        }
-    }
-
     /** @callback callback functions for comments api */
     public static function comment_template($options) {
         $ret = <<<EOD
Index: moodle/blocks/navigation/block_navigation.php
--- moodle/blocks/navigation/block_navigation.php No Base Revision
+++ moodle/blocks/navigation/block_navigation.php Locally New
@@ -0,0 +1,292 @@
+<?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_navigation extends block_base {
+
+    /** @var int */
+    public static $navcount;
+    /** @var string */
+    public $blockname = null;
+    /** @var bool */
+    protected $contentgenerated = false;
+    /** @var bool|null */
+    protected $docked = null;
+
+    /**
+     * Set the initial properties for the block
+     */
+    function init() {
+        global $CFG;
+        $this->blockname = get_class($this);
+        $this->title = get_string('pluginname', $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;
+    }
+
+    function instance_can_be_docked() {
+        return (parent::instance_can_be_docked() && (empty($this->config->enabledock) || $this->config->enabledock=='yes'));
+    }
+
+    function get_required_javascript() {
+        global $CFG;
+        $this->page->requires->js_module(array('name'=>'core_dock', 'fullpath'=>'/blocks/dock.js', 'requires'=>array('base', 'cookie', 'dom', 'io', 'node', 'event-custom', 'event-mouseenter', 'yui2-container')));
+        $this->page->requires->js_module(array('name'=>'block_navigation', 'fullpath'=>'/blocks/navigation/navigation.js', 'requires'=>array('core_dock', 'io', 'node', 'dom', 'event-custom', 'json-parse')));
+        user_preference_allow_ajax_update('docked_block_instance_'.$this->instance->id, PARAM_INT);
+    }
+
+    /**
+     * 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 $this->content;
+        }
+        $this->page->requires->yui2_lib('dom');
+        // JS for navigation moved to the standard theme, the code will probably have to depend on the actual page structure
+        // $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_navigation::$navcount++;
+
+        // Check if this block has been docked
+        if ($this->docked === null) {
+            $this->docked = get_user_preferences('nav_in_tab_panel_globalnav'.block_navigation::$navcount, 0);
+        }
+
+        // Check if there is a param to change the docked state
+        if ($this->docked && optional_param('undock', null, PARAM_INT)==$this->instance->id) {
+            unset_user_preference('nav_in_tab_panel_globalnav'.block_navigation::$navcount);
+            $url = $this->page->url;
+            $url->remove_params(array('undock'));
+            redirect($url);
+        } else if (!$this->docked && optional_param('dock', null, PARAM_INT)==$this->instance->id) {
+            set_user_preferences(array('nav_in_tab_panel_globalnav'.block_navigation::$navcount=>1));
+            $url = $this->page->url;
+            $url->remove_params(array('dock'));
+            redirect($url);
+        }
+
+        // Initialise (only actually happens if it hasn't already been done yet
+        $this->page->navigation->initialise();
+
+        if (!empty($this->config->showmyhistory) && $this->config->showmyhistory=='yes') {
+            $this->showmyhistory();
+        }
+
+        // Get the expandable items so we can pass them to JS
+        $expandable = array();
+        $this->page->navigation->find_expandable($expandable);
+
+        // Initialise the JS tree object
+        $module = array('name'=>'block_navigation', 'fullpath'=>'/blocks/navigation/navigation.js', 'requires'=>array('core_dock', 'io', 'node', 'dom', 'event-custom', 'json-parse'));
+        $arguments = array($this->instance->id, array('expansions'=>$expandable, 'instance'=>$this->instance->id, 'candock'=>$this->instance_can_be_docked()));
+        $this->page->requires->js_init_call('M.block_navigation.init_add_tree', $arguments, false, $module);
+
+        // Grab the items to display
+        $renderer = $this->page->get_renderer('block_navigation');
+        $this->content->text = $renderer->navigation_tree($this->page->navigation);
+
+        $reloadlink = new moodle_url($this->page->url, array('regenerate'=>'navigation'));
+
+        $this->content->footer .= $OUTPUT->action_icon($reloadlink, new pix_icon('t/reload', get_string('reload')), null, array('class'=>'customcommand reloadnavigation'));
+
+        // Set content generated to true so that we know it has been done
+        $this->contentgenerated = true;
+
+        return $this->content;
+    }
+
+    /**
+     * 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'] .= ' block_js_expansion';
+        }
+        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;
+
+        // 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() || isguestuser()) {
+            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_omit_querystring() == $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
+            $mymoodle = $PAGE->navigation->get('profile', navigation_node::TYPE_USER);
+            $myhistorybranch = $mymoodle->add(get_string('showmyhistorytitle', $this->blockname), null, navigation_node::TYPE_CUSTOM, null, 'myhistory');
+            foreach (array_reverse($history) as $node) {
+                $myhistorybranch->children->add($node);
+            }
+        }
+
+        // Cache the history (or update the cached history as it is)
+        $cache->history = $history;
+
+        return true;
+    }
+}
Index: moodle/blocks/navigation/db/upgrade.php
--- moodle/blocks/navigation/db/upgrade.php No Base Revision
+++ moodle/blocks/navigation/db/upgrade.php Locally New
@@ -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 navigation 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 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_navigation_upgrade($oldversion, $block) {
+    // Implemented at 2009082800
+    return true;
+}
Index: moodle/blocks/navigation/edit_form.php
--- moodle/blocks/navigation/edit_form.php No Base Revision
+++ moodle/blocks/navigation/edit_form.php Locally New
@@ -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 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_navigation_edit_form extends block_edit_form {
+    protected function specific_definition($mform) {
+        global $CFG;
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $mods = array('enabledock'=>'yes', 'enablehoverexpansion'=>'no', '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);
+            }
+        }
+    }
+}
Index: moodle/blocks/navigation/lang/en/block_navigation.php
--- moodle/blocks/navigation/lang/en/block_navigation.php No Base Revision
+++ moodle/blocks/navigation/lang/en/block_navigation.php Locally New
@@ -0,0 +1,35 @@
+<?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['everything'] = 'Everything';
+$string['courses'] = 'Categories and courses';
+$string['coursestructures'] = 'Categories, courses, and course structures';
+$string['courseactivities'] = 'Categories, courses, and course Activities';
+$string['enablehoverexpansiondesc'] = 'Enable mouseover expansion of this block';
+$string['enabledockdesc'] = 'Allow the user to dock this block';
+$string['pluginname'] = 'Navigation';
+$string['showmyhistorydesc'] = 'Show my history as a branch in the navigation';
+$string['showmyhistorytitle'] = 'My history';
Index: moodle/blocks/navigation/navigation.js
--- moodle/blocks/navigation/navigation.js No Base Revision
+++ moodle/blocks/navigation/navigation.js Locally New
@@ -0,0 +1,358 @@
+// 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
+ */
+
+/**
+ * This namespace will contain all of the contents of the navigation blocks
+ * global navigation and settings.
+ * @namespace
+ */
+M.block_navigation = M.block_navigation || {
+    /** The number of expandable branches in existence */
+    expandablebranchcount:0,
+    /** An array of initialised trees */
+    treecollection:[],
+    /**
+     * Will contain all of the classes for the navigation blocks
+     * @namespace
+     */
+    classes:{},
+    /**
+     * This function gets called when the module is first loaded as required by
+     * the YUI.add statement at the bottom of the page.
+     * 
+     * NOTE: This will only be executed ONCE
+     * @function
+     */
+    init:function(Y) {
+        if (M.core_dock.genericblock) {
+            // Give the tree class the dock block properties
+            Y.augment(M.block_navigation.classes.tree, M.core_dock.genericblock);
+        }
+    },
+    /**
+     * Add new instance of navigation tree to tree collection
+     */
+    init_add_tree:function(Y, id, properties) {
+    	M.block_navigation.treecollection[id] = new M.block_navigation.classes.tree(Y, id, properties);
+    }
+};
+
+/**
+ * @class tree
+ * @constructor
+ * @base M.core_dock.genericblock
+ * @param {YUI} Y A yui instance to use with the navigation
+ * @param {string} id The name of the tree
+ * @param {object} properties Object containing tree properties
+ */
+M.block_navigation.classes.tree = function(Y, id, properties) {
+    this.Y = Y;
+    this.id = id;
+    this.key = id;
+    this.errorlog = [];
+    this.ajaxbranches = 0;
+    this.expansions = [];
+    this.instance = id;
+    this.cachedcontentnode = null;
+    this.cachedfooter = null;
+    this.position = 'block';
+    this.skipsetposition = false;
+    this.candock = false;
+    
+    if (properties.expansions) {
+        this.expansions = properties.expansions;
+    }
+    if (properties.instance) {
+        this.instance = properties.instance;
+    }
+    if (properties.candock) {
+        this.candock = true;
+    }
+
+    var node = this.Y.one('#inst'+this.id);
+    
+    // Can't find the block instance within the page
+    if (node === null) {
+        return;
+    }
+
+    var reloadicon = node.one('.footer .reloadnavigation');
+    if (reloadicon) {
+        reloadicon.remove();
+    }
+    
+    // Attach event to toggle expansion
+    node.all('.tree_item.branch').on('click', this.toggleexpansion , this);
+
+    // Attache events to expand by AJAX
+    for (var i in this.expansions) {
+        this.Y.one('#'+this.expansions[i].id).on('ajaxload|click', this.init_load_ajax, this, this.expansions[i]);
+        M.block_navigation.expandablebranchcount++;
+    }
+
+    if (node.hasClass('block_js_expansion')) {
+        node.on('mouseover', function(e){this.toggleClass('mouseover');}, node);
+        node.on('mouseout', function(e){this.toggleClass('mouseover');}, node);
+    }
+
+    // Call the generic blocks init method to add all the generic stuff
+    if (this.candock) {
+        this.init(Y, node);
+    }
+
+    if (reloadicon) {
+        node.one('.header .block_action').insert(reloadicon, 0);
+    }
+}
+
+/**
+ * Loads a branch via AJAX
+ * @param {event} e The event object
+ * @param {object} branch A branch to load via ajax
+ */
+M.block_navigation.classes.tree.prototype.init_load_ajax = function(e, branch) {
+    e.stopPropagation();
+    if (e.target.get('nodeName').toUpperCase() != 'P') {
+        return true;
+    }
+    var cfginstance = '';
+    if (this.instance != null) {
+        cfginstance = '&instance='+this.instance
+    }
+    this.Y.io(M.cfg.wwwroot+'/lib/ajax/getnavbranch.php', {
+        method:'POST',
+        data:'elementid='+branch.id+'&id='+branch.branchid+'&type='+branch.type+'&sesskey='+M.cfg.sesskey+cfginstance,
+        on: {
+            complete:this.load_ajax,
+            success:function() {this.Y.detach('click', this.init_load_ajax, e.target);}
+        },
+        context:this,
+        arguments:{
+            target:e.target
+        }
+    });
+    return true;
+}
+
+/**
+ * Takes an branch provided through ajax and loads it into the tree
+ * @param {int} tid The transaction id
+ * @param {object} outcome
+ * @param {mixed} args
+ * @return bool
+ */
+M.block_navigation.classes.tree.prototype.load_ajax = function(tid, outcome, args) {
+    try {
+        var object = this.Y.JSON.parse(outcome.responseText);
+        if (this.add_branch(object, args.target.ancestor('LI') ,1)) {
+            if (this.candock) {
+                M.core_dock.resize();
+            }
+            return true;
+        }
+    } catch (e) {
+        // If we got here then there was an error parsing the result
+    }
+    // The branch is empty so class it accordingly
+    args.target.replaceClass('branch', 'emptybranch');
+    return true;
+}
+
+/**
+ * Adds a branch into the tree provided with some XML
+ * @param {xmldoc} branchxml
+ * @param {Y.Node} target
+ * @param {int} depth
+ * @return bool
+ */
+M.block_navigation.classes.tree.prototype.add_branch = function(branchobj, target, depth) {
+
+    // Make the new branch into an object
+    var branch = new M.block_navigation.classes.branch(this, branchobj);
+
+    var childrenul = false;
+    if (depth === 1) {
+        if (!branch.children) {
+            return false;
+        }
+        childrenul = this.Y.Node.create('<ul></ul>');
+        target.appendChild(childrenul);
+    } else {
+        childrenul = branch.inject_into_dom(target);
+    }
+    if (childrenul) {
+        for (i in branch.children) {
+            // Add each branch to the tree
+            this.add_branch(branch.children[i], childrenul, depth+1);
+        }
+    }
+    return true;
+}
+/**
+ * Toggle a branch as expanded or collapsed
+ * @param {Event} e
+ */
+M.block_navigation.classes.tree.prototype.toggleexpansion = function(e) {
+    // First check if they managed to click on the li iteslf, then find the closest
+    // LI ancestor and use that
+
+    if (e.target.get('nodeName').toUpperCase() == 'A') {
+        // A link has been clicked don't fire any more events just do the default.
+        e.stopPropagation();
+        return;
+    }
+
+    if (e.target.get('nodeName').toUpperCase() == 'LI') {
+        e.target.toggleClass('collapsed');
+    } else if (e.target.ancestor('LI')) {
+        e.target.ancestor('LI').toggleClass('collapsed');
+    }
+    if (this.candock) {
+        M.core_dock.resize();
+    }
+}
+
+/**
+ * This class represents a branch for a tree
+ * @class branch
+ * @constructor
+ * @param {M.block_navigation.classes.tree} tree
+ * @param {object|null} obj
+ */
+M.block_navigation.classes.branch = function(tree, obj) {
+    this.tree = tree;
+    this.name = null;
+    this.title = null;
+    this.classname = null;
+    this.id = null;
+    this.key = null;
+    this.type = null;
+    this.link = null;
+    this.icon = null;
+    this.expandable = null;
+    this.expansionceiling = null;
+    this.hidden = false;
+    this.haschildren = false;
+    this.children = false;
+    if (obj !== null) {
+        // Construct from the provided xml
+        this.construct_from_json(obj);
+    }
+}
+M.block_navigation.classes.branch.prototype.construct_from_json = function(obj) {
+    for (var i in obj) {
+        this[i] = obj[i];
+    }
+    if (this.children) {
+        this.haschildren = true;
+    } else {
+        this.children = [];
+    }
+    if (this.id && this.id.match(/^expandable_branch_\d+$/)) {
+        // Assign a new unique id for this new expandable branch
+        M.block_navigation.expandablebranchcount++;
+        this.id = 'expandable_branch_'+M.block_navigation.expandablebranchcount;
+    }
+}
+/**
+ * Injects a branch into the tree at the given location
+ * @param {element} element
+ */
+M.block_navigation.classes.branch.prototype.inject_into_dom = function(element) {
+
+    var branchli = this.tree.Y.Node.create('<li></li>');
+    var branchp = this.tree.Y.Node.create('<p class="tree_item"></p>');
+
+    if ((this.expandable !== null || this.haschildren) && this.expansionceiling===null) {
+        branchli.addClass('collapsed');
+        branchp.addClass('branch');
+        branchp.on('click', this.tree.toggleexpansion, this.tree);
+        if (this.expandable) {
+            branchp.on('ajaxload|click', this.tree.init_load_ajax, this.tree, {branchid:this.key,id:this.id,type:this.type});
+        }
+    }
+
+    if (this.myclass !== null) {
+        branchp.addClass(this.myclass);
+    }
+    if (this.id !== null) {
+        branchp.setAttribute('id', this.id);
+    }
+
+    // Prepare the icon, should be an object representing a pix_icon
+    var branchicon = false;
+    if (this.icon != null) {
+        branchicon = this.tree.Y.Node.create('<img src="'+M.util.image_url(this.icon.pix, this.icon.component)+'" alt="" />');
+        if (this.icon.alt) {
+            branchicon.setAttribute('alt', this.icon.alt);
+        }
+        if (this.icon.title) {
+            branchicon.setAttribute('alt', this.icon.title);
+        }
+        if (this.icon.classes) {
+            for (var i in this.icon.classes) {
+                branchicon.addClass(this.icon.classes[i]);
+            }
+        }
+        this.name = '&nbsp;'+this.name;
+    }
+    
+    if (this.link === null) {
+        if (branchicon) {
+            branchp.appendChild(branchicon);
+        }
+        branchp.append(this.name.replace(/\n/g, '<br />'));
+    } else {
+        var branchlink = this.tree.Y.Node.create('<a title="'+this.title+'" href="'+this.link+'"></a>');
+        if (branchicon) {
+            branchlink.appendChild(branchicon);
+        }
+        branchlink.append(this.name.replace(/\n/g, '<br />'));
+        if (this.hidden) {
+            branchlink.addClass('dimmed');
+        }
+        branchp.appendChild(branchlink);
+    }
+
+    branchli.appendChild(branchp);
+    if (this.haschildren) {
+        var childrenul = this.tree.Y.Node.create('<ul></ul>');
+        branchli.appendChild(childrenul);
+        element.appendChild(branchli);
+        return childrenul
+    } else {
+        element.appendChild(branchli);
+        return false;
+    }
+}
+
+/**
+ * Causes the navigation block module to initalise the first time the module
+ * is used!
+ *
+ * NOTE: Never convert the second argument to a function reference...
+ * doing so causes scoping issues
+ */
+YUI.add('block_navigation', function(Y){M.block_navigation.init(Y);}, '0.0.0.1', M.yui.loader.modules.block_navigation.requires);
Index: moodle/blocks/navigation/renderer.php
--- moodle/blocks/navigation/renderer.php No Base Revision
+++ moodle/blocks/navigation/renderer.php Locally New
@@ -0,0 +1,101 @@
+<?php
+
+class block_navigation_renderer extends plugin_renderer_base {
+
+    public function navigation_tree(global_navigation $navigation) {
+        $content = $this->navigation_node(array($navigation), array('class'=>'block_tree list'));
+        if (isset($navigation->id) && !is_numeric($navigation->id) && !empty($content)) {
+            $content = $this->output->box($content, 'block_tree_box', $navigation->id);
+        }
+        return $content;
+    }
+
+    protected function navigation_node($items, $attrs=array()) {
+
+        // exit if empty, we don't want an empty ul element
+        if (count($items)==0) {
+            return '';
+        }
+
+        // array of nested li elements
+        $lis = array();
+        foreach ($items as $item) {
+            if (!$item->display) {
+                continue;
+            }
+            $content = $item->get_content();
+            $title = $item->get_title();
+            if ($item->icon instanceof renderable) {
+                $icon = $this->output->render($item->icon);
+                $content = $icon.'&nbsp;'.$content; // use CSS for spacing of icons
+            }
+            if ($item->helpbutton !== null) {
+                $content = trim($item->helpbutton).html_writer::tag('span', $content, array('class'=>'clearhelpbutton'));
+            }
+
+            if ($content === '') {
+                continue;
+            }
+
+            if ($item->action instanceof action_link) {
+                //TODO: to be replaced with something else
+                $link = $item->action;
+                if ($item->hidden) {
+                    $link->add_class('dimmed');
+                }
+                $content = $this->output->render($link);
+            } else if ($item->action instanceof moodle_url) {
+                $attributes = array();
+                if ($title !== '') {
+                    $attributes['title'] = $title;
+                }
+                if ($item->hidden) {
+                    $attributes['class'] = 'dimmed_text';
+                }
+                $content = html_writer::link($item->action, $content, $attributes);
+
+            } else if (is_string($item->action) || empty($item->action)) {
+                $attributes = array();
+                if ($title !== '') {
+                    $attributes['title'] = $title;
+                }
+                if ($item->hidden) {
+                    $attributes['class'] = 'dimmed_text';
+                }
+                $content = html_writer::tag('span', $content, $attributes);
+            }
+
+            // this applies to the li item which contains all child lists too
+            $liclasses = array($item->get_css_type());
+            if (!$item->forceopen || (!$item->forceopen && $item->collapse) || ($item->children->count()==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 ($item->has_children()) {
+                $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 = html_writer::tag('p', $content, $divattr) . $this->navigation_node($item->children);
+            if (!empty($item->preceedwithhr) && $item->preceedwithhr===true) {
+                $content = html_writer::empty_tag('hr') . $content;
+            }
+            $content = html_writer::tag('li', $content, $liattr);
+            $lis[] = $content;
+        }
+        return html_writer::tag('ul', implode("\n", $lis), $attrs);
+    }
+
+}
Index: moodle/blocks/navigation/styles.css
--- moodle/blocks/navigation/styles.css No Base Revision
+++ moodle/blocks/navigation/styles.css Locally New
@@ -0,0 +1,22 @@
+/** JavaScript state rules **/
+.jsenabled .block_navigation.dock_on_load,
+.block_navigation .block_tree_box .requiresjs {display:none;}
+.jsenabled .block_navigation .block_tree_box .requiresjs {display:inline;}
+
+/** General display rules **/
+.block_navigation .block_tree {margin:5px;padding-left:0px;overflow-x:auto;overflow-y:visible;}
+.block_navigation .block_tree li {margin:0;list-style: none;}
+.block_navigation .block_tree li ul {padding-left:16px;margin:0;}
+.block_navigation .block_tree .tree_item {white-space:nowrap;margin:2px 0px;padding-left: 16px;margin:3px 0px;white-space:nowrap;text-align:left;}
+.block_navigation .block_tree .tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: center left;background-repeat: no-repeat;}
+.block_navigation .block_tree .root_node.leaf {padding-left:0px;}
+.block_navigation .block_tree .current_branch {font-weight:bold;}
+.jsenabled .block_navigation .block_tree .tree_item.branch {cursor:pointer;}
+.jsenabled .block_navigation .block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty]]);background-position: center left;background-repeat: no-repeat;}
+.jsenabled .block_navigation .block_tree .collapsed ul {display: none;}
+.jsenabled .block_navigation .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed]]);}
+
+/** Internet explorer specific rules **/
+.ie6 .block_navigation .block_tree,
+.ie7 .block_navigation .block_tree {overflow-x:scroll;}
+.ie6 .block_navigation .block_tree .tree_item {width:100%;}
Index: moodle/blocks/settings/block_settings.php
--- moodle/blocks/settings/block_settings.php No Base Revision
+++ moodle/blocks/settings/block_settings.php Locally New
@@ -0,0 +1,155 @@
+<?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 extends block_base {
+
+    /** @var string */
+    public static $navcount;
+    public $blockname = null;
+    /** @var bool */
+    protected $contentgenerated = false;
+    /** @var bool|null */
+    protected $docked = null;
+
+    /**
+     * Set the initial properties for the block
+     */
+    function init() {
+        $this->blockname = get_class($this);
+        $this->title = get_string('pluginname', $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;
+    }
+
+    function instance_can_be_docked() {
+        return (parent::instance_can_be_docked() && (empty($this->config->enabledock) || $this->config->enabledock=='yes'));
+    }
+
+    function get_required_javascript() {
+        global $CFG;
+        $this->page->requires->js_module(array('name'=>'core_dock', 'fullpath'=>'/blocks/dock.js', 'requires'=>array('base', 'cookie', 'dom', 'io', 'node', 'event-custom', 'event-mouseenter', 'yui2-container')));
+        $module = array('name'=>'block_navigation', 'fullpath'=>'/blocks/navigation/navigation.js', 'requires'=>array('core_dock', 'io', 'node', 'dom', 'event-custom', 'json-parse'));
+        $arguments = array($this->instance->id, array('instance'=>$this->instance->id, 'candock'=>$this->instance_can_be_docked()));
+        $this->page->requires->js_init_call('M.block_navigation.init_add_tree', $arguments, false, $module);
+        user_preference_allow_ajax_update('docked_block_instance_'.$this->instance->id, PARAM_INT);
+    }
+
+    /**
+     * 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->yui2_lib('dom');
+        // JS for navigation moved to the standard theme, the code will probably have to depend on the actual page structure
+        // $this->page->requires->js('/lib/javascript-navigation.js');
+        block_settings::$navcount++;
+
+        // Check if this block has been docked
+        if ($this->docked === null) {
+            $this->docked = get_user_preferences('nav_in_tab_panel_settingsnav'.block_settings::$navcount, 0);
+        }
+
+        // Check if there is a param to change the docked state
+        if ($this->docked && optional_param('undock', null, PARAM_INT)==$this->instance->id) {
+            unset_user_preference('nav_in_tab_panel_settingsnav'.block_settings::$navcount, 0);
+            $url = $this->page->url;
+            $url->remove_params(array('undock'));
+            redirect($url);
+        } else if (!$this->docked && optional_param('dock', null, PARAM_INT)==$this->instance->id) {
+            set_user_preferences(array('nav_in_tab_panel_settingsnav'.block_settings::$navcount=>1));
+            $url = $this->page->url;
+            $url->remove_params(array('dock'));
+            redirect($url);
+        }
+
+        $renderer = $this->page->get_renderer('block_settings');
+        $this->content->text = $renderer->settings_tree($this->page->settingsnav);
+
+        // only do search if you have moodle/site:config
+        if (!empty($this->content->text)) {
+            if (has_capability('moodle/site:config',get_context_instance(CONTEXT_SYSTEM)) ) {
+                $this->content->footer = $renderer->search_form(new moodle_url("$CFG->wwwroot/$CFG->admin/search.php"), optional_param('query', '', PARAM_RAW));
+            } else {
+                $this->content->footer = '';
+            }
+
+            $reloadlink = new moodle_url($this->page->url, array('regenerate'=>'navigation'));
+            $this->content->footer .= $OUTPUT->action_icon($reloadlink, new pix_icon('t/reload', get_string('reload')), null, array('class'=>'customcommand reloadnavigation'));
+
+            if (!empty($this->config->enabledock) && $this->config->enabledock == 'yes') {
+                user_preference_allow_ajax_update('nav_in_tab_panel_settingsnav'.block_settings::$navcount, PARAM_INT);
+            }
+        }
+
+        $this->contentgenerated = true;
+        return true;
+    }
+
+    function html_attributes() {
+        $attributes = parent::html_attributes();
+        if (!empty($this->config->enablehoverexpansion) && $this->config->enablehoverexpansion == 'yes') {
+            $attributes['class'] .= ' block_js_expansion';
+        }
+        return $attributes;
+    }
+}
Index: moodle/blocks/settings/edit_form.php
--- moodle/blocks/settings/edit_form.php No Base Revision
+++ moodle/blocks/settings/edit_form.php Locally New
@@ -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_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_enabledock', get_string('enabledock', $this->block->blockname), $yesnooptions);
+        if (empty($this->block->config->enabledock) || $this->block->config->enabledock=='yes') {
+            $mform->getElement('config_enabledock')->setSelected('yes');
+        } else {
+            $mform->getElement('config_enabledock')->setSelected('no');
+        }
+    }
+}
Index: moodle/blocks/settings/lang/en/block_settings.php
--- moodle/blocks/settings/lang/en/block_settings.php No Base Revision
+++ moodle/blocks/settings/lang/en/block_settings.php Locally New
@@ -0,0 +1,29 @@
+<?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['enablehoverexpansion'] = 'Enable mouseover expansion of this block';
+$string['enabledock'] = 'Allow the user to dock this block';
+$string['pluginname'] = 'Settings';
Index: moodle/blocks/settings/renderer.php
--- moodle/blocks/settings/renderer.php No Base Revision
+++ moodle/blocks/settings/renderer.php Locally New
@@ -0,0 +1,79 @@
+<?php
+
+class block_settings_renderer extends plugin_renderer_base {
+
+    public function settings_tree(settings_navigation $navigation) {
+        $count = 0;
+        foreach ($navigation->children as &$child) {
+            $child->preceedwithhr = ($count!==0);
+            $count++;
+        }
+        $content = $this->navigation_node($navigation, array('class'=>'block_tree list'));
+        if (isset($navigation->id) && !is_numeric($navigation->id) && !empty($content)) {
+            $content = $this->output->box($content, 'block_tree_box', $navigation->id);
+        }
+        return $content;
+    }
+
+    protected function navigation_node(navigation_node $node, $attrs=array()) {
+        $items = $node->children;
+
+        // exit if empty, we don't want an empty ul element
+        if ($items->count()==0) {
+            return '';
+        }
+
+        // array of nested li elements
+        $lis = array();
+        foreach ($items as $item) {
+            if (!$item->display) {
+                continue;
+            }
+
+            $content = $this->output->render($item);
+
+            // this applies to the li item which contains all child lists too
+            $liclasses = array($item->get_css_type());
+            if (!$item->forceopen || (!$item->forceopen && $item->collapse) || ($item->children->count()==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 ($item->children->count()>0  || $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 = html_writer::tag('p', $content, $divattr) . $this->navigation_node($item);
+            if (!empty($item->preceedwithhr) && $item->preceedwithhr===true) {
+                $content = html_writer::empty_tag('hr') . $content;
+            }
+            $content = html_writer::tag('li', $content, $liattr);
+            $lis[] = $content;
+        }
+        return html_writer::tag('ul', implode("\n", $lis), $attrs);
+    }
+
+    public function search_form(moodle_url $formtarget, $searchvalue) {
+        $content = html_writer::start_tag('form', array('class'=>'adminsearchform', 'method'=>'get', 'action'=>$formtarget));
+        $content .= html_writer::start_tag('div');
+        $content .= html_writer::tag('label', s(get_string('searchinsettings', 'admin')), array('for'=>'adminsearchquery', 'class'=>'accesshide'));
+        $content .= html_writer::empty_tag('input', array('id'=>'adminsearchquery', 'type'=>'text', 'name'=>'query', 'value'=>s($searchvalue)));
+        $content .= html_writer::empty_tag('input', array('type'=>'submit', 'value'=>s(get_string('search'))));
+        $content .= html_writer::end_tag('div');
+        $content .= html_writer::end_tag('form');
+        return $content;
+    }
+
+}
Index: moodle/blocks/settings/styles.css
--- moodle/blocks/settings/styles.css No Base Revision
+++ moodle/blocks/settings/styles.css Locally New
@@ -0,0 +1,22 @@
+/** JavaScript state rules **/
+.jsenabled .block_settings.dock_on_load,
+.block_settings .block_tree_box .requiresjs {display:none;}
+.jsenabled .block_settings .block_tree_box .requiresjs {display:inline;}
+
+/** General display rules **/
+.block_settings .block_tree {margin:5px;padding-left:0px;overflow-x:auto;overflow-y:visible;}
+.block_settings .block_tree li {margin:0;list-style: none;}
+.block_settings .block_tree li ul {padding-left:16px;margin:0;}
+.block_settings .block_tree .tree_item {white-space:nowrap;margin:2px 0px;padding-left: 16px;margin:3px 0px;white-space:nowrap;text-align:left;}
+.block_settings .block_tree .tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: center left;background-repeat: no-repeat;}
+.block_settings .block_tree .root_node.leaf {padding-left:0px;}
+.block_settings .block_tree .current_branch {font-weight:bold;}
+.jsenabled .block_settings .block_tree .tree_item.branch {cursor:pointer;}
+.jsenabled .block_settings .block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty]]);background-position: center left;background-repeat: no-repeat;}
+.jsenabled .block_settings .block_tree .collapsed ul {display: none;}
+.jsenabled .block_settings .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed]]);}
+
+/** Internet explorer specific rules **/
+.ie6 .block_settings .block_tree,
+.ie7 .block_settings .block_tree {overflow-x:scroll;}
+.ie6 .block_settings .block_tree .tree_item {width:100%;}
Index: moodle/blocks/settings_navigation_tree/block_settings_navigation_tree.php
--- moodle/blocks/settings_navigation_tree/block_settings_navigation_tree.php Base (1.28)
+++ moodle/blocks/settings_navigation_tree/block_settings_navigation_tree.php Locally Deleted
@@ -1,165 +0,0 @@
-<?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;
-    /** @var bool */
-    protected $contentgenerated = false;
-    /** @var bool|null */
-    protected $docked = null;
-
-    /**
-     * Set the initial properties for the block
-     */
-    function init() {
-        $this->blockname = get_class($this);
-        $this->title = get_string('pluginname', $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;
-    }
-
-    function get_required_javascript() {
-        global $CFG;
-        $this->_initialise_dock();
-        $this->page->requires->js_module(array('name'=>'core_dock', 'fullpath'=>'/blocks/dock.js', 'requires'=>array('base', 'cookie', 'dom', 'io', 'node', 'event-custom', 'event-mouseenter', 'yui2-container')));
-        $module = array('name'=>'block_navigation', 'fullpath'=>'/blocks/global_navigation_tree/navigation.js', 'requires'=>array('core_dock', 'io', 'node', 'dom', 'event-custom', 'json-parse'));
-        $arguments = array($this->instance->id, array('instance'=>$this->instance->id, 'candock'=>$this->instance_can_be_docked()));
-        $this->page->requires->js_init_call('M.block_navigation.init_add_tree', $arguments, false, $module);
-        user_preference_allow_ajax_update('docked_block_instance_'.$this->instance->id, PARAM_INT);
-    }
-
-    /**
-     * 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->yui2_lib('dom');
-        // JS for navigation moved to the standard theme, the code will probably have to depend on the actual page structure
-        // $this->page->requires->js('/lib/javascript-navigation.js');
-        block_settings_navigation_tree::$navcount++;
-
-        // Check if this block has been docked
-        if ($this->docked === null) {
-            $this->docked = get_user_preferences('nav_in_tab_panel_settingsnav'.block_settings_navigation_tree::$navcount, 0);
-        }
-
-        // Check if there is a param to change the docked state
-        if ($this->docked && optional_param('undock', null, PARAM_INT)==$this->instance->id) {
-            unset_user_preference('nav_in_tab_panel_settingsnav'.block_settings_navigation_tree::$navcount, 0);
-            $url = $this->page->url;
-            $url->remove_params(array('undock'));
-            redirect($url);
-        } else if (!$this->docked && optional_param('dock', null, PARAM_INT)==$this->instance->id) {
-            set_user_preferences(array('nav_in_tab_panel_settingsnav'.block_settings_navigation_tree::$navcount=>1));
-            $url = $this->page->url;
-            $url->remove_params(array('dock'));
-            redirect($url);
-        }
-
-        if (!$this->page->settingsnav->contains_active_node() && !$this->page->navigation->contains_active_node()) {
-            if (!$this->page->settingsnav->reiterate_active_nodes()) {
-                $this->page->settingsnav->reiterate_active_nodes(URL_MATCH_BASE);
-            }
-        }
-
-        // 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)) ) {
-                $value = optional_param('query', '', PARAM_RAW);
-                $target = new moodle_url("$CFG->wwwroot/$CFG->admin/search.php");
-                $form = '<form class="adminsearchform" method="get" action="'.$target.'">';
-                $form .= '<div><label for="adminsearchquery" class="accesshide">'.s(get_string('searchinsettings', 'admin')).'</label>';
-                $form .= '<input id="adminsearchquery" type="text" name="query" value="'.s($value).'"/>';
-                $form .= '<input type="submit" value="'.s(get_string('search')).'" />';
-                $form .= '</div></form>';
-                $this->content->footer = $form;
-            } else {
-                $this->content->footer = '';
-            }
-
-            $reloadlink = new moodle_url($this->page->url, array('regenerate'=>'navigation'));
-            $this->content->footer .= $OUTPUT->action_icon($reloadlink, new pix_icon('t/reload', get_string('reload')), null, array('class'=>'customcommand'));
-
-            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);
-            }
-        }
-
-        $this->contentgenerated = true;
-        return true;
-    }
-
-    function html_attributes() {
-        $attributes = parent::html_attributes();
-        if (!empty($this->config->enablehoverexpansion) && $this->config->enablehoverexpansion == 'yes') {
-            $attributes['class'] .= ' block_js_expansion';
-        }
-        return $attributes;
-    }
-}
Index: moodle/blocks/settings_navigation_tree/edit_form.php
--- moodle/blocks/settings_navigation_tree/edit_form.php Base (1.1)
+++ moodle/blocks/settings_navigation_tree/edit_form.php Locally Deleted
@@ -1,54 +0,0 @@
-<?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');
-        }
-    }
-}
Index: moodle/blocks/settings_navigation_tree/lang/en/block_settings_navigation_tree.php
--- moodle/blocks/settings_navigation_tree/lang/en/block_settings_navigation_tree.php Base (1.3)
+++ moodle/blocks/settings_navigation_tree/lang/en/block_settings_navigation_tree.php Locally Deleted
@@ -1,28 +0,0 @@
-<?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/>.
-
-/**
- * Strings for component 'block_settings_navigation_tree', language 'en', branch 'MOODLE_20_STABLE'
- *
- * @package   block_settings_navigation_tree
- * @copyright 2009 Sam Hemelryk
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-$string['enablehoverexpansion'] = 'Enable mouseover expansion of this block';
-$string['enablesidebarpopout'] = 'Allow the user to switch the block to a sidbar popout';
-$string['pluginname'] = 'Settings';
Index: moodle/blocks/settings_navigation_tree/styles.css
--- moodle/blocks/settings_navigation_tree/styles.css Base (1.1)
+++ moodle/blocks/settings_navigation_tree/styles.css Locally Deleted
@@ -1,22 +0,0 @@
-/** JavaScript state rules **/
-.jsenabled .block_settings_navigation_tree.dock_on_load,
-.block_settings_navigation_tree .block_tree_box .requiresjs {display:none;}
-.jsenabled .block_settings_navigation_tree .block_tree_box .requiresjs {display:inline;}
-
-/** General display rules **/
-.block_settings_navigation_tree .block_tree {margin:5px;padding-left:0px;overflow-x:auto;overflow-y:visible;}
-.block_settings_navigation_tree .block_tree li {margin:0;list-style: none;}
-.block_settings_navigation_tree .block_tree li ul {padding-left:16px;margin:0;}
-.block_settings_navigation_tree .block_tree .tree_item {white-space:nowrap;margin:2px 0px;padding-left: 16px;margin:3px 0px;white-space:nowrap;text-align:left;}
-.block_settings_navigation_tree .block_tree .tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: center left;background-repeat: no-repeat;}
-.block_settings_navigation_tree .block_tree .root_node.leaf {padding-left:0px;}
-.block_settings_navigation_tree .block_tree .current_branch {font-weight:bold;}
-.jsenabled .block_settings_navigation_tree .block_tree .tree_item.branch {cursor:pointer;}
-.jsenabled .block_settings_navigation_tree .block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty]]);background-position: center left;background-repeat: no-repeat;}
-.jsenabled .block_settings_navigation_tree .block_tree .collapsed ul {display: none;}
-.jsenabled .block_settings_navigation_tree .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed]]);}
-
-/** Internet explorer specific rules **/
-.ie6 .block_settings_navigation_tree .block_tree,
-.ie7 .block_settings_navigation_tree .block_tree {overflow-x:scroll;}
-.ie6 .block_settings_navigation_tree .block_tree .tree_item {width:100%;}
Index: moodle/config-dist.php
--- moodle/config-dist.php Base (1.132)
+++ moodle/config-dist.php Locally Modified (Based On 1.132)
@@ -217,7 +217,7 @@
 // The blocks in this list will be protected from deletion, and this is primarily
 // used to protect the navigation and settings blocks which can be very hard to
 // get back if accidentally delete.
-//      $CFG->undeletableblocktypes = 'global_navigation_tree,settings_navigation_tree';
+//      $CFG->undeletableblocktypes = 'navigation,settings';
 //
 // You can specify a different class to be created for the $PAGE global, and to
 // compute which blocks appear on each page. However, I cannot think of any good
Index: moodle/course/format/topics/lib.php
--- moodle/course/format/topics/lib.php Base (1.2)
+++ moodle/course/format/topics/lib.php Locally Modified (Based On 1.2)
@@ -33,8 +33,8 @@
  * @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');
+function callback_topics_load_content(&$navigation, $course, $coursenode) {
+    return $navigation->load_generic_course_sections($course, $coursenode, get_string('topic'), 'topic');
 }
 
 /**
Index: moodle/course/format/weeks/lib.php
--- moodle/course/format/weeks/lib.php Base (1.3)
+++ moodle/course/format/weeks/lib.php Locally Modified (Based On 1.3)
@@ -33,8 +33,8 @@
  * @param array $path An array of keys to the course node
  * @param stdClass $course The course we are loading the section for
  */
-function callback_weeks_load_content(&$navigation, $keys, $course) {
-    $navigation->add_course_section_generic($keys, $course, get_string('week'), 'week');
+function callback_weeks_load_content(&$navigation, $course, $coursenode) {
+    return $navigation->load_generic_course_sections($course, $coursenode, get_string('week'), 'week');
 }
 
 /**
Index: moodle/course/loginas.php
--- moodle/course/loginas.php Base (1.61)
+++ moodle/course/loginas.php Locally Modified (Based On 1.61)
@@ -8,10 +8,7 @@
     $return = optional_param('return', 0, PARAM_BOOL);   // return to the page we came from
 
     if (session_is_loggedinas()) {
-        if (!confirm_sesskey()) {
-            print_error('confirmsesskeybad');
-        }
-
+    require_sesskey();
         session_unloginas();
 
         if ($return and isset($_SERVER["HTTP_REFERER"])) { // That's all we wanted to do, so let's go back
@@ -33,14 +30,9 @@
     }
     $PAGE->set_url($url);
 
-    if (!confirm_sesskey()) {
-        print_error('confirmsesskeybad');
-    }
+require_sesskey();
+$course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST);
 
-    if (!$course = $DB->get_record('course', array('id'=>$id))) {
-        print_error("invalidcourseid");
-    }
-
 /// User must be logged in
 
     $systemcontext = get_context_instance(CONTEXT_SYSTEM);
@@ -53,6 +45,7 @@
             print_error('nologinas');
         }
         $context = $systemcontext;
+    $PAGE->set_context($context);
     } else {
         require_login($course);
         require_capability('moodle/user:loginas', $coursecontext);
@@ -78,6 +71,3 @@
     $PAGE->set_title($strloggedinas);
     $PAGE->navbar->add($strloggedinas);
     notice($strloggedinas, "$CFG->wwwroot/course/view.php?id=$course->id");
-
-
-
Index: moodle/lib/adminlib.php
--- moodle/lib/adminlib.php Base (1.452)
+++ moodle/lib/adminlib.php Locally Modified (Based On 1.452)
@@ -5851,7 +5851,7 @@
         'comments',
         'course_list',
         'course_summary',
-        'global_navigation_tree',
+        'navigation',
         'glossary_random',
         'html',
         'loancalc',
@@ -5869,7 +5869,7 @@
         'search',
         'search_forums',
         'section_links',
-        'settings_navigation_tree',
+        'settings',
         'site_main_menu',
         'social_activities',
         'tag_flickr',
Index: moodle/lib/ajax/getnavbranch.php
--- moodle/lib/ajax/getnavbranch.php Base (1.6)
+++ moodle/lib/ajax/getnavbranch.php Locally Modified (Based On 1.6)
@@ -41,22 +41,17 @@
     $instanceid = optional_param('instance', null, PARAM_INT);
 
     // Create a global nav object
-    $navigation = new global_navigation_for_ajax();
+    $navigation = new global_navigation_for_ajax($PAGE);
 
     // 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'));
+        $blockrecords = $DB->get_record('block_instances', array('id'=>$instanceid,'blockname'=>'navigation'));
         if ($blockrecords!=false) {
                 // Instantiate a block_instance object so we can access congif
-            $block = block_instance('global_navigation_tree', $blockrecords);
+            $block = block_instance('navigation', $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;
             }
@@ -67,13 +62,8 @@
     $expandable = $navigation->initialise($branchtype, $branchid);
     $converter = new navigation_json();
 
-    if ($toggledisplay) {
-        // Toggle display of item types we dont' want to display
-        $navigation->toggle_type_display($navigation->expansionlimit);
-        $converter->set_expansionceiling($navigation->expansionlimit);
-    }
     // Find the actuall branch we are looking for
-    $branch = $navigation->find_child($branchid, $branchtype);
+    $branch = $navigation->find($branchid, $branchtype);
 
     // Stop buffering errors at this point
     $html = ob_get_contents();
Index: moodle/lib/blocklib.php
--- moodle/lib/blocklib.php Base (1.241)
+++ moodle/lib/blocklib.php Locally Modified (Based On 1.241)
@@ -874,7 +874,7 @@
         global $CFG;
 
         if (!isset($CFG->undeletableblocktypes) || (!is_array($CFG->undeletableblocktypes) && !is_string($CFG->undeletableblocktypes))) {
-            $CFG->undeletableblocktypes = array('global_navigation_tree','settings_navigation_tree');
+            $CFG->undeletableblocktypes = array('navigation','settings');
         } else if (is_string($CFG->undeletableblocktypes)) {
             $CFG->undeletableblocktypes = explode(',', $CFG->undeletableblocktypes);
         }
@@ -1775,6 +1775,6 @@
 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('global_navigation_tree', 'settings_navigation_tree')), '*', null, true);
+    $page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('navigation', 'settings')), '*', null, true);
     $page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('admin_bookmarks')), 'admin-*', null, null, 2);
 }
Index: moodle/lib/db/upgrade.php
--- moodle/lib/db/upgrade.php Base (1.387)
+++ moodle/lib/db/upgrade.php Locally Modified (Based On 1.387)
@@ -19,6 +19,15 @@
 // Please do not forget to use upgrade_set_timeout()
 // before any action that may take longer time to finish.
 
+/**
+ *
+ * @global stdClass $CFG
+ * @global stdClass $USER
+ * @global moodle_database $DB
+ * @global core_renderer $OUTPUT
+ * @param int $oldversion
+ * @return bool
+ */
 function xmldb_main_upgrade($oldversion) {
     global $CFG, $USER, $DB, $OUTPUT;
 
@@ -3497,6 +3506,17 @@
         upgrade_main_savepoint($result, 2010041300);
     }
 
+    if ($result && $oldversion < 2010041301) {
+        $sql = "UPDATE {block} SET name=? WHERE name=?";
+        $DB->execute($sql, array('navigation', 'global_navigation_tree'));
+        $DB->execute($sql, array('settings', 'settings_navigation_tree'));
+
+        $sql = "UPDATE {block_instances} SET blockname=? WHERE blockname=?";
+        $DB->execute($sql, array('navigation', 'global_navigation_tree'));
+        $DB->execute($sql, array('settings', 'settings_navigation_tree'));
+        upgrade_main_savepoint($result, 2010041301);
+    }
+
     return $result;
 }
 
Index: moodle/lib/navigationlib.php
--- moodle/lib/navigationlib.php Base (1.86)
+++ moodle/lib/navigationlib.php Locally Modified (Based On 1.86)
@@ -50,31 +50,35 @@
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class navigation_node {
-    /** Used to identify this node a leaf (default) */
+class navigation_node implements renderable {
+    /** @var int Used to identify this node a leaf (default) 0 */
     const NODETYPE_LEAF =   0;
-    /** Used to identify this node a branch, happens with children */
+    /** @var int Used to identify this node a branch, happens with children  1 */
     const NODETYPE_BRANCH = 1;
-    /** Unknown node type */
+    /** @var null Unknown node type null */
     const TYPE_UNKNOWN =    null;
-    /**  System node type */
-    const TYPE_SYSTEM =     0;
-    /**  Category node type */
+    /** @var int System node type 0 */
+    const TYPE_ROOTNODE =   0;
+    /** @var int System node type 1 */
+    const TYPE_SYSTEM =     1;
+    /** @var int Category node type 10 */
     const TYPE_CATEGORY =   10;
-    /**  Course node type */
+    /** @var int Course node type 20 */
     const TYPE_COURSE =     20;
-    /**  Course Structure node type */
+    /** @var int Course Structure node type 30 */
     const TYPE_SECTION =    30;
-    /**  Activity node type, e.g. Forum, Quiz */
+    /** @var int Activity node type, e.g. Forum, Quiz 40 */
     const TYPE_ACTIVITY =   40;
-    /**  Resource node type, e.g. Link to a file, or label */
+    /** @var int Resource node type, e.g. Link to a file, or label 50 */
     const TYPE_RESOURCE =   50;
-    /**  A custom node type, default when adding without specifing type */
+    /** @var int A custom node type, default when adding without specifing type 60 */
     const TYPE_CUSTOM =     60;
-    /**  Setting node type, used only within settings nav */
+    /** @var int Setting node type, used only within settings nav 70 */
     const TYPE_SETTING =    70;
-    /**  Setting node type, used only within settings nav */
+    /** @var int Setting node type, used only within settings nav 80 */
     const TYPE_USER =       80;
+    /** @var int Setting node type, used for containers of no importance 90 */
+    const TYPE_CONTAINER =  90;
 
     /** @var int Parameter to aid the coder in tracking [optional] */
     public $id = null;
@@ -88,7 +92,7 @@
     public $title = null;
     /** @var string A string that can be used to build a help button */
     public $helpbutton = null;
-    /** @var moodle_url|string|null An action for the node (link) */
+    /** @var moodle_url|action_link|null An action for the node (link) */
     public $action = null;
     /** @var pix_icon The path to an icon to use for this node */
     public $icon = null;
@@ -100,13 +104,13 @@
     public $collapse = false;
     /** @var bool If set to true the node will be expanded by default */
     public $forceopen = false;
-    /** @var string An array of CSS classes for the node */
+    /** @var array An array of CSS classes for the node */
     public $classes = array();
-    /** @var array An array of child nodes */
+    /** @var navigation_node_collection An array of child nodes */
     public $children = array();
     /** @var bool If set to true the node will be recognised as active */
     public $isactive = false;
-    /** @var string If set to true the node will be dimmed */
+    /** @var bool If set to true the node will be dimmed */
     public $hidden = false;
     /** @var bool If set to false the node will not be displayed */
     public $display = true;
@@ -116,6 +120,8 @@
     public $mainnavonly = false;
     /** @var bool If set to true a title will be added to the action no matter what */
     public $forcetitle = false;
+    /** @var navigation_node A reference to the node parent */
+    public $parent = null;
     /** @var array */
     protected $namedtypes = array(0=>'system',10=>'category',20=>'course',30=>'structure',40=>'activity',50=>'resource',60=>'custom',70=>'setting', 80=>'user');
     /** @var moodle_url */
@@ -124,54 +130,27 @@
     public static $autofindactive = true;
 
     /**
-     * Establish the node, with either text string or array or properites
+     * Constructs a new navigation_node
      *
-     * Called when first creating the node, requires one argument which can be either
-     * a string containing the text for the node or an array or properties one of
-     * which must be text.
-     *
-     * <code>
-     * $PAGE->navigation->newitem = 'This is a new nav item';
-     *  // or
-     * $properties = array()
-     * $properties['text'] = 'This is a new nav item';
-     * $properties['short'] = 'This is a new nav item';
-     * $properties['action'] = moodle_url($CFG->wwwroot.'/course/category.php');
-     * $properties['icon'] = new pix_icon('i/course', '');
-     * $properties['type'] = navigation_node::TYPE_COURSE;
-     * $properties['key'] = 'newitem';
-     * $PAGE->navigation->newitem = $properties;
-     * </code>
-     *
-     * The following are properties that must/can be set in the properties array
-     * <ul>
-     * <li><b>text</b>: You must set text, if this is not set a coding exception is thrown.</li>
-     * <li><b>short</b> <i>optional</i>: A short description used for navbar optional.</li>
-     * <li><b>action</b> <i>optional</i>: This can be either a {@link moodle_url} for a link, or string that can be directly output in instead of the text.</li>
-     * <li><b>icon</b> <i>optional</i>: The path to an icon to display with the node.</li>
-     * <li><b>type</b> <i>optional</i>: This type of the node, defaults to TYPE_CUSTOM.</li>
-     * <li><b>key</b> <i>optional</i>: This can be set to allow you to easily retrieve a node you have created.</li>
-     * </ul>
-     *
-     * @param string|array $properties
+     * @param array|string $properties Either an array of properties or a string to use
+     *                     as the text for the node
      */
     public function __construct($properties) {
         if (is_array($properties)) {
+            // Check the array for each property that we allow to set at construction.
+            // text         - The main content for the node
+            // shorttext    - A short text if required for the node
+            // icon         - The icon to display for the node
+            // type         - The type of the node
+            // key          - The key to use to identify the node
+            // parent       - A reference to the nodes parent
+            // action       - The action to attribute to this node, usually a URL to link to
             if (array_key_exists('text', $properties)) {
                 $this->text = $properties['text'];
             }
             if (array_key_exists('shorttext', $properties)) {
                 $this->shorttext = $properties['shorttext'];
             }
-            if (array_key_exists('action', $properties)) {
-                $this->action = $properties['action'];
-                if (is_string($this->action)) {
-                    $this->action = new moodle_url($this->action);
-                }
-                if (self::$autofindactive) {
-                    $this->check_if_active();
-                }
-            }
             if (array_key_exists('icon', $properties)) {
                 $this->icon = $properties['icon'];
                 if ($this->icon instanceof pix_icon) {
@@ -190,654 +169,553 @@
             if (array_key_exists('key', $properties)) {
                 $this->key = $properties['key'];
             }
+            if (array_key_exists('parent', $properties)) {
+                $this->parent = $properties['parent'];
+            }
+            // This needs to happen last because of the check_if_active call that occurs
+            if (array_key_exists('action', $properties)) {
+                $this->action = $properties['action'];
+                if (is_string($this->action)) {
+                    $this->action = new moodle_url($this->action);
+                }
+                if (self::$autofindactive) {
+                    $this->check_if_active();
+                }
+            }
         } else if (is_string($properties)) {
             $this->text = $properties;
         }
         if ($this->text === null) {
             throw new coding_exception('You must set the text for the node when you create it.');
         }
+        // Default the title to the text
         $this->title = $this->text;
         $textlib = textlib_get_instance();
         if (strlen($this->text)>50) {
+            // Truncate the text to 50 characters
             $this->text = $textlib->substr($this->text, 0, 50).'...';
         }
         if (is_string($this->shorttext) && strlen($this->shorttext)>25) {
+            // Truncate the shorttext
             $this->shorttext = $textlib->substr($this->shorttext, 0, 25).'...';
         }
+        // Instantiate a new navigation node collection for this nodes children
+        $this->children = new navigation_node_collection();
     }
 
     /**
-     * This function overrides the active URL that is used to compare new nodes
-     * to find out if they are active.
+     * Checks if this node is the active node.
      *
-     * If null is passed then $fullmeurl will be regenerated when the next node
-     * is created/added
-     */
-    public static function override_active_url(moodle_url $url=null) {
-        self::$fullmeurl = $url;
-    }
-
-    /**
-     * This function checks if the node is the active child by comparing its action
-     * to the current page URL obtained via $PAGE->url
+     * This is determined by comparing the action for the node against the
+     * defined URL for the page. A match will see this node marked as active.
      *
-     * This function compares the nodes url to the static var {@link navigation_node::fullmeurl}
-     * and if they match (based on $strenght) then the node is considered active.
-     *
-     * Note: This function is recursive, when you call it it will check itself and all
-     * children recursivily.
-     *
-     * @staticvar moodle_url $fullmeurl
-     * @param int $strength When using the moodle_url compare function how strictly
-     *                       to check for a match. Defaults to URL_MATCH_EXACT
-     *                       Can be URL_MATCH_EXACT or URL_MATCH_BASE
-     * @return bool True is active, false otherwise
+     * @global string $FULLME
+     * @global moodle_page $PAGE
+     * @param int $strength One of URL_MATCH_EXACT, URL_MATCH_PARAMS, or URL_MATCH_BASE
+     * @return bool
      */
     public function check_if_active($strength=URL_MATCH_EXACT) {
         global $FULLME, $PAGE;
+        // Set fullmeurl if it hasn't already been set
         if (self::$fullmeurl == null) {
             if ($PAGE->has_set_url()) {
-                $this->override_active_url(new moodle_url($PAGE->url));
+                self::override_active_url(new moodle_url($PAGE->url));
             } else {
-                $this->override_active_url(new moodle_url($FULLME));
+                self::override_active_url(new moodle_url($FULLME));
             }
         }
 
+        // Compare the action of this node against the fullmeurl
         if ($this->action instanceof moodle_url && $this->action->compare(self::$fullmeurl, $strength)) {
             $this->make_active();
             return true;
-        } else if (is_string($this->action) && $this->action==self::$fullmeurl->out()) {
-            $this->make_active();
-            return true;
         }
         return false;
     }
+
     /**
-     * This function allows the user to add a child node to this node.
+     * Overrides the fullmeurl variable providing
      *
-     * @param string $text The text to display in the node
-     * @param string $action Either a moodle_url or a bit of html to use instead of the text <i>optional</i>
-     * @param int $type The type of node should be one of the const types of navigation_node <i>optional</i>
-     * @param string $shorttext The short text to use for this node
-     * @param string|int $key Sets the key that can be used to retrieve this node <i>optional</i>
-     * @param string $icon The path to an icon to use for this node <i>optional</i>
-     * @return string The key that was used for this node
+     * @param moodle_url $url The url to use for the fullmeurl.
      */
-    public function add($text, $action=null, $type=null, $shorttext=null, $key=null, pix_icon $icon=null) {
+    public static function override_active_url(moodle_url $url) {
+        self::$fullmeurl = $url;
+    }
+
+    /**
+     * Adds a navigation node as a child of this node.
+     * 
+     * @param string $text
+     * @param moodle_url|action_link $action
+     * @param int $type
+     * @param string $shorttext
+     * @param string|int $key
+     * @param pix_icon $icon
+     * @return navigation_node
+     */
+    public function add($text, $action=null, $type=self::TYPE_CUSTOM, $shorttext=null, $key=null, pix_icon $icon=null) {
+        // First convert the nodetype for this node to a branch as it will now have children
         if ($this->nodetype !== self::NODETYPE_BRANCH) {
             $this->nodetype = self::NODETYPE_BRANCH;
         }
-        $itemarray = array('text'=>$text);
-        if ($type!==null) {
-            $itemarray['type'] = $type;
-        } else {
-            $type = self::TYPE_CUSTOM;
-        }
+        // Properties array used when creating the new navigation node
+        $itemarray = array(
+            'text' => $text,
+            'type' => $type
+        );
+        // Set the action if one was provided
         if ($action!==null) {
             $itemarray['action'] = $action;
         }
-
+        // Set the shorttext if one was provided
         if ($shorttext!==null) {
             $itemarray['shorttext'] = $shorttext;
         }
+        // Set the icon if one was provided
         if ($icon!==null) {
             $itemarray['icon'] = $icon;
         }
-        if ($key===null) {
-            $key = count($this->children);
+        // Default the key to the number of children if not provided
+        if ($key === null) {
+            $key = $this->children->count();
         }
-
-        $key = $key.':'.$type;
-
+        // Set the key
         $itemarray['key'] = $key;
-        $this->children[$key] = new navigation_node($itemarray);
+        // Set the parent to this node
+        $itemarray['parent'] = $this;
+        // Add the child using the navigation_node_collections add method
+        $node = $this->children->add(new navigation_node($itemarray));
+        // If the node is a category node or the user is logged in and its a course
+        // then mark this node as a branch (makes it expandable by AJAX)
         if (($type==self::TYPE_CATEGORY) || (isloggedin() && $type==self::TYPE_COURSE)) {
-            $this->children[$key]->nodetype = self::NODETYPE_BRANCH;
+            $node->nodetype = self::NODETYPE_BRANCH;
         }
+        // If this node is hidden mark it's children as hidden also
         if ($this->hidden) {
-            $this->children[$key]->hidden = true;
+            $node->hidden = true;
         }
-        return $key;
+        // Return the node (reference returned by $this->children->add()
+        return $node;
     }
 
     /**
-     * Adds a new node to a particular point by recursing through an array of node keys
+     * Searches for a node of the given type with the given key.
      *
-     * @param array $patharray An array of keys to recurse to find the correct node
-     * @param string $text The text to display in the node
-     * @param string|int $key Sets the key that can be used to retrieve this node <i>optional</i>
-     * @param int $type The type of node should be one of the const types of navigation_node <i>optional</i>
-     * @param string $action Either a moodle_url or a bit of html to use instead of the text <i>optional</i>
-     * @param string $icon The path to an icon to use for this node <i>optional</i>
-     * @return mixed Either the key used for the node once added or false for failure
+     * This searches this node plus all of its children, and their children....
+     * If you know the node you are looking for is a child of this node then please
+     * use the get method instead.
+     *
+     * @param int|string $key The key of the node we are looking for
+     * @param int $type One of navigation_node::TYPE_*
+     * @return navigation_node|false
      */
-    public function add_to_path($patharray, $key=null, $text=null, $shorttext=null, $type=null, $action=null, pix_icon $icon=null) {
-        if (count($patharray)==0) {
-            $key = $this->add($text, $action, $type, $shorttext, $key, $icon);
-            return $key;
-        } else {
-            $pathkey = array_shift($patharray);
-            $child = $this->get($pathkey);
-            if ($child!==false) {
-                return $child->add_to_path($patharray, $key, $text, $shorttext, $type, $action, $icon);
-            } else {
-                return false;
+    public function find($key, $type) {
+        return $this->children->find($key, $type);
             }
-        }
-    }
 
     /**
-     * Add a css class to this particular node
+     * Get ths child of this node that has the given key + (optional) type.
      *
-     * @param string $class The css class to add
-     * @return bool Returns true
+     * If you are looking for a node and want to search all children + thier children
+     * then please use the find method instead.
+     *
+     * @param int|string $key The key of the node we are looking for
+     * @param int $type One of navigation_node::TYPE_*
+     * @return navigation_node|false
      */
-    public function add_class($class) {
-        if (!in_array($class, $this->classes)) {
-            $this->classes[] = $class;
+    public function get($key, $type=null) {
+        return $this->children->get($key, $type);
         }
-        return true;
-    }
 
     /**
-     * Removes a given class from this node if it exists
+     * Removes this node.
      *
-     * @param string $class
      * @return bool
      */
-    public function remove_class($class) {
-        if (in_array($class, $this->classes)) {
-            $key = array_search($class,$this->classes);
-            if ($key!==false) {
-                unset($this->classes[$key]);
-                return true;
+    public function remove() {
+        return $this->parent->children->remove($this->key, $this->type);
             }
-        }
-        return false;
-    }
 
     /**
-     * Recurse down child nodes and collapse everything once a given
-     * depth of recursion has been reached.
+     * Checks if this node has or could have any children
      *
-     * This function is used internally during the initialisation of the nav object
-     * after the tree has been generated to collapse it to a suitable depth.
-     *
-     * @param int $depth defualts to 2
-     * @return bool Returns true
+     * @return bool Returns true if it has children or could have (by AJAX expansion)
      */
-    protected function collapse_at_depth($depth=2) {
-        if ($depth>0 && $this->nodetype===self::NODETYPE_BRANCH) {
-            foreach (array_keys($this->children) as $key) {
-                $this->children[$key]->collapse_at_depth($depth-1);
+    public function has_children() {
+        return ($this->nodetype === navigation_node::NODETYPE_BRANCH || $this->children->count()>0);
             }
-            return true;
-        } else {
-            $this->collapse_children();
-            return true;
+
+    /**
+     * Marks this node as active and forces it open.
+     */
+    public function make_active() {
+        $this->isactive = true;
+        $this->add_class('active_tree_node');
+        $this->force_open();
+        if ($this->parent !== null) {
+            $this->parent->make_inactive();
         }
     }
 
     /**
-     * Collapses all of the child nodes recursion optional
-     *
-     * @param bool $recurse If set to true child nodes are closed recursively
-     * @return bool Returns true
+     * Marks a node as inactive and recusised back to the base of the tree
+     * doing the same to all parents.
      */
-    protected function collapse_children($recurse=true) {
-        if ($this->nodetype === self::NODETYPE_BRANCH && count($this->children)>0) {
-            foreach ($this->children as &$child) {
-                if (!$this->forceopen) {
-                    $child->collapse = true;
+    public function make_inactive() {
+        $this->isactive = false;
+        $this->remove_class('active_tree_node');
+        if ($this->parent !== null) {
+            $this->parent->make_inactive();
                 }
-                if ($recurse && $child instanceof navigation_node) {
-                    $child->collapse_children($recurse);
                 }
-            }
-            unset($child);
-        }
-        return true;
-    }
 
     /**
-     * Produce the actual HTML content for the node including any action or icon
+     * Forces this node to be open and at the same time forces open all
+     * parents until the root node.
      *
-     * @param bool $shorttext If true then short text is used rather than text if it has been set
-     * @return string The HTML content
+     * Recursive.
      */
-    public function content($shorttext=false) {
-        global $OUTPUT;
-        if (!$this->display) {
-            return '';
+    public function force_open() {
+        $this->forceopen = true;
+        if ($this->parent !== null) {
+            $this->parent->force_open();
         }
-        if ($shorttext && $this->shorttext!==null) {
-            $content = format_string($this->shorttext);
-        } else {
-            $content = format_string($this->text);
         }
-        $title = '';
-        if ($this->forcetitle || ($this->shorttext!==null && $this->title !== $this->shorttext) || $this->title !== $this->text) {
-             $title = $this->title;
-        }
 
-        if ($this->icon instanceof renderable) {
-            $icon = $OUTPUT->render($this->icon);
-            $content = $icon.'&nbsp;'.$content; // use CSS for spacing of icons
-        } else if ($this->helpbutton !== null) {
-            $content = trim($this->helpbutton).html_writer::tag('span', $content, array('class'=>'clearhelpbutton'));
+    /**
+     * Adds a CSS class to this node.
+     *
+     * @param string $class
+     * @return bool
+     */
+    public function add_class($class) {
+        if (!in_array($class, $this->classes)) {
+            $this->classes[] = $class;
         }
-
-        if ($content === '') {
-            return '';
+        return true;
         }
 
-        if ($this->action instanceof action_link) {
-            //TODO: to be replaced with something else
-            $link = $this->action;
-            if ($this->hidden) {
-                $link->add_class('dimmed');
+    /**
+     * Removes a CSS class from this node.
+     *
+     * @param string $class
+     * @return bool True if the class was successfully removed.
+     */
+    public function remove_class($class) {
+        if (in_array($class, $this->classes)) {
+            $key = array_search($class,$this->classes);
+            if ($key!==false) {
+                unset($this->classes[$key]);
+                return true;
             }
-            $content = $OUTPUT->render($link);
-
-        } else if ($this->action instanceof moodle_url) {
-            $attributes = array();
-            if ($title !== '') {
-                $attributes['title'] = $title;
             }
-            if ($this->hidden) {
-                $attributes['class'] = 'dimmed_text';
+        return false;
             }
-            $content = html_writer::link($this->action, $content, $attributes);
 
-        } else if (is_string($this->action) || empty($this->action)) {
-            $attributes = array();
-            if ($title !== '') {
-                $attributes['title'] = $title;
+    /**
+     * Sets the title for this node and forces Moodle to utilise it.
+     * @param string $title
+     */
+    public function title($title) {
+        $this->title = $title;
+        $this->forcetitle = true;
             }
-            if ($this->hidden) {
-                $attributes['class'] = 'dimmed_text';
-            }
-            $content = html_writer::tag('span', $content, $attributes);
-        }
 
-        return $content;
-    }
-
     /**
-     * Get the CSS type for this node
-     *
-     * @return string
+     * Resets the page specific information on this node if it is being unserialised.
      */
-    public function get_css_type() {
-        if (array_key_exists($this->type, $this->namedtypes)) {
-            return 'type_'.$this->namedtypes[$this->type];
+    public function __wakeup(){
+        $this->forceopen = false;
+        $this->isactive = false;
+        $this->remove_class('active_tree_node');
         }
-        return 'type_unknown';
-    }
 
     /**
-     * Find and return a child node if it exists (returns a reference to the child)
+     * Checks if this node or any of its children contain the active node.
      *
-     * This function is used to search for and return a reference to a child node when provided
-     * with the child nodes key and type.
-     * If the child is found a reference to it is returned otherwise the default is returned.
+     * Recursive.
      *
-     * @param string|int $key The key of the child node you are searching for.
-     * @param int $type The type of the node you are searching for. Defaults to TYPE_CATEGORY
-     * @param mixed $default The value to return if the child cannot be found
-     * @return mixed The child node or what ever default contains (usually false)
+     * @return bool
      */
-    public function find_child($key, $type=self::TYPE_CATEGORY, $default = false) {
-        list($key, $type) = $this->split_key_type($key, $type);
-        if (array_key_exists($key.":".$type, $this->children)) {
-            return $this->children[$key.":".$type];
-        } else if ($this->nodetype === self::NODETYPE_BRANCH && count($this->children)>0 && $this->type<=$type) {
-            foreach ($this->children as &$child) {
-                $outcome = $child->find_child($key, $type);
-                if ($outcome !== false) {
-                    return $outcome;
+    public function contains_active_node() {
+        if ($this->isactive) {
+            return true;
+        } else {
+            foreach ($this->children as $child) {
+                if ($child->isactive || $child->contains_active_node()) {
+                    return true;
                 }
             }
         }
-        return $default;
+        return false;
     }
 
     /**
-     * Find the active child
+     * Finds the active node.
      *
-     * @param null|int $type
-     * @return navigation_node|bool
+     * Searches this nodes children plus all of the children for the active node
+     * and returns it if found.
+     *
+     * Recursive.
+     *
+     * @return navigation_node|false
      */
-    public function find_active_node($type=null) {
-        if ($this->contains_active_node()) {
-            if ($type!==null && $this->type===$type) {
+    public function find_active_node() {
+        if ($this->isactive) {
                 return $this;
-            }
-            if ($this->nodetype === self::NODETYPE_BRANCH && count($this->children)>0) {
-                foreach ($this->children as $child) {
-                    if ($child->isactive && !$child->contains_active_node()) {
-                        return $child;
                     } else {
-                        $outcome = $child->find_active_node($type);
-                        if ($outcome!==false) {
+            foreach ($this->children as &$child) {
+                $outcome = $child->find_active_node();
+                if ($outcome !== false) {
                             return $outcome;
                         }
                     }
                 }
-            }
-        }
         return false;
     }
 
     /**
-     * Returns the depth of a child
+     * Gets the content for this node.
      *
-     * @param string|int $key The key for the child we are looking for
-     * @param int $type The type of the child we are looking for
-     * @return int The depth of the child once found
+     * @param bool $shorttext If true shorttext is used rather than the normal text
+     * @return string
      */
-    public function find_child_depth($key, $type=self::TYPE_CATEGORY) {
-        $depth = 0;
-        list($key, $type) = $this->split_key_type($key, $type);
-        if (array_key_exists($key.':'.$type, $this->children)) {
-            $depth = 1;
-        } else if ($this->nodetype === self::NODETYPE_BRANCH && count($this->children)>0 && $this->type<=$type) {
-            foreach ($this->children as $child) {
-                $depth += $child->find_child_depth($key, $type);
+    public function get_content($shorttext=false) {
+        if ($shorttext && $this->shorttext!==null) {
+            return format_string($this->shorttext);
+        } else {
+            return format_string($this->text);
             }
         }
-        return $depth;
-    }
 
     /**
-     * Finds all nodes that have the specified type
+     * Gets the title to use for this node.
      *
-     * @param int $type One of navigation_node::TYPE_*
-     * @return array An array of navigation_node references for nodes of type $type
+     * @return string
      */
-    public function get_children_by_type($type) {
-        $nodes = array();
-        if (count($this->children)>0) {
-            foreach ($this->children as &$child) {
-                if ($child->type === $type) {
-                    $nodes[] = $child;
+    public function get_title() {
+        if ($this->forcetitle || ($this->shorttext!==null && $this->title !== $this->shorttext) || $this->title !== $this->text) {
+            return $this->title;
+        } else {
+            return '';
                 }
             }
-        }
-        return $nodes;
-    }
 
     /**
-     * Finds all nodes (recursivily) that have the specified type, regardless of
-     * assumed order or position.
+     * Gets the CSS class to add to this node to describe its type
      *
-     * @param int $type One of navigation_node::TYPE_*
-     * @return array An array of navigation_node references for nodes of type $type
+     * @return string
      */
-    public function find_children_by_type($type) {
-        $nodes = array();
-        if (count($this->children)>0) {
-            foreach ($this->children as &$child) {
-                if ($child->type === $type) {
-                    $nodes[] = $child;
+    public function get_css_type() {
+        if (array_key_exists($this->type, $this->namedtypes)) {
+            return 'type_'.$this->namedtypes[$this->type];
                 }
-                if (count($child->children)>0) {
-                    $nodes = array_merge($nodes, $child->find_children_by_type($type));
+        return 'type_unknown';
                 }
-            }
-        }
-        return $nodes;
-    }
 
     /**
-     * Toogles display of nodes and child nodes based on type
+     * Finds all nodes that are expandable by AJAX
      *
-     * If the type of a node if more than the type specified it's display property is set to false
-     * and it is not shown
-     *
-     * @param int $type
-     * @param bool $display
+     * @param array $expandable An array by reference to populate with expandable nodes.
      */
-    public function toggle_type_display($type=self::TYPE_COURSE, $display=false) {
-        if ((int)$this->type > $type) {
-            $this->display = $display;
+    public function find_expandable(array &$expandable) {
+        if (!isloggedin()) {
+            return;
         }
-        if (count($this->children)>0) {
-            foreach ($this->children as $child) {
-                $child->toggle_type_display($type, $display);
+        foreach ($this->children as &$child) {
+            if ($child->nodetype == self::NODETYPE_BRANCH && $child->children->count()==0) {
+                $child->id = 'expandable_branch_'.(count($expandable)+1);
+                $this->add_class('canexpand');
+                $expandable[] = array('id'=>$child->id,'branchid'=>$child->key,'type'=>$child->type);
             }
+            $child->find_expandable($expandable);
         }
     }
+}
 
     /**
-     * Find out if a child (or subchild) of this node contains an active node
+ * Navigation node collection
      *
-     * @return bool True if it does fales otherwise
+ * This class is responsible for managing a collection of navigation nodes.
+ * It is required because a node's unique identifier is a combination of both its
+ * key and its type.
+ *
+ * Originally an array was used with a string key that was a combination of the two
+ * however it was decided that a better solution would be to use a class that
+ * implements the standard IteratorAggregate interface.
+ *
+ * @package moodlecore
+ * @subpackage navigation
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      */
-    public function contains_active_node() {
-        if ($this->nodetype === self::NODETYPE_BRANCH && count($this->children)>0) {
-            foreach ($this->children as $child) {
-                if ($child->isactive || $child->contains_active_node()) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
+class navigation_node_collection implements IteratorAggregate {
     /**
-     * Find all nodes that are expandable for this node and its given children.
+     * A multidimensional array to where the first key is the type and the second
+     * key is the nodes key.
+     * @var array
+     */
+    protected $collection = array();
+    /**
+     * An array that contains references to nodes in the same order they were added.
+     * This is maintained as a progressive array.
+     * @var array
+     */
+    protected $orderedcollection = array();
+    /**
+     * A reference to the last node that was added to the collection
+     * @var navigation_node
+     */
+    protected $last = null;
+    /**
+     * The total number of items added to this array.
+     * @var int
+     */
+    protected $count = 0;
+    /**
+     * Adds a navigation node to the collection
      *
-     * This function recursively finds all nodes that are expandable by AJAX within
-     * [and including] this child.
-     *
-     * @param array $expandable An array to fill with the HTML id's of all branches
-     * that can be expanded by AJAX. This is a forced reference.
-     * @param int $expansionlimit Optional/used internally can be one of navigation_node::TYPE_*
+     * @global stdClass $CFG
+     * @param navigation_node $node
+     * @return navigation_node
      */
-    public function find_expandable(&$expandable, $expansionlimit = null) {
-        static $branchcount;
-        if ($branchcount==null) {
-            $branchcount=1;
+    public function add(navigation_node $node) {
+        global $CFG;
+        $key = $node->key;
+        $type = $node->type;
+        // First check we have a 2nd dimension for this type
+        if (!array_key_exists($type, $this->orderedcollection)) {
+            $this->orderedcollection[$type] = array();
         }
-        if ($this->nodetype == self::NODETYPE_BRANCH && count($this->children)==0 && ($expansionlimit === null || $this->type < $expansionlimit)) {
-            $this->id = 'expandable_branch_'.$branchcount;
-            $this->add_class('canexpand');
-            $branchcount++;
-            $expandable[] = array('id'=>$this->id,'branchid'=>$this->key,'type'=>$this->type);
-        } else if ($this->nodetype==self::NODETYPE_BRANCH && ($expansionlimit === null || $this->type <= $expansionlimit)) {
-            foreach ($this->children as $child) {
-                $child->find_expandable($expandable, $expansionlimit);
+        // Check for a collision and report if debugging is turned on
+        if ($CFG->debug && array_key_exists($key, $this->orderedcollection[$type])) {
+            debugging('Navigation node intersect: Adding a node that already exists '.$key, DEBUG_DEVELOPER);
             }
+        // Add the node to the appropriate place in the ordered structure.
+        $this->orderedcollection[$type][$key] = $node;
+        // Add a reference to the node to the progressive collection.
+        $this->collection[$this->count] = &$this->orderedcollection[$type][$key];
+        // Update the last property to a reference to this new node.
+        $this->last = &$this->orderedcollection[$type][$key];
+        $this->count++;
+        // Return the reference to the now added node
+        return $this->last;
         }
-    }
 
     /**
-     * Used to return a child node with a given key
+     * Fetches a node from this collection.
      *
-     * This function searchs for a child node with the provided key and returns the
-     * child. If the child doesn't exist then this function returns false.
-     *
-     * @param int|string $key The key to search for
-     * @param int $type Optional one of TYPE_* constants
-     * @param navigation_node|bool The child if it exists or false
+     * @param string|int $key The key of the node we want to find.
+     * @param int $type One of navigation_node::TYPE_*.
+     * @return navigation_node|null
      */
     public function get($key, $type=null) {
-        if ($key===false) {
-            return false;
+        if ($type !== null) {
+            // If the type is known then we can simply check and fetch
+            if (!empty($this->orderedcollection[$type][$key])) {
+                return $this->orderedcollection[$type][$key];
         }
-        list($key, $type) = $this->split_key_type($key);
-        if ($this->nodetype === self::NODETYPE_BRANCH && count($this->children)>0) {
-            if ($type!==null) {
-                if (array_key_exists($key.':'.$type, $this->children)) {
-                    return $this->children[$key.':'.$type];
-                }
             } else {
-                foreach (array_keys($this->children) as $childkey) {
-                    if (strpos($childkey, $key.':')===0) {
-                        return $this->children[$childkey];
+            // Because we don't know the type we look in the progressive array
+            foreach ($this->collection as $node) {
+                if ($node->key === $key) {
+                    return $node;
                     }
                 }
             }
-        }
         return false;
     }
-
     /**
-     * This function is used to split a key into its key and value parts if the
-     * key is a combination of the two.
+     * Searches for a node with matching key and type.
      *
-     * Was introduced to help resolve MDL-20543
+     * This function searches both the nodes in this collection and all of
+     * the nodes in each collection belonging to the nodes in this collection.
      *
-     * @param string $key
-     * @param int|null $type
-     * @return array
-     */
-    protected function split_key_type($key, $type=null) {
-        /**
-         * If the key is a combination it will be of the form `key:type` where key
-         * could be anything and type will be an int value
-         */
-        if (preg_match('#^(.*)\:(\d{1,3})$#', $key, $match)) {
-            /**
-             * If type is null then we want to collect and return the type otherwise
-             * we will use the provided type. This ensures that if a type was specified
-             * it is not lost
-             */
-            if ($type===null) {
-                $type = $match[2];
-            }
-            $key = $match[1];
-        }
-        return array($key, $type);
-    }
-
-    /**
-     * Fetch a node given a set of keys that describe its path
+     * Recursive.
      *
-     * @param array $keys An array of keys
-     * @return navigation_node|bool The node or false
+     * @param string|int $key  The key of the node we want to find.
+     * @param int $type  One of navigation_node::TYPE_*.
+     * @return navigation_node|null
      */
-    public function get_by_path($keys) {
-        if (count($keys)==1) {
-            $key = array_shift($keys);
-            return $this->get($key);
+    public function find($key, $type=null) {
+        if ($type !== null && array_key_exists($type, $this->orderedcollection) && array_key_exists($key, $this->orderedcollection[$type])) {
+            return $this->orderedcollection[$type][$key];
         } else {
-            $key = array_shift($keys);
-            $child = $this->get($key);
-
-            if ($child !== false) {
-                return $child->get_by_path($keys);
+            $nodes = $this->getIterator();
+            // Search immediate children first
+            foreach ($nodes as &$node) {
+                if ($node->key == $key && ($type == null || $type === $node->type)) {
+                    return $node;
             }
-            return false;
         }
+            // Now search each childs children
+            foreach ($nodes as &$node) {
+                $result = $node->children->find($key, $type);
+                if ($result !== false) {
+                    return $result;
     }
-
-    /**
-     * Returns the child marked as active if there is one, false otherwise.
-     *
-     * @return navigation_node|bool The active node or false
-     */
-    public function get_active_node() {
-        foreach ($this->children as $child) {
-            if ($child->isactive) {
-                return $child;
             }
         }
         return false;
     }
 
     /**
-     * Mark this node as active
+     * Fetches the last node that was added to this collection
      *
-     * This function marks the node as active my forcing the node to be open,
-     * setting isactive to true, and adding the class active_tree_node
+     * @return navigation_node
      */
-     public function make_active() {
-        $this->forceopen = true;
-        $this->isactive = true;
-        $this->add_class('active_tree_node');
+    public function last() {
+        return $this->last;
      }
-
     /**
-     * This intense little function looks for branches that are forced open
-     * and checks to ensure that all parent nodes are also forced open.
+     * Fetches all nodes of a given type from this collection
      */
-    public function respect_forced_open() {
-        foreach ($this->children as $child) {
-            $child->respect_forced_open();
-            if ($child->forceopen) {
-                $this->forceopen = true;
+    public function type($type) {
+        if (!array_key_exists($type, $this->orderedcollection)) {
+            $this->orderedcollection[$type] = array();
             }
+        return $this->orderedcollection[$type];
         }
-    }
-
     /**
-     * This function simply removes a given child node
+     * Removes the node with the given key and type from the collection
      *
-     * @param string|int $key The key that identifies a child node
+     * @param string|int $key
+     * @param int $type
      * @return bool
      */
-    public function remove_child($key, $type=null) {
-        if ($key instanceof navigation_node) {
-            $key = $key->key;
-        }
+    public function remove($key, $type=null) {
         $child = $this->get($key, $type);
-        if ($child) {
-            unset($this->children[$child->key]);
-            return true;
+        if ($child !== false) {
+            foreach ($this->collection as $colkey => $node) {
+                if ($node->key == $key && $node->type == $type) {
+                    unset($this->collection[$colkey]);
+                    break;
         }
-        return false;
     }
-
-    /**
-     * Iterate all children and check if any of them are active
-     *
-     * This function iterates all children recursively until it sucecssfully marks
-     * a node as active, or gets to the end of the tree.
-     * This can be used on a cached branch to mark the active child.
-     *
-     * @param int $strength When using the moodle_url compare function how strictly
-     *                       to check for a match. Defaults to URL_MATCH_EXACTLY
-     * @return bool True is a node was marked active false otherwise
-     */
-    public function reiterate_active_nodes($strength=URL_MATCH_EXACT) {
-        if ($this->nodetype !== self::NODETYPE_BRANCH) {
-            return false;
-        }
-        foreach ($this->children as $child) {
-            $outcome = $child->check_if_active($strength);
-            if (!$outcome && $child->nodetype === self::NODETYPE_BRANCH) {
-                $outcome = $child->reiterate_active_nodes($strength);
-            }
-            if ($outcome) {
-                $this->forceopen = true;
+            unset($this->orderedcollection[$child->type][$child->key]);
+            $this->count--;
                 return true;
             }
+        return false;
         }
-    }
 
     /**
-     * This function sets the title for the node and at the same time sets
-     * forcetitle to true to ensure that it is used if possible
-     *
-     * @param string $title
+     * Gets the number of nodes in this collection
+     * @return int
      */
-    public function title($title) {
-        $this->title = $title;
-        $this->forcetitle = true;
+    public function count() {
+        return count($this->collection);
     }
-
     /**
-     * Magic Method: When we unserialise an object make it `unactive`
+     * Gets an array iterator for the collection.
      *
-     * This is to ensure that when we take a branch out of the cache it is not marked
-     * active anymore, as we can't be sure it still is (infact it most likely isnt)
+     * This is required by the IteratorAggregator interface and is used by routines
+     * such as the foreach loop.
+     *
+     * @return ArrayIterator
      */
-    public function __wakeup(){
-        $this->forceopen = false;
-        $this->isactive = false;
-        $this->remove_class('active_tree_node');
+    public function getIterator() {
+        return new ArrayIterator($this->collection);
     }
 }
 
@@ -859,143 +737,437 @@
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class global_navigation extends navigation_node {
-    /** @var int */
-    protected $depthforward = 1;
-    /** @var cache */
-    protected $cache = null;
+    /**
+     * The Moodle page this navigation object belongs to.
+     * @var moodle_page
+     */
+    protected $page;
     /** @var bool */
     protected $initialised = false;
-
-    /** @var null|int */
-    public $expansionlimit = null;
-    /** @var stdClass */
-    public $context = null;
-    /** @var mixed */
-    public $expandable = null;
+    /** @var array */
+    protected $mycourses = array();
+    /** @var array */
+    protected $rootnodes = array();
     /** @var bool */
-    public $showemptybranches = true;
-    /** @var bool  */
-    protected $isloggedin = false;
-    /** @var array Array of user objects to extend the navigation with */
+    protected $showemptysections = false;
+    /** @var array */
     protected $extendforuser = array();
-    /** @var bool Gets set to true if all categories have been loaded */
-    protected $allcategoriesloaded = false;
-
+    /** @var navigation_cache */
+    protected $cache;
+    /** @var array */
+    protected $addedcourses = array();
     /**
-     * Sets up the object with basic settings and preparse it for use
+     * Constructs a new global navigation
+     *
+     * @global stdClass $SITE
+     * @global stdClass $USER
+     * @param moodle_page $page The page this navigation object belongs to
      */
-    public function __construct() {
-        global $CFG;
+    public function __construct(moodle_page $page) {
+        global $SITE, $USER;
+
         if (during_initial_install()) {
-            return false;
+            return;
         }
-        $this->key = 0;
-        $this->type = self::TYPE_SYSTEM;
-        $this->isloggedin = isloggedin();
-        $this->text = get_string('home');
+
+        // Use the parents consturctor.... good good reuse
+        $properties = array(
+            'key' => 'home',
+            'type' => navigation_node::TYPE_SYSTEM,
+            'text' => get_string('home'),
+            'action' => new moodle_url('/my/')
+        );
+        parent::__construct($properties);
+
+        // Initalise and set defaults
+        $this->page = $page;
         $this->forceopen = true;
-        $this->action = new moodle_url($CFG->wwwroot);
         $this->cache = new navigation_cache(NAVIGATION_CACHE_NAME);
+
+        // Check if we need to clear the cache
         $regenerate = optional_param('regenerate', null, PARAM_TEXT);
-        if ($regenerate==='navigation') {
+        if ($regenerate === 'navigation') {
             $this->cache->clear();
         }
     }
 
     /**
-     * Override: This function generated the content of the navigation
+     * Initialises the navigation object.
      *
-     * If an expansion limit has been set then we hide everything to after that
-     * set limit type
+     * This causes the navigation object to look at the current state of the page
+     * that it is associated with and then load the appropriate content.
      *
-     * @return string
-     */
-    public function content() {
-        if ($this->expansionlimit!==null) {
-            $this->toggle_type_display($this->expansionlimit);
-        }
-        return parent::content();
-    }
-
-    /**
-     * Initialise the navigation object, calling it to auto generate
+     * This should only occur the first time that the navigation structure is utilised
+     * which will normally be either when the navbar is called to be displayed or
+     * when a block makes use of it.
      *
-     * This function starts the navigation object automatically retrieving what it
-     * needs from Moodle objects.
-     *
-     * It also passed Javascript args and function calls as required
-     *
-     * @return bool Returns true
+     * @global stdClass $SITE
+     * @global stdClass $USER
+     * @return bool
      */
-    public function initialise($jsargs = null) {
-        global $PAGE, $SITE, $USER;
+    public function initialise() {
+        global $SITE, $USER;
+        // Check if it has alread been initialised
         if ($this->initialised || during_initial_install()) {
             return true;
         }
-        $start = microtime(false);
-        $this->depthforward = 1;
-        $this->context = $PAGE->context;
-        $contextlevel = $this->context->contextlevel;
-        if ($contextlevel == CONTEXT_COURSE && $PAGE->course->id==$SITE->id) {
-            $contextlevel = 10;
+
+        // Set up the five base root nodes. These are nodes where we will put our
+        // content and are as follows:
+        // site:        Navigation for the front page.
+        // profile:     User profile information goes here.
+        // mycourses:   The users courses get added here.
+        // courses:     Additional courses are added here.
+        // users:       Other users information loaded here.
+        $this->rootnodes = array();
+        $this->rootnodes['site']      = $this->add_course($SITE);
+        $this->rootnodes['profile']   = $this->add(get_string('profile'), null, self::TYPE_USER, null, 'profile');
+        $this->rootnodes['mycourses'] = $this->add(get_string('mycourses'), null, self::TYPE_ROOTNODE, null, 'mycourses');
+        $this->rootnodes['courses']   = $this->add(get_string('courses'), null, self::TYPE_ROOTNODE, null, 'courses');
+        $this->rootnodes['users']     = $this->add(get_string('users'), null, self::TYPE_ROOTNODE, null, 'users');
+
+        // Fetch all of the users courses.
+        $this->mycourses = get_my_courses($USER->id);
+        // Check if any courses were returned.
+        if (count($this->mycourses) > 0) {
+            // Add all of the users courses to the navigation
+            foreach ($this->mycourses as &$course) {
+              $course->coursenode = $this->add_course($course);
         }
-        $depth = 0;
+        } else {
+            // The user had no specific courses! they could be no logged in, guest
+            // or admin so load all courses instead.
+            $this->load_all_courses();
+        }
 
-        /**
-         * We always want to load the front page activities into the tree, these
-         * will appear at the bottom of the opening (site) node.
-         */
-        $sitekeys = array();
-        $this->load_course_activities($sitekeys, $SITE);
-        $this->load_section_activities($sitekeys, false, $SITE);
-        switch ($contextlevel) {
-            case CONTEXT_SYSTEM:
-                $this->cache->volatile();
-                $depth = $this->load_for_category(false);
+        // Next load context specific content into the navigation
+        switch ($this->page->context->contextlevel) {
+            case CONTEXT_SYSTEM :
+            case CONTEXT_COURSECAT :
+                // Load the front page course navigation
+                $this->load_course($SITE);
                 break;
-            case CONTEXT_COURSECAT:
-                $depth = $this->load_for_category();
+            case CONTEXT_BLOCK :
+            case CONTEXT_COURSE :
+                // Load the course associated with the page into the navigation
+                $course = $this->page->course;
+                $coursenode = $this->load_course($course);
+                // Make it active
+                $coursenode->make_active();
+                // Add the essentials such as reports etc...
+                $this->add_course_essentials($coursenode, $course);
+                if ($this->format_display_course_content($course->format)) {
+                    // Load the course sections
+                    $sections = $this->load_course_sections($course, $coursenode);
+                }
                 break;
-            case CONTEXT_BLOCK:
-            case CONTEXT_COURSE:
-                $depth = $this->load_for_course();
+            case CONTEXT_MODULE :
+                $course = $this->page->course;
+                $cm = $this->page->cm;
+                // Load the course associated with the page into the navigation
+                $coursenode = $this->load_course($course);
+                $this->add_course_essentials($coursenode, $course);
+                // Load the course sections into the page
+                $sections = $this->load_course_sections($course, $coursenode);
+                if ($course->id !== SITEID) {
+                    // Find the section for the $CM associated with the page and collect
+                    // its section number.
+                    foreach ($sections as $section) {
+                        if ($section->id == $cm->section) {
+                            $cm->sectionnumber = $section->section;
                 break;
-            case CONTEXT_MODULE:
-                $depth = $this->load_for_activity();
+                        }
+                    }
+
+                    // Load all of the section activities for the section the cm belongs to.
+                    $activities = $this->load_section_activities($sections[$cm->sectionnumber]->sectionnode, $cm->sectionnumber, get_fast_modinfo($course));
+                    // Finally load the cm specific navigaton information
+                } else {
+                    $activities = array();
+                    $activities[$cm->id] = $coursenode->get($cm->id, navigation_node::TYPE_ACTIVITY);
+                }
+                $this->load_activity($cm, $course, $activities[$cm->id]);
+                // And make the activity node active.
+                $activities[$cm->id]->make_active();
                 break;
-            case CONTEXT_USER:
-                // If the PAGE course is not the site then add the content of the
-                // course
-                if ($PAGE->course->id !== SITEID) {
-                    $depth = $this->load_for_course();
+            case CONTEXT_USER :
+                $course = $this->page->course;
+                if ($course->id != SITEID) {
+                    // Load the course associated with the user into the navigation
+                    $coursenode = $this->load_course($course);
+                    $this->add_course_essentials($coursenode, $course);
+                    $sections = $this->load_course_sections($course, $coursenode);
                 }
                 break;
         }
 
+        // Load for the current user
+        $this->load_for_user();
         // Load each extending user into the navigation.
         foreach ($this->extendforuser as $user) {
             if ($user->id !== $USER->id) {
                 $this->load_for_user($user);
             }
         }
-        // Load the current user into the the navigation
-        $this->load_for_user();
 
-        $this->collapse_at_depth($this->depthforward+$depth);
-        $this->respect_forced_open();
-        $this->expandable = array();
-        $this->find_expandable($this->expandable);
+        // Remove any empty root nodes
+        foreach ($this->rootnodes as $node) {
+            if (!$node->has_children()) {
+                $node->remove();
+            }
+        }
+
+        // If the user is not logged in modify the navigation structure as detailed
+        // in {@link http://docs.moodle.org/en/Development:Navigation_2.0_structure}
+        if (!isloggedin()) {
+            $activities = clone($this->rootnodes['site']->children);
+            $this->rootnodes['site']->remove();
+            $children = clone($this->children);
+            $this->children = new navigation_node_collection();
+            foreach ($activities as $child) {
+                $this->children->add($child);
+            }
+            foreach ($children as $child) {
+                $this->children->add($child);
+            }
+            $this->action = new moodle_url('/');
+        }
+
         $this->initialised = true;
         return true;
     }
     /**
-     * This function loads the global navigation structure for a user.
+     * Checks the course format to see whether it wants the navigation to load
+     * additional information for the course.
      *
-     * This gets called by {@link initialise()} when the context is CONTEXT_USER
-     * @param object|int|null $user
+     * This function utilises a callback that can exist within the course format lib.php file
+     * The callback should be a function called:
+     * callback_{formatname}_display_content()
+     * It doesn't get any arguments and should return true if additional content is
+     * desired. If the callback doesn't exist we assume additional content is wanted.
+     *
+     * @global stdClass $CFG
+     * @param string $format The course format
+     * @return bool
      */
+    protected function format_display_course_content($format) {
+        global $CFG;
+        $formatlib = $CFG->dirroot.'/course/format/'.$format.'/lib.php';
+        if (file_exists($formatlib)) {
+            require_once($formatlib);
+            $displayfunc = 'callback_'.$format.'_display_content';
+            if (function_exists($displayfunc) && !$displayfunc()) {
+                return $displayfunc();
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Loads of the the courses in Moodle into the navigation.
+     *
+     * @global moodle_database $DB
+     * @global stdClass $USER
+     * @return array An array of navigation_node
+     */
+    protected function load_all_courses() {
+        global $DB, $USER;
+        list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx');
+        $sql = "SELECT c.id,c.sortorder,c.visible,c.fullname,c.shortname,c.category,cat.path AS categorypath $ccselect
+                FROM {course} c
+                $ccjoin
+                LEFT JOIN {course_categories} cat ON cat.id=c.category
+                WHERE c.id != :siteid
+                ORDER BY c.sortorder ASC";
+        $courses = $DB->get_records_sql($sql, array('siteid'=>SITEID));
+        $coursenodes = array();
+        foreach ($courses as $course) {
+            context_instance_preload($course);
+            $coursenodes[$course->id] = $this->add_course($course);
+        }
+        return $coursenodes;
+    }
+
+    /**
+     * Loads the given course into the navigation
+     *
+     * @param stdClass $course
+     * @return navigation_node
+     */
+    protected function load_course(stdClass $course) {
+        if ($course->id == SITEID) {
+            $coursenode = $this->rootnodes['site'];
+        } else if (array_key_exists($course->id, $this->mycourses)) {
+            if (!isset($this->mycourses[$course->id]->coursenode)) {
+                $this->mycourses[$course->id]->coursenode = $this->add_course($course);
+            }
+            $coursenode = $this->mycourses[$course->id]->coursenode;
+        } else {
+            $coursenode = $this->add_course($course);
+        }
+        return $coursenode;
+    }
+
+    /**
+     * Loads all of the courses section into the navigation.
+     *
+     * This function utilisies a callback that can be implemented within the course
+     * formats lib.php file to customise the navigation that is generated at this
+     * point for the course.
+     *
+     * By default (if not defined) the method {@see load_generic_course_sections} is
+     * called instead.
+     *
+     * @global stdClass $CFG
+     * @param stdClass $course Database record for the course
+     * @param navigation_node $coursenode The course node within the navigation
+     * @return array Array of navigation nodes for the section with key = section id
+     */
+    protected function load_course_sections(stdClass $course, navigation_node $coursenode) {
+        global $CFG;
+        $structurefile = $CFG->dirroot.'/course/format/'.$course->format.'/lib.php';
+        $structurefunc = 'callback_'.$course->format.'_load_content';
+        if (function_exists($structurefunc)) {
+            return $structurefunc($this, $course, $coursenode);
+        } else if (file_exists($structurefile)) {
+            require_once $structurefile;
+            if (function_exists($structurefunc)) {
+                return $structurefunc($this, $course, $coursenode);
+            } else {
+                return $this->load_generic_course_sections($course, $coursenode, get_string('topic'), 'topic');
+            }
+        } else {
+            return $this->load_generic_course_sections($course, $coursenode, get_string('topic'), 'topic');
+        }
+    }
+
+    /**
+     * Generically loads the course sections into the course's navigation.
+     *
+     * @param stdClass $course
+     * @param navigation_node $coursenode
+     * @param string $name The string that identifies each section. e.g Topic, or Week
+     * @param string $activeparam The url used to identify the active section
+     * @return array An array of course section nodes
+     */
+    public function load_generic_course_sections(stdClass $course, navigation_node $coursenode, $name, $activeparam) {
+        $modinfo = get_fast_modinfo($course);
+        $sections = array_slice(get_all_sections($course->id), 0, $course->numsections+1, true);
+        $viewhiddensections = has_capability('moodle/course:viewhiddensections', $this->page->context);
+
+        $strgeneral = get_string('general');
+        foreach ($sections as &$section) {
+            if ($course->id == SITEID) {
+                $this->load_section_activities($coursenode, $section->section, $modinfo);
+            } else {
+                if ((!$viewhiddensections && !$section->visible) || (!$this->showemptysections && !array_key_exists($section->section, $modinfo->sections))) {
+                    continue;
+                }
+                if ($section->section == 0) {
+                    $sectionname = $strgeneral;
+                } else {
+                    $sectionname = $name.' '.$section->section;
+                }
+                $url = new moodle_url('/course/view.php', array('id'=>$course->id, $activeparam=>$section->section));
+                $sectionnode = $coursenode->add($sectionname, $url, navigation_node::TYPE_SECTION, null, $section->id);
+                $sectionnode->nodetype = navigation_node::NODETYPE_BRANCH;
+                $sectionnode->hidden = (!$section->visible);
+                if ($sectionnode->isactive) {
+                    $this->load_section_activities($sectionnode, $section->section, $modinfo);
+                }
+                $section->sectionnode = $sectionnode;
+            }
+        }
+        return $sections;
+    }
+    /**
+     * Loads all of the activities for a section into the navigation structure.
+     *
+     * @param navigation_node $sectionnode
+     * @param int $sectionnumber
+     * @param stdClass $modinfo Object returned from {@see get_fast_modinfo()}
+     * @return array Array of activity nodes
+     */
+    protected function load_section_activities(navigation_node $sectionnode, $sectionnumber, $modinfo) {
+        if (!array_key_exists($sectionnumber, $modinfo->sections)) {
+            return true;
+        }
+
+        $viewhiddenactivities = has_capability('moodle/course:viewhiddenactivities', $this->page->context);
+
+        $activities = array();
+
+        foreach ($modinfo->sections[$sectionnumber] as $cmid) {
+            $cm = $modinfo->cms[$cmid];
+            if (!$viewhiddenactivities && !$cm->visible) {
+                continue;
+            }
+            if ($cm->icon) {
+                $icon = new pix_icon($cm->icon, '', $cm->iconcomponent);
+            } else {
+                $icon = new pix_icon('icon', '', $cm->modname);
+            }
+            $url = new moodle_url('/mod/'.$cm->modname.'/view.php', array('id'=>$cm->id));
+            $activitynode = $sectionnode->add($cm->name, $url, navigation_node::TYPE_ACTIVITY, $cm->name, $cm->id, $icon);
+            $activitynode->title(get_string('modulename', $cm->modname));
+            $activitynode->hidden = (!$cm->visible);
+            if ($this->module_extends_navigation($cm->modname)) {
+                $child->nodetype = navigation_node::NODETYPE_BRANCH;
+            }
+            $activities[$cmid] = $activitynode;
+        }
+
+        return $activities;
+    }
+    /**
+     * Loads the navigation structure for the given activity into the activities node.
+     *
+     * This method utilises a callback within the modules lib.php file to load the
+     * content specific to activity given.
+     *
+     * The callback is a method: {modulename}_extend_navigation()
+     * Examples:
+     *  * {@see forum_extend_navigation()}
+     *  * {@see workshop_extend_navigation()}
+     *
+     * @global stdClass $CFG
+     * @global moodle_database $DB
+     * @param stdClass $cm
+     * @param stdClass $course
+     * @param navigation_node $activity
+     * @return bool
+     */
+    protected function load_activity(stdClass $cm, stdClass $course, navigation_node $activity) {
+        global $CFG, $DB;
+
+        $activity->make_active();
+        $file = $CFG->dirroot.'/mod/'.$cm->modname.'/lib.php';
+        $function = $cm->modname.'_extend_navigation';
+
+        if (file_exists($file)) {
+            require_once($file);
+            if (function_exists($function)) {
+                $activtyrecord = $DB->get_record($cm->modname, array('id' => $cm->instance), '*', MUST_EXIST);
+                $function($activity, $course, $activtyrecord, $cm);
+                return true;
+            }
+        }
+        $activity->nodetype = navigation_node::NODETYPE_LEAF;
+        return false;
+    }
+    /**
+     * Loads user specific information into the navigation in the appopriate place.
+     *
+     * If no user is provided the current user is assumed.
+     *
+     * @global moodle_database $DB
+     * @global stdClass $CFG
+     * @global stdClass $USER
+     * @param stdClass $user
+     * @return bool
+     */
     protected function load_for_user($user=null) {
-        global $DB, $PAGE, $CFG, $USER;
+        global $DB, $CFG, $USER;
 
         $iscurrentuser = false;
         if ($user === null) {
@@ -1010,57 +1182,50 @@
             // If the user is not an object then get them from the database
             $user = $DB->get_record('user', array('id'=>(int)$user), '*', MUST_EXIST);
         }
-        $baseargs = array('id'=>$user->id);
         $usercontext = get_context_instance(CONTEXT_USER, $user->id);
 
         // Get the course set against the page, by default this will be the site
-        $course = $PAGE->course;
+        $course = $this->page->course;
+        $baseargs = array('id'=>$user->id);
         if ($course->id !== SITEID) {
-            // Load all categories if required.
-            if (!empty($CFG->navshowallcourses)) {
-                $this->load_categories();
+            if (array_key_exists($course->id, $this->mycourses)) {
+                $coursenode = $this->mycourses[$course->id]->coursenode;
+            } else {
+                $coursenode = $this->rootnodes['courses']->find($course->id, navigation_node::TYPE_COURSE);
+                if (!$coursenode) {
+                    $coursenode = $this->load_course($course);
             }
-            // Attempt to find the course node within the navigation structure.
-            $coursetab = $this->find_child($course->id, self::TYPE_COURSE);
-            if (!$coursetab) {
-                // Load for the course.... this should never happen but is here to
-                // ensure if it ever does things don't break.
-                $this->load_for_course();
-                $coursetab = $this->find_child($course->id, self::TYPE_COURSE);
             }
-            // Get the context for the course
-            $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
             $baseargs['course'] = $course->id;
+            $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
             $issitecourse = false;
         } else {
             // Load all categories and get the context for the system
-            $this->load_categories();
             $coursecontext = get_context_instance(CONTEXT_SYSTEM);
             $issitecourse = true;
         }
 
         // Create a node to add user information under.
         if ($iscurrentuser) {
-            // If it's the current user the information will go under the my moodle dashboard node
-            $usernode = $this->add(get_string('mymoodledashboard'), null, navigation_node::TYPE_CUSTOM, get_string('mymoodledashboard'), 'mymoodle');
-            $usernode = $this->get($usernode);
+            // If it's the current user the information will go under the profile root node
+            $usernode = $this->rootnodes['profile'];
         } else {
             if (!$issitecourse) {
                 // Not the current user so add it to the participants node for the current course
-                $usersnode = $coursetab->find_child('participants', self::TYPE_SETTING);
+                $usersnode = $coursenode->get('participants', navigation_node::TYPE_CONTAINER);
             } else {
                 // This is the site so add a users node to the root branch
-                $usersnode = $this->find_child('users', self::TYPE_CUSTOM);
-                if (!$usersnode) {
-                    $usersnode = $this->add(get_string('users'), new moodle_url('/user/index.php', array('id'=>SITEID)), self::TYPE_CUSTOM, null, 'users');
-                    $usersnode = $this->get($usersnode);
+                $usersnode = $this->rootnodes['users'];
+                $usersnode->action = new moodle_url('/user/index.php', array('id'=>$course->id));
                 }
-            }
             // Add a branch for the current user
             $usernode = $usersnode->add(fullname($user, true));
-            $usernode = $usersnode->get($usernode);
         }
 
+        if ($this->page->context->contextlevel == CONTEXT_USER && $user->id == $this->page->context->instanceid) {
+            $usernode->force_open();
+        }
+
         // If the user is the current user or has permission to view the details of the requested
         // user than add a view profile link.
         if ($iscurrentuser || has_capability('moodle/user:viewdetails', $coursecontext) || has_capability('moodle/user:viewdetails', $usercontext)) {
@@ -1072,7 +1237,6 @@
         $canviewdiscussions = has_capability('mod/forum:viewdiscussion', $coursecontext);
         if ($canviewposts || $canviewdiscussions) {
             $forumtab = $usernode->add(get_string('forumposts', 'forum'));
-            $forumtab = $usernode->get($forumtab);
             if ($canviewposts) {
                 $forumtab->add(get_string('posts', 'forum'), new moodle_url('/mod/forum/user.php', $baseargs));
             }
@@ -1083,12 +1247,15 @@
 
         // Add a node to view the users notes if permitted
         if (!empty($CFG->enablenotes) && has_any_capability(array('moodle/notes:manage', 'moodle/notes:view'), $coursecontext)) {
-            $usernode->add(get_string('notes', 'notes'), new moodle_url('/notes/index.php',array('user'=>$user->id, 'course'=>$coursecontext->instanceid)));
+            $url = new moodle_url('/notes/index.php',array('user'=>$user->id));
+            if ($coursecontext->instanceid) {
+                $url->param('course', $coursecontext->instanceid);
         }
+            $usernode->add(get_string('notes', 'notes'), $url);
+        }
 
         // Add a reports tab and then add reports the the user has permission to see.
         $reporttab = $usernode->add(get_string('activityreports'));
-        $reporttab = $usernode->get($reporttab);
         $anyreport  = has_capability('moodle/user:viewuseractivitiesreport', $usercontext);
         $viewreports = ($anyreport || ($course->showreports && $iscurrentuser));
         $reportargs = array('user'=>$user->id);
@@ -1154,204 +1321,9 @@
     }
 
     /**
-     * Adds the provided user to an array and when the navigation is generated
-     * it is extended for this user.
+     * This method simply checks to see if a given module can extend the navigation.
      *
-     * @param object $user
-     */
-    public function extend_for_user($user) {
-        $this->extendforuser[] = $user;
-    }
-
-    /**
-     * Called by the initalise methods if the context was system or category
-     *
-     * @param bool $lookforid If system context then we dont want ID because
-     *      it could be userid, courseid, or anything else
-     * @return int The depth to the active(requested) node
-     */
-    protected function load_for_category($lookforid=true) {
-        global $PAGE, $CFG;
-        $id = optional_param('id', null, PARAM_INT);
-        if ($lookforid && $id!==null) {
-            if (!empty($CFG->navshowallcourses)) {
-                $this->load_categories();
-            }
-            $this->load_categories($id);
-            $depth = $this->find_child_depth($id);
-        } else {
-            $depth = $this->load_categories();
-        }
-        return $depth;
-    }
-
-    /**
-     * Called by the initialise methods if the context was course
-     *
-     * @return int The depth to the active(requested) node
-     */
-    protected function load_for_course() {
-        global $PAGE, $CFG, $USER;
-        $keys = array();
-        if (!empty($CFG->navshowallcourses)) {
-            $this->load_categories();
-        }
-        $depth = $this->load_course_categories($keys);
-        $depth += $this->load_course($keys);
-        if (!$this->format_display_course_content($PAGE->course->format)) {
-            $child = $this->get_by_path($keys);
-            if ($child!==false) {
-                $child->nodetype = self::NODETYPE_LEAF;
-            }
-            return $depth;
-        }
-
-        if (isloggedin() && has_capability('moodle/course:participate', get_context_instance(CONTEXT_COURSE, $PAGE->course->id))) {
-            $depth += $this->load_course_activities($keys);
-            $depth += $this->load_course_sections($keys);
-        }
-        return $depth;
-    }
-
-    /**
-     * Check whether the course format defines a display_course_content function
-     * that can be used to toggle whether or not to display course content
-     *
-     * $default is set to true, which may seem counter productive, however it ensures
-     * backwards compatibility for course types that havn't yet defined the callback
-     *
-     * @param string $format
-     * @param bool $default
-     * @return bool
-     */
-    protected function format_display_course_content($format, $default=true) {
-        global $CFG;
-        $formatlib = $CFG->dirroot.'/course/format/'.$format.'/lib.php';
-        if (file_exists($formatlib)) {
-            require_once($formatlib);
-            $displayfunc = 'callback_'.$format.'_display_content';
-            if (function_exists($displayfunc) && !$displayfunc()) {
-                return $displayfunc();
-            }
-        }
-        return $default;
-    }
-
-    /**
-     * Internal method to load course activities into the global navigation structure
-     * Course activities are activities that are in section 0
-     *
-     * @param array $keys By reference
-     */
-    protected function load_course_activities(&$keys, $course=null) {
-        global $PAGE, $CFG, $FULLME;
-
-        if ($course === null) {
-            $course = $PAGE->course;
-        }
-
-        if (!$this->cache->compare('modinfo'.$course->id, $course->modinfo, false)) {
-            $this->cache->{'modinfo'.$course->id} = get_fast_modinfo($course);
-        }
-        $modinfo =  $this->cache->{'modinfo'.$course->id};
-
-        if (!$this->cache->cached('canviewhiddenactivities')) {
-            $this->cache->canviewhiddenactivities = has_capability('moodle/course:viewhiddenactivities', $this->context);
-        }
-        $viewhiddenactivities = $this->cache->canviewhiddenactivities;
-
-        $labelformatoptions = new object();
-        $labelformatoptions->noclean = true;
-        $labelformatoptions->para = false;
-
-        foreach ($modinfo->cms as $module) {
-            if ($module->sectionnum!='0' || (!$viewhiddenactivities && !$module->visible)) {
-                continue;
-            }
-            $icon = null;
-            if ($module->icon) {
-                $icon = new pix_icon($module->icon, '', $module->iconcomponent);
-            } else {
-                $icon = new pix_icon('icon', '', $module->modname);
-            }
-            $url = new moodle_url('/mod/'.$module->modname.'/view.php', array('id'=>$module->id));
-            $this->add_to_path($keys, $module->id, $module->name, $module->name, self::TYPE_ACTIVITY, $url, $icon);
-            $child = $this->find_child($module->id, self::TYPE_ACTIVITY);
-            if ($child != false) {
-                $child->title(get_string('modulename', $module->modname));
-                if ($this->module_extends_navigation($module->modname)) {
-                    $child->nodetype = self::NODETYPE_BRANCH;
-                }
-                if (!$module->visible) {
-                    $child->hidden = true;
-                }
-            }
-        }
-    }
-    /**
-     * Internal function to load the activities within sections
-     *
-     * @param array $keys By reference
-     */
-    protected function load_section_activities(&$keys, $singlesectionid=false, $course=null) {
-        global $PAGE, $CFG, $FULLME;
-
-        if ($course === null) {
-            $course = $PAGE->course;
-        }
-
-        if (!$this->cache->compare('modinfo'.$course->id, $course->modinfo, false)) {
-            $this->cache->{'modinfo'.$course->id} = get_fast_modinfo($course);
-        }
-        $modinfo =  $this->cache->{'modinfo'.$course->id};
-
-        if (!$this->cache->cached('coursesections'.$course->id)) {
-            $this->cache->{'coursesections'.$course->id} = get_all_sections($course->id);
-        }
-        $sections = $this->cache->{'coursesections'.$course->id};
-
-        if (!$this->cache->cached('canviewhiddenactivities')) {
-            $this->cache->canviewhiddenactivities = has_capability('moodle/course:viewhiddenactivities', $this->context);
-        }
-        $viewhiddenactivities = $this->cache->viewhiddenactivities;
-
-        $labelformatoptions = new object();
-        $labelformatoptions->noclean = true;
-        $labelformatoptions->para = false;
-
-        foreach ($modinfo->cms as $module) {
-            if ($module->sectionnum=='0' || (!$viewhiddenactivities && !$module->visible) || ($singlesectionid!=false && $module->sectionnum!==$singlesectionid)) {
-                continue;
-            }
-            $icon = null;
-            if ($module->icon) {
-                $icon = new pix_icon($module->icon, '', $module->iconcomponent);
-            } else {
-                $icon = new pix_icon('icon', '', $module->modname);
-            }
-            $url = new moodle_url('/mod/'.$module->modname.'/view.php', array('id'=>$module->id));
-
-            $path = $keys;
-            if ($course->id !== SITEID) {
-                $path[] = $sections[$module->sectionnum]->id;
-            }
-            $this->add_to_path($path, $module->id, $module->name, $module->name, navigation_node::TYPE_ACTIVITY, $url, $icon);
-            $child = $this->find_child($module->id, navigation_node::TYPE_ACTIVITY);
-            if ($child != false) {
-                $child->title(get_string('modulename', $module->modname));
-                if (!$module->visible) {
-                    $child->hidden = true;
-                }
-                if ($this->module_extends_navigation($module->modname)) {
-                    $child->nodetype = self::NODETYPE_BRANCH;
-                }
-            }
-        }
-    }
-
-    /**
-     * Check if a given module has a method to extend the navigation
-     *
+     * @global stdClass $CFG
      * @param string $modname
      * @return bool
      */
@@ -1376,200 +1348,65 @@
         return false;
     }
     /**
-     * Load the global navigation structure for an activity
+     * Extends the navigation for the given user.
      *
-     * @return int
+     * @param stdClass $user A user from the database
      */
-    protected function load_for_activity() {
-        global $PAGE, $DB, $CFG;
-        $keys = array();
-
-        $sectionnum = false;
-        if (!empty($PAGE->cm->section)) {
-            $section = $DB->get_record('course_sections', array('id'=>$PAGE->cm->section));
-            if (!empty($section->section)) {
-                $sectionnum = $section->section;
+    public function extend_for_user($user) {
+        $this->extendforuser[] = $user;
             }
-        }
-
-        if (!empty($CFG->navshowallcourses)) {
-            $this->load_categories();
-        }
-
-        $depth = $this->load_course_categories($keys);
-        $depth += $this->load_course($keys);
-        $depth += $this->load_course_activities($keys);
-        $depth += $this->load_course_sections($keys);
-        $depth += $this->load_section_activities($keys,$sectionnum);
-        $depth += $this->load_activity($keys);
-        return $depth;
-    }
-
     /**
-     * This function loads any navigation items that might exist for an activity
-     * by looking for and calling a function within the modules lib.php
+     * Adds the given course to the navigation structure.
      *
-     * @param int $instanceid
-     * @return void
+     * @param stdClass $course
+     * @return navigation_node
      */
-    protected function load_activity($keys) {
-        global $CFG, $PAGE;
-
-        if (!$PAGE->cm && $this->context->contextlevel == CONTEXT_MODULE && $this->context->instanceid) {
-            // This is risky but we have no other choice... we need that module and the module
-            // itself hasn't set PAGE->cm (usually set by require_login)
-            // Chances are this is a front page module.
-            $cm = get_coursemodule_from_id(false, $this->context->instanceid);
-            $PAGE->set_cm($cm, $PAGE->course);
+    public function add_course(stdClass $course) {
+        if (array_key_exists($course->id, $this->addedcourses)) {
+            return $this->addedcourses[$course->id];
         }
 
-        $node = $this->find_child($PAGE->cm->id, self::TYPE_ACTIVITY);
-        if ($node) {
-            $node->make_active();
-            $this->context = $PAGE->context;
-            $file = $CFG->dirroot.'/mod/'.$PAGE->activityname.'/lib.php';
-            $function = $PAGE->activityname.'_extend_navigation';
-
-            if (file_exists($file)) {
-                require_once($file);
-                if (function_exists($function)) {
-                    $function($node, $PAGE->course, $PAGE->activityrecord, $PAGE->cm);
+        $canviewhidden = has_capability('moodle/course:viewhiddencourses', $this->page->context);
+        if ($course->id !== SITEID && !$canviewhidden && (!$course->visible || !course_parent_visible($course))) {
+            return false;
                 }
-            }
-        }
-    }
 
-    /**
-     * Recursively adds an array of category objexts to the path provided by $keys
-     *
-     * @param array $keys An array of keys representing the path to add to
-     * @param array $categories An array of [nested] categories to add
-     * @param int $depth The current depth, this ensures we don't generate more than
-     *      we need to
-     */
-    protected function add_categories(&$keys, $categories, $depth=0) {
-        if (is_array($categories) && count($categories)>0) {
-            foreach ($categories as $category) {
-                $url = new moodle_url('/course/category.php', array('id'=>$category->id, 'categoryedit'=>'on', 'sesskey'=>sesskey()));
-                $categorykey = $this->add_to_path($keys,  $category->id, $category->name, $category->name, self::TYPE_CATEGORY, $url);
-                if ($depth < $this->depthforward) {
-                    $this->add_categories(array_merge($keys, array($categorykey)), $category->id, $depth+1);
-                }
-            }
-        }
-    }
-
-    /**
-     * This function adds a category to the nav tree based on the categories path
-     *
-     * @param stdClass $category
-     */
-    protected function add_category_by_path($category) {
-        $url = new moodle_url('/course/category.php', array('id'=>$category->id, 'categoryedit'=>'on', 'sesskey'=>sesskey()));
-        $keys = explode('/',trim($category->path,'/ '));
-        // Check this category hadsn't already been added
-        if (!$this->get_by_path($keys)) {
-            $currentcategory = array_pop($keys);
-            $categorykey = $this->add_to_path($keys,  $category->id, $category->name, $category->name, self::TYPE_CATEGORY, $url);
-        } else {
-            $currentcategory = array_pop($keys);
-            $categorykey = $currentcategory.':'.self::TYPE_CATEGORY;
-        }
-        return $categorykey;
-    }
-
-    /**
-     * Adds an array of courses to thier correct categories if the categories exist
-     *
-     * @param array $courses An array of course objects
-     * @param int $categoryid An override to add the courses to
-     * @return bool
-     */
-    public function add_courses($courses, $categoryid=null) {
-        global $SITE;
-        if (is_array($courses) && count($courses)>0) {
-            // Work out if the user can view hidden courses, just incase
-            if (!$this->cache->cached('canviewhiddencourses')) {
-                $this->cache->canviewhiddencourses = has_capability('moodle/course:viewhiddencourses', $this->context);
-            }
-            $canviewhidden = $this->cache->canviewhiddencourses;
-            $expandcourse = $this->can_display_type(self::TYPE_SECTION);
-            foreach ($courses as $course) {
-                // Check if the user can't view hidden courses and if the course is hidden, if so skip and continue
-                if ($course->id!=$SITE->id && !$canviewhidden && (!$course->visible || !course_parent_visible($course))) {
-                    continue;
-                }
-                // Process this course into the nav structure
+        if ($course->id == SITEID) {
+            $parent = $this;
+            $url = new moodle_url('/');
+        } else if (array_key_exists($course->id, $this->mycourses)) {
+            $parent = $this->rootnodes['mycourses'];
                 $url = new moodle_url('/course/view.php', array('id'=>$course->id));
-                if ($categoryid===null) {
-                    $category = $this->find_child($course->category, self::TYPE_CATEGORY);
-                } else if ($categoryid === false) {
-                    $category = $this;
                 } else {
-                    $category = $this->find_child($categoryid);
+            $parent = $this->rootnodes['courses'];
+            $url = new moodle_url('/course/view.php', array('id'=>$course->id));
                 }
-                if ($category!==false) {
-                    // Check that this course hasn't already been added.
-                    // This function only adds a skeleton and we don't want to overwrite
-                    // a fully built course object
-                    if (!$category->get($course->id, self::TYPE_COURSE)) {
-                        $coursekey = $category->add($course->fullname, $url, self::TYPE_COURSE, $course->shortname, $course->id, new pix_icon('i/course', ''));
-                        if (!$course->visible) {
-                            $category->get($course->id)->hidden = true;
+        $coursenode = $parent->add($course->fullname, $url, self::TYPE_COURSE, $course->shortname, $course->id);
+        $coursenode->nodetype = self::NODETYPE_BRANCH;
+        $coursenode->hidden = (!$course->visible);
+        $this->addedcourses[$course->id] = &$coursenode;
+        return $coursenode;
                         }
-                        if ($expandcourse!==true) {
-                            $category->get($course->id)->nodetype = self::NODETYPE_LEAF;
-                        }
-                    }
-                }
-            }
-        }
-        return true;
-    }
-
     /**
-     * Loads the current course into the navigation structure
+     * Adds essential course nodes to the navigation for the given course.
      *
-     * Loads the current course held by $PAGE {@link moodle_page()} into the navigation
-     * structure.
-     * If the course structure has an appropriate display method then the course structure
-     * will also be displayed.
+     * This method adds nodes such as reports, blogs and participants
      *
-     * @param array $keys The path to add the course to
+     * @global stdClass $CFG
+     * @param navigation_node $coursenode
+     * @param stdClass $course
      * @return bool
      */
-    protected function load_course(&$keys, $course=null) {
-        global $PAGE, $CFG;
-        if ($course===null) {
-            $course = $PAGE->course;
-        }
-        if (is_object($course) && $course->id !== SITEID) {
+    public function add_course_essentials(navigation_node $coursenode, $course) {
+        global $CFG;
 
-            if (!$this->cache->cached('canviewhiddencourses')) {
-                $this->cache->canviewhiddencourses = has_capability('moodle/course:viewhiddencourses', $this->context);
+        if ($coursenode == false || $coursenode->get('participants', navigation_node::TYPE_CONTAINER)) {
+            return true;
             }
-            $canviewhidden = $this->cache->canviewhiddencourses;
-
-            if (!$canviewhidden && (!$course->visible || !course_parent_visible($course))) {
-                return;
-            }
-            $url = new moodle_url('/course/view.php', array('id'=>$course->id));
-            $keys[] = $this->add_to_path($keys, $course->id, $course->fullname, $course->shortname, self::TYPE_COURSE, $url, new pix_icon('i/course', ''));
-            $currentcourse = $this->find_child($course->id, self::TYPE_COURSE);
-            if ($currentcourse!==false){
-                $currentcourse->make_active();
-                if (!$course->visible) {
-                    $currentcourse->hidden = true;
-                }
-
                 //Participants
-                if (has_capability('moodle/course:viewparticipants', $this->context)) {
-                    $participantskey = $currentcourse->add(get_string('participants'), new moodle_url('/user/index.php?id='.$course->id), self::TYPE_SETTING, get_string('participants'), 'participants');
-                    $participants = $currentcourse->get($participantskey);
-                    if ($participants) {
-
+        if (has_capability('moodle/course:viewparticipants', $this->page->context)) {
+            $participants = $coursenode->add(get_string('participants'), new moodle_url('/user/index.php?id='.$course->id), self::TYPE_CONTAINER, get_string('participants'), 'participants');
                         require_once($CFG->dirroot.'/blog/lib.php');
-
                         $currentgroup = groups_get_course_group($course, true);
                         if ($course->id == SITEID) {
                             $filterselect = '';
@@ -1579,23 +1416,18 @@
                             $filterselect = $currentgroup;
                         }
                         $filterselect = clean_param($filterselect, PARAM_INT);
-
                         if ($CFG->bloglevel >= 3) {
                             $blogsurls = new moodle_url('/blog/index.php', array('courseid' => $filterselect));
                             $participants->add(get_string('blogs','blog'), $blogsurls->out());
                         }
-
-                        if (!empty($CFG->enablenotes) && (has_capability('moodle/notes:manage', $this->context) || has_capability('moodle/notes:view', $this->context))) {
+            if (!empty($CFG->enablenotes) && (has_capability('moodle/notes:manage', $this->page->context) || has_capability('moodle/notes:view', $this->page->context))) {
                             $participants->add(get_string('notes','notes'), new moodle_url('/notes/index.php', array('filtertype'=>'course', 'filterselect'=>$filterselect)));
                         }
                     }
-                }
 
                 // View course reports
-                if (has_capability('moodle/site:viewreports', $this->context)) { // basic capability for listing of reports
-                    $reportkey = $currentcourse->add(get_string('reports'), new moodle_url('/course/report.php', array('id'=>$course->id)), self::TYPE_SETTING, null, null, new pix_icon('i/stats', ''));
-                    $reportnav = $currentcourse->get($reportkey);
-                    if ($reportnav) {
+        if (has_capability('moodle/site:viewreports', $this->page->context)) { // basic capability for listing of reports
+            $reportnav = $coursenode->add(get_string('reports'), new moodle_url('/course/report.php', array('id'=>$course->id)), self::TYPE_CONTAINER, null, null, new pix_icon('i/stats', ''));
                         $coursereports = get_plugin_list('coursereport');
                         foreach ($coursereports as $report=>$dir) {
                             $libfile = $CFG->dirroot.'/course/report/'.$report.'/lib.php';
@@ -1603,314 +1435,23 @@
                                 require_once($libfile);
                                 $reportfunction = $report.'_report_extend_navigation';
                                 if (function_exists($report.'_report_extend_navigation')) {
-                                    $reportfunction($reportnav, $course, $this->context);
+                        $reportfunction($reportnav, $course, $this->page->context);
                                 }
                             }
                         }
                     }
-                }
-            }
-
-            if (!$this->can_display_type(self::TYPE_SECTION)) {
-                if ($currentcourse!==false) {
-                    $currentcourse->nodetype = self::NODETYPE_LEAF;
-                }
                 return true;
             }
-        }
-    }
-    /**
-     * Loads the sections for a course
-     *
-     * @param array $keys By reference
-     * @param stdClass $course The course that we are loading sections for
-     */
-    protected function load_course_sections(&$keys, $course=null) {
-        global $PAGE, $CFG;
-        if ($course === null) {
-            $course = $PAGE->course;
-        }
-        $structurefile = $CFG->dirroot.'/course/format/'.$course->format.'/lib.php';
-        $structurefunc = 'callback_'.$course->format.'_load_content';
-        if (function_exists($structurefunc)) {
-            $structurefunc($this, $keys, $course);
-        } else if (file_exists($structurefile)) {
-            require_once $structurefile;
-            if (function_exists($structurefunc)) {
-                $structurefunc($this, $keys, $course);
-            } else {
-                $this->add_course_section_generic($keys, $course);
-            }
-        } else {
-            $this->add_course_section_generic($keys, $course);
-        }
-    }
-    /**
-     * This function loads the sections for a course if no given course format
-     * methods have been defined to do so. Thus generic
-     *
-     * @param array $keys By reference
-     * @param stdClass $course The course object to load for
-     * @param string $name String to use to describe the current section to the user
-     * @param string $activeparam Request variable to look for to determine the current section
-     * @return bool
-     */
-    public function add_course_section_generic(&$keys, $course=null, $name=null, $activeparam = null) {
-        global $PAGE;
 
-        if ($course === null) {
-            $course = $PAGE->course;
-        }
-
-        $coursesecstr = 'coursesections'.$course->id;
-        if (!$this->cache->cached($coursesecstr)) {
-            $sections = get_all_sections($course->id);
-            $this->cache->$coursesecstr = $sections;
-        } else {
-            $sections = $this->cache->$coursesecstr;
-        }
-
-        if (!$this->cache->compare('modinfo'.$course->id, $course->modinfo, false)) {
-            $this->cache->{'modinfo'.$course->id} = get_fast_modinfo($course);
-        }
-        $modinfo =  $this->cache->{'modinfo'.$course->id};
-
-        $depthforward = 0;
-        if (!is_array($modinfo->sections)) {
-            return $keys;
-        }
-
-        if ($name === null) {
-            $name = get_string('topic');
-        }
-
-        if ($activeparam === null) {
-            $activeparam = 'topic';
-        }
-
-        $coursenode = $this->find_child($course->id, navigation_node::TYPE_COURSE);
-        if ($coursenode!==false) {
-            $coursenode->action->param($activeparam,'0');
-        }
-
-        if (!$this->cache->cached('canviewhiddenactivities')) {
-            $this->cache->canviewhiddenactivities = has_capability('moodle/course:viewhiddenactivities', $this->context);
-        }
-        $viewhiddenactivities = $this->cache->canviewhiddenactivities;
-
-        if (!$this->cache->cached('canviewhiddensections')) {
-            $this->cache->canviewhiddensections = has_capability('moodle/course:viewhiddensections', $this->context);
-        }
-        $viewhiddensections = $this->cache->canviewhiddensections;
-
-        // MDL-20242 + MDL-21564
-        $sections = array_slice($sections, 0, $course->numsections+1, true);
-
-        foreach ($sections as $section) {
-            if ((!$viewhiddensections && !$section->visible) || (!$this->showemptybranches && !array_key_exists($section->section, $modinfo->sections))) {
-                continue;
-            }
-            if ($section->section!=0) {
-                $sectionkeys = $keys;
-                $url = new moodle_url('/course/view.php', array('id'=>$course->id, $activeparam=>$section->section));
-                $this->add_to_path($sectionkeys, $section->id, $name.' '.$section->section, null, navigation_node::TYPE_SECTION, $url);
-                $sectionchild = $this->find_child($section->id, navigation_node::TYPE_SECTION);
-                if ($sectionchild !== false) {
-                    $sectionchild->nodetype = self::NODETYPE_BRANCH;
-                    if ($sectionchild->isactive) {
-                        $this->load_section_activities($sectionkeys, $section->section);
-                    }
-                    if (!$section->visible) {
-                        $sectionchild->hidden = true;
-                    }
-                }
-            }
-        }
-        return true;
-    }
-
     /**
-     * Check if we are permitted to display a given type
-     *
-     * @return bool True if we are, False otherwise
+     * Clears the navigation cache
      */
-    protected function can_display_type($type) {
-        if (!is_null($this->expansionlimit) && $this->expansionlimit < $type) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Loads the categories for the current course into the navigation structure
-     *
-     * @param array $keys Forced reference to and array to use for the keys
-     * @return int The number of categories
-     */
-    protected function load_course_categories(&$keys) {
-        global $PAGE;
-        $categories = $PAGE->categories;
-        if (is_array($categories) && count($categories)>0) {
-            $categories = array_reverse($categories);
-            foreach ($categories as $category) {
-                $key = $category->id.':'.self::TYPE_CATEGORY;
-                if (!$this->get_by_path(array_merge($keys, array($key)))) {
-                    $url = new moodle_url('/course/category.php', array('id'=>$category->id, 'categoryedit'=>'on', 'sesskey'=>sesskey()));
-                    $keys[] = $this->add_to_path($keys, $category->id, $category->name, $category->name, self::TYPE_CATEGORY, $url);
-                } else {
-                    $keys[] = $key;
-                }
-            }
-        }
-        return count($categories);
-    }
-
-    /**
-     * This is called by load_for_category to load categories into the navigation structure
-     *
-     * @param int $categoryid The specific category to load
-     * @return int The depth of categories that were loaded
-     */
-    protected function load_categories($categoryid=0) {
-        global $CFG, $DB, $USER;
-
-        if ($categoryid === 0 && $this->allcategoriesloaded) {
-            return 0;
-        }
-
-        $systemcontext = get_context_instance(CONTEXT_SYSTEM);
-
-        // If the user is logged in (but not as a guest), doesnt have the site config capability,
-        // and my courses havn't been disabled then we will show the user's courses in the
-        // global navigation, otherwise we will show up to FRONTPAGECOURSELIMIT available courses
-        if (isloggedin() && !is_siteadmin() && !isguestuser() && empty($CFG->disablemycourses)) {
-            if (!$this->cache->cached('mycourses')) {
-                $this->cache->mycourses = get_my_courses($USER->id);
-            }
-            $courses = $this->cache->mycourses;
-        } else {
-            // Check whether we have already cached the available courses
-            if (!$this->cache->cached('availablecourses')) {
-                // Non-cached - get accessinfo
-                if (isset($USER->access)) {
-                    $accessinfo = $USER->access;
-                } else {
-                    $accessinfo = get_user_access_sitewide($USER->id);
-                }
-                // Get the available courses using get_user_courses_bycap
-                $this->cache->availablecourses = get_user_courses_bycap($USER->id, 'moodle/course:participate',
-                                                                        $accessinfo, true, 'c.sortorder ASC',
-                                                                        array('fullname','visible', 'category'),
-                                                                        FRONTPAGECOURSELIMIT);
-            }
-            // Cache the available courses for a refresh
-            $courses = $this->cache->availablecourses;
-        }
-
-        // Iterate through all courses, and explode thier course category paths so that
-        // we can retrieve all of the individual category id's that are required
-        // to display the list of courses in the tree
-        $categoryids = array();
-        foreach ($courses as $course) {
-            // If a category id has been specified and the current course is not within
-            // that category or one of its children then skip this course
-            if ($categoryid!==0 && !preg_match('#/('.$categoryid.')(/|$)#', $course->categorypath)) {
-                continue;
-            }
-            $categorypathids = explode('/',trim($course->categorypath,' /'));
-            // If no category has been specified limit the depth we display immediatly to
-            // that of the nav var depthforwards
-            if ($categoryid===0 && count($categorypathids)>($this->depthforward+1) && empty($CFG->navshowallcourses)) {
-                $categorypathids = array_slice($categorypathids, 0, ($this->depthforward+1));
-            }
-            $categoryids = array_merge($categoryids, $categorypathids);
-        }
-        // Remove duplicate categories (and there will be a few)
-        $categoryids = array_unique($categoryids);
-
-        // Check whether we have some category ids to display and make sure that either
-        // no category has been specified ($categoryid===0) or that the category that
-        // has been specified is in the list.
-        if (count($categoryids)>0 && ($categoryid===0 || in_array($categoryid, $categoryids))) {
-            $catcachestr = 'categories'.join($categoryids);
-            if (!$this->cache->cached($catcachestr)) {
-                $this->cache->{$catcachestr} = $DB->get_records_select('course_categories', 'id IN ('.join(',', $categoryids).')', array(), 'path ASC, sortorder ASC');
-            }
-            $categories = $this->cache->{$catcachestr};
-            // Retrieve the nessecary categories and then proceed to add them to the tree
-            foreach ($categories as $category) {
-                $this->add_category_by_path($category);
-            }
-            // Add the courses that were retrieved earlier to the
-            $this->add_courses($courses);
-        } else if ($categoryid === 0) {
-            $keys = array();
-            $categories = $DB->get_records('course_categories', array('parent' => $categoryid), 'sortorder ASC');
-            $this->add_categories($keys, $categories);
-            $this->add_courses($courses, $categoryid);
-        }
-        $this->allcategoriesloaded = true;
-        return 0;
-    }
-
-    /**
-     * This function marks the cache as volatile so it is cleared during shutdown
-     */
     public function clear_cache() {
-        $this->cache->volatile();
+        $this->cache->clear();
     }
-
-    /**
-     * Finds all expandable nodes whilst ensuring that expansion limit is respected
-     *
-     * @param array $expandable A reference to an array that will be populated as
-     * we go.
-     */
-    public function find_expandable(&$expandable) {
-        parent::find_expandable($expandable, $this->expansionlimit);
     }
 
     /**
-     * Loads categories that contain no courses into the structure.
-     *
-     * These categories would normally be skipped, as such this function is purely
-     * for the benefit of code external to navigationlib
-     */
-    public function load_empty_categories() {
-        $categories = array();
-        $categorynames = array();
-        $categoryparents = array();
-        make_categories_list($categorynames, $categoryparents, '', 0, $category = NULL);
-        foreach ($categorynames as $id=>$name) {
-            if (!$this->find_child($id, self::TYPE_CATEGORY)) {
-                $category = new stdClass;
-                $category->id = $id;
-                if (array_key_exists($id, $categoryparents)) {
-                    $category->path = '/'.join('/',array_merge($categoryparents[$id],array($id)));
-                    $name = explode('/', $name);
-                    $category->name = join('/', array_splice($name, count($categoryparents[$id])));
-                } else {
-                    $category->path = '/'.$id;
-                    $category->name = $name;
-                }
-                $this->add_category_by_path($category);
-            }
-        }
-    }
-
-    public function collapse_course_categories() {
-        $categories = $this->get_children_by_type(self::TYPE_CATEGORY);
-        while (count($categories) > 0) {
-            foreach ($categories as $category) {
-                $this->children = array_merge($this->children, $category->children);
-                $this->remove_child($category->key, self::TYPE_CATEGORY);
-            }
-            $categories = $this->get_children_by_type(self::TYPE_CATEGORY);
-        }
-    }
-}
-
-/**
  * The limited global navigation class used for the AJAX extension of the global
  * navigation class.
  *
@@ -1927,20 +1468,33 @@
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class global_navigation_for_ajax extends global_navigation {
+
+    /** @var array */
+    protected $expandable = array();
+
     /**
-     * Initialise the limited navigation object, calling it to auto generate
+     * Constructs the navigation for use in AJAX request
+     * @global stdClass $SITE
+     */
+    public function __construct() {
+        global $SITE;
+        $this->cache = new navigation_cache(NAVIGATION_CACHE_NAME);
+        $this->children = new navigation_node_collection();
+        $this->rootnodes = array();
+        //$this->rootnodes['site']      = $this->add_course($SITE);
+        $this->rootnodes['courses'] = $this->add(get_string('courses'), null, self::TYPE_ROOTNODE, null, 'courses');
+    }
+    /**
+     * Initialise the navigation given the type and id for the branch to expand.
      *
-     * This function can be used to initialise the global navigation object more
-     * flexibly by providing a couple of overrides.
-     * This is used when the global navigation is being generated without other fully
-     * initialised Moodle objects
-     *
-     * @param int $branchtype What to load for e.g. TYPE_SYSTEM
-     * @param int $id The instance id for what ever is being loaded
-     * @return array An array of nodes that are expandable by AJAX
+     * @global moodle_database $DB
+     * @global moodle_page $PAGE
+     * @param int $branchtype One of navigation_node::TYPE_*
+     * @param int $id
+     * @return array The expandable nodes
      */
     public function initialise($branchtype, $id) {
-        global $DB;
+        global $DB, $PAGE;
 
         if ($this->initialised || during_initial_install()) {
             return $this->expandable;
@@ -1948,264 +1502,56 @@
 
         // Branchtype will be one of navigation_node::TYPE_*
         switch ($branchtype) {
-            case self::TYPE_CATEGORY :
-                require_login();
-                $depth = $this->load_category($id);
-                break;
             case self::TYPE_COURSE :
                 $course = $DB->get_record('course', array('id' => $id), '*', MUST_EXIST);
                 require_course_login($course);
-                $depth = $this->load_course($id);
+                $this->page = $PAGE;
+                $coursenode = $this->add_course($course);
+                $this->add_course_essentials($coursenode, $course);
+                if ($this->format_display_course_content($course->format)) {
+                    $this->load_course_sections($course, $coursenode);
+                }
                 break;
             case self::TYPE_SECTION :
-                $sql = 'SELECT c.*
+                $sql = 'SELECT c.*, cs.section AS sectionnumber
                         FROM {course} c
                         LEFT JOIN {course_sections} cs ON cs.course = c.id
                         WHERE cs.id = ?';
                 $course = $DB->get_record_sql($sql, array($id), MUST_EXIST);
                 require_course_login($course);
-                $depth = $this->load_section($id);
+                $this->page = $PAGE;
+                $coursenode = $this->add_course($course);
+                $this->add_course_essentials($coursenode, $course);
+                $sections = $this->load_course_sections($course, $coursenode);
+                $this->load_section_activities($sections[$course->sectionnumber]->sectionnode, $course->sectionnumber, get_fast_modinfo($course));
                 break;
             case self::TYPE_ACTIVITY :
                 $cm = get_coursemodule_from_id(false, $id, 0, false, MUST_EXIST);
                 $course = $DB->get_record('course', array('id'=>$cm->course), '*', MUST_EXIST);
                 require_course_login($course, true, $cm);
-                $depth = $this->load_activity($id);
+                $this->page = $PAGE;
+                $coursenode = $this->load_course($course);
+                $sections = $this->load_course_sections($course, $coursenode);
+                foreach ($sections as $section) {
+                    if ($section->id == $cm->section) {
+                        $cm->sectionnumber = $section->section;
                 break;
+                    }
+                }
+                $activities = $this->load_section_activities($sections[$cm->sectionnumber]->sectionnode, $cm->sectionnumber, get_fast_modinfo($course));
+                $modulenode = $this->load_activity($cm, $course, $activities[$cm->id]);
+                break;
             default:
+                throw new Exception('Unknown type');
                 return $this->expandable;
-                break;
         }
 
-        $this->collapse_at_depth($this->depthforward+$depth);
-        $this->respect_forced_open();
-        $this->expandable = array();
         $this->find_expandable($this->expandable);
-        $this->initialised = true;
         return $this->expandable;
     }
-
-    /**
-     * Loads the content (sub categories and courses) for a given a category
-     *
-     * @param int $instanceid
-     */
-    protected function load_category($instanceid) {
-        if (!$this->cache->cached('coursecatcontext'.$instanceid)) {
-            $this->cache->{'coursecatcontext'.$instanceid} = get_context_instance(CONTEXT_COURSECAT, $instanceid);
         }
-        $this->context = $this->cache->{'coursecatcontext'.$instanceid};
-        $this->load_categories($instanceid);
-    }
 
     /**
-     * Use the instance id to load a course
-     *
-     * {@link global_navigation::load_course()}
-     * @param int $instanceid
-     */
-    protected function load_course($instanceid) {
-        global $DB, $PAGE;
-
-        if (!$this->cache->cached('course'.$instanceid)) {
-            if ($PAGE->course->id == $instanceid) {
-                $this->cache->{'course'.$instanceid} = $PAGE->course;
-            } else {
-                $this->cache->{'course'.$instanceid} = $DB->get_record('course', array('id'=>$instanceid), '*', MUST_EXIST);
-            }
-        }
-        $course = $this->cache->{'course'.$instanceid};
-
-        if (!$this->format_display_course_content($course->format)) {
-            return true;
-        }
-
-        if (!$this->cache->cached('coursecontext'.$course->id)) {
-            $this->cache->{'coursecontext'.$course->id} = get_context_instance(CONTEXT_COURSE, $course->id);
-        }
-        $this->context = $this->cache->{'coursecontext'.$course->id};
-
-        $keys = array();
-        parent::load_course($keys, $course);
-
-        if (isloggedin() && has_capability('moodle/course:participate', $this->context)) {
-            if (!$this->cache->cached('course'.$course->id.'section0')) {
-                $this->cache->{'course'.$course->id.'section0'} = get_course_section('0', $course->id);
-            }
-            $section = $this->cache->{'course'.$course->id.'section0'};
-            $this->load_section_activities($course, $section);
-            if ($this->depthforward>0) {
-                $this->load_course_sections($keys, $course);
-            }
-        }
-    }
-    /**
-     * Use the instance id to load a specific course section
-     *
-     * @param int $instanceid
-     */
-    protected function load_section($instanceid=0) {
-        global $DB, $PAGE, $CFG;
-
-        $section = $DB->get_record('course_sections', array('id'=>$instanceid), '*', MUST_EXIST);
-
-        if (!$this->cache->cached('course'.$section->course)) {
-            if ($PAGE->course->id == $section->course) {
-                $this->cache->{'course'.$section->course} = $PAGE->course;
-            } else {
-                $this->cache->{'course'.$section->course} = $DB->get_record('course', array('id'=>$section->course), '*', MUST_EXIST);
-            }
-        }
-        $course = $this->cache->{'course'.$section->course};
-
-        if (!$this->cache->cached('coursecontext'.$course->id)) {
-            $this->cache->{'coursecontext'.$course->id} = get_context_instance(CONTEXT_COURSE, $course->id);
-        }
-        $this->context = $this->cache->{'coursecontext'.$course->id};
-
-        // Call the function to generate course section
-        $keys = array();
-        $structurefile = $CFG->dirroot.'/course/format/'.$course->format.'/navigation_format.php';
-        $structurefunc = 'callback_'.$course->format.'_load_limited_section';
-        if (function_exists($structurefunc)) {
-            $sectionnode = $structurefunc($this, $keys, $course, $section);
-        } else if (file_exists($structurefile)) {
-            include $structurefile;
-            if (function_exists($structurefunc)) {
-                $sectionnode = $structurefunc($this, $keys, $course, $section);
-            } else {
-                $sectionnode = $this->limited_load_section_generic($keys, $course, $section);
-            }
-        } else {
-            $sectionnode = $this->limited_load_section_generic($keys, $course, $section);
-        }
-        if ($this->depthforward>0) {
-            $this->load_section_activities($course, $section);
-        }
-    }
-    /**
-     * This function is called if there is no specific course format function set
-     * up to load sections into the global navigation.
-     *
-     * Note that if you are writing a course format you can call this function from your
-     * callback function if you don't want to load anything special but just specify the
-     * GET argument that identifies the current section as well as the string that
-     * can be used to describve the section. e.g. weeks or topic
-     *
-     * @param array $keys
-     * @param stdClass $course
-     * @param stdClass $section
-     * @param string $name
-     * @param string $activeparam
-     * @return navigation_node|bool
-     */
-    public function limited_load_section_generic($keys, $course, $section, $name=null, $activeparam = 'topic') {
-        global $PAGE, $CFG;
-
-        if ($name === null) {
-            $name = get_string('topic');
-        }
-
-        if (!$this->cache->cached('canviewhiddensections')) {
-            $this->cache->canviewhiddensections = has_capability('moodle/course:viewhiddensections', $this->context);
-        }
-        $viewhiddensections = $this->cache->canviewhiddensections;
-
-        if (!$viewhiddensections && !$section->visible) {
-            return false;
-        }
-        if ($section->section!=0) {
-            $url = new moodle_url('/course/view.php', array('id'=>$course->id, $activeparam=>$section->id));
-            $keys[] = $this->add_to_path($keys, $section->id, $name.' '.$section->section, null, navigation_node::TYPE_SECTION, $url);
-            $sectionchild = $this->find_child($section->id, navigation_node::TYPE_SECTION);
-            if ($sectionchild !== false) {
-                $sectionchild->nodetype = self::NODETYPE_BRANCH;
-                $sectionchild->make_active();
-                if (!$section->visible) {
-                    $sectionchild->hidden = true;
-                }
-                return $sectionchild;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * This function is used to load a course sections activities
-     *
-     * @param stdClass $course
-     * @param stdClass $section
-     * @return void
-     */
-    protected function load_section_activities($course, $section) {
-        global $CFG;
-        if (!is_object($section)) {
-            return;
-        }
-        if ($section->section=='0') {
-            $keys = array($section->course);
-        } else {
-            $keys = array($section->id);
-        }
-
-        $modinfo = get_fast_modinfo($course);
-
-        if (!$this->cache->cached('canviewhiddenactivities')) {
-            $this->cache->canviewhiddenactivities = has_capability('moodle/course:viewhiddenactivities', $this->context);
-        }
-        $viewhiddenactivities = $this->cache->canviewhiddenactivities;
-
-        foreach ($modinfo->cms as $module) {
-            if ((!$viewhiddenactivities && !$module->visible) || $module->sectionnum != $section->section) {
-                continue;
-            }
-            $icon = null;
-            if ($module->icon) {
-                $icon = new pix_icon($module->icon, '', $module->iconcomponent);
-            } else {
-                $icon = new pix_icon('icon', '', $module->modname);
-            }
-            $url = new moodle_url('/mod/'.$module->modname.'/view.php', array('id'=>$module->id));
-            $this->add_to_path($keys, $module->id, $module->name, $module->name, navigation_node::TYPE_ACTIVITY, $url, $icon);
-            $child = $this->find_child($module->id, navigation_node::TYPE_ACTIVITY);
-            if ($child != false) {
-                $child->title(get_string('modulename', $module->modname));
-                if (!$module->visible) {
-                    $child->hidden = true;
-                }
-                if ($this->module_extends_navigation($module->modname)) {
-                    $child->nodetype = self::NODETYPE_BRANCH;
-                }
-            }
-        }
-    }
-
-    /**
-     * This function loads any navigation items that might exist for an activity
-     * by looking for and calling a function within the modules lib.php
-     *
-     * @param int $instanceid
-     * @return void
-     */
-    protected function load_activity($instanceid) {
-        global $CFG, $PAGE;
-
-        $this->context = get_context_instance(CONTEXT_COURSE, $PAGE->course->id);
-        $key = $this->add($PAGE->activityname, null, self::TYPE_ACTIVITY, null, $instanceid);
-
-        $file = $CFG->dirroot.'/mod/'.$PAGE->activityname.'/lib.php';
-        $function = $PAGE->activityname.'_extend_navigation';
-
-        if (file_exists($file)) {
-            require_once($file);
-            if (function_exists($function)) {
-                $function($this->get($key), $PAGE->course, $PAGE->activityrecord, $PAGE->cm);
-            }
-        }
-    }
-}
-
-/**
  * Navbar class
  *
  * This class is used to manage the navbar, which is initialised from the navigation
@@ -2223,7 +1569,7 @@
     protected $keys = array();
     /** @var null|string */
     protected $content = null;
-    /** @var page object */
+    /** @var moodle_page object */
     protected $page;
     /** @var bool */
     protected $ignoreactive = false;
@@ -2231,11 +1577,16 @@
     protected $duringinstall = false;
     /** @var bool */
     protected $hasitems = false;
-
+    /** @var array */
+    protected $items;
+    /** @var array */
+    public $children = array();
     /**
      * The almighty constructor
+     *
+     * @param moodle_page $page
      */
-    public function __construct(&$page) {
+    public function __construct(moodle_page $page) {
         global $CFG;
         if (during_initial_install()) {
             $this->duringinstall = true;
@@ -2260,153 +1611,98 @@
         } else if ($this->hasitems !== false) {
             return true;
         }
-        $this->page->navigation->initialise();
+        $this->page->navigation->initialise($this->page);
 
         $activenodefound = ($this->page->navigation->contains_active_node() ||
-                            $this->page->settingsnav->contains_active_node() ||
-                            $this->page->navigation->reiterate_active_nodes(URL_MATCH_BASE) ||
-                            $this->page->settingsnav->reiterate_active_nodes(URL_MATCH_BASE));
+                            $this->page->settingsnav->contains_active_node());
 
-        $outcome = (count($this->page->navbar->children)>0 || (!$this->ignoreactive && $activenodefound));
+        $outcome = (count($this->children)>0 || (!$this->ignoreactive && $activenodefound));
         $this->hasitems = $outcome;
         return $outcome;
     }
 
+    /**
+     * Turn on/off ignore active
+     *
+     * @param bool $setting
+     */
     public function ignore_active($setting=true) {
         $this->ignoreactive = ($setting);
     }
-
     /**
-     * Generate the XHTML content for the navbar and return it
+     * Returns an array of navigation_node's that make up the navbar.
      *
-     * We are lucky in that we can rely on PAGE->navigation for the structure
-     * we simply need to look for the `active` path through the tree. We make this
-     * easier by calling {@link strip_down_to_final_active()}.
-     *
-     * This function should in the future be refactored to work with a copy of the
-     * PAGE->navigation object and strip it down to just this the active nodes using
-     * a function that could be written again navigation_node called something like
-     * strip_inactive_nodes(). I wrote this originally but currently the navigation
-     * object is managed via references.
-     *
-     * @return string XHTML navbar content
+     * @return array
      */
-    public function content() {
-        if ($this->duringinstall) {
-            return '';
-        }
-
+    public function get_items() {
+        $items = array();
         // Make sure that navigation is initialised
         if (!$this->has_items()) {
-            return '';
+            return $items;
         }
+        if ($this->items !== null) {
+            return $this->items;
+        }
 
-        if ($this->content !== null) {
-            return $this->content;
+        if (count($this->children) > 0) {
+            // Add the custom children
+            $items = array_reverse($this->children);
         }
 
-        // For screen readers
-        $output = get_accesshide(get_string('youarehere','access'), 'h2').html_writer::start_tag('ul');
+        $navigationactivenode = $this->page->navigation->find_active_node();
+        $settingsactivenode = $this->page->settingsnav->find_active_node();
 
-        $navigationactive = $this->page->navigation->contains_active_node();
-        $settingsactive = $this->page->settingsnav->contains_active_node();
-
         // Check if navigation contains the active node
         if (!$this->ignoreactive) {
-            if ($navigationactive && $settingsactive) {
+            
+            if ($navigationactivenode && $settingsactivenode) {
                 // Parse a combined navigation tree
-                $output .= $this->parse_branch_to_html($this->page->navigation->children, true, true);
-                $activenode = $this->page->settingsnav->find_active_node();
-                if ($activenode) {
-                    $output .= $this->parse_branch_to_html(array($activenode), false);
+                while ($settingsactivenode && $settingsactivenode->parent !== null) {
+                    if (!$settingsactivenode->mainnavonly) {
+                        $items[] = $settingsactivenode;
                 }
-            } else if ($navigationactive) {
-                // Parse the navigation tree to get the active node
-                $output .= $this->parse_branch_to_html($this->page->navigation->children, true);
-            } else if ($settingsactive) {
-                // Parse the settings navigation to get the active node
-                $output .= $this->parse_branch_to_html($this->page->settingsnav->children, true);
+                    $settingsactivenode = $settingsactivenode->parent;
             }
-        } else {
-            $output .= $this->parse_branch_to_html($this, true);
+                // Removes the first node from the settings (root node) from the list
+                array_pop($items);
+                while ($navigationactivenode && $navigationactivenode->parent !== null) {
+                    if (!$navigationactivenode->mainnavonly) {
+                        $items[] = $navigationactivenode;
         }
-
-        if (!empty($this->children)) {
-            // Add the custom children
-            $output .= $this->parse_branch_to_html($this->children, false, false);
+                    $navigationactivenode = $navigationactivenode->parent;
         }
-
-        $output .= html_writer::end_tag('ul');
-        $this->content = $output;
-        return $output;
+            } else if ($navigationactivenode) {
+                // Parse the navigation tree to get the active node
+                while ($navigationactivenode && $navigationactivenode->parent !== null) {
+                    if (!$navigationactivenode->mainnavonly) {
+                        $items[] = $navigationactivenode;
     }
-    /**
-     * This function converts an array of nodes into XHTML for the navbar
-     *
-     * @param array $navarray
-     * @param bool $firstnode
-     * @return string HTML
-     */
-    protected function parse_branch_to_html($navarray, $firstnode=true, $morecoming=false) {
-        global $CFG;
-        $separator = get_separator();
-        $output = '';
-        if ($firstnode===true) {
-            // If this is the first node add the class first and display the
-            // navbar properties (normally sitename)
-            $output .= html_writer::tag('li', parent::content(true), array('class'=>'first'));
+                    $navigationactivenode = $navigationactivenode->parent;
         }
-        $count = 0;
-        if (!is_array($navarray)) {
-            return $output;
+            } else if ($settingsactivenode) {
+                // Parse the settings navigation to get the active node
+                while ($settingsactivenode && $settingsactivenode->parent !== null) {
+                    if (!$settingsactivenode->mainnavonly) {
+                        $items[] = $settingsactivenode;
         }
-        // Iterate the navarray and display each node
-        while (count($navarray)>0) {
-            // Sanity check make sure we don't display WAY too much information
-            // on the navbar. If we get to 20 items just stop!
-            $count++;
-            if ($count>20) {
-                // Maximum number of nodes in the navigation branch
-                return $output;
+                    $settingsactivenode = $settingsactivenode->parent;
             }
-            $child = false;
-            // Iterate the nodes in navarray and find the active node
-            foreach ($navarray as $tempchild) {
-                if ($tempchild->isactive || $tempchild->contains_active_node()) {
-                    $child = $tempchild;
-                    // We've got the first child we can break out of this foreach
-                    break;
                 }
             }
-            // Check if we found the child
-            if ($child===false || $child->mainnavonly) {
-                // Set navarray to an empty array so that we complete the while
-                $navarray = array();
-            } else {
-                // We found an/the active node, set navarray to it's children so that
-                // we come back through this while with the children of the active node
-                $navarray = $child->children;
-                // If there are not more arrays being processed after this AND this is the last element
-                // then we want to set the action to null so that it is not used
-                if (empty($this->children) && !$morecoming && (!$child->contains_active_node() || ($child->find_active_node()==false || $child->find_active_node()->mainnavonly))) {
-                    $oldaction = $child->action;
-                    $child->action = null;
-                }
-                if ($child->type !== navigation_node::TYPE_CATEGORY || !isset($CFG->navshowcategories) || !empty($CFG->navshowcategories)) {
-                    // Now display the node
-                    $output .= html_writer::tag('li', $separator.' '.$child->content(true));
-                }
-                if (isset($oldaction)) {
-                    $child->action = $oldaction;
-                }
-            }
-        }
 
-        // XHTML
-        return $output;
+        $items[] = new navigation_node(array(
+            'text'=>$this->page->navigation->text,
+            'shorttext'=>$this->page->navigation->shorttext,
+            'key'=>$this->page->navigation->key,
+            'action'=>$this->page->navigation->action
+        ));
+
+        $this->items = array_reverse($items);
+        return $this->items;
     }
+
     /**
-     * Add a new node to the navbar, overrides parent::add
+     * Add a new navigation_node to the navbar, overrides parent::add
      *
      * This function overrides {@link navigation_node::add()} so that we can change
      * the way nodes get added to allow us to simply call add and have the node added to the
@@ -2418,25 +1714,43 @@
      * @param string|int $key
      * @param string $shorttext
      * @param string $icon
-     * @return string|int Identifier for this particular node
+     * @return navigation_node
      */
     public function add($text, $action=null, $type=self::TYPE_CUSTOM, $shorttext=null, $key=null, pix_icon $icon=null) {
-        // Check if there are any keys in the objects keys array
-        if (count($this->keys)===0) {
-            // If there are no keys then we can use the add method
-            $key = parent::add($text, $action, $type, $shorttext, $key, $icon);
-        } else {
-            $key = $this->add_to_path($this->keys, $key, $text, $shorttext, $type, $action, $icon);
+        if ($this->content !== null) {
+            debugging('Nav bar items must be printed before $OUTPUT->header() has been called', DEBUG_DEVELOPER);
         }
-        $this->keys[] = $key;
-        $child = $this->get_by_path($this->keys);
-        if ($child!==false) {
-            // This ensure that the child will be shown
-            $child->make_active();
+        
+        // Properties array used when creating the new navigation node
+        $itemarray = array(
+            'text' => $text,
+            'type' => $type
+        );
+        // Set the action if one was provided
+        if ($action!==null) {
+            $itemarray['action'] = $action;
         }
-        return $key;
+        // Set the shorttext if one was provided
+        if ($shorttext!==null) {
+            $itemarray['shorttext'] = $shorttext;
     }
+        // Set the icon if one was provided
+        if ($icon!==null) {
+            $itemarray['icon'] = $icon;
 }
+        // Default the key to the number of children if not provided
+        if ($key === null) {
+            $key = count($this->children);
+        }
+        // Set the key
+        $itemarray['key'] = $key;
+        // Set the parent to this node
+        $itemarray['parent'] = $this;
+        // Add the child using the navigation_node_collections add method
+        $this->children[] = new navigation_node($itemarray);
+        return $this;
+    }
+}
 
 /**
  * Class used to manage the settings option for the current page
@@ -2452,14 +1766,16 @@
 class settings_navigation extends navigation_node {
     /** @var stdClass */
     protected $context;
-    /** @var cache */
+    /** @var navigation_cache */
     protected $cache;
-    /** @var page object */
+    /** @var moodle_page */
     protected $page;
-    /** @var adminsection string */
+    /** @var string */
     protected $adminsection;
     /**
      * Sets up the object with basic settings and preparse it for use
+     * 
+     * @param moodle_page $page
      */
     public function __construct(moodle_page &$page) {
         if (during_initial_install()) {
@@ -2471,12 +1787,15 @@
         $this->page->navigation->initialise();
         // Initialise the navigation cache
         $this->cache = new navigation_cache(NAVIGATION_CACHE_NAME);
+        $this->children = new navigation_node_collection();
     }
     /**
      * Initialise the settings navigation based on the current context
      *
      * This function initialises the settings navigation tree for a given context
      * by calling supporting functions to generate major parts of the tree.
+     *
+     * @global moodle_database $DB
      */
     public function initialise() {
         global $DB;
@@ -2520,13 +1839,13 @@
                 break;
         }
 
-        $settingskey = $this->load_user_settings($this->page->course->id);
-        $adminkey = $this->load_administration_settings();
+        $settings = $this->load_user_settings($this->page->course->id);
+        $admin = $this->load_administration_settings();
 
-        if ($context->contextlevel == CONTEXT_SYSTEM) {
-            $this->get($adminkey)->forceopen = true;
-        } else if ($context->contextlevel == CONTEXT_USER) {
-            $this->get($settingskey)->forceopen = true;
+        if ($context->contextlevel == CONTEXT_SYSTEM && $admin) {
+            $admin->force_open();
+        } else if ($context->contextlevel == CONTEXT_USER && $settings) {
+            $settings->force_open();
         }
 
         // Check if the user is currently logged in as another user
@@ -2539,12 +1858,13 @@
         }
 
         // Make sure the first child doesnt have proceed with hr set to true
-        reset($this->children);
-        current($this->children)->preceedwithhr = false;
 
-        $this->remove_empty_root_branches();
-        $this->respect_forced_open();
+        foreach ($this->children as $key=>$node) {
+            if ($node->nodetype != self::NODETYPE_BRANCH || $node->children->count()===0) {
+                $node->remove();
     }
+        }
+    }
     /**
      * Override the parent function so that we can add preceeding hr's and set a
      * root node class against all first level element
@@ -2558,13 +1878,12 @@
      * @param string|int $key
      * @param int $type
      * @param string $icon
-     * @return sting|int A key that can be used to reference the newly added node
+     * @return navigation_node
      */
     public function add($text, $url=null, $type=null, $shorttext=null, $key=null, pix_icon $icon=null) {
-        $key = parent::add($text, $url, $type, $shorttext, $key, $icon);
-        $this->get($key)->add_class('root_node');
-        $this->get($key)->preceedwithhr = true;
-        return $key;
+        $node = parent::add($text, $url, $type, $shorttext, $key, $icon);
+        $node->add_class('root_node');
+        return $node;
     }
 
     /**
@@ -2577,28 +1896,25 @@
      * @param string|int $key
      * @param int $type
      * @param string $icon
-     * @return sting|int A key that can be used to reference the newly added node
+     * @return navigation_node
      */
     public function prepend($text, $url=null, $type=null, $shorttext=null, $key=null, pix_icon $icon=null) {
-        $key = $this->add($text, $url, $type, $shorttext, $key, $icon);
         $children = $this->children;
-        $this->children = array();
-        $this->children[$key] = array_pop($children);
-        foreach ($children as $k=>$child) {
-            $this->children[$k] = $child;
-            $this->get($k)->add_class('root_node');
-            $this->get($k)->preceedwithhr = true;
+        $this->children = new get_class($children);
+        $node = $this->add($text, $url, $type, $shorttext, $key, $icon);
+        foreach ($children as $child) {
+            $this->children->add($child);
         }
-        return $key;
+        return $node;
     }
     /**
      * Load the site administration tree
      *
      * This function loads the site administration tree by using the lib/adminlib library functions
      *
-     * @param null|navigation_node $referencebranch A reference to a branch in the settings
+     * @param navigation_node $referencebranch A reference to a branch in the settings
      *      navigation tree
-     * @param null|part_of_admin_tree $adminbranch The branch to add, if null generate the admin
+     * @param part_of_admin_tree $adminbranch The branch to add, if null generate the admin
      *      tree and start at the beginning
      * @return mixed A key to access the admin tree by
      */
@@ -2618,22 +1934,23 @@
 
             // Disable the navigation from automatically finding the active node
             navigation_node::$autofindactive = false;
-            $branchkey = $this->add(get_string('administrationsite'), null, self::TYPE_SETTING, null, 'root');
-            $referencebranch = $this->get($branchkey);
+            $referencebranch = $this->add(get_string('administrationsite'), null, self::TYPE_SETTING, null, 'root');
             foreach ($adminroot->children as $adminbranch) {
                 $this->load_administration_settings($referencebranch, $adminbranch);
             }
             navigation_node::$autofindactive = true;
 
             // Use the admin structure to locate the active page
-            if ($current = $adminroot->locate($this->adminsection, true)) {
-                // Get the active node using the path in the active page
-                if ($child = $this->get_by_path(array_reverse($current->path))) {
-                    // Make the node active!
-                    $child->make_active();
+            if (!$this->contains_active_node() && $current = $adminroot->locate($this->adminsection, true)) {
+                $currentnode = $this;
+                while (($pathkey = array_pop($current->path))!==null && $currentnode) {
+                    $currentnode = $currentnode->get($pathkey);
                 }
+                if ($currentnode) {
+                    $currentnode->make_active();
             }
-            return $branchkey;
+            }
+            return $referencebranch;
         } else if ($adminbranch->check_access()) {
             // We have a reference branch that we can access and is not hidden `hurrah`
             // Now we need to display it and any children it may have
@@ -2646,8 +1963,7 @@
             }
 
             // Add the branch
-            $branchkey = $referencebranch->add($adminbranch->visiblename, $url, self::TYPE_SETTING, null, $adminbranch->name, $icon);
-            $reference = $referencebranch->get($branchkey);
+            $reference = $referencebranch->add($adminbranch->visiblename, $url, self::TYPE_SETTING, null, $adminbranch->name, $icon);
 
             if ($adminbranch->is_hidden()) {
                 if (($adminbranch instanceof admin_externalpage || $adminbranch instanceof admin_settingpage) && $adminbranch->name == $this->adminsection) {
@@ -2674,6 +1990,21 @@
     }
 
     /**
+     * Gets a navigation node given an array of keys that represent the path to
+     * the desired node.
+     *
+     * @param array $path
+     * @return navigation_node|false
+     */
+    protected function get_by_path(array $path) {
+        $node = $this->get(array_shift($path));
+        foreach ($path as $key) {
+            $node->get($key);
+        }
+        return $node;
+    }
+
+    /**
      * Generate the list of modules for the given course.
      *
      * The array of resources and activities that can be added to a course is then
@@ -2739,7 +2070,7 @@
      * This function loads the course settings that are available for the user
      *
      * @param bool $forceopen If set to true the course node will be forced open
-     * @return bool|mixed Either false of a key to access the course tree by
+     * @return navigation_node|false
      */
     protected function load_course_settings($forceopen = false) {
         global $CFG, $USER, $SESSION, $OUTPUT;
@@ -2753,9 +2084,10 @@
             return false;
         }
 
-        $coursenodekey = $this->add(get_string('courseadministration'), null, self::TYPE_COURSE, null, 'courseadmin');
-        $coursenode = $this->get($coursenodekey);
-        $coursenode->forceopen = ($forceopen==true);
+        $coursenode = $this->add(get_string('courseadministration'), null, self::TYPE_COURSE, null, 'courseadmin');
+        if ($forceopen) {
+            $coursenode->force_open();
+        }
 
         if (has_capability('moodle/course:update', $coursecontext)) {
             // Add the turn on/off settings
@@ -2785,11 +2117,11 @@
                 }
                 $sections = $this->cache->{'coursesections'.$course->id};
 
-                $addresource = $this->get($this->add(get_string('addresource')));
-                $addactivity = $this->get($this->add(get_string('addactivity')));
+                $addresource = $this->add(get_string('addresource'));
+                $addactivity = $this->add(get_string('addactivity'));
                 if ($formatidentifier!==0) {
-                    $addresource->forceopen = true;
-                    $addactivity->forceopen = true;
+                    $addresource->force_open();
+                    $addactivity->force_open();
                 }
 
                 if (!$this->cache->cached('course'.$course->id.'resources')) {
@@ -2821,7 +2153,7 @@
                         } else {
                             $url->param('add', $value);
                         }
-                        $addresource->get($sectionresources)->add($resource, $url, self::TYPE_SETTING);
+                        $sectionresources->add($resource, $url, self::TYPE_SETTING);
                     }
                     $subbranch = false;
                     foreach ($activities as $activityname=>$activity) {
@@ -2830,7 +2162,7 @@
                             continue;
                         }
                         if (strpos($activity, '--')===0) {
-                            $subbranch = $addactivity->get($sectionactivities)->add(trim($activity, '-'));
+                            $subbranch = $sectionresources->add(trim($activity, '-'));
                             continue;
                         }
                         $url = new moodle_url('/course/mod.php', array('id'=>$course->id, 'sesskey'=>sesskey(), 'section'=>$section->section));
@@ -2842,9 +2174,9 @@
                             $url->param('add', $activityname);
                         }
                         if ($subbranch !== false) {
-                            $addactivity->get($sectionactivities)->get($subbranch)->add($activity, $url, self::TYPE_SETTING);
+                            $subbranch->add($activity, $url, self::TYPE_SETTING);
                         } else {
-                            $addactivity->get($sectionactivities)->add($activity, $url, self::TYPE_SETTING);
+                            $sectionresources->add($activity, $url, self::TYPE_SETTING);
                         }
                     }
                 }
@@ -2910,8 +2242,8 @@
                 $url = new moodle_url('/course/importstudents.php', array('id'=>$course->id));
                 $coursenode->add(get_string('childcourses'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/course', ''));
             } else if (has_capability('moodle/role:assign', $coursecontext)) {
-                $key = $coursenode->add(get_string('childcourses'), null,  self::TYPE_SETTING, null, null, new pix_icon('i/course', ''));
-                $coursenode->get($key)->hidden = true;;
+                $roleassign = $coursenode->add(get_string('childcourses'), null,  self::TYPE_SETTING, null, null, new pix_icon('i/course', ''));
+                $roleassign->hidden = true;
             }
         }
 
@@ -3008,12 +2340,6 @@
             }
         }
 
-        // Link to the user own profile (except guests)
-        if (!isguestuser() and isloggedin()) {
-            $url = new moodle_url('/user/view.php', array('id'=>$USER->id, 'course'=>$course->id));
-            $coursenode->add(get_string('profile'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/user', ''));
-        }
-
         // Switch roles
         $roles = array();
         $assumedrole = $this->in_alternative_role();
@@ -3032,20 +2358,20 @@
             }
         }
         if (is_array($roles) && count($roles)>0) {
-            $switchroleskey = $this->add(get_string('switchroleto'));
+            $switchroles = $this->add(get_string('switchroleto'));
             if ((count($roles)==1 && array_key_exists(0, $roles))|| $assumedrole!==false) {
-                $this->get($switchroleskey)->forceopen = true;
+                $switchroles->force_open();
             }
             $returnurl = $this->page->url;
             $returnurl->param('sesskey', sesskey());
             $SESSION->returnurl = serialize($returnurl);
             foreach ($roles as $key=>$name) {
                 $url = new moodle_url('/course/switchrole.php', array('id'=>$course->id,'sesskey'=>sesskey(), 'switchrole'=>$key, 'returnurl'=>'1'));
-                $this->get($switchroleskey)->add($name, $url, self::TYPE_SETTING, null, $key, new pix_icon('i/roles', ''));
+                $switchroles->add($name, $url, self::TYPE_SETTING, null, $key, new pix_icon('i/roles', ''));
             }
         }
         // Return we are done
-        return $coursenodekey;
+        return $coursenode;
     }
 
     /**
@@ -3057,7 +2383,7 @@
      *
      * For examples mod/forum/lib.php ::: forum_extend_settings_navigation()
      *
-     * @return void|mixed The key to access the module method by
+     * @return navigation_node|false
      */
     protected function load_module_settings() {
         global $CFG;
@@ -3067,9 +2393,8 @@
             $this->page->set_cm($cm, $this->page->course);
         }
 
-        $modulekey = $this->add(get_string($this->page->activityname.'administration', $this->page->activityname));
-        $modulenode = $this->get($modulekey);
-        $modulenode->forceopen = true;
+        $modulenode = $this->add(get_string($this->page->activityname.'administration', $this->page->activityname));
+        $modulenode->force_open();
 
         // Settings for the module
         if (has_capability('moodle/course:manageactivities', $this->page->cm->context)) {
@@ -3104,17 +2429,17 @@
             require_once($file);
         }
         if (!function_exists($function)) {
-            return $modulekey;
+            return $modulenode;
         }
 
         $function($this, $modulenode);
 
         // Remove the module node if there are no children
         if (empty($modulenode->children)) {
-            $this->remove_child($modulekey);
+            $modulenode->remove();
         }
 
-        return $modulekey;
+        return $modulenode;
     }
 
     /**
@@ -3128,6 +2453,7 @@
      * any bright ideas please feel free to intervene.
      *
      * @param int $courseid The course id of the current course
+     * @return navigation_node|false
      */
     protected function load_user_settings($courseid=SITEID) {
         global $USER, $FULLME, $CFG;
@@ -3141,11 +2467,10 @@
         // and the key depends on the current location
         // Default to look at id
         $userkey='id';
-
         if (strpos($FULLME,'/blog/') || strpos($FULLME, $CFG->admin.'/roles/')) {
             // And blog and roles just do thier own thing using `userid`
             $userkey = 'userid';
-        } else if ($this->context->contextlevel >= CONTEXT_COURSECAT && strpos($FULLME, '/message/')===false && strpos($FULLME, '/mod/forum/user')===false) {
+        } else if ($this->context->contextlevel >= CONTEXT_COURSECAT && strpos($FULLME, '/message/')===false && strpos($FULLME, '/mod/forum/user')===false && strpos($FULLME, '/user/editadvanced')===false) {
             // If we have a course context and we are not in message or forum
             // Message and forum both pick the user up from `id`
             $userkey = 'user';
@@ -3153,12 +2478,12 @@
 
         $userid = optional_param($userkey, $USER->id, PARAM_INT);
         if ($userid!=$USER->id) {
-            $userkey = $this->generate_user_settings($courseid, $userid, 'userviewingsettings');
+            $usernode = $this->generate_user_settings($courseid, $userid, 'userviewingsettings');
             $this->generate_user_settings($courseid, $USER->id);
         } else {
-            $userkey = $this->generate_user_settings($courseid, $USER->id);
+            $usernode = $this->generate_user_settings($courseid, $USER->id);
         }
-        return $userkey;
+        return $usernode;
     }
 
     /**
@@ -3168,7 +2493,7 @@
      * @param int $courseid The current course' id
      * @param int $userid The user id to load for
      * @param string $gstitle The string to pass to get_string for the branch title
-     * @return string|int The key to reference this user's settings
+     * @return navigation_node|false
      */
     protected function generate_user_settings($courseid, $userid, $gstitle='usercurrentsettings') {
         global $DB, $CFG, $USER, $SITE;
@@ -3215,8 +2540,7 @@
         $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $this->page->context));
 
         // Add a user setting branch
-        $usersettingskey = $this->add(get_string($gstitle, 'moodle', $fullname));
-        $usersetting = $this->get($usersettingskey);
+        $usersetting = $this->add(get_string($gstitle, 'moodle', $fullname));
         $usersetting->id = 'usersettings';
 
         // Check if the user has been deleted
@@ -3271,34 +2595,34 @@
 
         // View the roles settings
         if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride','moodle/role:override', 'moodle/role:manage'), $usercontext)) {
-            $roleskey = $usersetting->add(get_string('roles'), null, self::TYPE_SETTING);
+            $roles = $usersetting->add(get_string('roles'), null, self::TYPE_SETTING);
 
             $url = new moodle_url('/admin/roles/usersroles.php', array('userid'=>$user->id, 'courseid'=>$course->id));
-            $usersetting->get($roleskey)->add(get_string('thisusersroles', 'role'), $url, self::TYPE_SETTING);
+            $roles->add(get_string('thisusersroles', 'role'), $url, self::TYPE_SETTING);
 
             $assignableroles = get_assignable_roles($usercontext, ROLENAME_BOTH);
 
             if (!empty($assignableroles)) {
                 $url = new moodle_url('/admin/roles/assign.php', array('contextid'=>$usercontext->id,'userid'=>$user->id, 'courseid'=>$course->id));
-                $usersetting->get($roleskey)->add(get_string('assignrolesrelativetothisuser', 'role'), $url, self::TYPE_SETTING);
+                $roles->add(get_string('assignrolesrelativetothisuser', 'role'), $url, self::TYPE_SETTING);
             }
 
             if (has_capability('moodle/role:review', $usercontext) || count(get_overridable_roles($usercontext, ROLENAME_BOTH))>0) {
                 $url = new moodle_url('/admin/roles/permissions.php', array('contextid'=>$usercontext->id,'userid'=>$user->id, 'courseid'=>$course->id));
-                $usersetting->get($roleskey)->add(get_string('permissions', 'role'), $url, self::TYPE_SETTING);
+                $roles->add(get_string('permissions', 'role'), $url, self::TYPE_SETTING);
             }
 
             $url = new moodle_url('/admin/roles/check.php', array('contextid'=>$usercontext->id,'userid'=>$user->id, 'courseid'=>$course->id));
-            $usersetting->get($roleskey)->add(get_string('checkpermissions', 'role'), $url, self::TYPE_SETTING);
+            $roles->add(get_string('checkpermissions', 'role'), $url, self::TYPE_SETTING);
         }
 
         // Portfolio
         if ($currentuser && !empty($CFG->enableportfolios) && has_capability('moodle/portfolio:export', $systemcontext)) {
             require_once($CFG->libdir . '/portfoliolib.php');
             if (portfolio_instances(true, false)) {
-                $portfoliokey = $usersetting->add(get_string('portfolios', 'portfolio'), null, self::TYPE_SETTING);
-                $usersetting->get($portfoliokey)->add(get_string('configure', 'portfolio'), new moodle_url('/user/portfolio.php'), self::TYPE_SETTING);
-                $usersetting->get($portfoliokey)->add(get_string('logs', 'portfolio'), new moodle_url('/user/portfoliologs.php'), self::TYPE_SETTING);
+                $portfolio = $usersetting->add(get_string('portfolios', 'portfolio'), null, self::TYPE_SETTING);
+                $portfolio->add(get_string('configure', 'portfolio'), new moodle_url('/user/portfolio.php'), self::TYPE_SETTING);
+                $portfolio->add(get_string('logs', 'portfolio'), new moodle_url('/user/portfoliologs.php'), self::TYPE_SETTING);
             }
         }
 
@@ -3324,20 +2648,19 @@
             $usersetting->add(get_string('editmymessage', 'message'), $url, self::TYPE_SETTING);
         }
 
-        return $usersettingskey;
+        return $usersetting;
     }
 
     /**
      * Loads block specific settings in the navigation
      *
-     * @return string The key that can be used to retrieve the navigation node
+     * @return navigation_node
      */
     protected function load_block_settings() {
         global $CFG;
 
-        $blocksettingskey = $this->add(print_context_name($this->context));
-        $blocknode = $this->get($blocksettingskey);
-        $blocknode->forceopen = true;
+        $blocknode = $this->add(print_context_name($this->context));
+        $blocknode->force_open();
 
         // Assign local roles
         $assignurl = new moodle_url('/'.$CFG->admin.'/roles/assign.php', array('contextid'=>$this->context->id));
@@ -3354,20 +2677,19 @@
             $blocknode->add(get_string('checkpermissions', 'role'), $url, self::TYPE_SETTING);
         }
 
-        return $blocksettingskey;
+        return $blocknode;
     }
 
     /**
      * Loads category specific settings in the navigation
      *
-     * @return string
+     * @return navigation_node
      */
     protected function load_category_settings() {
         global $CFG;
 
-        $blocksettingskey = $this->add(print_context_name($this->context));
-        $blocknode = $this->get($blocksettingskey);
-        $blocknode->forceopen = true;
+        $blocknode = $this->add(print_context_name($this->context));
+        $blocknode->force_open();
 
         if ($this->page->user_is_editing() && has_capability('moodle/category:manage', $this->context)) {
             $blocknode->add(get_string('editcategorythis'), new moodle_url('/course/editcategory.php', array('id' => $this->context->instanceid)));
@@ -3389,7 +2711,7 @@
             $blocknode->add(get_string('checkpermissions', 'role'), $url, self::TYPE_SETTING);
         }
 
-        return $blocksettingskey;
+        return $blocknode;
     }
 
     /**
@@ -3420,6 +2742,7 @@
     /**
      * This function loads all of the front page settings into the settings navigation.
      * This function is called when the user is on the front page, or $COURSE==$SITE
+     * @return navigation_node
      */
     protected function load_front_page_settings($forceopen = false) {
         global $SITE, $CFG;
@@ -3427,9 +2750,10 @@
         $course = clone($SITE);
         $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);   // Course context
 
-        $frontpagekey = $this->add(get_string('frontpagesettings'), null, self::TYPE_SETTING, null, 'frontpage');
-        $frontpage = $this->get($frontpagekey);
-        $frontpage->forceopen = $forceopen;
+        $frontpage = $this->add(get_string('frontpagesettings'), null, self::TYPE_SETTING, null, 'frontpage');
+        if ($forceopen) {
+            $frontpage->force_open();
+        }
         $frontpage->id = 'frontpagesettings';
 
         if (has_capability('moodle/course:update', $coursecontext)) {
@@ -3513,20 +2837,10 @@
             $url = new moodle_url('/files/index.php', array('id'=>$course->id));
             $frontpage->add(get_string('files'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/files', ''));
         }
+        return $frontpage;
     }
 
     /**
-     * This function removes all root branches that have no children
-     */
-    public function remove_empty_root_branches() {
-        foreach ($this->children as $key=>$node) {
-            if ($node->nodetype != self::NODETYPE_BRANCH || count($node->children)===0) {
-                $this->remove_child($key);
-            }
-        }
-    }
-
-    /**
      * This function marks the cache as volatile so it is cleared during shutdown
      */
     public function clear_cache() {
@@ -3547,8 +2861,6 @@
     protected $nodetype = array('node','branch');
     /** @var array */
     protected $expandable = array();
-    /** @var int */
-    protected $expansionceiling = array();
     /**
      * Turns a branch and all of its children into XML
      *
@@ -3562,6 +2874,7 @@
     /**
      * Set the expandable items in the array so that we have enough information
      * to attach AJAX events
+     * @param array $expandable
      */
     public function set_expandable($expandable) {
         foreach ($expandable as $node) {
@@ -3569,19 +2882,11 @@
         }
     }
     /**
-     * Sets the upper limit for expandable nodes. Any nodes that are of the specified
-     * type or larger will not be expandable
-     *
-     * @param int $expansionceiling One of navigation_node::TYPE_*
-     */
-    public function set_expansionceiling($expansionceiling) {
-        $tihs->expansionceiling = $expansionceiling;
-    }
-    /**
      * Recusively converts a child node and its children to XML for output
      *
      * @param navigation_node $child The child to convert
      * @param int $depth Pointlessly used to track the depth of the XML structure
+     * @return string JSON
      */
     protected function convert_child($child, $depth=1) {
         global $OUTPUT;
@@ -3619,8 +2924,6 @@
         if (array_key_exists((string)$child->key, $this->expandable)) {
             $attributes['expandable'] = $child->key;
             $child->add_class($this->expandable[$child->key]['id']);
-        } else if ($child->type >= $this->expansionceiling) {
-            $attributes['expansionceiling'] = $child->key;
         }
 
         if (count($child->classes)>0) {
@@ -3632,7 +2935,7 @@
             $attributes['link'] = $child->action->out();
         }
         $attributes['hidden'] = ($child->hidden);
-        $attributes['haschildren'] = (count($child->children)>0 || $child->type == navigation_node::TYPE_CATEGORY);
+        $attributes['haschildren'] = ($child->children->count()>0 || $child->type == navigation_node::TYPE_CATEGORY);
 
         if (count($child->children)>0) {
             $attributes['children'] = array();
Index: moodle/lib/outputrenderers.php
--- moodle/lib/outputrenderers.php Base (1.179)
+++ moodle/lib/outputrenderers.php Locally Modified (Based On 1.179)
@@ -1990,7 +1990,7 @@
             // 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)) {
+            if (!$item->forceopen || (!$item->forceopen && $item->collapse) || ($item->children->count()==0  && $item->nodetype==navigation_node::NODETYPE_BRANCH)) {
                 $liclasses[] = 'collapsed';
             }
             if ($item->isactive === true) {
@@ -1999,7 +1999,7 @@
             $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) {
+            if ($item->children->count()>0  || $item->nodetype==navigation_node::NODETYPE_BRANCH) {
                 $divclasses[] = 'branch';
             } else {
                 $divclasses[] = 'leaf';
@@ -2026,9 +2026,65 @@
      * @return string XHTML navbar
      */
     public function navbar() {
-        return $this->page->navbar->content();
+        //return $this->page->navbar->content();
+
+        $items = $this->page->navbar->get_items();
+
+        $count = 0;
+
+        $htmlblocks = array();
+        // Iterate the navarray and display each node
+        foreach ($items as $item) {
+            $htmlblocks[] = html_writer::tag('li', $this->render($item));
     }
 
+        // XHTML
+        return join(get_separator(), $htmlblocks);
+    }
+
+    protected function render_navigation_node(navigation_node $item) {
+        $content = $item->get_content();
+        $title = $item->get_title();
+        if ($item->icon instanceof renderable) {
+            $icon = $this->render($item->icon);
+            $content = $icon.'&nbsp;'.$content; // use CSS for spacing of icons
+        }
+        if ($item->helpbutton !== null) {
+            $content = trim($item->helpbutton).html_writer::tag('span', $content, array('class'=>'clearhelpbutton'));
+        }
+        if ($content === '') {
+            continue;
+        }
+        if ($item->action instanceof action_link) {
+            //TODO: to be replaced with something else
+            $link = $item->action;
+            if ($item->hidden) {
+                $link->add_class('dimmed');
+            }
+            $content = $this->output->render($link);
+        } else if ($item->action instanceof moodle_url) {
+            $attributes = array();
+            if ($title !== '') {
+                $attributes['title'] = $title;
+            }
+            if ($item->hidden) {
+                $attributes['class'] = 'dimmed_text';
+            }
+            $content = html_writer::link($item->action, $content, $attributes);
+
+        } else if (is_string($item->action) || empty($item->action)) {
+            $attributes = array();
+            if ($title !== '') {
+                $attributes['title'] = $title;
+            }
+            if ($item->hidden) {
+                $attributes['class'] = 'dimmed_text';
+            }
+            $content = html_writer::tag('span', $content, $attributes);
+        }
+        return $content;
+    }
+
     /**
      * Accessibility: Right arrow-like character is
      * used in the breadcrumb trail, course navigation menu
Index: moodle/lib/outputrequirementslib.php
--- moodle/lib/outputrequirementslib.php Base (1.22)
+++ moodle/lib/outputrequirementslib.php Locally Modified (Based On 1.22)
@@ -379,7 +379,8 @@
                 case 'core_dock':
                     $module = array('name'     => 'core_dock',
                                     'fullpath' => '/blocks/dock.js',
-                                    'requires' => array('base', 'cookie', 'dom', 'io', 'node', 'event-custom', 'event-mouseenter', 'yui2-container'));
+                                    'requires' => array('base', 'cookie', 'dom', 'io', 'node', 'event-custom', 'event-mouseenter', 'yui2-container'),
+                                    'strings' => array(array('addtodock', 'block'),array('undockitem', 'block'),array('undockall', 'block')));
                     break;
                 case 'core_calendar':
                     $module = array('name'     => 'core_calendar',
Index: moodle/lib/pagelib.php
--- moodle/lib/pagelib.php Base (1.176)
+++ moodle/lib/pagelib.php Locally Modified (Based On 1.176)
@@ -171,7 +171,7 @@
     protected $_button = '';
 
     protected $_theme = null;
-    /** @var null|global_navigation Contains the global navigation structure*/
+    /** @var global_navigation Contains the global navigation structure*/
     protected $_navigation = null;
     /** @var null|settings_navigation Contains the settings navigation structure*/
     protected $_settingsnav = null;
@@ -520,7 +520,7 @@
      */
     protected function magic_get_navigation() {
         if ($this->_navigation === null) {
-            $this->_navigation = new global_navigation();
+            $this->_navigation = new global_navigation($this);
         }
         return $this->_navigation;
     }
Index: moodle/mod/assignment/type/online/assignment.class.php
--- moodle/mod/assignment/type/online/assignment.class.php Base (1.88)
+++ moodle/mod/assignment/type/online/assignment.class.php Locally Modified (Based On 1.88)
@@ -348,13 +348,13 @@
             $node->add(get_string('viewmysubmission', 'assignment'), $link, navigation_node::TYPE_SETTING);
 
             if (!empty($submission->timemodified)) {
-                $key = $node->add(get_string('submitted', 'assignment') . ' ' . userdate($submission->timemodified));
-                $node->get($key)->text = preg_replace('#([^,])\s#', '$1&nbsp;', $node->get($key)->text);
-                $node->get($key)->add_class('note');
+                $submittednode = $node->add(get_string('submitted', 'assignment') . ' ' . userdate($submission->timemodified));
+                $submittednode->text = preg_replace('#([^,])\s#', '$1&nbsp;', $submittednode->text);
+                $submittednode->add_class('note');
                 if ($submission->timemodified <= $this->assignment->timedue || empty($this->assignment->timedue)) {
-                    $node->get($key)->add_class('early');
+                    $submittednode->add_class('early');
                 } else {
-                    $node->get($key)->add_class('late');
+                    $submittednode->add_class('late');
                 }
             }
         }
Index: moodle/mod/assignment/type/upload/assignment.class.php
--- moodle/mod/assignment/type/upload/assignment.class.php Base (1.97)
+++ moodle/mod/assignment/type/upload/assignment.class.php Locally Modified (Based On 1.97)
@@ -1084,13 +1084,13 @@
             $link = new moodle_url('/mod/assignment/view.php', array('id'=>$this->cm->id));
             $node->add(get_string('viewmysubmission', 'assignment'), $link, navigation_node::TYPE_SETTING);
             if (!empty($submission->timemodified)) {
-                $key = $node->add(get_string('submitted', 'assignment') . ' ' . userdate($submission->timemodified));
-                $node->get($key)->text = preg_replace('#([^,])\s#', '$1&nbsp;', $node->get($key)->text);
-                $node->get($key)->add_class('note');
+                $submittednode = $node->add(get_string('submitted', 'assignment') . ' ' . userdate($submission->timemodified));
+                $submittednode->text = preg_replace('#([^,])\s#', '$1&nbsp;', $submittednode->text);
+                $submittednode->add_class('note');
                 if ($submission->timemodified <= $this->assignment->timedue || empty($this->assignment->timedue)) {
-                    $node->get($key)->add_class('early');
+                    $submittednode->add_class('early');
                 } else {
-                    $node->get($key)->add_class('late');
+                    $submittednode->add_class('late');
                 }
             }
         }
@@ -1100,15 +1100,15 @@
             $fs = get_file_storage();
             if ($files = $fs->get_area_files($this->context->id, 'assignment_submission', $USER->id, "timemodified", false)) {
                 if (!$this->drafts_tracked() or !$this->isopen() or $this->is_finalized($submission)) {
-                    $filekey = $node->add(get_string('submission', 'assignment'));
+                    $filenode = $node->add(get_string('submission', 'assignment'));
                 } else {
-                    $filekey = $node->add(get_string('submissiondraft', 'assignment'));
+                    $filenode = $node->add(get_string('submissiondraft', 'assignment'));
                 }
                 foreach ($files as $file) {
                     $filename = $file->get_filename();
                     $mimetype = $file->get_mimetype();
                     $link = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.$this->context->id.'/assignment_submission/'.$USER->id.'/'.$filename);
-                    $node->get($filekey)->add($filename, $link, navigation_node::TYPE_SETTING, null, null, new pix_icon(file_mimetype_icon($mimetype),''));
+                    $filenode->add($filename, $link, navigation_node::TYPE_SETTING, null, null, new pix_icon(file_mimetype_icon($mimetype),''));
                 }
             }
         }
Index: moodle/mod/assignment/type/uploadsingle/assignment.class.php
--- moodle/mod/assignment/type/uploadsingle/assignment.class.php Base (1.55)
+++ moodle/mod/assignment/type/uploadsingle/assignment.class.php Locally Modified (Based On 1.55)
@@ -204,13 +204,13 @@
             $link = new moodle_url('/mod/assignment/view.php', array('id'=>$this->cm->id));
             $node->add(get_string('viewmysubmission', 'assignment'), $link, navigation_node::TYPE_SETTING);
             if (!empty($submission->timemodified)) {
-                $key = $node->add(get_string('submitted', 'assignment') . ' ' . userdate($submission->timemodified));
-                $node->get($key)->text = preg_replace('#([^,])\s#', '$1&nbsp;', $node->get($key)->text);
-                $node->get($key)->add_class('note');
+                $submissionnode = $node->add(get_string('submitted', 'assignment') . ' ' . userdate($submission->timemodified));
+                $submissionnode->text = preg_replace('#([^,])\s#', '$1&nbsp;', $submissionnode->text);
+                $submissionnode->add_class('note');
                 if ($submission->timemodified <= $this->assignment->timedue || empty($this->assignment->timedue)) {
-                    $node->get($key)->add_class('early');
+                    $submissionnode->add_class('early');
                 } else {
-                    $node->get($key)->add_class('late');
+                    $submissionnode->add_class('late');
                 }
             }
         }
@@ -219,12 +219,12 @@
         if ($submission && has_capability('mod/assignment:submit', $this->context) && $this->count_user_files($USER->id)) {
             $fs = get_file_storage();
             if ($files = $fs->get_area_files($this->context->id, 'assignment_submission', $USER->id, "timemodified", false)) {
-                $filekey = $node->add(get_string('submission', 'assignment'));
+                $filenode = $node->add(get_string('submission', 'assignment'));
                 foreach ($files as $file) {
                     $filename = $file->get_filename();
                     $mimetype = $file->get_mimetype();
                     $link = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.$this->context->id.'/assignment_submission/'.$USER->id.'/'.$filename);
-                    $node->get($filekey)->add($filename, $link, navigation_node::TYPE_SETTING, null, null, new pix_icon(file_mimetype_icon($mimetype), ''));
+                    $filenode->add($filename, $link, navigation_node::TYPE_SETTING, null, null, new pix_icon(file_mimetype_icon($mimetype), ''));
                 }
             }
         }
Index: moodle/mod/chat/lib.php
--- moodle/mod/chat/lib.php Base (1.166)
+++ moodle/mod/chat/lib.php Locally Modified (Based On 1.166)
@@ -1274,8 +1274,7 @@
 
     $chatusers = chat_get_users($cm->instance, $currentgroup, $cm->groupingid);
     if (is_array($chatusers) && count($chatusers)>0) {
-        $userskey = $navigation->add(get_string('currentusers', 'chat'));
-        $users = $navigation->get($userskey);
+        $users = $navigation->add(get_string('currentusers', 'chat'));
         foreach ($chatusers as $chatuser) {
             $userlink = new moodle_url('/user/view.php', array('id'=>$chatuser->id,'course'=>$course->id));
             $users->add(fullname($chatuser).' '.format_time(time() - $chatuser->lastmessageping), $userlink, navigation_node::TYPE_USER, null, null, new pix_icon('c/user', ''));
@@ -1294,8 +1293,8 @@
     $chat = $DB->get_record("chat", array("id" => $PAGE->cm->instance));
 
     if ($chat->chattime && $chat->schedule) {
-        $key = $chatnode->add(get_string('nextsession', 'chat').': '.userdate($chat->chattime).' ('.usertimezone($USER->timezone));
-        $chatnode->get($key)->add_class('note');
+        $nextsessionnode = $chatnode->add(get_string('nextsession', 'chat').': '.userdate($chat->chattime).' ('.usertimezone($USER->timezone));
+        $nextsessionnode->add_class('note');
     }
 
     $currentgroup = groups_get_activity_group($PAGE->cm, true);
Index: moodle/mod/choice/lib.php
--- moodle/mod/choice/lib.php Base (1.124)
+++ moodle/mod/choice/lib.php Locally Modified (Based On 1.124)
Index: moodle/mod/data/lib.php
--- moodle/mod/data/lib.php Base (1.270)
+++ moodle/mod/data/lib.php Locally Modified (Based On 1.270)
@@ -2848,8 +2848,8 @@
     /// Check the number of entries required against the number of entries already made (doesn't apply to teachers)
     if ($data->requiredentries > 0 && $numentries < $data->requiredentries && !has_capability('mod/data:manageentries', get_context_instance(CONTEXT_MODULE, $cm->id))) {
         $data->entriesleft = $data->requiredentries - $numentries;
-        $key = $navigation->add(get_string('entrieslefttoadd', 'data', $data));
-        $navigation->get($key)->add_class('note');
+        $entriesnode = $navigation->add(get_string('entrieslefttoadd', 'data', $data));
+        $entriesnode->add_class('note');
     }
 
     $navigation->add(get_string('list', 'data'), new moodle_url('/mod/data/view.php', array('d'=>$cm->instance)));
@@ -2904,8 +2904,7 @@
             $defaultemplate = 'singletemplate';
         }
 
-        $templatekey = $datanode->add(get_string('templates', 'data'));
-        $templates = $datanode->get($templatekey);
+        $templates = $datanode->add(get_string('templates', 'data'));
 
         $templatelist = array ('listtemplate', 'singletemplate', 'asearchtemplate', 'addtemplate', 'rsstemplate', 'csstemplate', 'jstemplate');
         foreach ($templatelist as $template) {
Index: moodle/mod/feedback/lib.php
--- moodle/mod/feedback/lib.php Base (1.66)
+++ moodle/mod/feedback/lib.php Locally Modified (Based On 1.66)
@@ -2277,19 +2277,15 @@
             print_error('badcontext');
     }
 
-    // $capabilities = feedback_load_capabilities($PAGE->cm->id);
-
-    // if($capabilities->edititems) {
-    if(has_capability('mod/feedback:edititems', $context)) {
-        $qkey = $feedbacknode->add(get_string('questions', 'feedback'));
-        $feedbacknode->get($qkey)->add(get_string('edit_items', 'feedback'), new moodle_url('/mod/feedback/edit.php', array('id'=>$PAGE->cm->id, 'do_show'=>'edit')));
-        $feedbacknode->get($qkey)->add(get_string('export_questions', 'feedback'), new moodle_url('/mod/feedback/export.php', array('id'=>$PAGE->cm->id, 'action'=>'exportfile')));
-        $feedbacknode->get($qkey)->add(get_string('import_questions', 'feedback'), new moodle_url('/mod/feedback/import.php', array('id'=>$PAGE->cm->id)));
-        $feedbacknode->get($qkey)->add(get_string('templates', 'feedback'), new moodle_url('/mod/feedback/edit.php', array('id'=>$PAGE->cm->id, 'do_show'=>'templates')));
+    if (has_capability('mod/feedback:edititems', $context)) {
+        $questionnode = $feedbacknode->add(get_string('questions', 'feedback'));
+        $questionnode->add(get_string('edit_items', 'feedback'), new moodle_url('/mod/feedback/edit.php', array('id'=>$PAGE->cm->id, 'do_show'=>'edit')));
+        $questionnode->add(get_string('export_questions', 'feedback'), new moodle_url('/mod/feedback/export.php', array('id'=>$PAGE->cm->id, 'action'=>'exportfile')));
+        $questionnode->add(get_string('import_questions', 'feedback'), new moodle_url('/mod/feedback/import.php', array('id'=>$PAGE->cm->id)));
+        $questionnode->add(get_string('templates', 'feedback'), new moodle_url('/mod/feedback/edit.php', array('id'=>$PAGE->cm->id, 'do_show'=>'templates')));
     }
 
-    // if($capabilities->viewreports) {
-    if(has_capability('mod/feedback:viewreports', $context)) {
+    if (has_capability('mod/feedback:viewreports', $context)) {
         $feedback = $DB->get_record('feedback', array('id'=>$PAGE->cm->instance));
         if($feedback->course == SITEID){
             $feedbacknode->add(get_string('analysis', 'feedback'), new moodle_url('/mod/feedback/analysis_course.php', array('id'=>$PAGE->cm->id, 'course'=>$PAGE->course->id,'do_show'=>'analysis')));
Index: moodle/mod/forum/lib.php
--- moodle/mod/forum/lib.php Base (1.858)
+++ moodle/mod/forum/lib.php Locally Modified (Based On 1.858)
@@ -7973,13 +7973,13 @@
     if (!is_array($discussions) || count($discussions)==0) {
         return;
     }
-    $discussionkey = $navref->add(get_string('discussions', 'forum').' ('.$discussioncount.')');
-    $navref->get($discussionkey)->mainnavonly = true;
+    $discussionnode = $navref->add(get_string('discussions', 'forum').' ('.$discussioncount.')');
+    $discussionnode->mainnavonly = true;
 
     foreach ($discussions as $discussion) {
         $icon = new pix_icon('i/feedback', '');
         $url = new moodle_url('/mod/forum/discuss.php', array('d'=>$discussion->discussion));
-        $navref->get($discussionkey)->add($discussion->subject, $url, navigation_node::TYPE_SETTING, null, null, $icon);
+        $discussionnode->add($discussion->subject, $url, navigation_node::TYPE_SETTING, null, null, $icon);
     }
 
     if ($discussioncount > count($discussions)) {
@@ -7988,7 +7988,7 @@
         } else {
             $url = new moodle_url('/mod/forum/view.php', array('id'=>$cm->id));
         }
-        $childkey = $navref->get($discussionkey)->add(get_string('viewalldiscussions', 'forum'), $url, navigation_node::TYPE_SETTING, null, null, $icon);
+        $discussionnode->add(get_string('viewalldiscussions', 'forum'), $url, navigation_node::TYPE_SETTING, null, null, $icon);
     }
 
     $index = 0;
@@ -8002,13 +8002,13 @@
     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;
+        $recentnode = $navref->add(get_string('recentactivity').' ('.count($recentposts).')');
+        $recentnode->mainnavonly = true;
         foreach ($recentposts as $post) {
             $icon = new pix_icon('i/feedback', '');
             $url = new moodle_url('/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, $url, navigation_node::TYPE_SETTING, null, null, $icon);
+            $recentnode->add($title, $url, navigation_node::TYPE_SETTING, null, null, $icon);
         }
     }
 }
@@ -8027,10 +8027,10 @@
         $PAGE->cm->context = get_context_instance(CONTEXT_MODULE, $PAGE->cm->instance);
     }
     if (is_enrolled($PAGE->cm->context)) { // means enrolled users only
-        $notekey = false;
+        $notenode = false;
         $helpbutton = false;
         if (forum_is_forcesubscribed($forumobject)) {
-            $notekey = $forumnode->add(get_string("forcessubscribe", 'forum'));
+            $notenode = $forumnode->add(get_string("forcessubscribe", 'forum'));
             $string = get_string('allowchoice', 'forum');
             $helpbutton = $OUTPUT->old_help_icon("subscription", $string, "forum");
             if (has_capability('mod/forum:managesubscriptions', $PAGE->cm->context)) {
@@ -8041,11 +8041,11 @@
             }
         } else if ($forumobject->forcesubscribe == FORUM_DISALLOWSUBSCRIBE) {
             $string = get_string('disallowsubscribe', 'forum');
-            $notekey = $forumnode->add($string);
+            $notenode = $forumnode->add($string);
             $helpbutton = $OUTPUT->old_help_icon("subscription", $string, "forum");
         } else {
             $string = get_string("forcesubscribe", "forum");
-            $notekey = $forumnode->add(get_string("allowsallsubscribe", 'forum'));
+            $notenode = $forumnode->add(get_string("allowsallsubscribe", 'forum'));
             $helpbutton = $OUTPUT->old_help_icon("subscription", $string, "forum");
 
             if (has_capability('mod/forum:managesubscriptions', $PAGE->cm->context)) {
@@ -8081,10 +8081,10 @@
             $url = new moodle_url('/mod/forum/settracking.php', array('id'=>$forumobject->id));
             $forumnode->add($linktext, $url, navigation_node::TYPE_SETTING);
         }
-        if ($notekey!==false) {
-            $forumnode->get($notekey)->add_class('note');
+        if ($notenode!==false) {
+            $notenode->add_class('note');
             if ($helpbutton!==false) {
-                $forumnode->get($notekey)->helpbutton = $helpbutton;
+                $notenode->helpbutton = $helpbutton;
             }
         }
         }
Index: moodle/mod/glossary/lib.php
--- moodle/mod/glossary/lib.php Base (1.290)
+++ moodle/mod/glossary/lib.php Locally Modified (Based On 1.290)
Index: moodle/mod/lesson/lib.php
--- moodle/mod/lesson/lib.php Base (1.87)
+++ moodle/mod/lesson/lib.php Locally Modified (Based On 1.87)
@@ -804,19 +804,19 @@
     $canedit = has_capability('mod/lesson:edit', $PAGE->cm->context);
 
     $url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id));
-    $key = $lessonnode->add(get_string('preview', 'lesson'), $url);
+    $lessonnode->add(get_string('preview', 'lesson'), $url);
 
     if ($canedit) {
         $url = new moodle_url('/mod/lesson/edit.php', array('id'=>$PAGE->cm->id));
-        $key = $lessonnode->add(get_string('edit', 'lesson'), $url);
+        $lessonnode->add(get_string('edit', 'lesson'), $url);
     }
 
     if (has_capability('mod/lesson:manage', $PAGE->cm->context)) {
-        $key = $lessonnode->add(get_string('reports', 'lesson'));
+        $reportsnode = $lessonnode->add(get_string('reports', 'lesson'));
         $url = new moodle_url('/mod/lesson/report.php', array('id'=>$PAGE->cm->id, 'action'=>'reportoverview'));
-        $lessonnode->get($key)->add(get_string('overview', 'lesson'), $url);
+        $reportsnode->add(get_string('overview', 'lesson'), $url);
         $url = new moodle_url('/mod/lesson/report.php', array('id'=>$PAGE->cm->id, 'action'=>'reportdetail'));
-        $lessonnode->get($key)->add(get_string('detailedstats', 'lesson'), $url);
+        $reportsnode->add(get_string('detailedstats', 'lesson'), $url);
     }
 
     if ($canedit) {
Index: moodle/mod/quiz/lib.php
--- moodle/mod/quiz/lib.php Base (1.358)
+++ moodle/mod/quiz/lib.php Locally Modified (Based On 1.358)
@@ -1625,13 +1625,13 @@
     }
     if (has_capability('mod/quiz:viewreports', $PAGE->cm->context)) {
         $url = new moodle_url('/mod/quiz/report.php', array('q'=>$PAGE->cm->instance));
-        $reportkey = $quiznode->add(get_string('results', 'quiz'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/report', ''));
+        $reportnode = $quiznode->add(get_string('results', 'quiz'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/report', ''));
 
         require_once($CFG->dirroot.'/mod/quiz/report/reportlib.php');
         $reportlist = quiz_report_list($PAGE->cm->context);
         foreach ($reportlist as $report) {
             $url = new moodle_url('/mod/quiz/report.php', array('q'=>$PAGE->cm->instance, 'mode'=>$report));
-            $quiznode->get($reportkey)->add(get_string($report, 'quiz_'.$report), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/item', ''));
+            $reportnode->add(get_string($report, 'quiz_'.$report), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/item', ''));
         }
     }
     if (has_capability('mod/quiz:preview', $PAGE->cm->context)) {
Index: moodle/mod/survey/lib.php
--- moodle/mod/survey/lib.php Base (1.91)
+++ moodle/mod/survey/lib.php Locally Modified (Based On 1.91)
@@ -825,19 +825,19 @@
     global $PAGE;
 
     if (has_capability('mod/survey:readresponses', $PAGE->cm->context)) {
-        $key = $surveynode->add(get_string("responsereports", "survey"));
+        $responsesnode = $surveynode->add(get_string("responsereports", "survey"));
 
         $url = new moodle_url('/mod/survey/report.php', array('id' => $PAGE->cm->id, 'action'=>'summary'));
-        $surveynode->get($key)->add(get_string("summary", "survey"), $url);
+        $responsesnode->add(get_string("summary", "survey"), $url);
 
         $url = new moodle_url('/mod/survey/report.php', array('id' => $PAGE->cm->id, 'action'=>'scales'));
-        $surveynode->get($key)->add(get_string("scales", "survey"), $url);
+        $responsesnode->add(get_string("scales", "survey"), $url);
 
         $url = new moodle_url('/mod/survey/report.php', array('id' => $PAGE->cm->id, 'action'=>'questions'));
-        $surveynode->get($key)->add(get_string("question", "survey"), $url);
+        $responsesnode->add(get_string("question", "survey"), $url);
 
         $url = new moodle_url('/mod/survey/report.php', array('id' => $PAGE->cm->id, 'action'=>'students'));
-        $surveynode->get($key)->add(get_string('participants'), $url);
+        $responsesnode->add(get_string('participants'), $url);
 
         if (has_capability('mod/survey:download', $PAGE->cm->context)) {
             $url = new moodle_url('/mod/survey/report.php', array('id' => $PAGE->cm->id, 'action'=>'download'));
Index: moodle/mod/workshop/lib.php
--- moodle/mod/workshop/lib.php Base (1.144)
+++ moodle/mod/workshop/lib.php Locally Modified (Based On 1.144)
@@ -676,8 +676,8 @@
 
     if (has_capability('mod/workshop:submit', get_context_instance(CONTEXT_MODULE, $cm->id))) {
         $url = new moodle_url('/mod/workshop/submission.php', array('cmid' => $cm->id));
-        $mysubmissionkey = $navref->add(get_string('mysubmission', 'workshop'), $url);
-        $navref->get($mysubmissionkey)->mainnavonly = true;
+        $mysubmission = $navref->add(get_string('mysubmission', 'workshop'), $url);
+        $mysubmission->mainnavonly = true;
     }
 }
 
Index: moodle/my/index.php
--- moodle/my/index.php Base (1.46)
+++ moodle/my/index.php Locally Modified (Based On 1.46)
@@ -41,7 +41,6 @@
     $button = $OUTPUT->single_button($url, $string);
 
     $header = $SITE->shortname . ': ' . $strmymoodle;
-    $PAGE->navbar->add($strmymoodle);
 
     $PAGE->set_title($strmymoodle);
     $PAGE->set_heading($header);
Index: moodle/notes/index.php
--- moodle/notes/index.php Base (1.21)
+++ moodle/notes/index.php Locally Modified (Based On 1.21)
@@ -22,12 +22,6 @@
 if ($userid !== 0) {
     $url->param('user', $userid);
 }
-if ($filtertype !== '') {
-    $url->param('filtertype', $filtertype);
-}
-if ($filterselect !== 0) {
-    $url->param('filterselect', $filterselect);
-}
 $PAGE->set_url($url);
 
 /// tabs compatibility
@@ -41,15 +35,11 @@
 }
 
 /// locate course information
-if (!$course = $DB->get_record('course', array('id'=>$courseid))) {
-    print_error('invalidcourseid');
-}
+$course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
 
 /// locate user information
 if ($userid) {
-    if (!$user = $DB->get_record('user', array('id'=>$userid))) {
-        print_error('invaliduserid');
-    }
+    $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
     $filtertype = 'user';
     $filterselect = $user->id;
 
@@ -82,16 +72,19 @@
 $systemcontext = get_context_instance(CONTEXT_SYSTEM);   // SYSTEM context
 
 $strnotes = get_string('notes', 'notes');
+if ($userid) {
+    $PAGE->set_context(get_context_instance(CONTEXT_USER, $user->id));
+    $PAGE->navigation->extend_for_user($user);
+} else {
 $link = null;
 if (has_capability('moodle/course:viewparticipants', $coursecontext) || has_capability('moodle/site:viewparticipants', $systemcontext)) {
     $link = new moodle_url('/user/index.php',array('id'=>$course->id));
 }
-if ($userid) {
-    $PAGE->navigation->extend_for_user($user);
-} else {
     $PAGE->navbar->add(get_string('participants'), $link);
     $PAGE->navbar->add($strnotes);
 }
+
+$PAGE->set_pagelayout('course');
 $PAGE->set_title($course->shortname . ': ' . $strnotes);
 $PAGE->set_heading($course->fullname);
 
Index: moodle/theme/standard/style/dock.css
--- moodle/theme/standard/style/dock.css Base (1.1)
+++ moodle/theme/standard/style/dock.css Locally Modified (Based On 1.1)
@@ -13,6 +13,10 @@
 .dock .controls img {cursor:pointer;}
 .dock .bd.oversized_content {overflow-y:auto;overflow-x:visible;height:inherit;}
 .dock .bd.oversized_content .content {margin:6px 6px 6px 0px;padding-bottom:6px;}
+.dock .yui-panel .hd {text-align:right;border-width:0 0 1px 0;padding:3px 5px;}
+.dock .yui-panel .hd .commands img {margin-right:2px;}
+
+/**.dock .bd .content .sideblockcommands {text-align:right;border:1px solid #AAA;border-width:0 0 1px 1px;background-image:url([[pix:theme|hgradient]]);background-repeat: repeat-x;}**/
 /** YUI overrides **/
 .yui-skin-sam .dock .yui-panel {border-width:1px 2px 1px 1px;border-color:#AAA;min-width:150px;}
 .yui-skin-sam .dock .yui-panel .bd {border-width:0;background-color:#FAFAFA;}
Index: moodle/user/editadvanced.php
--- moodle/user/editadvanced.php Base (1.69)
+++ moodle/user/editadvanced.php Locally Modified (Based On 1.69)
@@ -41,14 +41,14 @@
 }
 $PAGE->set_url($url);
 
-if (!$course = $DB->get_record('course', array('id'=>$course))) {
-    print_error('invalidcourseid');
-}
+$course = $DB->get_record('course', array('id'=>$course), '*', MUST_EXIST);
+
 if (!empty($USER->newadminuser)) {
     $PAGE->set_course($SITE);
     $PAGE->set_pagelayout('maintenance');
 } else {
     require_login($course);
+    $PAGE->set_pagelayout('admin');
 }
 
 if ($course->id == SITEID) {
@@ -60,19 +60,20 @@
 
 if ($id == -1) {
     // creating new user
-    require_capability('moodle/user:create', $systemcontext);
     $user = new object();
     $user->id = -1;
     $user->auth = 'manual';   
     $user->confirmed = 1;
     $user->deleted = 0;
+    require_capability('moodle/user:create', $systemcontext);
+    admin_externalpage_setup('addnewuser', '', array('id' => -1));
 } else {
     // editing existing user
     require_capability('moodle/user:update', $systemcontext);
-    if (!$user = $DB->get_record('user', array('id'=>$id))) {
-        print_error('invaliduserid');
+    $user = $DB->get_record('user', array('id'=>$id), '*', MUST_EXIST);
+    $PAGE->set_context(get_context_instance(CONTEXT_USER, $user->id));
+    $PAGE->navigation->extend_for_user($user);
     }
-}
 
 // remote users cannot be edited
 if ($user->id != -1 and is_mnet_remote_user($user)) {
@@ -94,12 +95,6 @@
     die;
 }
 
-if ($user->id == -1) {
-    admin_externalpage_setup('addnewuser', '', array('id' => -1));
-} else if ($user->id != $USER->id) {
-    admin_externalpage_setup('editusers', '', array('id' => $user->id, 'course' => SITEID), $CFG->wwwroot . '/user/editadvanced.php');
-}
-
 //load user preferences
 useredit_load_preferences($user);
 
@@ -259,15 +254,6 @@
     $strnewuser       = get_string('newuser');
     $userfullname     = fullname($user, true);
 
-    $link = null;
-    if (has_capability('moodle/course:viewparticipants', $coursecontext) || has_capability('moodle/site:viewparticipants', $systemcontext)) {
-        $link = new moodle_url("/user/index.php", array('id'=>$course->id));
-    }
-    $PAGE->navbar->add($strparticipants, $link);
-    $link = new moodle_url('/user/view.php', array('id'=>$user->id, 'course'=>$course->id));
-    $PAGE->navbar->add($userfullname, $link);
-    $PAGE->navbar->add($streditmyprofile);
-
     $PAGE->set_title("$course->shortname: $streditmyprofile");
     $PAGE->set_heading($course->fullname);
 
Index: moodle/version.php
--- moodle/version.php Base (1.1515)
+++ moodle/version.php Locally Modified (Based On 1.1515)
@@ -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 = 2010041300;  // YYYYMMDD   = date of the last version bump
+    $version = 2010041301;  // YYYYMMDD   = date of the last version bump
                             //         XX = daily increments
 
     $release = '2.0 dev (Build: 20100414)';  // Human-friendly version name
