From 6644741db6948142e4064bb4b4c34b4966fd62ac Mon Sep 17 00:00:00 2001 From: samhemelryk Date: Wed, 14 Oct 2009 09:08:43 +0000 Subject: [PATCH] navigation MDL-20558 Fixed AJAX bug with multiple navigation trees concerning ajax requests + DOM interaction --- lib/ajax/getnavbranch.php | 5 +- lib/javascript-navigation.js | 17 +++++-- lib/navigationlib.php | 94 ++++++++++++++++++++++++++++++++---- 3 files changed, 102 insertions(+), 14 deletions(-) diff --git a/lib/ajax/getnavbranch.php b/lib/ajax/getnavbranch.php index 8be709a76e403..dd57c0f6ae820 100644 --- a/lib/ajax/getnavbranch.php +++ b/lib/ajax/getnavbranch.php @@ -49,7 +49,7 @@ // Get the db record for the block instance $blockrecords = $DB->get_record('block_instances', array('id'=>$instanceid,'blockname'=>'global_navigation_tree')); if ($blockrecords!=false) { - // Instantiate a block_instance object so we can access congif + // Instantiate a block_instance object so we can access congif $block = block_instance('global_navigation_tree', $blockrecords); // Check if the expansion limit config option has been set and isn't the default [everything] if (!empty($block->config->expansionlimit) && $block->config->expansionlimit > '0') { @@ -65,10 +65,12 @@ // Create a navigation object to use, we can't guarantee PAGE will be complete $expandable = $navigation->initialise($branchtype, $branchid); +$converter = new navigation_xml(); 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); @@ -87,7 +89,6 @@ } // Prepare an XML converter for the branch -$converter = new navigation_xml(); $converter->set_expandable($expandable); // Set XML headers header('Content-type: text/xml'); diff --git a/lib/javascript-navigation.js b/lib/javascript-navigation.js index d16f0658d299c..59c591d5a68b0 100644 --- a/lib/javascript-navigation.js +++ b/lib/javascript-navigation.js @@ -43,6 +43,7 @@ YAHOO.namespace('moodle.navigation.treecollection'); YAHOO.moodle.navigation.sideblockwidth = null; YAHOO.moodle.navigation.tabpanel = null; YAHOO.moodle.navigation.treecollection = Array(); +YAHOO.moodle.navigation.expandablebranchcount = 0; /** * Navigation Tree object (function) used to control a global navigation tree @@ -108,6 +109,7 @@ navigation_tree.prototype.initialise = function() { try { this.expansions[i].element = document.getElementById(this.expansions[i].id); YAHOO.util.Event.addListener(this.expansions[i].id, 'click', this.init_load_ajax, this.expansions[i], this); + YAHOO.moodle.navigation.expandablebranchcount++; } catch (err) { this.errorlog += "attaching ajax load events: \t"+err+"\n"; } @@ -242,7 +244,7 @@ navigation_tree.prototype.load_ajax = function(outcome) { * @return {bool} */ navigation_tree.prototype.add_branch = function(branchxml, target, depth) { - var branch = new navigation_tree_branch(); + var branch = new navigation_tree_branch(this.name); branch.load_from_xml_node(branchxml); if (depth>1) { target = branch.inject_into_dom(target,this); @@ -694,7 +696,8 @@ navigation_tab_panel.prototype.remove_from_tab_panel = function(tabname) { * @class navigation_tree_branch * @constructor */ -function navigation_tree_branch() { +function navigation_tree_branch(treename) { + this.treename = treename; this.myname = null; this.mytitle = null; this.myclass = null; @@ -704,6 +707,7 @@ function navigation_tree_branch() { this.mylink = null; this.myicon = null; this.myexpandable = null; + this.expansionceiling = null; this.myhidden = false; this.haschildren = false; this.mychildren = false; @@ -722,8 +726,15 @@ navigation_tree_branch.prototype.load_from_xml_node = function (branch) { this.mykey = branch.getAttribute('key'); this.mytype = branch.getAttribute('type'); this.myexpandable = branch.getAttribute('expandable'); + this.expansionceiling = branch.getAttribute('expansionceiling'); this.myhidden = (branch.getAttribute('hidden')=='true'); this.haschildren = (branch.getAttribute('haschildren')=='true'); + + if (this.myid && this.myid.match(/^expandable_branch_\d+$/)) { + YAHOO.moodle.navigation.expandablebranchcount++; + this.myid = 'expandable_branch_'+YAHOO.moodle.navigation.expandablebranchcount; + } + for (var i=0; ichildren)>0) { + foreach ($this->children as &$child) { + if ($child->type === $type) { + $nodes[] = $child; + } + if (count($child->children)>0) { + $nodes = array_merge($nodes, $child->find_children_by_type($type)); + } + } + } + return $nodes; + } + /** * Toogles display of nodes and child nodes based on type * @@ -571,19 +593,21 @@ public function contains_active_node() { * * @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_* */ - public function find_expandable(&$expandable) { + public function find_expandable(&$expandable, $expansionlimit = null) { static $branchcount; if ($branchcount==null) { $branchcount=1; } - if ($this->nodetype == self::NODETYPE_BRANCH && count($this->children)==0) { + 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) { + } else if ($this->nodetype==self::NODETYPE_BRANCH && ($expansionlimit === null || $this->type <= $expansionlimit)) { foreach ($this->children as $child) { - $child->find_expandable($expandable); + $child->find_expandable($expandable, $expansionlimit); } } } @@ -1559,7 +1583,7 @@ protected function load_categories($categoryid=0) { 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)) { + if ($categoryid!==0 && !preg_match('#/('.$categoryid.')(/|$)#', $course->categorypath)) { continue; } $categorypathids = explode('/',trim($course->categorypath,' /')); @@ -1588,7 +1612,7 @@ protected function load_categories($categoryid=0) { } // Add the courses that were retrieved earlier to the $this->add_courses($courses); - } else { + } else if ($categoryid === 0) { $keys = array(); if ($categoryid!=0) { if (!$this->cache->cached('category'.$categoryid)) { @@ -1617,6 +1641,44 @@ protected function load_categories($categoryid=0) { public function clear_cache() { $this->cache->volatile(); } + + /** + * 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); + } + } + } } /** @@ -1681,10 +1743,10 @@ public function initialise($type, $instanceid) { * @param int $instanceid */ protected function load_category($instanceid) { - if (!$this->cache->cached('coursecontext'.$instanceid)) { - $this->cache->{'coursecontext'.$instanceid} = get_context_instance(CONTEXT_COURSE, $instanceid); + if (!$this->cache->cached('coursecatcontext'.$instanceid)) { + $this->cache->{'coursecatcontext'.$instanceid} = get_context_instance(CONTEXT_COURSECAT, $instanceid); } - $this->context = $this->cache->{'coursecontext'.$instanceid}; + $this->context = $this->cache->{'coursecatcontext'.$instanceid}; $this->load_categories($instanceid); } @@ -3080,6 +3142,8 @@ class navigation_xml { 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 * @@ -3099,6 +3163,15 @@ public function set_expandable($expandable) { $this->expandable[(string)$node['branchid']] = $node; } } + /** + * 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 * @@ -3123,7 +3196,10 @@ protected function convert_child($child, $depth=1) { 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) { $attributes['class'] .= ' '.join(' ',$child->classes); }