The biggest change is that the navigation block has been converted to a proper YUI module.
The following are the other changes made at the same time:
* A loading icon is displayed when a branch is being loaded by AJAX.
* Fixed a bug where you could trigger multiple AJAX requests by rapidly clicking an unloaded branch.
* Fixed a bug where empty branches weren't being marked as such after a successful AJAX load.
* When docked the width of the blocks dock panel is now inspected an increased if required to try avoid horizontal scrolling.
* Removed the no longer needed inclusion of the YUI2 dom library from the navigation and settings block.
* Expandable nodes are now passed as JS data allowing the navigation JS to be initialised through block_navigation::get_required_javascript.
* AJAX is now focused around the branch in question rather than the tree in general.
* Expansion of branches is now delegated to the tree rather than being an individual event on all branches.
* Tidied up the code in general removing unneeded-unused parameters.
}
return;
};
+ /**
+ * Increases the width of the panel to avoid horizontal scrolling
+ * if possible.
+ */
+ dockpanel.correctWidth = function() {
+ var bd = this.one('.dockeditempanel_bd');
+
+ // Width of content
+ var w = bd.get('clientWidth');
+ // Scrollable width of content
+ var s = bd.get('scrollWidth');
+ // Width of content container with overflow
+ var ow = this.get('offsetWidth');
+ // The new width
+ var nw = w;
+ // The max width (80% of screen)
+ var mw = Math.round(this.get('winWidth') * 0.8);
+
+ // If the scrollable width is more than the visible width
+ if (s > w) {
+ // Content width
+ // + the difference
+ // + any rendering difference (borders, padding)
+ // + 10px to make it look nice.
+ nw = w + (s-w) + ((ow-w)*2) + 10;
+ }
+
+ // Make sure its not more then the maxwidth
+ if (nw > mw) {
+ nw = mw;
+ }
+
+ // Set the new width if its more than the old width.
+ if (nw > ow) {
+ this.setStyle('width', nw+'px');
+ }
+ }
// Put the dockpanel in the body
parent.append(dockpanel);
// Return it
if (!this.initialised) {
this.init(Y);
}
- new this.genericblock(id).init(Y, Y.one('#inst'+id));
+ new this.genericblock(id).initialise_block(Y, Y.one('#inst'+id));
};
/**
* Removes the node at the given index and puts it back into conventional page sturcture
* @param {YUI.Node} node The node that contains all of the block's content
* @return {M.core_dock.genericblock}
*/
- init : function(Y, node) {
+ initialise_block : function(Y, node) {
M.core_dock.init(Y);
this.Y = Y;
panel.setHeader(this.titlestring, this.commands);
panel.setBody(Y.Node.create('<div class="'+this.blockclass+' block_docked"></div>').append(this.contents));
panel.show();
+ panel.correctWidth();
this.active = true;
// Add active item class first up
function get_required_javascript() {
global $CFG;
user_preference_allow_ajax_update('docked_block_instance_'.$this->instance->id, PARAM_INT);
+ $this->page->requires->js_module('core_dock');
+ $limit = 20;
+ if (!empty($CFG->navcourselimit)) {
+ $limit = $CFG->navcourselimit;
+ }
+ $arguments = array('id'=>$this->instance->id, 'instance'=>$this->instance->id, 'candock'=>$this->instance_can_be_docked(), 'courselimit'=>$limit);
+ $this->page->requires->yui_module(array('core_dock', 'moodle-block_navigation-navigation'), 'M.block_navigation.init_add_tree', array($arguments));
}
/**
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
}
}
- // 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'), 'strings'=>array(array('viewallcourses','moodle')));
- $limit = 20;
- if (!empty($CFG->navcourselimit)) {
- $limit = $CFG->navcourselimit;
- }
- $arguments = array($this->instance->id, array('expansions'=>$expandable, 'instance'=>$this->instance->id, 'candock'=>$this->instance_can_be_docked(), 'courselimit'=>$limit));
- $this->page->requires->js_init_call('M.block_navigation.init_add_tree', $arguments, false, $module);
+ $this->page->requires->data_for_js('navtreeexpansions'.$this->instance->id, $expandable);
$options = array();
$options['linkcategories'] = (!empty($this->config->linkcategories) && $this->config->linkcategories == 'yes');
+++ /dev/null
-// 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:{},
- courselimit : 20,
- /**
- * 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) {
- M.core_dock.init(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) {
- if (properties.courselimit) {
- this.courselimit = properties.courselimit;
- }
- 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;
- }
-
- // Attach event to toggle expansion
- node.all('.tree_item.branch').on('click', this.toggleexpansion , this);
-
- // Attach events to expand by AJAX
- //var expandablenode;
- for (var i in this.expansions) {
- var expandablenode = Y.one('#'+this.expansions[i].id);
- if (expandablenode) {
- expandablenode.on('ajaxload|click', this.init_load_ajax, this, this.expansions[i]);
- M.block_navigation.expandablebranchcount++;
- } else if (M.cfg.debug) {
- Y.one(document.body).append(Y.Node.create('<div class="notification" style="font-size:6pt;">Expandable node within navigation was missing [#'+this.expansions[i].id+']</div>'));
- } else {
- // Failing over silently
- }
- }
-
- 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();
- var target = e.target;
- if (target.test('span')) {
- target = target.ancestor('p');
- }
- if (!target || !target.test('p')) {
- return true;
- }
- var cfginstance = '', Y = this.Y;
- if (this.instance != null) {
- cfginstance = '&instance='+this.instance
- }
- 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() {Y.detach('click', this.init_load_ajax, target);}
- },
- context:this,
- arguments:{
- target: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 {object} branchobj
- * @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, Y = this.Y;
- if (depth === 1) {
- if (!branch.children) {
- return false;
- }
- childrenul = Y.Node.create('<ul></ul>');
- target.appendChild(childrenul);
- } else {
- childrenul = branch.inject_into_dom(target);
- }
- if (childrenul) {
- var count = 0;
- for (var i in branch.children) {
- // Add each branch to the tree
- if (branch.children[i].type == 20) {
- count++;
- }
- if (typeof(branch.children[i])=='object') {
- this.add_branch(branch.children[i], childrenul, depth+1);
- }
- }
- if (branch.type == 10 && count >= M.block_navigation.courselimit) {
- var properties = Array();
- properties['name'] = M.str.moodle.viewallcourses;
- properties['title'] = M.str.moodle.viewallcourses;
- properties['link'] = M.cfg.wwwroot+'/course/category.php?id='+branch.key;
- properties['haschildren'] = false;
- properties['icon'] = {'pix':"i/navigationitem",'component':'moodle'};
- this.add_branch(properties, 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;
- }
-
- var target = e.target;
- if (!target.test('li')) {
- target = target.ancestor('li')
- }
-
- if (target && !target.hasClass('depth_1')) {
- target.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);
- }
-};
-/**
- * Populates this branch from a JSON object
- * @param {object} 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.children.length > 0) {
- 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 Y = this.tree.Y;
-
- var isbranch = ((this.expandable !== null || this.haschildren) && this.expansionceiling===null);
- var branchli = Y.Node.create('<li></li>');
- var branchp = Y.Node.create('<p class="tree_item"></p>');
-
- if (isbranch) {
- branchli.addClass('collapsed');
- branchli.addClass('contains_branch');
- 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 && (!isbranch || this.type == 40)) {
- branchicon = Y.Node.create('<img alt="" />');
- branchicon.setAttribute('src', M.util.image_url(this.icon.pix, this.icon.component));
- branchli.addClass('item_with_icon');
- 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]);
- }
- }
- }
-
- if (this.link === null) {
- if (branchicon) {
- branchp.appendChild(branchicon);
- }
- branchp.append(this.name.replace(/\n/g, '<br />'));
- } else {
- var branchlink = 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 = 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);
\ No newline at end of file
.block_navigation .block_tree .active_tree_node {font-weight:bold;}
.block_navigation .block_tree .depth_1.current_branch ul {font-weight:normal;}
+.dock .block_navigation .tree_item {white-space: nowrap;}
+
.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: 0% 5%;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]]);}
+.jsenabled .block_navigation .block_tree .tree_item.branch.loadingbranch {background-image:url([[pix:i/loading_small]]);}
/** JavaScript state rules **/
.jsenabled .block_navigation.dock_on_load,
--- /dev/null
+YUI.add('moodle-block_navigation-navigation', function(Y){
+
+/**
+ * Navigation tree class.
+ *
+ * This class establishes the tree initially, creating expandable branches as
+ * required, and delegating the expand/collapse event.
+ */
+var TREE = function(config) {
+ TREE.superclass.constructor.apply(this, arguments);
+}
+TREE.prototype = {
+ /**
+ * The tree's ID, normally its block instance id.
+ */
+ id : null,
+ /**
+ * Initialise the tree object when its first created.
+ */
+ initializer : function(config) {
+ this.id = config.id;
+
+ var node = Y.one('#inst'+config.id);
+
+ // Can't find the block instance within the page
+ if (node === null) {
+ return;
+ }
+
+ // Delegate event to toggle expansion
+ var self = this;
+ Y.delegate('click', function(e){self.toggleExpansion(e);}, node.one('.block_tree'), '.tree_item.branch');
+
+ // Gather the expandable branches ready for initialisation.
+ var expansions = [];
+ if (config.expansions) {
+ expansions = config.expansions;
+ } else if (window['navtreeexpansions'+config.id]) {
+ expansions = window['navtreeexpansions'+config.id];
+ }
+ // Establish each expandable branch as a tree branch.
+ for (var i in expansions) {
+ new BRANCH({
+ tree:this,
+ branchobj:expansions[i],
+ overrides : {
+ expandable : true,
+ children : [],
+ haschildren : true
+ }
+ }).wire();
+ M.block_navigation.expandablebranchcount++;
+ }
+
+ // Call the generic blocks init method to add all the generic stuff
+ if (this.get('candock')) {
+ this.initialise_block(Y, node);
+ }
+ },
+ /**
+ * This is a callback function responsible for expanding and collapsing the
+ * branches of the tree. It is delegated to rather than multiple event handles.
+ */
+ 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.test('a')) {
+ // A link has been clicked don't fire any more events just do the default.
+ e.stopPropagation();
+ return;
+ }
+
+ // Makes sure we can get to the LI containing the branch.
+ var target = e.target;
+ if (!target.test('li')) {
+ target = target.ancestor('li')
+ }
+ if (!target) {
+ return;
+ }
+
+ // Toggle expand/collapse providing its not a root level branch.
+ if (!target.hasClass('depth_1')) {
+ target.toggleClass('collapsed');
+ }
+
+ // If the accordian feature has been enabled collapse all siblings.
+ if (this.get('accordian')) {
+ target.siblings('li').each(function(){
+ if (this.get('id') !== target.get('id') && !this.hasClass('collapsed')) {
+ this.addClass('collapsed');
+ }
+ });
+ }
+
+ // If this block can dock tell the dock to resize if required and check
+ // the width on the dock panel in case it is presently in use.
+ if (this.get('candock')) {
+ M.core_dock.resize();
+ var panel = M.core_dock.getPanel();
+ if (panel.visible) {
+ panel.correctWidth();
+ }
+ }
+ }
+}
+// The tree extends the YUI base foundation.
+Y.extend(TREE, Y.Base, TREE.prototype, {
+ NAME : 'navigation-tree',
+ ATTRS : {
+ instance : {
+ value : null
+ },
+ candock : {
+ validator : Y.Lang.isBool,
+ value : false
+ },
+ accordian : {
+ validator : Y.Lang.isBool,
+ value : false
+ }
+ }
+});
+if (M.core_dock && M.core_dock.genericblock) {
+ Y.augment(TREE, M.core_dock.genericblock);
+}
+
+/**
+ * The tree branch class.
+ * This class is used to manage a tree branch, in particular its ability to load
+ * its contents by AJAX.
+ */
+var BRANCH = function(config) {
+ BRANCH.superclass.constructor.apply(this, arguments);
+}
+BRANCH.prototype = {
+ /**
+ * The node for this branch (p)
+ */
+ node : null,
+ /**
+ * A reference to the ajax load event handle when created.
+ */
+ event_ajaxload : null,
+ /**
+ * Initialises the branch when it is first created.
+ */
+ initializer : function(config) {
+ if (config.branchobj !== null) {
+ // Construct from the provided xml
+ for (var i in config.branchobj) {
+ this.set(i, config.branchobj[i]);
+ }
+ var children = this.get('children');
+ this.set('haschildren', (children.length > 0));
+ }
+ if (config.overrides !== null) {
+ // Construct from the provided xml
+ for (var i in config.overrides) {
+ this.set(i, config.overrides[i]);
+ }
+ }
+ this.node = Y.one('#', this.get('id'));
+ },
+ /**
+ * Draws the branch within the tree.
+ *
+ * This function creates a DOM structure for the branch and then injects
+ * it into the navigation tree at the correct point.
+ */
+ draw : function(element) {
+
+ var isbranch = (this.get('expandable') || this.get('haschildren'));
+ var branchli = Y.Node.create('<li></li>');
+ var branchp = Y.Node.create('<p class="tree_item"></p>').setAttribute('id', this.get('id'));
+
+ if (isbranch) {
+ branchli.addClass('collapsed').addClass('contains_branch');
+ branchp.addClass('branch');
+ }
+
+ // Prepare the icon, should be an object representing a pix_icon
+ var branchicon = false;
+ var icon = this.get('icon');
+ if (icon && (!isbranch || this.get('type') == 40)) {
+ branchicon = Y.Node.create('<img alt="" />');
+ branchicon.setAttribute('src', M.util.image_url(icon.pix, icon.component));
+ branchli.addClass('item_with_icon');
+ if (icon.alt) {
+ branchicon.setAttribute('alt', icon.alt);
+ }
+ if (icon.title) {
+ branchicon.setAttribute('title', icon.title);
+ }
+ if (icon.classes) {
+ for (var i in icon.classes) {
+ branchicon.addClass(icon.classes[i]);
+ }
+ }
+ }
+
+ var link = this.get('link');
+ if (!link) {
+ if (branchicon) {
+ branchp.appendChild(branchicon);
+ }
+ branchp.append(this.get('name'));
+ } else {
+ var branchlink = Y.Node.create('<a title="'+this.get('title')+'" href="'+link+'"></a>');
+ if (branchicon) {
+ branchlink.appendChild(branchicon);
+ }
+ branchlink.append(this.get('name'));
+ if (this.get('hidden')) {
+ branchlink.addClass('dimmed');
+ }
+ branchp.appendChild(branchlink);
+ }
+
+ branchli.appendChild(branchp);
+ element.appendChild(branchli);
+ this.node = branchp;
+ return this;
+ },
+ /**
+ * Attaches required events to the branch structure.
+ */
+ wire : function() {
+ this.node = this.node || Y.one('#'+this.get('id'));
+ if (!this.node) {
+ return false;
+ }
+ if (this.get('expandable')) {
+ this.event_ajaxload = this.node.on('ajaxload|click', this.ajaxLoad, this);
+ }
+ return this;
+ },
+ /**
+ * Gets the UL element that children for this branch should be inserted into.
+ */
+ getChildrenUL : function() {
+ var ul = this.node.next('ul');
+ if (!ul) {
+ ul = Y.Node.create('<ul></ul>');
+ this.node.ancestor().append(ul);
+ }
+ return ul;
+ },
+ /**
+ * Load the content of the branch via AJAX.
+ *
+ * This function calls ajaxProcessResponse with the result of the AJAX
+ * request made here.
+ */
+ ajaxLoad : function(e) {
+ e.stopPropagation();
+
+ if (this.node.hasClass('loadingbranch')) {
+ return true;
+ }
+
+ this.node.addClass('loadingbranch');
+
+ var params = {
+ elementid : this.get('id'),
+ id : this.get('key'),
+ type : this.get('type'),
+ sesskey : M.cfg.sesskey,
+ instance : this.get('tree').get('instance')
+ };
+
+ Y.io(M.cfg.wwwroot+'/lib/ajax/getnavbranch.php', {
+ method:'POST',
+ data: build_querystring(params),
+ on: {
+ complete: this.ajaxProcessResponse
+ },
+ context:this
+ });
+ return true;
+ },
+ /**
+ * Processes an AJAX request to load the content of this branch through
+ * AJAX.
+ */
+ ajaxProcessResponse : function(tid, outcome) {
+ this.node.removeClass('loadingbranch');
+ this.event_ajaxload.detach();
+ try {
+ var object = Y.JSON.parse(outcome.responseText);
+ if (object.children && object.children.length > 0) {
+ for (var i in object.children) {
+ if (typeof(object.children[i])=='object') {
+ this.addChild(object.children[i]);
+ }
+ }
+ this.get('tree').toggleExpansion({target:this.node});
+ return true;
+ }
+ } catch (ex) {
+ // If we got here then there was an error parsing the result
+ }
+ // The branch is empty so class it accordingly
+ this.node.replaceClass('branch', 'emptybranch');
+ return true;
+ },
+ /**
+ * Turns the branch object passed to the method into a proper branch object
+ * and then adds it as a child of this branch.
+ */
+ addChild : function(branchobj) {
+ // Make the new branch into an object
+ var branch = new BRANCH({tree:this.get('tree'), branchobj:branchobj});
+ if (branch.draw(this.getChildrenUL())) {
+ branch.wire();
+ var count = 0, i, children = branch.get('children');
+ for (i in children) {
+ // Add each branch to the tree
+ if (children[i].type == 20) {
+ count++;
+ }
+ if (typeof(children[i])=='object') {
+ branch.addChild(children[i]);
+ }
+ }
+ if (branch.get('type') == 10 && count >= M.block_navigation.courselimit) {
+ branch.addChild({
+ name : M.str.moodle.viewallcourses,
+ title : M.str.moodle.viewallcourses,
+ link : M.cfg.wwwroot+'/course/category.php?id='+branch.get('key'),
+ haschildren : false,
+ icon : {'pix':"i/navigationitem",'component':'moodle'}
+ }, branch);
+ }
+ }
+ return true;
+ }
+}
+Y.extend(BRANCH, Y.Base, BRANCH.prototype, {
+ NAME : 'navigation-branch',
+ ATTRS : {
+ tree : {
+ validator : Y.Lang.isObject
+ },
+ name : {
+ value : '',
+ validator : Y.Lang.isString,
+ setter : function(val) {
+ return val.replace(/\n/g, '<br />');
+ }
+ },
+ title : {
+ value : '',
+ validator : Y.Lang.isString
+ },
+ id : {
+ value : '',
+ validator : Y.Lang.isString,
+ getter : function(val) {
+ if (val == '') {
+ val = 'expandable_branch_'+M.block_navigation.expandablebranchcount;
+ M.block_navigation.expandablebranchcount++;
+ }
+ return val;
+ }
+ },
+ key : {
+ value : null
+ },
+ type : {
+ value : null
+ },
+ link : {
+ value : false
+ },
+ icon : {
+ value : false,
+ validator : Y.Lang.isObject
+ },
+ expandable : {
+ value : false,
+ validator : Y.Lang.isBool
+ },
+ hidden : {
+ value : false,
+ validator : Y.Lang.isBool
+ },
+ haschildren : {
+ value : false,
+ validator : Y.Lang.isBool
+ },
+ children : {
+ value : [],
+ validator : Y.Lang.isArray
+ }
+ }
+});
+
+/**
+ * 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:1,
+ courselimit : 20,
+ instance : null,
+ /**
+ * Add new instance of navigation tree to tree collection
+ */
+ init_add_tree:function(properties) {
+ if (properties.courselimit) {
+ this.courselimit = properties.courselimit;
+ }
+ if (M.core_dock) {
+ M.core_dock.init(Y);
+ }
+ new TREE(properties);
+ }
+};
+
+}, '@VERSION@', {requires:['base', 'core_dock', 'io', 'node', 'dom', 'event-custom', 'event-delegate', 'json-parse']});
\ No newline at end of file
function get_required_javascript() {
global $CFG;
- $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);
+ $arguments = array('id'=>$this->instance->id, 'instance'=>$this->instance->id, 'candock'=>$this->instance_can_be_docked());
+ $this->page->requires->yui_module(array('core_dock', 'moodle-block_navigation-navigation'), 'M.block_navigation.init_add_tree', array($arguments));
user_preference_allow_ajax_update('docked_block_instance_'.$this->instance->id, PARAM_INT);
}
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++;
if ($child->nodetype == self::NODETYPE_BRANCH && $child->children->count()==0 && $child->display) {
$child->id = 'expandable_branch_'.(count($expandable)+1);
$this->add_class('canexpand');
- $expandable[] = array('id'=>$child->id,'branchid'=>$child->key,'type'=>$child->type);
+ $expandable[] = array('id'=>$child->id,'key'=>$child->key,'type'=>$child->type);
}
$child->find_expandable($expandable);
}
*/
public function set_expandable($expandable) {
foreach ($expandable as $node) {
- $this->expandable[$node['branchid'].':'.$node['type']] = $node;
+ $this->expandable[$node['key'].':'.$node['type']] = $node;
}
}
/**