From 892e21aadd5af7fad06e3c6b37085da6b07e5624 Mon Sep 17 00:00:00 2001 From: Sam Hemelryk Date: Fri, 28 Nov 2014 09:15:44 +1300 Subject: [PATCH] MDL-36296 block_navigation: consistency fixes This change fixes a couple of consistency issues in the navigation block. At the same time it fixes it the CSS for the navigation block as it had really degraded over the last years. Notable points about this change: * Fixed icon display by wrapping content in a span allowing columns to be styled. * Re-wrote the CSS entirely as it could be done much better. * Fixed inconsistencies between the php and JS for rendering nodes. --- blocks/navigation/renderer.php | 50 +++--- blocks/navigation/styles.css | 149 +++++++++++------- ...oodle-block_navigation-navigation-debug.js | 17 +- .../moodle-block_navigation-navigation-min.js | 4 +- .../moodle-block_navigation-navigation.js | 17 +- .../yui/src/navigation/js/navigation.js | 17 +- 6 files changed, 167 insertions(+), 87 deletions(-) diff --git a/blocks/navigation/renderer.php b/blocks/navigation/renderer.php index c92ef41f0a1..74cc0885f7b 100644 --- a/blocks/navigation/renderer.php +++ b/blocks/navigation/renderer.php @@ -51,7 +51,7 @@ class block_navigation_renderer extends plugin_renderer_base { /** * Produces a navigation node for the navigation tree * - * @param array $items + * @param navigation_node[] $items * @param array $attrs * @param int $expansionlimit * @param array $options @@ -59,13 +59,12 @@ class block_navigation_renderer extends plugin_renderer_base { * @return string */ protected function navigation_node($items, $attrs=array(), $expansionlimit=null, array $options = array(), $depth=1) { - - // exit if empty, we don't want an empty ul element - if (count($items)==0) { + // Exit if empty, we don't want an empty ul element. + if (count($items) === 0) { return ''; } - // array of nested li elements + // Turn our navigation items into list items. $lis = array(); foreach ($items as $item) { if (!$item->display && !$item->contains_active_node()) { @@ -86,10 +85,13 @@ class block_navigation_renderer extends plugin_renderer_base { if ($hasicon) { $icon = $this->output->render($item->icon); + // Because an icon is being used we're going to wrap the actual content in a span. + // This will allow designers to create columns for the content, as we've done in styles.css. + $content = $icon . html_writer::span($content, 'item-content-wrap'); } else { $icon = ''; } - $content = $icon.$content; // use CSS for spacing of icons + if ($item->helpbutton !== null) { $content = trim($item->helpbutton).html_writer::tag('span', $content, array('class'=>'clearhelpbutton')); } @@ -116,13 +118,16 @@ class block_navigation_renderer extends plugin_renderer_base { $link->text = $icon.$link->text; $link->attributes = array_merge($link->attributes, $attributes); $content = $this->output->render($link); - $linkrendered = true; } else if ($item->action instanceof moodle_url) { $content = html_writer::link($item->action, $content, $attributes); } - // this applies to the li item which contains all child lists too + // This applies to the li item which contains all child lists too. $liclasses = array($item->get_css_type(), 'depth_'.$depth); + + // Class attribute on the div item which only contains the item content. + $divclasses = array('tree_item'); + $liexpandable = array(); if ($item->has_children() && (!$item->forceopen || $item->collapse)) { $liclasses[] = 'collapsed'; @@ -130,30 +135,30 @@ class block_navigation_renderer extends plugin_renderer_base { if ($isbranch) { $liclasses[] = 'contains_branch'; $liexpandable = array('aria-expanded' => in_array('collapsed', $liclasses) ? "false" : "true"); - } else if ($hasicon) { - $liclasses[] = 'item_with_icon'; - } - if ($item->isactive === true) { - $liclasses[] = 'current_branch'; - } - $liattr = array('class' => join(' ',$liclasses)) + $liexpandable; - // class attribute on the div item which only contains the item content - $divclasses = array('tree_item'); - if ($isbranch) { $divclasses[] = 'branch'; } else { $divclasses[] = 'leaf'; } if ($hasicon) { + // Add this class if the item has an icon, whether it is a branch or not. + $liclasses[] = 'item_with_icon'; $divclasses[] = 'hasicon'; } + if ($item->isactive === true) { + $liclasses[] = 'current_branch'; + } if (!empty($item->classes) && count($item->classes)>0) { $divclasses[] = join(' ', $item->classes); } + + // Now build attribute arrays. + $liattr = array('class' => join(' ', $liclasses)) + $liexpandable; $divattr = array('class'=>join(' ', $divclasses)); if (!empty($item->id)) { $divattr['id'] = $item->id; } + + // Create the structure. $content = html_writer::tag('p', $content, $divattr); if ($isexpandable) { $content .= $this->navigation_node($item->children, array(), $expansionlimit, $options, $depth+1); @@ -165,11 +170,14 @@ class block_navigation_renderer extends plugin_renderer_base { $lis[] = $content; } - if (count($lis)) { - return html_writer::tag('ul', implode("\n", $lis), $attrs); - } else { + if (count($lis) === 0) { + // There is still a chance, despite having items, that nothing had content and no list items were created. return ''; } + + // We used to separate using new lines, however we don't do that now, instead we'll save a few chars. + // The source is complex already anyway. + return html_writer::tag('ul', implode('', $lis), $attrs); } } diff --git a/blocks/navigation/styles.css b/blocks/navigation/styles.css index c25945c08c5..c35c764fb21 100644 --- a/blocks/navigation/styles.css +++ b/blocks/navigation/styles.css @@ -1,66 +1,105 @@ -/** General display rules **/ -.block_navigation .block_tree {margin:5px;padding-left:0px;overflow:visible;} -.block_navigation .block_tree li {margin:3px;list-style: none;padding:0;} -.block_navigation .block_tree li.item_with_icon > p {position:relative; padding-left: 21px;} -.block_navigation .block_tree li.item_with_icon > p img, -.block_navigation .block_tree .type_activity > p.tree_item.active_tree_node img, -.block_navigation .block_tree li > p.hasicon img {vertical-align:middle;position:absolute;left:0;top:-1px;width:16px;height:16px;} -.block_navigation .block_tree li.item_with_icon.contains_branch > p img {left:16px;} -.block_navigation .block_tree .type_activity > p.branch.hasicon, -.block_navigation .block_tree .type_activity > p.emptybranch.hasicon, -.block_navigation .block_tree li.item_with_icon.contains_branch > .tree_item {padding-left:37px;} +.block_navigation .block_tree { + margin: 0; + list-style: none; +} -.block_navigation .block_tree li ul {padding-left:0;margin:0;} -.block_navigation .block_tree li.depth_2 ul {padding-left:16px;margin:0;} -.block_navigation .block_tree .type_activity > p.tree_item.branch.hasicon.active_tree_node, -.block_navigation .block_tree .tree_item {padding-left: 21px;margin:3px 0px;text-align:left;} +.block_navigation .block_tree .depth_1 > .tree_item.branch, +.block_navigation .block_tree .depth_1 > .tree_item.emptybranch { + padding-left: 0; + background-image: none; +} -.block_navigation .block_tree .tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: 0 0;background-repeat: no-repeat;} -.block_navigation .block_tree .tree_item.branch.navigation_node {background-image:none;padding-left:0;} -.block_navigation .block_tree .type_activity > .tree_item.emptybranch, -.block_navigation .block_tree .type_activity > .tree_item.branch {background-image:none;position:relative;} -.block_navigation .block_tree .type_activity > .tree_item.hasicon.emptybranch img, -.block_navigation .block_tree .type_activity > .tree_item.branch img {left: 16px;} -.block_navigation .block_tree .root_node.leaf {padding-left:0px;} -.block_navigation .block_tree .active_tree_node {font-weight:bold;} -.block_navigation .block_tree .depth_1.current_branch ul {font-weight:normal;} +.block_navigation .block_tree .tree_item { + margin: 3px 0; + background-position: 0 50%; + background-repeat: no-repeat; +} -.dock .block_navigation .tree_item {white-space: nowrap;} +.block_navigation .block_tree .tree_item.branch { + padding-left: 21px; + cursor: pointer; + background-image: url('[[pix:t/expanded]]'); +} -.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 0;background-repeat: no-repeat;} -.jsenabled .block_navigation .block_tree .collapsed ul {display: none;} -.jsenabled .block_navigation .block_tree .type_activity > .tree_item.branch {background-image: url([[pix:t/expanded]]);} -.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]]);} +.block_navigation .block_tree .tree_item.emptybranch { + padding-left: 21px; + background-image: url('[[pix:t/collapsed_empty]]'); +} -/** JavaScript state rules **/ -.jsenabled .block_navigation.dock_on_load, -.block_navigation .block_tree_box .requiresjs {display:none;} -.jsenabled .block_navigation .block_tree_box .requiresjs {display:inline;} +.block_navigation .block_tree .tree_item.loadingbranch { + background-image: url('[[pix:i/loading_small]]'); +} -/** Internet explorer specific rules **/ -.ie6 .block_navigation .block_tree .tree_item {width:100%;} +.block_navigation .block_tree .tree_item img { + width: 16px; + height: 16px; + margin-top: 3px; + margin-right: 5px; + vertical-align: top; +} -/** Overide for RTL layout **/ -.dir-rtl .block_navigation .block_tree li.depth_2 ul {padding-left: 0; padding-right: 16px;} -.dir-rtl .block_navigation .block_tree .type_activity > p.tree_item.branch.hasicon.active_tree_node, -.dir-rtl .block_navigation .block_tree .tree_item {padding-right: 21px;text-align:right;} +.block_navigation .block_tree .tree_item.active_tree_node { + font-weight: bold; +} -.dir-rtl .block_navigation .block_tree .tree_item.branch {background-position: center right;} +.block_navigation .block_tree .tree_item.hasicon { + white-space: nowrap; +} -.dir-rtl .block_navigation .block_tree, -.dir-rtl .block_navigation .block_tree li ul, -.dir-rtl .block_navigation .block_tree .navigation_node.tree_item.branch, -.dir-rtl .block_navigation .block_tree .root_node.leaf {padding-right:0;} +.block_navigation .block_tree .tree_item.hasicon .item-content-wrap { + display: inline-block; + white-space: normal; +} -.dir-rtl .block_navigation .block_tree li.item_with_icon > p img, -.dir-rtl .block_navigation .block_tree .type_activity > p.tree_item.active_tree_node img, -.dir-rtl .block_navigation .block_tree li > p.hasicon img {left:auto; right:0;} -.dir-rtl .block_navigation .block_tree li.item_with_icon.contains_branch > p img {left: auto; right:16px;} -.dir-rtl .block_navigation .block_tree .type_activity > p.branch.hasicon, -.dir-rtl .block_navigation .block_tree li.item_with_icon.contains_branch > .tree_item {padding-right:37px; padding-left: 0;} -.dir-rtl .block_navigation .block_tree .type_activity > .tree_item.branch img {right: 16px; left: auto;} +.block_navigation .block_tree ul { + margin: 0; +} -.jsenabled.dir-rtl .block_navigation .block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty_rtl]]);background-position: center right;} -.jsenabled.dir-rtl .block_navigation .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed_rtl]]);} +.block_navigation .block_tree ul ul { + margin: 0 0 0 16px; + list-style: none; +} + +.jsenabled .block_navigation .block_tree li.collapsed ul { + display: none; +} + +.jsenabled .block_navigation .block_tree li.collapsed .tree_item.branch { + background-image: url('[[pix:t/collapsed]]'); +} + +.jsenabled .block_navigation.dock_on_load { + display: none; +} + +.dir-rtl .block_navigation .block_tree .depth_1 .tree_item { + padding-left: 0; +} + +.dir-rtl .block_navigation .block_tree .tree_item { + background-position: 100% 50%; +} + +.dir-rtl .block_navigation .block_tree .tree_item.branch { + padding-right: 21px; + padding-left: 0; +} + +.dir-rtl .block_navigation .block_tree .tree_item.emptybranch { + padding-right: 21px; + padding-left: 0; + background-image: url('[[pix:t/collapsed_empty_rtl]]'); +} + +.dir-rtl .block_navigation .block_tree .tree_item img { + margin-right: 0; + margin-left: 5px; +} + +.dir-rtl .block_navigation .block_tree ul { + margin: 0 16px 0 0; +} + +.dir-rtl.jsenabled .block_navigation .block_tree .collapsed .tree_item.branch { + background-image: url('[[pix:t/collapsed_rtl]]'); +} diff --git a/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-debug.js b/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-debug.js index 20737009573..2d587027658 100644 --- a/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-debug.js +++ b/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-debug.js @@ -483,6 +483,9 @@ BRANCH.prototype = { * This function creates a DOM structure for the branch and then injects * it into the navigation tree at the correct point. * + * It is important that this is kept in check with block_navigation_renderer::navigation_node as that produces + * the same thing as this but on the php side. + * * @method draw * @chainable * @param {Node} element @@ -494,6 +497,7 @@ BRANCH.prototype = { var branchli = Y.Node.create('
  • '); var link = this.get('link'); var branchp = Y.Node.create('

    ').setAttribute('id', this.get('id')); + var name; if (!link) { //add tab focus if not link (so still one focus per menu node). // it was suggested to have 2 foci. one for the node and one for the link in MDL-27428. @@ -508,10 +512,11 @@ BRANCH.prototype = { // 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') === NODETYPE.ACTIVITY)) { + if (icon && (!isbranch || this.get('type') === NODETYPE.ACTIVITY || this.get('type') === NODETYPE.RESOURCE)) { branchicon = Y.Node.create(''); branchicon.setAttribute('src', M.util.image_url(icon.pix, icon.component)); branchli.addClass('item_with_icon'); + branchp.addClass('hasicon'); if (icon.alt) { branchicon.setAttribute('alt', icon.alt); } @@ -529,8 +534,11 @@ BRANCH.prototype = { var branchspan = Y.Node.create(''); if (branchicon) { branchspan.appendChild(branchicon); + name = '' + this.get('name') + ''; + } else { + name = this.get('name'); } - branchspan.append(this.get('name')); + branchspan.append(name); if (this.get('hidden')) { branchspan.addClass('dimmed_text'); } @@ -539,8 +547,11 @@ BRANCH.prototype = { var branchlink = Y.Node.create(''); if (branchicon) { branchlink.appendChild(branchicon); + name = '' + this.get('name') + ''; + } else { + name = this.get('name'); } - branchlink.append(this.get('name')); + branchlink.append(name); if (this.get('hidden')) { branchlink.addClass('dimmed'); } diff --git a/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-min.js b/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-min.js index 962ebaa85f8..7c67d98753c 100644 --- a/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-min.js +++ b/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-min.js @@ -1,2 +1,2 @@ -YUI.add("moodle-block_navigation-navigation",function(e,t){M.block_navigation=M.block_navigation||{},M.block_navigation.expandablebranchcount=1,M.block_navigation.courselimit=20,M.block_navigation.init_add_tree=function(e){e.courselimit&&(this.courselimit=e.courselimit),new u(e)},e.Event.define("actionkey",{_event:e.UA.webkit||e.UA.ie?"keydown":"keypress",_keys:{37:"collapse",39:"expand",32:"toggle",13:"enter"},_keyHandler:function(e,t,n){var r;n.actions?r=n.actions:r={collapse:!0,expand:!0,toggle:!0,enter:!0},this._keys[e.keyCode]&&r[this._keys[e.keyCode]]&&(e.action=this._keys[e.keyCode],t.fire(e))},on:function(e,t,n){t.args===null?t._detacher=e.on(this._event,this._keyHandler,this,n,{actions:!1}):t._detacher=e.on(this._event,this._keyHandler,this,n,t.args[0])},detach:function(e,t){t._detacher.detach()},delegate:function(e,t,n,r){t.args===null?t._delegateDetacher=e.delegate(this._event,this._keyHandler,r,this,n,{actions:!1}):t._delegateDetacher=e.delegate(this._event,this._keyHandler,r,this,n,t.args[0])},detachDelegate:function(e,t){t._delegateDetacher.detach()}});var n=0,r=20,i=30,s=40,o={ROOTNODE:0,SYSTEM:1,CATEGORY:10,MYCATEGORY:11,COURSE:20,SECTION:30,ACTIVITY:40,RESOURCE:50,CUSTOM:60,SETTING:70,SITEADMIN:71,USER:80,CONTAINER:90},u=function(){u.superclass.constructor.apply(this,arguments)};u.prototype={id:null,branches:[],initializer:function(t){this.id=parseInt(t.id,10);var n=e.one("#inst"+t.id);if(n===null)return;e.delegate("click",this.toggleExpansion,n.one(".block_tree"),".tree_item.branch",this),e.delegate("actionkey",this.toggleExpansion,n.one(".block_tree"),".tree_item.branch",this);var r=[];t.expansions?r=t.expansions:window["navtreeexpansions"+t.id]&&(r=window["navtreeexpansions"+t.id]);for(var i in r){var s=(new a({tree:this,branchobj:r[i],overrides:{expandable:!0,children:[],haschildren:!0}})).wire();M.block_navigation.expandablebranchcount++,this.branches[s.get("id")]=s}if(window.siteadminexpansion){var o=(new a({tree:this,branchobj:window.siteadminexpansion,overrides:{expandable:!0,children:[],haschildren:!0}})).wire();M.block_navigation.expandablebranchcount++,this.branches[o.get("id")]=o;if(o.node){var u=o.node.get("childNodes").item(0);if(u){var f=e.Node.create(''+u.get("innerHTML")+"");o.node.replaceChild(f,u)}}}M.block_navigation.expandablebranchcount>0&&(e.delegate("click",this.fire_branch_action,n.one(".block_tree"),".tree_item.branch[data-expandable]",this),e.delegate("actionkey",this.fire_branch_action,n.one(".block_tree"),".tree_item.branch[data-expandable]",this))},fire_branch_action:function(e){var t=e.currentTarget.getAttribute("id"),n=this.branches[t];n.ajaxLoad(e)},toggleExpansion:function(e){if(!e.target.test("a")||e.keyCode!==0&&e.keyCode!==13){var t=e.target;t.test("li")||(t=t.ancestor("li"));if(!t)return;if(!t.hasClass("depth_1"))if(e.type==="actionkey"){switch(e.action){case"expand":t.removeClass("collapsed"),t.set("aria-expanded",!0);break;case"collapse":t.addClass("collapsed"),t.set("aria-expanded",!1);break;default:t.toggleClass("collapsed"),t.set("aria-expanded",!t.hasClass("collapsed"))}e.halt()}else t.toggleClass("collapsed"),t.set("aria-expanded",!t.hasClass("collapsed"));return this.get("accordian")&&t.siblings("li").each(function(){this.get("id")!==t.get("id")&&!this.hasClass("collapsed")&&(this.addClass("collapsed"),this.set("aria-expanded",!1))}),this.get("candock")&&M.core.dock.notifyBlockChange&&M.core.dock.notifyBlockChange(this.id),!0}e.stopPropagation();return}},e.extend(u,e.Base,u.prototype,{NAME:"navigation-tree",ATTRS:{candock:{validator:e.Lang.isBool,value:!1},accordian:{validator:e.Lang.isBool,value:!1},expansionlimit:{value:0,setter:function(e){return e=parseInt(e,10),e!==n&&e!==r&&e!==i&&e!==s&&(e=n),e}},instance:{value:!1,setter:function(e){return parseInt(e,10)}}}});var a=function(){a.superclass.constructor.apply(this,arguments)};a.prototype={node:null,initializer:function(t){var r,i;if(t.branchobj!==null){for(r in t.branchobj)this.set(r,t.branchobj[r]);i=this.get("children"),this.set("haschildren",i.length>0)}if(t.overrides!==null)for(r in t.overrides)this.set(r,t.overrides[r]);this.node=e.one("#"+this.get("id"));var o=this.get("tree").get("expansionlimit"),u=this.get("type");o!==n&&u>=o&&u<=s&&(this.set("expandable",!1),this.set("haschildren",!1))},draw:function(t){var n=this.get("expandable")||this.get("haschildren"),r=e.Node.create("
  • "),i=this.get("link"),s=e.Node.create('

    ').setAttribute("id",this.get("id"));i||s.setAttribute("tabindex","0"),n&&(r.addClass("collapsed").addClass("contains_branch"),r.set("aria-expanded",!1),s.addClass("branch"));var u=!1,a=this.get("icon");if(a&&(!n||this.get("type")===o.ACTIVITY)){u=e.Node.create(''),u.setAttribute("src",M.util.image_url(a.pix,a.component)),r.addClass("item_with_icon"),a.alt&&u.setAttribute("alt",a.alt),a.title&&u.setAttribute("title",a.title);if(a.classes)for(var f in a.classes)u.addClass(a.classes[f])}if(!i){var l=e.Node.create("");u&&l.appendChild(u),l.append(this.get("name")),this.get("hidden")&&l.addClass("dimmed_text"),s.appendChild(l)}else{var c=e.Node.create('');u&&c.appendChild(u),c.append(this.get("name")),this.get("hidden")&&c.addClass("dimmed"),s.appendChild(c)}return r.appendChild(s),t.appendChild(r),this.node=s,this},wire:function(){return this.node=this.node||e.one("#"+this.get("id")),this.node?(this.get("expandable")&&(this.node.setAttribute("data-expandable","1"),this.node.setAttribute("data-loaded","0")),this):this},getChildrenUL:function(){var t=this.node.next("ul");return t||(t=e.Node.create(""),this.node.ancestor().append(t)),t},ajaxLoad:function(t){t.type==="actionkey"&&t.action!=="enter"?t.halt():t.stopPropagation();if(t.type==="actionkey"&&t.action==="enter"||t.target.test("a"))return this.node.setAttribute("data-expandable","0"),this.node.setAttribute("data-loaded","1"),!0;if(this.node.hasClass("loadingbranch" -))return!0;if(this.node.getAttribute("data-loaded")==="1")return!0;this.node.addClass("loadingbranch");var n={elementid:this.get("id"),id:this.get("key"),type:this.get("type"),sesskey:M.cfg.sesskey,instance:this.get("tree").get("instance")},r="/lib/ajax/getnavbranch.php";return this.get("type")===o.SITEADMIN&&(r="/lib/ajax/getsiteadminbranch.php"),e.io(M.cfg.wwwroot+r,{method:"POST",data:n,on:{complete:this.ajaxProcessResponse},context:this}),!0},ajaxProcessResponse:function(t,n){this.node.removeClass("loadingbranch"),this.node.setAttribute("data-loaded","1");try{var r=e.JSON.parse(n.responseText);if(r.error)return e.use("moodle-core-notification-ajaxexception",function(){return(new M.core.ajaxException(r)).show()}),!1;if(r.children&&r.children.length>0){var i=0;for(var s in r.children)typeof r.children[s]=="object"&&(r.children[s].type===o.COURSE&&i++,this.addChild(r.children[s]));return(this.get("type")===o.CATEGORY||this.get("type")===o.ROOTNODE||this.get("type")===o.MYCATEGORY)&&i>=M.block_navigation.courselimit&&this.addViewAllCoursesChild(this),this.get("tree").get("candock")&&M.core.dock.notifyBlockChange&&M.core.dock.notifyBlockChange(this.get("tree").id),!0}}catch(u){return n&&n.status&&n.status>0&&e.use("moodle-core-notification-exception",function(){return(new M.core.exception(u)).show()}),!1}return this.node.replaceClass("branch","emptybranch"),!0},addChild:function(e){var t=new a({tree:this.get("tree"),branchobj:e});if(t.draw(this.getChildrenUL())){this.get("tree").branches[t.get("id")]=t,t.wire();var n=0,r,i=t.get("children");for(r in i)i[r].type===o.COURSE&&n++,typeof i[r]=="object"&&t.addChild(i[r]);(t.get("type")===o.CATEGORY||t.get("type")===o.MYCATEGORY)&&n>=M.block_navigation.courselimit&&this.addViewAllCoursesChild(t)}return!0},addViewAllCoursesChild:function(e){var t=null;e.get("type")===o.ROOTNODE?e.get("key")==="mycourses"?t=M.cfg.wwwroot+"/my":t=M.cfg.wwwroot+"/course/index.php":t=M.cfg.wwwroot+"/course/index.php?categoryid="+e.get("key"),e.addChild({name:M.util.get_string("viewallcourses","moodle"),title:M.util.get_string("viewallcourses","moodle"),link:t,haschildren:!1,icon:{pix:"i/navigationitem",component:"moodle"}})}},e.extend(a,e.Base,a.prototype,{NAME:"navigation-branch",ATTRS:{tree:{writeOnce:"initOnly",validator:e.Lang.isObject},name:{value:"",validator:e.Lang.isString,setter:function(e){return e.replace(/\n/g,"
    ")}},title:{value:"",validator:e.Lang.isString},id:{value:"",validator:e.Lang.isString,getter:function(e){return e===""&&(e="expandable_branch_"+M.block_navigation.expandablebranchcount,M.block_navigation.expandablebranchcount++),e}},key:{value:null},type:{value:null,setter:function(e){return parseInt(e,10)}},link:{value:!1},icon:{value:!1,validator:e.Lang.isObject},expandable:{value:!1,validator:e.Lang.isBool},hidden:{value:!1,validator:e.Lang.isBool},haschildren:{value:!1,validator:e.Lang.isBool},children:{value:[],validator:e.Lang.isArray}}})},"@VERSION@",{requires:["base","io-base","node","event-synthetic","event-delegate","json-parse"]}); +YUI.add("moodle-block_navigation-navigation",function(e,t){M.block_navigation=M.block_navigation||{},M.block_navigation.expandablebranchcount=1,M.block_navigation.courselimit=20,M.block_navigation.init_add_tree=function(e){e.courselimit&&(this.courselimit=e.courselimit),new u(e)},e.Event.define("actionkey",{_event:e.UA.webkit||e.UA.ie?"keydown":"keypress",_keys:{37:"collapse",39:"expand",32:"toggle",13:"enter"},_keyHandler:function(e,t,n){var r;n.actions?r=n.actions:r={collapse:!0,expand:!0,toggle:!0,enter:!0},this._keys[e.keyCode]&&r[this._keys[e.keyCode]]&&(e.action=this._keys[e.keyCode],t.fire(e))},on:function(e,t,n){t.args===null?t._detacher=e.on(this._event,this._keyHandler,this,n,{actions:!1}):t._detacher=e.on(this._event,this._keyHandler,this,n,t.args[0])},detach:function(e,t){t._detacher.detach()},delegate:function(e,t,n,r){t.args===null?t._delegateDetacher=e.delegate(this._event,this._keyHandler,r,this,n,{actions:!1}):t._delegateDetacher=e.delegate(this._event,this._keyHandler,r,this,n,t.args[0])},detachDelegate:function(e,t){t._delegateDetacher.detach()}});var n=0,r=20,i=30,s=40,o={ROOTNODE:0,SYSTEM:1,CATEGORY:10,MYCATEGORY:11,COURSE:20,SECTION:30,ACTIVITY:40,RESOURCE:50,CUSTOM:60,SETTING:70,SITEADMIN:71,USER:80,CONTAINER:90},u=function(){u.superclass.constructor.apply(this,arguments)};u.prototype={id:null,branches:[],initializer:function(t){this.id=parseInt(t.id,10);var n=e.one("#inst"+t.id);if(n===null)return;e.delegate("click",this.toggleExpansion,n.one(".block_tree"),".tree_item.branch",this),e.delegate("actionkey",this.toggleExpansion,n.one(".block_tree"),".tree_item.branch",this);var r=[];t.expansions?r=t.expansions:window["navtreeexpansions"+t.id]&&(r=window["navtreeexpansions"+t.id]);for(var i in r){var s=(new a({tree:this,branchobj:r[i],overrides:{expandable:!0,children:[],haschildren:!0}})).wire();M.block_navigation.expandablebranchcount++,this.branches[s.get("id")]=s}if(window.siteadminexpansion){var o=(new a({tree:this,branchobj:window.siteadminexpansion,overrides:{expandable:!0,children:[],haschildren:!0}})).wire();M.block_navigation.expandablebranchcount++,this.branches[o.get("id")]=o;if(o.node){var u=o.node.get("childNodes").item(0);if(u){var f=e.Node.create(''+u.get("innerHTML")+"");o.node.replaceChild(f,u)}}}M.block_navigation.expandablebranchcount>0&&(e.delegate("click",this.fire_branch_action,n.one(".block_tree"),".tree_item.branch[data-expandable]",this),e.delegate("actionkey",this.fire_branch_action,n.one(".block_tree"),".tree_item.branch[data-expandable]",this))},fire_branch_action:function(e){var t=e.currentTarget.getAttribute("id"),n=this.branches[t];n.ajaxLoad(e)},toggleExpansion:function(e){if(!e.target.test("a")||e.keyCode!==0&&e.keyCode!==13){var t=e.target;t.test("li")||(t=t.ancestor("li"));if(!t)return;if(!t.hasClass("depth_1"))if(e.type==="actionkey"){switch(e.action){case"expand":t.removeClass("collapsed"),t.set("aria-expanded",!0);break;case"collapse":t.addClass("collapsed"),t.set("aria-expanded",!1);break;default:t.toggleClass("collapsed"),t.set("aria-expanded",!t.hasClass("collapsed"))}e.halt()}else t.toggleClass("collapsed"),t.set("aria-expanded",!t.hasClass("collapsed"));return this.get("accordian")&&t.siblings("li").each(function(){this.get("id")!==t.get("id")&&!this.hasClass("collapsed")&&(this.addClass("collapsed"),this.set("aria-expanded",!1))}),this.get("candock")&&M.core.dock.notifyBlockChange&&M.core.dock.notifyBlockChange(this.id),!0}e.stopPropagation();return}},e.extend(u,e.Base,u.prototype,{NAME:"navigation-tree",ATTRS:{candock:{validator:e.Lang.isBool,value:!1},accordian:{validator:e.Lang.isBool,value:!1},expansionlimit:{value:0,setter:function(e){return e=parseInt(e,10),e!==n&&e!==r&&e!==i&&e!==s&&(e=n),e}},instance:{value:!1,setter:function(e){return parseInt(e,10)}}}});var a=function(){a.superclass.constructor.apply(this,arguments)};a.prototype={node:null,initializer:function(t){var r,i;if(t.branchobj!==null){for(r in t.branchobj)this.set(r,t.branchobj[r]);i=this.get("children"),this.set("haschildren",i.length>0)}if(t.overrides!==null)for(r in t.overrides)this.set(r,t.overrides[r]);this.node=e.one("#"+this.get("id"));var o=this.get("tree").get("expansionlimit"),u=this.get("type");o!==n&&u>=o&&u<=s&&(this.set("expandable",!1),this.set("haschildren",!1))},draw:function(t){var n=this.get("expandable")||this.get("haschildren"),r=e.Node.create("
  • "),i=this.get("link"),s=e.Node.create('

    ').setAttribute("id",this.get("id")),u;i||s.setAttribute("tabindex","0"),n&&(r.addClass("collapsed").addClass("contains_branch"),r.set("aria-expanded",!1),s.addClass("branch"));var a=!1,f=this.get("icon");if(f&&(!n||this.get("type")===o.ACTIVITY||this.get("type")===o.RESOURCE)){a=e.Node.create(''),a.setAttribute("src",M.util.image_url(f.pix,f.component)),r.addClass("item_with_icon"),s.addClass("hasicon"),f.alt&&a.setAttribute("alt",f.alt),f.title&&a.setAttribute("title",f.title);if(f.classes)for(var l in f.classes)a.addClass(f.classes[l])}if(!i){var c=e.Node.create("");a?(c.appendChild(a),u=''+this.get("name")+""):u=this.get("name"),c.append(u),this.get("hidden")&&c.addClass("dimmed_text"),s.appendChild(c)}else{var h=e.Node.create('');a?(h.appendChild(a),u=''+this.get("name")+""):u=this.get("name"),h.append(u),this.get("hidden")&&h.addClass("dimmed"),s.appendChild(h)}return r.appendChild(s),t.appendChild(r),this.node=s,this},wire:function(){return this.node=this.node||e.one("#"+this.get("id")),this.node?(this.get("expandable")&&(this.node.setAttribute("data-expandable","1"),this.node.setAttribute("data-loaded","0")),this):this},getChildrenUL:function(){var t=this.node.next("ul");return t||(t=e.Node.create(""),this.node.ancestor().append(t)),t},ajaxLoad:function(t){t.type==="actionkey"&&t.action!=="enter"?t.halt():t.stopPropagation();if( +t.type==="actionkey"&&t.action==="enter"||t.target.test("a"))return this.node.setAttribute("data-expandable","0"),this.node.setAttribute("data-loaded","1"),!0;if(this.node.hasClass("loadingbranch"))return!0;if(this.node.getAttribute("data-loaded")==="1")return!0;this.node.addClass("loadingbranch");var n={elementid:this.get("id"),id:this.get("key"),type:this.get("type"),sesskey:M.cfg.sesskey,instance:this.get("tree").get("instance")},r="/lib/ajax/getnavbranch.php";return this.get("type")===o.SITEADMIN&&(r="/lib/ajax/getsiteadminbranch.php"),e.io(M.cfg.wwwroot+r,{method:"POST",data:n,on:{complete:this.ajaxProcessResponse},context:this}),!0},ajaxProcessResponse:function(t,n){this.node.removeClass("loadingbranch"),this.node.setAttribute("data-loaded","1");try{var r=e.JSON.parse(n.responseText);if(r.error)return e.use("moodle-core-notification-ajaxexception",function(){return(new M.core.ajaxException(r)).show()}),!1;if(r.children&&r.children.length>0){var i=0;for(var s in r.children)typeof r.children[s]=="object"&&(r.children[s].type===o.COURSE&&i++,this.addChild(r.children[s]));return(this.get("type")===o.CATEGORY||this.get("type")===o.ROOTNODE||this.get("type")===o.MYCATEGORY)&&i>=M.block_navigation.courselimit&&this.addViewAllCoursesChild(this),this.get("tree").get("candock")&&M.core.dock.notifyBlockChange&&M.core.dock.notifyBlockChange(this.get("tree").id),!0}}catch(u){return n&&n.status&&n.status>0&&e.use("moodle-core-notification-exception",function(){return(new M.core.exception(u)).show()}),!1}return this.node.replaceClass("branch","emptybranch"),!0},addChild:function(e){var t=new a({tree:this.get("tree"),branchobj:e});if(t.draw(this.getChildrenUL())){this.get("tree").branches[t.get("id")]=t,t.wire();var n=0,r,i=t.get("children");for(r in i)i[r].type===o.COURSE&&n++,typeof i[r]=="object"&&t.addChild(i[r]);(t.get("type")===o.CATEGORY||t.get("type")===o.MYCATEGORY)&&n>=M.block_navigation.courselimit&&this.addViewAllCoursesChild(t)}return!0},addViewAllCoursesChild:function(e){var t=null;e.get("type")===o.ROOTNODE?e.get("key")==="mycourses"?t=M.cfg.wwwroot+"/my":t=M.cfg.wwwroot+"/course/index.php":t=M.cfg.wwwroot+"/course/index.php?categoryid="+e.get("key"),e.addChild({name:M.util.get_string("viewallcourses","moodle"),title:M.util.get_string("viewallcourses","moodle"),link:t,haschildren:!1,icon:{pix:"i/navigationitem",component:"moodle"}})}},e.extend(a,e.Base,a.prototype,{NAME:"navigation-branch",ATTRS:{tree:{writeOnce:"initOnly",validator:e.Lang.isObject},name:{value:"",validator:e.Lang.isString,setter:function(e){return e.replace(/\n/g,"
    ")}},title:{value:"",validator:e.Lang.isString},id:{value:"",validator:e.Lang.isString,getter:function(e){return e===""&&(e="expandable_branch_"+M.block_navigation.expandablebranchcount,M.block_navigation.expandablebranchcount++),e}},key:{value:null},type:{value:null,setter:function(e){return parseInt(e,10)}},link:{value:!1},icon:{value:!1,validator:e.Lang.isObject},expandable:{value:!1,validator:e.Lang.isBool},hidden:{value:!1,validator:e.Lang.isBool},haschildren:{value:!1,validator:e.Lang.isBool},children:{value:[],validator:e.Lang.isArray}}})},"@VERSION@",{requires:["base","io-base","node","event-synthetic","event-delegate","json-parse"]}); diff --git a/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation.js b/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation.js index 0f46ccda6ec..b661bfdfbd3 100644 --- a/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation.js +++ b/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation.js @@ -482,6 +482,9 @@ BRANCH.prototype = { * This function creates a DOM structure for the branch and then injects * it into the navigation tree at the correct point. * + * It is important that this is kept in check with block_navigation_renderer::navigation_node as that produces + * the same thing as this but on the php side. + * * @method draw * @chainable * @param {Node} element @@ -493,6 +496,7 @@ BRANCH.prototype = { var branchli = Y.Node.create('
  • '); var link = this.get('link'); var branchp = Y.Node.create('

    ').setAttribute('id', this.get('id')); + var name; if (!link) { //add tab focus if not link (so still one focus per menu node). // it was suggested to have 2 foci. one for the node and one for the link in MDL-27428. @@ -507,10 +511,11 @@ BRANCH.prototype = { // 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') === NODETYPE.ACTIVITY)) { + if (icon && (!isbranch || this.get('type') === NODETYPE.ACTIVITY || this.get('type') === NODETYPE.RESOURCE)) { branchicon = Y.Node.create(''); branchicon.setAttribute('src', M.util.image_url(icon.pix, icon.component)); branchli.addClass('item_with_icon'); + branchp.addClass('hasicon'); if (icon.alt) { branchicon.setAttribute('alt', icon.alt); } @@ -528,8 +533,11 @@ BRANCH.prototype = { var branchspan = Y.Node.create(''); if (branchicon) { branchspan.appendChild(branchicon); + name = '' + this.get('name') + ''; + } else { + name = this.get('name'); } - branchspan.append(this.get('name')); + branchspan.append(name); if (this.get('hidden')) { branchspan.addClass('dimmed_text'); } @@ -538,8 +546,11 @@ BRANCH.prototype = { var branchlink = Y.Node.create(''); if (branchicon) { branchlink.appendChild(branchicon); + name = '' + this.get('name') + ''; + } else { + name = this.get('name'); } - branchlink.append(this.get('name')); + branchlink.append(name); if (this.get('hidden')) { branchlink.addClass('dimmed'); } diff --git a/blocks/navigation/yui/src/navigation/js/navigation.js b/blocks/navigation/yui/src/navigation/js/navigation.js index e237023cab4..3678bffeff2 100644 --- a/blocks/navigation/yui/src/navigation/js/navigation.js +++ b/blocks/navigation/yui/src/navigation/js/navigation.js @@ -481,6 +481,9 @@ BRANCH.prototype = { * This function creates a DOM structure for the branch and then injects * it into the navigation tree at the correct point. * + * It is important that this is kept in check with block_navigation_renderer::navigation_node as that produces + * the same thing as this but on the php side. + * * @method draw * @chainable * @param {Node} element @@ -492,6 +495,7 @@ BRANCH.prototype = { var branchli = Y.Node.create('
  • '); var link = this.get('link'); var branchp = Y.Node.create('

    ').setAttribute('id', this.get('id')); + var name; if (!link) { //add tab focus if not link (so still one focus per menu node). // it was suggested to have 2 foci. one for the node and one for the link in MDL-27428. @@ -506,10 +510,11 @@ BRANCH.prototype = { // 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') === NODETYPE.ACTIVITY)) { + if (icon && (!isbranch || this.get('type') === NODETYPE.ACTIVITY || this.get('type') === NODETYPE.RESOURCE)) { branchicon = Y.Node.create(''); branchicon.setAttribute('src', M.util.image_url(icon.pix, icon.component)); branchli.addClass('item_with_icon'); + branchp.addClass('hasicon'); if (icon.alt) { branchicon.setAttribute('alt', icon.alt); } @@ -527,8 +532,11 @@ BRANCH.prototype = { var branchspan = Y.Node.create(''); if (branchicon) { branchspan.appendChild(branchicon); + name = '' + this.get('name') + ''; + } else { + name = this.get('name'); } - branchspan.append(this.get('name')); + branchspan.append(name); if (this.get('hidden')) { branchspan.addClass('dimmed_text'); } @@ -537,8 +545,11 @@ BRANCH.prototype = { var branchlink = Y.Node.create(''); if (branchicon) { branchlink.appendChild(branchicon); + name = '' + this.get('name') + ''; + } else { + name = this.get('name'); } - branchlink.append(this.get('name')); + branchlink.append(name); if (this.get('hidden')) { branchlink.addClass('dimmed'); }