Skip to content

Commit

Permalink
navigation MDL-20558 Fixed AJAX bug with multiple navigation trees co…
Browse files Browse the repository at this point in the history
…ncerning ajax requests + DOM interaction
  • Loading branch information
samhemelryk committed Oct 14, 2009
1 parent 72d0aed commit 6644741
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 14 deletions.
5 changes: 3 additions & 2 deletions lib/ajax/getnavbranch.php
Expand Up @@ -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') {
Expand All @@ -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);
Expand All @@ -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');
Expand Down
17 changes: 14 additions & 3 deletions lib/javascript-navigation.js
Expand Up @@ -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
Expand Down Expand Up @@ -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";
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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; i<branch.childNodes.length;i++) {
var node = branch.childNodes[i];
switch (node.nodeName.toLowerCase()) {
Expand All @@ -746,7 +757,7 @@ navigation_tree_branch.prototype.inject_into_dom = function (element, gntinstanc
var branchli = document.createElement('li');
var branchp = document.createElement('p');
YAHOO.util.Dom.addClass(branchp, 'tree_item');
if (this.myexpandable !==null || this.haschildren) {
if ((this.myexpandable !==null || this.haschildren) && this.expansionceiling===null) {
YAHOO.util.Dom.addClass(branchp, 'branch');
YAHOO.util.Dom.addClass(branchli, 'collapsed');
YAHOO.util.Event.addListener(branchp, 'click', gntinstance.toggleexpansion, this, gntinstance);
Expand Down
94 changes: 85 additions & 9 deletions lib/navigationlib.php
Expand Up @@ -527,6 +527,28 @@ public function find_child_depth($key, $type=self::TYPE_CATEGORY) {
return $depth;
}

/**
* Finds all nodes (recursivily) that have the specified type, regardless of
* assumed order or position.
*
* @param int $type One of navigation_node::TYPE_*
* @return array An array of navigation_node references for nodes of type $type
*/
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;
}
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
*
Expand Down Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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,' /'));
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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);
}
}
}
}

/**
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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
*
Expand All @@ -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
*
Expand All @@ -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);
}
Expand Down

0 comments on commit 6644741

Please sign in to comment.