From 2574fae6ef7597eb779832fb770817baeee5db53 Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Mon, 4 Jan 2010 23:51:48 +0000 Subject: [PATCH] MDL-21123 moved javascript for navigation bar - testing of themes JS and it may need to use different tricks in other themes with CSS column layouts --- .../block_global_navigation_tree.php | 3 +- .../block_settings_navigation_tree.php | 3 +- lib/ajax/ajaxlib.php | 6 +- lib/javascript-navigation.js | 874 ----------------- theme/standard/javascript/navigation.js | 881 ++++++++++++++++++ version.php | 2 +- 6 files changed, 890 insertions(+), 879 deletions(-) delete mode 100644 lib/javascript-navigation.js diff --git a/blocks/global_navigation_tree/block_global_navigation_tree.php b/blocks/global_navigation_tree/block_global_navigation_tree.php index fc4cbb6620..61d54342bf 100644 --- a/blocks/global_navigation_tree/block_global_navigation_tree.php +++ b/blocks/global_navigation_tree/block_global_navigation_tree.php @@ -89,7 +89,8 @@ class block_global_navigation_tree extends block_tree { return true; } $this->page->requires->yui2_lib('dom'); - $this->page->requires->js('lib/javascript-navigation.js'); + // 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 diff --git a/blocks/settings_navigation_tree/block_settings_navigation_tree.php b/blocks/settings_navigation_tree/block_settings_navigation_tree.php index 34bf3b1346..3f9b82ebff 100644 --- a/blocks/settings_navigation_tree/block_settings_navigation_tree.php +++ b/blocks/settings_navigation_tree/block_settings_navigation_tree.php @@ -88,7 +88,8 @@ class block_settings_navigation_tree extends block_tree { return true; } $this->page->requires->yui2_lib('dom'); - $this->page->requires->js('lib/javascript-navigation.js'); + // 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 diff --git a/lib/ajax/ajaxlib.php b/lib/ajax/ajaxlib.php index e12ccc28c6..f71682f8ea 100644 --- a/lib/ajax/ajaxlib.php +++ b/lib/ajax/ajaxlib.php @@ -163,8 +163,10 @@ class page_requirements_manager { // Note that, as a short-cut, the code // $js = "document.body.className += ' jsenabled';\n"; // is hard-coded in {@link page_requirements_manager::get_top_of_body_code) - $this->yui2_lib('container'); - $this->yui2_lib('connection'); + $this->yui2_lib('dom'); // needs to be migrated to YUI3 before we release 2.0 + $this->yui2_lib('container'); // needs to be migrated to YUI3 before we release 2.0 + $this->yui2_lib('connection'); // needs to be migrated to YUI3 before we release 2.0 + $this->string_for_js('confirmation', 'admin'); $this->string_for_js('cancel', 'moodle'); $this->string_for_js('yes', 'moodle'); diff --git a/lib/javascript-navigation.js b/lib/javascript-navigation.js deleted file mode 100644 index be4183b20d..0000000000 --- a/lib/javascript-navigation.js +++ /dev/null @@ -1,874 +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 . - -/** - * This file contains classes used to manage the navigation structures in Moodle - * and was introduced as part of the changes occuring in Moodle 2.0 - * - * @since 2.0 - * @package javascript - * @copyright 2009 Sam Hemelryk - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Some very important general namespaces to act as containers for the general - * objects required to manage the navigation. - * - * For anyone looking to improve this javascript taking a little time to turn - * the classes into namespaced classes, and giving the class structure in this file - * a similar structure to YUI on a moodle namespace would be AWESOME - */ -YAHOO.namespace('moodle.navigation'); -YAHOO.namespace('moodle.navigation.sideblockwidth'); -YAHOO.namespace('moodle.navigation.tabpanel'); -YAHOO.namespace('moodle.navigation.treecollection'); - -/** - * Instatiate some very important variables that allow us to manage the navigaiton - * objects without having to hit my arch enemy `undefined` - */ -YAHOO.moodle.navigation.sideblockwidth = null; -YAHOO.moodle.navigation.tabpanel = null; -YAHOO.moodle.navigation.treecollection = Array(); -YAHOO.moodle.navigation.expandablebranchcount = 0; - -/** - * Navigation Tree object (function) used to control a global navigation tree - * handling things such as collapse, expand, and AJAX requests for more branches - * - * You should never call this directly.. you should use {@link start_new_navtree()} - * which will create the class and make it accessible in a smart way - * - * @class navigation_tree - * @constructor - * @param {string} treename - * @param {string} key - */ -function navigation_tree (treename, key) { - this.name = treename; - this.key = key; - this.errorlog = ''; - this.ajaxbranches = 0; - this.expansions = Array(); - this.instance = null - this.cachedcontent = null; - this.cachedfooter = null; - this.position = 'block'; - this.skipsetposition = false; - this.togglesidetabdisplay = '[[togglesidetabdisplay]]'; - this.toggleblockdisplay = '[[toggleblockdisplay]]'; - this.sideblockwidth = null; - if (window[this.name]) { - if (window[this.name].expansions) { - this.expansions = window[this.name].expansions; - } - if (window[this.name].instance) { - this.instance = window[this.name].instance; - } - if (window[this.name].togglesidetabdisplay) { - this.togglesidetabdisplay = window[this.name].togglesidetabdisplay; - } - if (window[this.name].toggleblockdisplay) { - this.toggleblockdisplay = window[this.name].toggleblockdisplay; - } - } -} -/** - * Initialise function used to attach the initial events to the navigation tree - * This function attachs toggles and ajax calls - */ -navigation_tree.prototype.initialise = function() { - if (!document.getElementById(this.name)) { - return; - } - var e = document.getElementById(this.name); - var i = 0; - while (!YAHOO.util.Dom.hasClass(e, 'sideblock') && e.nodeName.toUpperCase()!='BODY') { - e = e.parentNode; - } - var movetos = YAHOO.util.Dom.getElementsByClassName('moveto', 'a', e); - if (movetos !== null && movetos.length > 0) { - for (i = 0;i0) { - for (i = 0; i 0) { - for (i = 0; i < customcommands.length; i++) { - customcommands[i].parentNode.removeChild(customcommands[i]); - commands[0].appendChild(customcommands[i]); - } - } - - if (YAHOO.util.Dom.hasClass(e, 'sideblock_js_sidebarpopout')) { - YAHOO.util.Dom.removeClass(e, 'sideblock_js_sidebarpopout'); - this.skipsetposition = true; - this.toggle_block_display(e, this); - } else if (YAHOO.util.Dom.hasClass(e, 'sideblock_js_expansion')) { - YAHOO.util.Event.addListener(e, 'mouseover', this.togglesize, e, this); - YAHOO.util.Event.addListener(e, 'mouseout', this.togglesize, e, this); - } -} -/** - * Toogle a branch either collapsed or expanded... CSS styled - * @param {object} e Event object - */ -navigation_tree.prototype.toggleexpansion = function(e) { - YAHOO.util.Event.stopPropagation(e); - var target = YAHOO.util.Event.getTarget(e); - var parent = target.parentNode; - while (parent.nodeName.toUpperCase()!='LI') { - parent = parent.parentNode; - } - if (YAHOO.util.Dom.hasClass(parent, 'collapsed')) { - YAHOO.util.Dom.removeClass(parent, 'collapsed'); - } else { - YAHOO.util.Dom.addClass(parent, 'collapsed'); - } - if (this.position === 'sidebar') { - YAHOO.moodle.navigation.tabpanel.resize_tab(); - } -} -/** - * Toggles the size on an element by adding/removing the mouseover class - * @param {object} e Event object - * @param {element} element The element to add/remove the class from - */ -navigation_tree.prototype.togglesize = function(e, element) { - if (e.type == 'mouseout') { - var mp = YAHOO.util.Event.getXY(e); - if (mp[0] == -1) { - return true; - } - var ep = YAHOO.util.Dom.getXY(element); - ep[2] = ep[0]+element.offsetWidth; - ep[3] = ep[1]+element.offsetHeight; - var withinrealm = (mp[0] > ep[0] && mp[0] < ep[2] && mp[1] > ep[1] && mp[1] < ep[3]); - if (!withinrealm) { - YAHOO.util.Event.stopEvent(e); - YAHOO.util.Dom.removeClass(element, 'mouseover'); - } - } else { - YAHOO.util.Event.stopEvent(e); - element.style.width = element.offsetWidth +'px'; - YAHOO.util.Dom.addClass(element, 'mouseover'); - } - return true; -} -/** - * This function makes the initial call to load a branch of the navigation - * tree by AJAX - * @param {object} e Event object - * @param {object} branch The branch object from navigation_tree::expansions - * @return {bool} - */ -navigation_tree.prototype.init_load_ajax = function(e, branch) { - YAHOO.util.Event.stopPropagation(e); - if (YAHOO.util.Event.getTarget(e).nodeName.toUpperCase() != 'P') { - return true; - } - var postargs = 'elementid='+branch.id+'&id='+branch.branchid+'&type='+branch.type+'&sesskey='+moodle_cfg.sesskey; - if (this.instance != null) { - postargs += '&instance='+this.instance; - } - YAHOO.util.Connect.asyncRequest('POST', moodle_cfg.wwwroot+'/lib/ajax/getnavbranch.php', callback={ - success:function(o) {this.load_ajax(o);}, - failure:function(o) {this.load_ajax(o);}, - argument: {gntinstance:this,branch:branch,event:e, target:YAHOO.util.Event.getTarget(e)}, - scope: this - }, postargs); - return true; -} -/** - * This function loads a branch returned by AJAX into the XHTML tree structure - * @param {object} outcome The AJAX response - * @return {bool} - */ -navigation_tree.prototype.load_ajax = function(outcome) { - // Check the status - if (outcome.status!=0 && outcome.responseXML!=null) { - var branch = outcome.responseXML.documentElement; - if (branch!=null && this.add_branch(branch,outcome.argument.target ,1)) { - // If we get here everything worked perfectly - YAHOO.util.Event.removeListener(outcome.argument.branch.element, 'click', navigation_tree.prototype.init_load_ajax); - if (this.position === 'sidebar') { - YAHOO.moodle.navigation.tabpanel.resize_tab(); - } - return true; - } - } - // Something went wrong or there simply wasn't anything more to display - // add the emptybranch css class so we can flag it - YAHOO.util.Dom.replaceClass(outcome.argument.target, 'branch', 'emptybranch'); - return false; -} -/** - * This recursive function takes an XML branch and includes it in the tree - * @param {xmlnode} branchxml The XML node for the branch - * @param {element} target The target node to add to - * @param {int} depth The depth we have delved (recusive counter) - * @return {bool} - */ -navigation_tree.prototype.add_branch = function(branchxml, target, depth) { - var branch = new navigation_tree_branch(this.name); - branch.load_from_xml_node(branchxml); - if (depth>1) { - target = branch.inject_into_dom(target,this); - } - var dropcount = 5; - while (target.nodeName.toUpperCase() !== 'LI') { - target = target.parentNode; - if (dropcount==0 && moodle_cfg.developerdebug) { - return alert("dropped because of exceeding dropcount"); - } - dropcount--; - } - if (branch.haschildren && branch.mychildren && branch.mychildren.childNodes) { - for (var i=0;i 0) { - for (var i=0;i0) { - for (var j=0;j"); - var commands = YAHOO.util.Dom.getElementsByClassName('commands', 'div', this.cachedcontent); - var tabcommands = null; - if (commands.length > 0) { - tabcommands = commands[0]; - } else { - tabcommands = document.createElement('div'); - YAHOO.util.Dom.addClass(tabcommands, 'commands'); - } - - if (YAHOO.util.Dom.hasClass(sideblocknode, 'block-region')) { - var blocks = YAHOO.util.Dom.getElementsByClassName('sideblock', 'div', sideblocknode); - if (blocks.length === 0) { - YAHOO.moodle.navigation.sideblockwidth = YAHOO.util.Dom.getStyle(sideblocknode, 'width'); - YAHOO.util.Dom.setStyle(sideblocknode, 'width', '0px'); - } - } - - if (YAHOO.moodle.navigation.tabpanel === null) { - YAHOO.moodle.navigation.tabpanel = new navigation_tab_panel(); - } - YAHOO.moodle.navigation.tabpanel.add_to_tab_panel(this.name, tabtitle, tabcontent, tabcommands); - if (!this.skipsetposition) { - set_user_preference('nav_in_tab_panel_'+this.name, 1); - } else { - this.skipsetposition = false; - } - return true; -} -/** - * This function gets called from {@link navigation_tree.toggle_block_display()} - * and is responsible for moving the block from the sidebar to the block position - * @return {bool} - */ -navigation_tree.prototype.move_to_block_position = function(e) { - - YAHOO.util.Event.stopEvent(e); - - if (this.sideblockwidth !== null) { - YAHOO.util.Dom.setStyle(sideblocknode, 'width', this.sideblockwidth); - this.sideblockwidth = null; - } - - var placeholder = document.getElementById(this.name+'_content_placeholder'); - if (!placeholder || YAHOO.moodle.navigation.tabpanel == null) { - return false; - } - - if (YAHOO.moodle.navigation.tabpanel.showntab !== null) { - YAHOO.moodle.navigation.tabpanel.hide_tab(e, YAHOO.moodle.navigation.tabpanel.showntab.tabname); - } - - var tabcontent = YAHOO.moodle.navigation.tabpanel.get_tab_panel_contents(this.name); - this.cachedcontent.appendChild(tabcontent); - placeholder.parentNode.replaceChild(this.cachedcontent, placeholder); - - if (YAHOO.moodle.navigation.sideblockwidth !== null) { - var sideblocknode = this.cachedcontent; - while (sideblocknode && !YAHOO.util.Dom.hasClass(sideblocknode, 'block-region')) { - sideblocknode = sideblocknode.parentNode; - } - if (YAHOO.util.Dom.hasClass(sideblocknode, 'block-region')) { - YAHOO.util.Dom.setStyle(sideblocknode, 'width', YAHOO.moodle.navigation.sideblockwidth); - } - } - - var moveto = YAHOO.util.Dom.getElementsByClassName('moveto customcommand', 'a', this.cachedcontent); - if (moveto.length > 0) { - for (var i=0;i0) { - for (var j=0;j 0 && YAHOO.env.ua.ie < 7) { - YAHOO.util.Dom.setStyle(navbar, 'height', YAHOO.util.Dom.getViewportHeight()+'px'); - } - - var navbarcontrol = document.createElement('div'); - YAHOO.util.Dom.addClass(navbarcontrol, 'controls'); - var removeall = document.createElement('img'); - removeall.setAttribute('src', get_image_url('t/movetoblock', 'moodle')); - removeall.setAttribute('title', mstr.moodle.moveallsidetabstoblock); - removeall.setAttribute('alt', mstr.moodle.moveallsidetabstoblock); - navbarcontrol.appendChild(removeall); - navbar.appendChild(navbarcontrol); - - document.getElementsByTagName('body')[0].appendChild(navbar); - navbar.appendChild(create_shadow(false, true, true, false)); - YAHOO.util.Dom.addClass(document.getElementsByTagName('body')[0], 'has_navigation_bar'); - this.navigationpanel = navbar; - this.tabpanelexists = true; - navbar.style.display = 'block'; - - YAHOO.util.Event.addListener(removeall, 'click', move_all_sidetabs_to_block_position); - - return true; -} -/** - * This removes the tab panel element from the page - * @method remove_tab_panel - * @return {bool} - */ -navigation_tab_panel.prototype.remove_tab_panel = function () { - var panel = document.getElementById('sidebarpopup'); - if (!panel) { - return false; - } - this.tabpanel = null; - panel.parentNode.removeChild(panel); - this.tabpanelexists = false; - this.navigationpanel = null; - if (YAHOO.util.Dom.hasClass(document.getElementsByTagName('body')[0], 'has_navigation_bar')) { - YAHOO.util.Dom.removeClass(document.getElementsByTagName('body')[0], 'has_navigation_bar') - } - return true; -} -/** - * This function retrieves the content of a tab in the navigation tab panel - * @method get_tab_panel_contents - * @param {string} tabname The name of the tab - * @return {element} The content element - */ -navigation_tab_panel.prototype.get_tab_panel_contents = function(tabname) { - remove_shadow(this.tabpanelelementcontents[tabname]); - return this.tabpanelelementcontents[tabname]; -} -/** - * This function adds a tab to the navigation tab panel - * - * If you find that it takes a long time to make the initial transaction then I - * would first check the time that set_user_preference is taking, during development - * the code needed to be re-jigged because it was taking a very long time to execute - * - * @method add_to_tab_panel - * @param {string} tabname The string name of the tab - * @param {element} tabtitle The title of the tab - * @param {element} tabcontent The content for the tab - * @param {element} tabcommands The commands for the tab - */ -navigation_tab_panel.prototype.add_to_tab_panel = function (tabname, tabtitle, tabcontent, tabcommands) { - if (!this.tabpanelexists) { - this.create_tab_panel(); - } - - var firsttab = (this.tabcount==0); - - var sidetab = document.createElement('div'); - sidetab.setAttribute('id', tabname+'_sidebarpopup'); - YAHOO.util.Dom.addClass(sidetab, 'sideblock_tab'); - - if (firsttab) { - YAHOO.util.Dom.addClass(sidetab, 'firsttab'); - } - var sidetabtitle = document.createElement('div'); - sidetabtitle.appendChild(tabtitle); - sidetabtitle.setAttribute('id', tabname+'_title'); - YAHOO.util.Dom.addClass(sidetabtitle, 'title'); - tabcontent.appendChild(create_shadow(true, true, true, false)); - sidetab.appendChild(sidetabtitle); - - if (tabcommands.childNodes.length>0) { - tabcontent.appendChild(tabcommands); - } - - this.navigationpanel.appendChild(sidetab); - - var position = YAHOO.util.Dom.getXY(sidetabtitle); - position[0] += sidetabtitle.offsetWidth; - if (YAHOO.env.ua.ie > 0 && YAHOO.env.ua.ie < 8) { - position[0] -= 2; - } - - this.tabpanels[tabname] = new YAHOO.widget.Panel('navigation_tab_panel_'+tabname, { - close:false, - draggable:false, - constraintoviewport: false, - underlay:"none", - visible:false, - monitorresize:false, - /*context:[tabname+'_title','tl','tr',['configChanged','beforeShow','changeBody']],*/ - xy:position, - autofillheight:'body'}); - this.tabpanels[tabname].showEvent.subscribe(this.resize_tab, this, true); - this.tabpanels[tabname].setBody(tabcontent); - this.tabpanels[tabname].render(this.navigationpanel); - - this.tabpanelelementnames[this.tabpanelelementnames.length] = tabname; - this.tabpanelelementcontents[tabname] = tabcontent; - this.tabcount++; - - YAHOO.util.Event.addListener(sidetab, "mouseover", this.show_tab, tabname, this); -} -/** - * This function handles checking the size, and positioning of the navigaiton - * panel when expansion events occur, or when the panel is shown, or if the window - * is resized - * - * There are undoubtably some bugs in this little bit of code. For one it relies - * on the padding set in CSS by the YUI:sam skin, if you are hitting a problem - * whereby the navigation extends beyond its border, or doesn't fill to its own - * border check the value assigned to padding for the panel body `.yui_panel .bd` - * - * @return {bool} - */ -navigation_tab_panel.prototype.resize_tab = function () { - var screenheight = YAHOO.util.Dom.getViewportHeight(); - var tabheight = parseInt(this.tabpanels[this.showntab.tabname].body.offsetHeight); - var tabtop = parseInt(this.tabpanels[this.showntab.tabname].cfg.getProperty('y')); - var titletop = YAHOO.util.Dom.getY(this.showntab.tabname+'_title'); - var scrolltop = (document.all)?document.body.scrollTop:window.pageYOffset; - // This makes sure that the panel is the same height as the tab title to - // begin with - if (tabtop > (10+scrolltop) && tabtop > (titletop+scrolltop)) { - this.tabpanels[this.showntab.tabname].cfg.setProperty('y', titletop+scrolltop); - } - - // This makes sure that if the panel is big it is moved up to ensure we don't - // have wasted space above the panel - if ((tabtop+tabheight)>(screenheight+scrolltop) && tabtop > 10) { - tabtop = (screenheight-tabheight-10); - if (tabtop<10) { - tabtop = 10; - } - this.tabpanels[this.showntab.tabname].cfg.setProperty('y', tabtop+scrolltop); - } - - // This makes the panel constrain to the screen's height if the panel is big - if (tabtop <= 10 && ((tabheight+tabtop*2) > screenheight || YAHOO.util.Dom.hasClass(this.tabpanels[this.showntab.tabname].body, 'oversized_content'))) { - this.tabpanels[this.showntab.tabname].cfg.setProperty('height', (screenheight-39)); - YAHOO.util.Dom.setStyle(this.tabpanels[this.showntab.tabname].body, 'height', (screenheight-59)+'px'); - YAHOO.util.Dom.addClass(this.tabpanels[this.showntab.tabname].body, 'oversized_content'); - } -} -/** - * This function sets everything up for the show even and then calls the panel's - * show event once we are happy. - * - * This function is responsible for closing any open panels, removing show events - * so we don't refresh unnessecarily and adding events to trap closing, and resizing - * events - * - * @param {event} e The event that fired to get us here - * @param {string} tabname The tabname to open - * @return {bool} - */ -navigation_tab_panel.prototype.show_tab = function (e, tabname) { - if (this.showntab !== null) { - this.hide_tab(e, this.showntab.tabname); - } - this.showntab = {event:e, tabname:tabname}; - this.tabpanels[tabname].show(e, this.tabpanel); - YAHOO.util.Dom.addClass(tabname+'_title', 'active_tab'); - YAHOO.util.Event.removeListener(tabname+'_sidebarpopup', "mouseover", this.show_tab); - YAHOO.util.Event.addListener('navigation_tab_panel_'+tabname, "click", function (e){this.preventhide = true}, this, true); - YAHOO.util.Event.addListener(tabname+'_sidebarpopup', "click", this.hide_tab, tabname, this); - YAHOO.util.Event.addListener(window, 'resize', this.resize_tab, this, true); - YAHOO.util.Event.addListener(document.body, "click", this.hide_tab, tabname, this); - return true; -} -/** - * This function closes the open tab and sets the listeners up to handle the show - * event again - * - * @param {event} e The event that fired to get us here - * @param {string} tabname The tabname to close - * @return {bool} - */ -navigation_tab_panel.prototype.hide_tab = function(e, tabname) { - if (this.preventhide===true) { - this.preventhide = false; - } else { - this.showntab = null; - YAHOO.util.Event.addListener(tabname+'_sidebarpopup', "mouseover", this.show_tab, tabname, this); - YAHOO.util.Event.removeListener(window, 'resize', this.resize_tab); - YAHOO.util.Event.removeListener(document.body, "click", this.hide_tab); - YAHOO.util.Dom.removeClass(tabname+'_title', 'active_tab'); - this.tabpanels[tabname].hide(e, this.tabpanel); - } -} -/** - * This function removes a tab from the navigation tab panel - * @param {string} tabname - * @return {bool} - */ -navigation_tab_panel.prototype.remove_from_tab_panel = function(tabname) { - var tab = document.getElementById(tabname+'_sidebarpopup'); - if (!tab) { - return false; - } - tab.parentNode.removeChild(tab); - this.tabpanels[tabname].destroy(); - this.tabpanels[tabname] = null; - this.tabcount--; - if (this.tabcount === 0) { - this.remove_tab_panel(); - } - return true; -} - -/** - * Global navigation tree branch object used to parse an XML branch - * into a usable object, and then to inject it into the DOM - * @class navigation_tree_branch - * @constructor - */ -function navigation_tree_branch(treename) { - this.treename = treename; - this.myname = null; - this.mytitle = null; - this.myclass = null; - this.myid = null; - this.mykey = null; - this.mytype = null; - this.mylink = null; - this.myicon = null; - this.myexpandable = null; - this.expansionceiling = null; - this.myhidden = false; - this.haschildren = false; - this.mychildren = false; -} -/** - * This function populates the object from an XML branch - * @param {xmlnode} branch The XML branch to turn into an object - */ -navigation_tree_branch.prototype.load_from_xml_node = function (branch) { - this.myname = null; - this.mytitle = branch.getAttribute('title'); - this.myclass = branch.getAttribute('class'); - this.myid = branch.getAttribute('id'); - this.mylink = branch.getAttribute('link'); - this.myicon = branch.getAttribute('icon'); - this.mykey = branch.getAttribute('key'); - this.mytype = branch.getAttribute('type'); - this.myexpandable = branch.getAttribute('expandable'); - this.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'))); - } else { - var branchlink = document.createElement('a'); - branchlink.setAttribute('title', this.mytitle); - branchlink.setAttribute('href', this.mylink); - if (branchicon !== false) { - branchlink.appendChild(branchicon); - } - branchlink.appendChild(document.createTextNode(this.myname.replace(/\n/g, '
'))); - if (this.myhidden) { - YAHOO.util.Dom.addClass(branchlink, 'dimmed'); - } - branchp.appendChild(branchlink); - } - branchli.appendChild(branchp); - element.appendChild(branchli); - return branchli; -} - -/** - * Creates a new JS instance of a global navigation tree and kicks it into gear - * @param {string} treename The name of the tree - */ -function setup_new_navtree(treename) { - var key = YAHOO.moodle.navigation.treecollection.length; - YAHOO.moodle.navigation.treecollection[key] = new navigation_tree(treename, key); - YAHOO.moodle.navigation.treecollection[key].initialise(); -} - -/** - * This function moves all navigation tree instances that are currently - * displayed in the sidebar back into their block positions - */ -function move_all_sidetabs_to_block_position(e) { - for (var i=0; i 0 && YAHOO.env.ua.ie < 7) { - // IE6 just doest like my shadow... - return shadow; - } - var createShadowDiv = function(cname) { - var shadowdiv = document.createElement('div'); - YAHOO.util.Dom.addClass(shadowdiv, cname); - if (YAHOO.env.ua.ie > 0 && YAHOO.env.ua.ie < 7) { - // IE version less than 7 doesnt support alpha - YAHOO.util.Dom.setStyle(shadowdiv, 'opacity', 0.3); - } - return shadowdiv; - } - if (top) shadow.appendChild(createShadowDiv('shadow_top')); - if (right) shadow.appendChild(createShadowDiv('shadow_right')); - if (bottom) shadow.appendChild(createShadowDiv('shadow_bottom')); - if (left) shadow.appendChild(createShadowDiv('shadow_left')); - if (top && left) shadow.appendChild(createShadowDiv('shadow_top_left')); - if (bottom && left) shadow.appendChild(createShadowDiv('shadow_bottom_left')); - if (top && right) shadow.appendChild(createShadowDiv('shadow_top_right')); - if (bottom && right) shadow.appendChild(createShadowDiv('shadow_bottom_right')); - return shadow; -} -/** - * This function removes any shadows that a node and its children may have - * @param {element} el The element to remove the shadow from - * @return {bool} - */ -function remove_shadow(el) { - var shadows = YAHOO.util.Dom.getElementsByClassName('divshadow', 'div', el); - if (shadows == null || shadows.length == 0) return true; - for (var i=0;i. + +/** + * This file contains classes used to manage the navigation structures in Moodle + * and was introduced as part of the changes occuring in Moodle 2.0 + * + * @since 2.0 + * @package javascript + * @copyright 2009 Sam Hemelryk + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * Some very important general namespaces to act as containers for the general + * objects required to manage the navigation. + * + * For anyone looking to improve this javascript taking a little time to turn + * the classes into namespaced classes, and giving the class structure in this file + * a similar structure to YUI on a moodle namespace would be AWESOME + */ +YAHOO.namespace('moodle.navigation'); +YAHOO.namespace('moodle.navigation.sideblockwidth'); +YAHOO.namespace('moodle.navigation.tabpanel'); +YAHOO.namespace('moodle.navigation.treecollection'); + +/** + * Instatiate some very important variables that allow us to manage the navigaiton + * objects without having to hit my arch enemy `undefined` + */ +YAHOO.moodle.navigation.sideblockwidth = null; +YAHOO.moodle.navigation.tabpanel = null; +YAHOO.moodle.navigation.treecollection = Array(); +YAHOO.moodle.navigation.expandablebranchcount = 0; + +/** + * Navigation Tree object (function) used to control a global navigation tree + * handling things such as collapse, expand, and AJAX requests for more branches + * + * You should never call this directly.. you should use {@link start_new_navtree()} + * which will create the class and make it accessible in a smart way + * + * @class navigation_tree + * @constructor + * @param {string} treename + * @param {string} key + */ +function navigation_tree (treename, key) { + this.name = treename; + this.key = key; + this.errorlog = ''; + this.ajaxbranches = 0; + this.expansions = Array(); + this.instance = null + this.cachedcontent = null; + this.cachedfooter = null; + this.position = 'block'; + this.skipsetposition = false; + this.togglesidetabdisplay = '[[togglesidetabdisplay]]'; + this.toggleblockdisplay = '[[toggleblockdisplay]]'; + this.sideblockwidth = null; + if (window[this.name]) { + if (window[this.name].expansions) { + this.expansions = window[this.name].expansions; + } + if (window[this.name].instance) { + this.instance = window[this.name].instance; + } + if (window[this.name].togglesidetabdisplay) { + this.togglesidetabdisplay = window[this.name].togglesidetabdisplay; + } + if (window[this.name].toggleblockdisplay) { + this.toggleblockdisplay = window[this.name].toggleblockdisplay; + } + } +} +/** + * Initialise function used to attach the initial events to the navigation tree + * This function attachs toggles and ajax calls + */ +navigation_tree.prototype.initialise = function() { + if (!document.getElementById(this.name)) { + return; + } + var e = document.getElementById(this.name); + var i = 0; + while (!YAHOO.util.Dom.hasClass(e, 'sideblock') && e.nodeName.toUpperCase()!='BODY') { + e = e.parentNode; + } + var movetos = YAHOO.util.Dom.getElementsByClassName('moveto', 'a', e); + if (movetos !== null && movetos.length > 0) { + for (i = 0;i0) { + for (i = 0; i 0) { + for (i = 0; i < customcommands.length; i++) { + customcommands[i].parentNode.removeChild(customcommands[i]); + commands[0].appendChild(customcommands[i]); + } + } + + if (YAHOO.util.Dom.hasClass(e, 'sideblock_js_sidebarpopout')) { + YAHOO.util.Dom.removeClass(e, 'sideblock_js_sidebarpopout'); + this.skipsetposition = true; + this.toggle_block_display(e, this); + } else if (YAHOO.util.Dom.hasClass(e, 'sideblock_js_expansion')) { + YAHOO.util.Event.addListener(e, 'mouseover', this.togglesize, e, this); + YAHOO.util.Event.addListener(e, 'mouseout', this.togglesize, e, this); + } +} +/** + * Toogle a branch either collapsed or expanded... CSS styled + * @param {object} e Event object + */ +navigation_tree.prototype.toggleexpansion = function(e) { + YAHOO.util.Event.stopPropagation(e); + var target = YAHOO.util.Event.getTarget(e); + var parent = target.parentNode; + while (parent.nodeName.toUpperCase()!='LI') { + parent = parent.parentNode; + } + if (YAHOO.util.Dom.hasClass(parent, 'collapsed')) { + YAHOO.util.Dom.removeClass(parent, 'collapsed'); + } else { + YAHOO.util.Dom.addClass(parent, 'collapsed'); + } + if (this.position === 'sidebar') { + YAHOO.moodle.navigation.tabpanel.resize_tab(); + } +} +/** + * Toggles the size on an element by adding/removing the mouseover class + * @param {object} e Event object + * @param {element} element The element to add/remove the class from + */ +navigation_tree.prototype.togglesize = function(e, element) { + if (e.type == 'mouseout') { + var mp = YAHOO.util.Event.getXY(e); + if (mp[0] == -1) { + return true; + } + var ep = YAHOO.util.Dom.getXY(element); + ep[2] = ep[0]+element.offsetWidth; + ep[3] = ep[1]+element.offsetHeight; + var withinrealm = (mp[0] > ep[0] && mp[0] < ep[2] && mp[1] > ep[1] && mp[1] < ep[3]); + if (!withinrealm) { + YAHOO.util.Event.stopEvent(e); + YAHOO.util.Dom.removeClass(element, 'mouseover'); + } + } else { + YAHOO.util.Event.stopEvent(e); + element.style.width = element.offsetWidth +'px'; + YAHOO.util.Dom.addClass(element, 'mouseover'); + } + return true; +} +/** + * This function makes the initial call to load a branch of the navigation + * tree by AJAX + * @param {object} e Event object + * @param {object} branch The branch object from navigation_tree::expansions + * @return {bool} + */ +navigation_tree.prototype.init_load_ajax = function(e, branch) { + YAHOO.util.Event.stopPropagation(e); + if (YAHOO.util.Event.getTarget(e).nodeName.toUpperCase() != 'P') { + return true; + } + var postargs = 'elementid='+branch.id+'&id='+branch.branchid+'&type='+branch.type+'&sesskey='+moodle_cfg.sesskey; + if (this.instance != null) { + postargs += '&instance='+this.instance; + } + YAHOO.util.Connect.asyncRequest('POST', moodle_cfg.wwwroot+'/lib/ajax/getnavbranch.php', callback={ + success:function(o) {this.load_ajax(o);}, + failure:function(o) {this.load_ajax(o);}, + argument: {gntinstance:this,branch:branch,event:e, target:YAHOO.util.Event.getTarget(e)}, + scope: this + }, postargs); + return true; +} +/** + * This function loads a branch returned by AJAX into the XHTML tree structure + * @param {object} outcome The AJAX response + * @return {bool} + */ +navigation_tree.prototype.load_ajax = function(outcome) { + // Check the status + if (outcome.status!=0 && outcome.responseXML!=null) { + var branch = outcome.responseXML.documentElement; + if (branch!=null && this.add_branch(branch,outcome.argument.target ,1)) { + // If we get here everything worked perfectly + YAHOO.util.Event.removeListener(outcome.argument.branch.element, 'click', navigation_tree.prototype.init_load_ajax); + if (this.position === 'sidebar') { + YAHOO.moodle.navigation.tabpanel.resize_tab(); + } + return true; + } + } + // Something went wrong or there simply wasn't anything more to display + // add the emptybranch css class so we can flag it + YAHOO.util.Dom.replaceClass(outcome.argument.target, 'branch', 'emptybranch'); + return false; +} +/** + * This recursive function takes an XML branch and includes it in the tree + * @param {xmlnode} branchxml The XML node for the branch + * @param {element} target The target node to add to + * @param {int} depth The depth we have delved (recusive counter) + * @return {bool} + */ +navigation_tree.prototype.add_branch = function(branchxml, target, depth) { + var branch = new navigation_tree_branch(this.name); + branch.load_from_xml_node(branchxml); + if (depth>1) { + target = branch.inject_into_dom(target,this); + } + var dropcount = 5; + while (target.nodeName.toUpperCase() !== 'LI') { + target = target.parentNode; + if (dropcount==0 && moodle_cfg.developerdebug) { + return alert("dropped because of exceeding dropcount"); + } + dropcount--; + } + if (branch.haschildren && branch.mychildren && branch.mychildren.childNodes) { + for (var i=0;i 0) { + for (var i=0;i0) { + for (var j=0;j"); + var commands = YAHOO.util.Dom.getElementsByClassName('commands', 'div', this.cachedcontent); + var tabcommands = null; + if (commands.length > 0) { + tabcommands = commands[0]; + } else { + tabcommands = document.createElement('div'); + YAHOO.util.Dom.addClass(tabcommands, 'commands'); + } + + if (YAHOO.util.Dom.hasClass(sideblocknode, 'block-region')) { + var blocks = YAHOO.util.Dom.getElementsByClassName('sideblock', 'div', sideblocknode); + if (blocks.length === 0) { + YAHOO.moodle.navigation.sideblockwidth = YAHOO.util.Dom.getStyle(sideblocknode, 'width'); + YAHOO.util.Dom.setStyle(sideblocknode, 'width', '0px'); + } + } + + if (YAHOO.moodle.navigation.tabpanel === null) { + YAHOO.moodle.navigation.tabpanel = new navigation_tab_panel(); + } + YAHOO.moodle.navigation.tabpanel.add_to_tab_panel(this.name, tabtitle, tabcontent, tabcommands); + if (!this.skipsetposition) { + set_user_preference('nav_in_tab_panel_'+this.name, 1); + } else { + this.skipsetposition = false; + } + return true; +} +/** + * This function gets called from {@link navigation_tree.toggle_block_display()} + * and is responsible for moving the block from the sidebar to the block position + * @return {bool} + */ +navigation_tree.prototype.move_to_block_position = function(e) { + + YAHOO.util.Event.stopEvent(e); + + if (this.sideblockwidth !== null) { + YAHOO.util.Dom.setStyle(sideblocknode, 'width', this.sideblockwidth); + this.sideblockwidth = null; + } + + var placeholder = document.getElementById(this.name+'_content_placeholder'); + if (!placeholder || YAHOO.moodle.navigation.tabpanel == null) { + return false; + } + + if (YAHOO.moodle.navigation.tabpanel.showntab !== null) { + YAHOO.moodle.navigation.tabpanel.hide_tab(e, YAHOO.moodle.navigation.tabpanel.showntab.tabname); + } + + var tabcontent = YAHOO.moodle.navigation.tabpanel.get_tab_panel_contents(this.name); + this.cachedcontent.appendChild(tabcontent); + placeholder.parentNode.replaceChild(this.cachedcontent, placeholder); + + if (YAHOO.moodle.navigation.sideblockwidth !== null) { + var sideblocknode = this.cachedcontent; + while (sideblocknode && !YAHOO.util.Dom.hasClass(sideblocknode, 'block-region')) { + sideblocknode = sideblocknode.parentNode; + } + if (YAHOO.util.Dom.hasClass(sideblocknode, 'block-region')) { + YAHOO.util.Dom.setStyle(sideblocknode, 'width', YAHOO.moodle.navigation.sideblockwidth); + } + } + + var moveto = YAHOO.util.Dom.getElementsByClassName('moveto customcommand', 'a', this.cachedcontent); + if (moveto.length > 0) { + for (var i=0;i0) { + for (var j=0;j 0 && YAHOO.env.ua.ie < 7) { + YAHOO.util.Dom.setStyle(navbar, 'height', YAHOO.util.Dom.getViewportHeight()+'px'); + } + + var navbarcontrol = document.createElement('div'); + YAHOO.util.Dom.addClass(navbarcontrol, 'controls'); + var removeall = document.createElement('img'); + removeall.setAttribute('src', get_image_url('t/movetoblock', 'moodle')); + removeall.setAttribute('title', mstr.moodle.moveallsidetabstoblock); + removeall.setAttribute('alt', mstr.moodle.moveallsidetabstoblock); + navbarcontrol.appendChild(removeall); + navbar.appendChild(navbarcontrol); + + document.getElementsByTagName('body')[0].appendChild(navbar); + navbar.appendChild(create_shadow(false, true, true, false)); + YAHOO.util.Dom.addClass(document.getElementsByTagName('body')[0], 'has_navigation_bar'); + this.navigationpanel = navbar; + this.tabpanelexists = true; + navbar.style.display = 'block'; + + YAHOO.util.Event.addListener(removeall, 'click', move_all_sidetabs_to_block_position); + + return true; +} +/** + * This removes the tab panel element from the page + * @method remove_tab_panel + * @return {bool} + */ +navigation_tab_panel.prototype.remove_tab_panel = function () { + var panel = document.getElementById('sidebarpopup'); + if (!panel) { + return false; + } + this.tabpanel = null; + panel.parentNode.removeChild(panel); + this.tabpanelexists = false; + this.navigationpanel = null; + if (YAHOO.util.Dom.hasClass(document.getElementsByTagName('body')[0], 'has_navigation_bar')) { + YAHOO.util.Dom.removeClass(document.getElementsByTagName('body')[0], 'has_navigation_bar') + } + return true; +} +/** + * This function retrieves the content of a tab in the navigation tab panel + * @method get_tab_panel_contents + * @param {string} tabname The name of the tab + * @return {element} The content element + */ +navigation_tab_panel.prototype.get_tab_panel_contents = function(tabname) { + remove_shadow(this.tabpanelelementcontents[tabname]); + return this.tabpanelelementcontents[tabname]; +} +/** + * This function adds a tab to the navigation tab panel + * + * If you find that it takes a long time to make the initial transaction then I + * would first check the time that set_user_preference is taking, during development + * the code needed to be re-jigged because it was taking a very long time to execute + * + * @method add_to_tab_panel + * @param {string} tabname The string name of the tab + * @param {element} tabtitle The title of the tab + * @param {element} tabcontent The content for the tab + * @param {element} tabcommands The commands for the tab + */ +navigation_tab_panel.prototype.add_to_tab_panel = function (tabname, tabtitle, tabcontent, tabcommands) { + if (!this.tabpanelexists) { + this.create_tab_panel(); + } + + var firsttab = (this.tabcount==0); + + var sidetab = document.createElement('div'); + sidetab.setAttribute('id', tabname+'_sidebarpopup'); + YAHOO.util.Dom.addClass(sidetab, 'sideblock_tab'); + + if (firsttab) { + YAHOO.util.Dom.addClass(sidetab, 'firsttab'); + } + var sidetabtitle = document.createElement('div'); + sidetabtitle.appendChild(tabtitle); + sidetabtitle.setAttribute('id', tabname+'_title'); + YAHOO.util.Dom.addClass(sidetabtitle, 'title'); + tabcontent.appendChild(create_shadow(true, true, true, false)); + sidetab.appendChild(sidetabtitle); + + if (tabcommands.childNodes.length>0) { + tabcontent.appendChild(tabcommands); + } + + this.navigationpanel.appendChild(sidetab); + + var position = YAHOO.util.Dom.getXY(sidetabtitle); + position[0] += sidetabtitle.offsetWidth; + if (YAHOO.env.ua.ie > 0 && YAHOO.env.ua.ie < 8) { + position[0] -= 2; + } + + this.tabpanels[tabname] = new YAHOO.widget.Panel('navigation_tab_panel_'+tabname, { + close:false, + draggable:false, + constraintoviewport: false, + underlay:"none", + visible:false, + monitorresize:false, + /*context:[tabname+'_title','tl','tr',['configChanged','beforeShow','changeBody']],*/ + xy:position, + autofillheight:'body'}); + this.tabpanels[tabname].showEvent.subscribe(this.resize_tab, this, true); + this.tabpanels[tabname].setBody(tabcontent); + this.tabpanels[tabname].render(this.navigationpanel); + + this.tabpanelelementnames[this.tabpanelelementnames.length] = tabname; + this.tabpanelelementcontents[tabname] = tabcontent; + this.tabcount++; + + YAHOO.util.Event.addListener(sidetab, "mouseover", this.show_tab, tabname, this); +} +/** + * This function handles checking the size, and positioning of the navigaiton + * panel when expansion events occur, or when the panel is shown, or if the window + * is resized + * + * There are undoubtably some bugs in this little bit of code. For one it relies + * on the padding set in CSS by the YUI:sam skin, if you are hitting a problem + * whereby the navigation extends beyond its border, or doesn't fill to its own + * border check the value assigned to padding for the panel body `.yui_panel .bd` + * + * @return {bool} + */ +navigation_tab_panel.prototype.resize_tab = function () { + var screenheight = YAHOO.util.Dom.getViewportHeight(); + var tabheight = parseInt(this.tabpanels[this.showntab.tabname].body.offsetHeight); + var tabtop = parseInt(this.tabpanels[this.showntab.tabname].cfg.getProperty('y')); + var titletop = YAHOO.util.Dom.getY(this.showntab.tabname+'_title'); + var scrolltop = (document.all)?document.body.scrollTop:window.pageYOffset; + // This makes sure that the panel is the same height as the tab title to + // begin with + if (tabtop > (10+scrolltop) && tabtop > (titletop+scrolltop)) { + this.tabpanels[this.showntab.tabname].cfg.setProperty('y', titletop+scrolltop); + } + + // This makes sure that if the panel is big it is moved up to ensure we don't + // have wasted space above the panel + if ((tabtop+tabheight)>(screenheight+scrolltop) && tabtop > 10) { + tabtop = (screenheight-tabheight-10); + if (tabtop<10) { + tabtop = 10; + } + this.tabpanels[this.showntab.tabname].cfg.setProperty('y', tabtop+scrolltop); + } + + // This makes the panel constrain to the screen's height if the panel is big + if (tabtop <= 10 && ((tabheight+tabtop*2) > screenheight || YAHOO.util.Dom.hasClass(this.tabpanels[this.showntab.tabname].body, 'oversized_content'))) { + this.tabpanels[this.showntab.tabname].cfg.setProperty('height', (screenheight-39)); + YAHOO.util.Dom.setStyle(this.tabpanels[this.showntab.tabname].body, 'height', (screenheight-59)+'px'); + YAHOO.util.Dom.addClass(this.tabpanels[this.showntab.tabname].body, 'oversized_content'); + } +} +/** + * This function sets everything up for the show even and then calls the panel's + * show event once we are happy. + * + * This function is responsible for closing any open panels, removing show events + * so we don't refresh unnessecarily and adding events to trap closing, and resizing + * events + * + * @param {event} e The event that fired to get us here + * @param {string} tabname The tabname to open + * @return {bool} + */ +navigation_tab_panel.prototype.show_tab = function (e, tabname) { + if (this.showntab !== null) { + this.hide_tab(e, this.showntab.tabname); + } + this.showntab = {event:e, tabname:tabname}; + this.tabpanels[tabname].show(e, this.tabpanel); + YAHOO.util.Dom.addClass(tabname+'_title', 'active_tab'); + YAHOO.util.Event.removeListener(tabname+'_sidebarpopup', "mouseover", this.show_tab); + YAHOO.util.Event.addListener('navigation_tab_panel_'+tabname, "click", function (e){this.preventhide = true}, this, true); + YAHOO.util.Event.addListener(tabname+'_sidebarpopup', "click", this.hide_tab, tabname, this); + YAHOO.util.Event.addListener(window, 'resize', this.resize_tab, this, true); + YAHOO.util.Event.addListener(document.body, "click", this.hide_tab, tabname, this); + return true; +} +/** + * This function closes the open tab and sets the listeners up to handle the show + * event again + * + * @param {event} e The event that fired to get us here + * @param {string} tabname The tabname to close + * @return {bool} + */ +navigation_tab_panel.prototype.hide_tab = function(e, tabname) { + if (this.preventhide===true) { + this.preventhide = false; + } else { + this.showntab = null; + YAHOO.util.Event.addListener(tabname+'_sidebarpopup', "mouseover", this.show_tab, tabname, this); + YAHOO.util.Event.removeListener(window, 'resize', this.resize_tab); + YAHOO.util.Event.removeListener(document.body, "click", this.hide_tab); + YAHOO.util.Dom.removeClass(tabname+'_title', 'active_tab'); + this.tabpanels[tabname].hide(e, this.tabpanel); + } +} +/** + * This function removes a tab from the navigation tab panel + * @param {string} tabname + * @return {bool} + */ +navigation_tab_panel.prototype.remove_from_tab_panel = function(tabname) { + var tab = document.getElementById(tabname+'_sidebarpopup'); + if (!tab) { + return false; + } + tab.parentNode.removeChild(tab); + this.tabpanels[tabname].destroy(); + this.tabpanels[tabname] = null; + this.tabcount--; + if (this.tabcount === 0) { + this.remove_tab_panel(); + } + return true; +} + +/** + * Global navigation tree branch object used to parse an XML branch + * into a usable object, and then to inject it into the DOM + * @class navigation_tree_branch + * @constructor + */ +function navigation_tree_branch(treename) { + this.treename = treename; + this.myname = null; + this.mytitle = null; + this.myclass = null; + this.myid = null; + this.mykey = null; + this.mytype = null; + this.mylink = null; + this.myicon = null; + this.myexpandable = null; + this.expansionceiling = null; + this.myhidden = false; + this.haschildren = false; + this.mychildren = false; +} +/** + * This function populates the object from an XML branch + * @param {xmlnode} branch The XML branch to turn into an object + */ +navigation_tree_branch.prototype.load_from_xml_node = function (branch) { + this.myname = null; + this.mytitle = branch.getAttribute('title'); + this.myclass = branch.getAttribute('class'); + this.myid = branch.getAttribute('id'); + this.mylink = branch.getAttribute('link'); + this.myicon = branch.getAttribute('icon'); + this.mykey = branch.getAttribute('key'); + this.mytype = branch.getAttribute('type'); + this.myexpandable = branch.getAttribute('expandable'); + this.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'))); + } else { + var branchlink = document.createElement('a'); + branchlink.setAttribute('title', this.mytitle); + branchlink.setAttribute('href', this.mylink); + if (branchicon !== false) { + branchlink.appendChild(branchicon); + } + branchlink.appendChild(document.createTextNode(this.myname.replace(/\n/g, '
'))); + if (this.myhidden) { + YAHOO.util.Dom.addClass(branchlink, 'dimmed'); + } + branchp.appendChild(branchlink); + } + branchli.appendChild(branchp); + element.appendChild(branchli); + return branchli; +} + +/** + * Creates a new JS instance of a global navigation tree and kicks it into gear + * @param {string} treename The name of the tree + */ +function setup_new_navtree(treename) { + var key = YAHOO.moodle.navigation.treecollection.length; + YAHOO.moodle.navigation.treecollection[key] = new navigation_tree(treename, key); + YAHOO.moodle.navigation.treecollection[key].initialise(); +} + +/** + * This function moves all navigation tree instances that are currently + * displayed in the sidebar back into their block positions + */ +function move_all_sidetabs_to_block_position(e) { + for (var i=0; i 0 && YAHOO.env.ua.ie < 7) { + // IE6 just doest like my shadow... + return shadow; + } + var createShadowDiv = function(cname) { + var shadowdiv = document.createElement('div'); + YAHOO.util.Dom.addClass(shadowdiv, cname); + if (YAHOO.env.ua.ie > 0 && YAHOO.env.ua.ie < 7) { + // IE version less than 7 doesnt support alpha + YAHOO.util.Dom.setStyle(shadowdiv, 'opacity', 0.3); + } + return shadowdiv; + } + if (top) shadow.appendChild(createShadowDiv('shadow_top')); + if (right) shadow.appendChild(createShadowDiv('shadow_right')); + if (bottom) shadow.appendChild(createShadowDiv('shadow_bottom')); + if (left) shadow.appendChild(createShadowDiv('shadow_left')); + if (top && left) shadow.appendChild(createShadowDiv('shadow_top_left')); + if (bottom && left) shadow.appendChild(createShadowDiv('shadow_bottom_left')); + if (top && right) shadow.appendChild(createShadowDiv('shadow_top_right')); + if (bottom && right) shadow.appendChild(createShadowDiv('shadow_bottom_right')); + return shadow; +} +/** + * This function removes any shadows that a node and its children may have + * @param {element} el The element to remove the shadow from + * @return {bool} + */ +function remove_shadow(el) { + var shadows = YAHOO.util.Dom.getElementsByClassName('divshadow', 'div', el); + if (shadows == null || shadows.length == 0) return true; + for (var i=0;i