[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 YUI.add('moodle-block_navigation-navigation', function (Y, NAME) { 2 3 /** 4 * Navigation block JS. 5 * 6 * This file contains the Navigation block JS.. 7 * 8 * @module moodle-block_navigation-navigation 9 */ 10 11 /** 12 * This namespace will contain all of the contents of the navigation blocks 13 * global navigation and settings. 14 * @class M.block_navigation 15 * @static 16 */ 17 M.block_navigation = M.block_navigation || {}; 18 /** 19 * The number of expandable branches in existence. 20 * 21 * @property expandablebranchcount 22 * @protected 23 * @static 24 * @type Number 25 */ 26 M.block_navigation.expandablebranchcount = 1; 27 /** 28 * The maximum number of courses to show as part of a branch. 29 * 30 * @property courselimit 31 * @protected 32 * @static 33 * @type Number 34 */ 35 M.block_navigation.courselimit = 20; 36 /** 37 * Add new instance of navigation tree to tree collection 38 * 39 * @method init_add_tree 40 * @static 41 * @param {Object} properties 42 */ 43 M.block_navigation.init_add_tree = function(properties) { 44 if (properties.courselimit) { 45 this.courselimit = properties.courselimit; 46 } 47 new TREE(properties); 48 }; 49 50 /** 51 * A 'actionkey' Event to help with Y.delegate(). 52 * The event consists of the left arrow, right arrow, enter and space keys. 53 * More keys can be mapped to action meanings. 54 * actions: collapse , expand, toggle, enter. 55 * 56 * This event is delegated to branches in the navigation tree. 57 * The on() method to subscribe allows specifying the desired trigger actions as JSON. 58 * 59 * @namespace M.block_navigation 60 * @class ActionKey 61 */ 62 Y.Event.define("actionkey", { 63 // Webkit and IE repeat keydown when you hold down arrow keys. 64 // Opera links keypress to page scroll; others keydown. 65 // Firefox prevents page scroll via preventDefault() on either 66 // keydown or keypress. 67 _event: (Y.UA.webkit || Y.UA.ie) ? 'keydown' : 'keypress', 68 69 /** 70 * The keys to trigger on. 71 * @method _keys 72 */ 73 _keys: { 74 //arrows 75 '37': 'collapse', 76 '39': 'expand', 77 '32': 'toggle', 78 '13': 'enter' 79 }, 80 81 /** 82 * Handles key events 83 * @method _keyHandler 84 * @param {EventFacade} e 85 * @param {SyntheticEvent.Notifier} notifier The notifier used to trigger the execution of subscribers 86 * @param {Object} args 87 */ 88 _keyHandler: function (e, notifier, args) { 89 var actObj; 90 if (!args.actions) { 91 actObj = {collapse:true, expand:true, toggle:true, enter:true}; 92 } else { 93 actObj = args.actions; 94 } 95 if (this._keys[e.keyCode] && actObj[this._keys[e.keyCode]]) { 96 e.action = this._keys[e.keyCode]; 97 notifier.fire(e); 98 } 99 }, 100 101 /** 102 * Subscribes to events. 103 * @method on 104 * @param {Node} node The node this subscription was applied to. 105 * @param {Subscription} sub The object tracking this subscription. 106 * @param {SyntheticEvent.Notifier} notifier The notifier used to trigger the execution of subscribers 107 */ 108 on: function (node, sub, notifier) { 109 // subscribe to _event and ask keyHandler to handle with given args[0] (the desired actions). 110 if (sub.args === null) { 111 //no actions given 112 sub._detacher = node.on(this._event, this._keyHandler,this, notifier, {actions:false}); 113 } else { 114 sub._detacher = node.on(this._event, this._keyHandler,this, notifier, sub.args[0]); 115 } 116 }, 117 118 /** 119 * Detaches an event listener 120 * @method detach 121 */ 122 detach: function (node, sub) { 123 //detach our _detacher handle of the subscription made in on() 124 sub._detacher.detach(); 125 }, 126 127 /** 128 * Creates a delegated event listener. 129 * @method delegate 130 * @param {Node} node The node this subscription was applied to. 131 * @param {Subscription} sub The object tracking this subscription. 132 * @param {SyntheticEvent.Notifier} notifier The notifier used to trigger the execution of subscribers 133 * @param {String|function} filter Selector string or function that accpets an event object and returns null. 134 */ 135 delegate: function (node, sub, notifier, filter) { 136 // subscribe to _event and ask keyHandler to handle with given args[0] (the desired actions). 137 if (sub.args === null) { 138 //no actions given 139 sub._delegateDetacher = node.delegate(this._event, this._keyHandler,filter, this, notifier, {actions:false}); 140 } else { 141 sub._delegateDetacher = node.delegate(this._event, this._keyHandler,filter, this, notifier, sub.args[0]); 142 } 143 }, 144 145 /** 146 * Detaches a delegated event listener. 147 * @method detachDelegate 148 * @param {Node} node The node this subscription was applied to. 149 * @param {Subscription} sub The object tracking this subscription. 150 * @param {SyntheticEvent.Notifier} notifier The notifier used to trigger the execution of subscribers 151 * @param {String|function} filter Selector string or function that accpets an event object and returns null. 152 */ 153 detachDelegate: function (node, sub) { 154 sub._delegateDetacher.detach(); 155 } 156 }); 157 158 var EXPANSIONLIMIT_EVERYTHING = 0, 159 EXPANSIONLIMIT_COURSE = 20, 160 EXPANSIONLIMIT_SECTION = 30, 161 EXPANSIONLIMIT_ACTIVITY = 40; 162 163 // Mappings for the different types of nodes coming from the navigation. 164 // Copied from lib/navigationlib.php navigation_node constants. 165 var NODETYPE = { 166 // @type int Root node = 0 167 ROOTNODE : 0, 168 // @type int System context = 1 169 SYSTEM : 1, 170 // @type int Course category = 10 171 CATEGORY : 10, 172 // @type int MYCATEGORY = 11 173 MYCATEGORY : 11, 174 // @type int Course = 20 175 COURSE : 20, 176 // @type int Course section = 30 177 SECTION : 30, 178 // @type int Activity (course module) = 40 179 ACTIVITY : 40, 180 // @type int Resource (course module = 50 181 RESOURCE : 50, 182 // @type int Custom node (could be anything) = 60 183 CUSTOM : 60, 184 // @type int Setting = 70 185 SETTING : 70, 186 // @type int site administration = 71 187 SITEADMIN : 71, 188 // @type int User context = 80 189 USER : 80, 190 // @type int Container = 90 191 CONTAINER : 90 192 }; 193 194 /** 195 * Navigation tree class. 196 * 197 * This class establishes the tree initially, creating expandable branches as 198 * required, and delegating the expand/collapse event. 199 * 200 * @namespace M.block_navigation 201 * @class Tree 202 * @constructor 203 * @extends Base 204 */ 205 var TREE = function() { 206 TREE.superclass.constructor.apply(this, arguments); 207 }; 208 TREE.prototype = { 209 /** 210 * The tree's ID, normally its block instance id. 211 * @property id 212 * @type Number 213 * @protected 214 */ 215 id : null, 216 /** 217 * An array of initialised branches. 218 * @property branches 219 * @type Array 220 * @protected 221 */ 222 branches : [], 223 /** 224 * Initialise the tree object when its first created. 225 * @method initializer 226 * @param {Object} config 227 */ 228 initializer : function(config) { 229 Y.log('Initialising navigation block tree', 'note', 'moodle-block_navigation'); 230 231 this.id = parseInt(config.id, 10); 232 233 var node = Y.one('#inst'+config.id); 234 235 // Can't find the block instance within the page 236 if (node === null) { 237 return; 238 } 239 240 // Delegate event to toggle expansion 241 Y.delegate('click', this.toggleExpansion, node.one('.block_tree'), '.tree_item.branch', this); 242 Y.delegate('actionkey', this.toggleExpansion, node.one('.block_tree'), '.tree_item.branch', this); 243 244 // Gather the expandable branches ready for initialisation. 245 var expansions = []; 246 if (config.expansions) { 247 expansions = config.expansions; 248 } else if (window['navtreeexpansions'+config.id]) { 249 expansions = window['navtreeexpansions'+config.id]; 250 } 251 // Establish each expandable branch as a tree branch. 252 for (var i in expansions) { 253 var branch = new BRANCH({ 254 tree:this, 255 branchobj:expansions[i], 256 overrides : { 257 expandable : true, 258 children : [], 259 haschildren : true 260 } 261 }).wire(); 262 M.block_navigation.expandablebranchcount++; 263 this.branches[branch.get('id')] = branch; 264 } 265 // Create siteadmin branch. 266 if (window.siteadminexpansion) { 267 var siteadminbranch = new BRANCH({ 268 tree: this, 269 branchobj: window.siteadminexpansion, 270 overrides : { 271 expandable : true, 272 children : [], 273 haschildren : true 274 } 275 }).wire(); 276 M.block_navigation.expandablebranchcount++; 277 this.branches[siteadminbranch.get('id')] = siteadminbranch; 278 // Remove link on site admin with JS to keep old UI. 279 if (siteadminbranch.node) { 280 var siteadminlinknode = siteadminbranch.node.get('childNodes').item(0); 281 if (siteadminlinknode) { 282 var siteadminnode = Y.Node.create('<span tabindex="0">'+siteadminlinknode.get('innerHTML')+'</span>'); 283 siteadminbranch.node.replaceChild(siteadminnode, siteadminlinknode); 284 } 285 } 286 } 287 if (M.block_navigation.expandablebranchcount > 0) { 288 // Delegate some events to handle AJAX loading. 289 Y.delegate('click', this.fire_branch_action, node.one('.block_tree'), '.tree_item.branch[data-expandable]', this); 290 Y.delegate('actionkey', this.fire_branch_action, node.one('.block_tree'), '.tree_item.branch[data-expandable]', this); 291 } 292 }, 293 /** 294 * Fire actions for a branch when an event occurs. 295 * @method fire_branch_action 296 * @param {EventFacade} event 297 */ 298 fire_branch_action : function(event) { 299 var id = event.currentTarget.getAttribute('id'); 300 var branch = this.branches[id]; 301 branch.ajaxLoad(event); 302 }, 303 /** 304 * This is a callback function responsible for expanding and collapsing the 305 * branches of the tree. It is delegated to rather than multiple event handles. 306 * @method toggleExpansion 307 * @param {EventFacade} e 308 * @return Boolean 309 */ 310 toggleExpansion : function(e) { 311 // First check if they managed to click on the li iteslf, then find the closest 312 // LI ancestor and use that 313 314 if (e.target.test('a') && (e.keyCode === 0 || e.keyCode === 13)) { 315 // A link has been clicked (or keypress is 'enter') don't fire any more events just do the default. 316 e.stopPropagation(); 317 return; 318 } 319 320 // Makes sure we can get to the LI containing the branch. 321 var target = e.target; 322 if (!target.test('li')) { 323 target = target.ancestor('li'); 324 } 325 if (!target) { 326 return; 327 } 328 329 // Toggle expand/collapse providing its not a root level branch. 330 if (!target.hasClass('depth_1')) { 331 if (e.type === 'actionkey') { 332 switch (e.action) { 333 case 'expand' : 334 target.removeClass('collapsed'); 335 target.set('aria-expanded', true); 336 break; 337 case 'collapse' : 338 target.addClass('collapsed'); 339 target.set('aria-expanded', false); 340 break; 341 default : 342 target.toggleClass('collapsed'); 343 target.set('aria-expanded', !target.hasClass('collapsed')); 344 } 345 e.halt(); 346 } else { 347 target.toggleClass('collapsed'); 348 target.set('aria-expanded', !target.hasClass('collapsed')); 349 } 350 } 351 352 // If the accordian feature has been enabled collapse all siblings. 353 if (this.get('accordian')) { 354 target.siblings('li').each(function(){ 355 if (this.get('id') !== target.get('id') && !this.hasClass('collapsed')) { 356 this.addClass('collapsed'); 357 this.set('aria-expanded', false); 358 } 359 }); 360 } 361 362 // If this block can dock tell the dock to resize if required and check 363 // the width on the dock panel in case it is presently in use. 364 if (this.get('candock') && M.core.dock.notifyBlockChange) { 365 M.core.dock.notifyBlockChange(this.id); 366 } 367 return true; 368 369 } 370 }; 371 // The tree extends the YUI base foundation. 372 Y.extend(TREE, Y.Base, TREE.prototype, { 373 NAME : 'navigation-tree', 374 ATTRS : { 375 /** 376 * True if the block can dock. 377 * @attribute candock 378 * @type Boolean 379 */ 380 candock : { 381 validator : Y.Lang.isBool, 382 value : false 383 }, 384 /** 385 * If set to true nodes will be opened/closed in an accordian fashion. 386 * @attribute accordian 387 * @type Boolean 388 */ 389 accordian : { 390 validator : Y.Lang.isBool, 391 value : false 392 }, 393 /** 394 * The nodes that get shown. 395 * @attribute expansionlimit 396 * @type Number 397 */ 398 expansionlimit : { 399 value : 0, 400 setter : function(val) { 401 val = parseInt(val, 10); 402 if (val !== EXPANSIONLIMIT_EVERYTHING && 403 val !== EXPANSIONLIMIT_COURSE && 404 val !== EXPANSIONLIMIT_SECTION && 405 val !== EXPANSIONLIMIT_ACTIVITY) { 406 val = EXPANSIONLIMIT_EVERYTHING; 407 } 408 return val; 409 } 410 }, 411 /** 412 * The navigation tree block instance. 413 * 414 * @attribute instance 415 * @default false 416 * @type Number 417 */ 418 instance : { 419 value : false, 420 setter : function(val) { 421 return parseInt(val, 10); 422 } 423 } 424 } 425 }); 426 427 /** 428 * The Branch class. 429 * 430 * This class is used to manage a tree branch, in particular its ability to load 431 * its contents by AJAX. 432 * 433 * @namespace M.block_navigation 434 * @class Branch 435 * @constructor 436 * @extends Base 437 */ 438 BRANCH = function() { 439 BRANCH.superclass.constructor.apply(this, arguments); 440 }; 441 BRANCH.prototype = { 442 /** 443 * The node for this branch (p) 444 * @property node 445 * @type Node 446 * @protected 447 */ 448 node : null, 449 /** 450 * Initialises the branch when it is first created. 451 * @method initializer 452 * @param {Object} config 453 */ 454 initializer : function(config) { 455 var i, 456 children; 457 if (config.branchobj !== null) { 458 // Construct from the provided xml 459 for (i in config.branchobj) { 460 this.set(i, config.branchobj[i]); 461 } 462 children = this.get('children'); 463 this.set('haschildren', (children.length > 0)); 464 } 465 if (config.overrides !== null) { 466 // Construct from the provided xml 467 for (i in config.overrides) { 468 this.set(i, config.overrides[i]); 469 } 470 } 471 // Get the node for this branch 472 this.node = Y.one('#'+this.get('id')); 473 var expansionlimit = this.get('tree').get('expansionlimit'); 474 var type = this.get('type'); 475 if (expansionlimit !== EXPANSIONLIMIT_EVERYTHING && type >= expansionlimit && type <= EXPANSIONLIMIT_ACTIVITY) { 476 this.set('expandable', false); 477 this.set('haschildren', false); 478 } 479 }, 480 /** 481 * Draws the branch within the tree. 482 * 483 * This function creates a DOM structure for the branch and then injects 484 * it into the navigation tree at the correct point. 485 * 486 * @method draw 487 * @chainable 488 * @param {Node} element 489 * @return Branch 490 */ 491 draw : function(element) { 492 493 var isbranch = (this.get('expandable') || this.get('haschildren')); 494 var branchli = Y.Node.create('<li></li>'); 495 var link = this.get('link'); 496 var branchp = Y.Node.create('<p class="tree_item"></p>').setAttribute('id', this.get('id')); 497 if (!link) { 498 //add tab focus if not link (so still one focus per menu node). 499 // it was suggested to have 2 foci. one for the node and one for the link in MDL-27428. 500 branchp.setAttribute('tabindex', '0'); 501 } 502 if (isbranch) { 503 branchli.addClass('collapsed').addClass('contains_branch'); 504 branchli.set('aria-expanded', false); 505 branchp.addClass('branch'); 506 } 507 508 // Prepare the icon, should be an object representing a pix_icon 509 var branchicon = false; 510 var icon = this.get('icon'); 511 if (icon && (!isbranch || this.get('type') === NODETYPE.ACTIVITY)) { 512 branchicon = Y.Node.create('<img alt="" />'); 513 branchicon.setAttribute('src', M.util.image_url(icon.pix, icon.component)); 514 branchli.addClass('item_with_icon'); 515 if (icon.alt) { 516 branchicon.setAttribute('alt', icon.alt); 517 } 518 if (icon.title) { 519 branchicon.setAttribute('title', icon.title); 520 } 521 if (icon.classes) { 522 for (var i in icon.classes) { 523 branchicon.addClass(icon.classes[i]); 524 } 525 } 526 } 527 528 if (!link) { 529 var branchspan = Y.Node.create('<span></span>'); 530 if (branchicon) { 531 branchspan.appendChild(branchicon); 532 } 533 branchspan.append(this.get('name')); 534 if (this.get('hidden')) { 535 branchspan.addClass('dimmed_text'); 536 } 537 branchp.appendChild(branchspan); 538 } else { 539 var branchlink = Y.Node.create('<a title="'+this.get('title')+'" href="'+link+'"></a>'); 540 if (branchicon) { 541 branchlink.appendChild(branchicon); 542 } 543 branchlink.append(this.get('name')); 544 if (this.get('hidden')) { 545 branchlink.addClass('dimmed'); 546 } 547 branchp.appendChild(branchlink); 548 } 549 550 branchli.appendChild(branchp); 551 element.appendChild(branchli); 552 this.node = branchp; 553 return this; 554 }, 555 /** 556 * Attaches required events to the branch structure. 557 * 558 * @chainable 559 * @method wire 560 * @return {BRANCH} This function is chainable, it always returns itself. 561 */ 562 wire : function() { 563 this.node = this.node || Y.one('#'+this.get('id')); 564 if (!this.node) { 565 return this; 566 } 567 if (this.get('expandable')) { 568 this.node.setAttribute('data-expandable', '1'); 569 this.node.setAttribute('data-loaded', '0'); 570 } 571 return this; 572 }, 573 /** 574 * Gets the UL element that children for this branch should be inserted into. 575 * @method getChildrenUL 576 * @return Node 577 */ 578 getChildrenUL : function() { 579 var ul = this.node.next('ul'); 580 if (!ul) { 581 ul = Y.Node.create('<ul></ul>'); 582 this.node.ancestor().append(ul); 583 } 584 return ul; 585 }, 586 /** 587 * Load the content of the branch via AJAX. 588 * 589 * This function calls ajaxProcessResponse with the result of the AJAX 590 * request made here. 591 * 592 * @method ajaxLoad 593 * @param {EventFacade} e 594 * @return Bool 595 */ 596 ajaxLoad : function(e) { 597 if (e.type === 'actionkey' && e.action !== 'enter') { 598 e.halt(); 599 } else { 600 e.stopPropagation(); 601 } 602 if ((e.type === 'actionkey' && e.action === 'enter') || e.target.test('a')) { 603 // No ajaxLoad for enter. 604 this.node.setAttribute('data-expandable', '0'); 605 this.node.setAttribute('data-loaded', '1'); 606 return true; 607 } 608 609 if (this.node.hasClass('loadingbranch')) { 610 // Already loading. Just skip. 611 return true; 612 } 613 614 if (this.node.getAttribute('data-loaded') === '1') { 615 // We've already loaded this stuff. 616 return true; 617 } 618 Y.log('Loading navigation branch via AJAX: '+this.get('key'), 'note', 'moodle-block_navigation'); 619 this.node.addClass('loadingbranch'); 620 621 var params = { 622 elementid : this.get('id'), 623 id : this.get('key'), 624 type : this.get('type'), 625 sesskey : M.cfg.sesskey, 626 instance : this.get('tree').get('instance') 627 }; 628 629 var ajaxfile = '/lib/ajax/getnavbranch.php'; 630 // For siteadmin navigation get tree from getsiteadminbranch.php. 631 if (this.get('type') === NODETYPE.SITEADMIN) { 632 ajaxfile = '/lib/ajax/getsiteadminbranch.php'; 633 } 634 635 Y.io(M.cfg.wwwroot + ajaxfile, { 636 method:'POST', 637 data: build_querystring(params), 638 on: { 639 complete: this.ajaxProcessResponse 640 }, 641 context:this 642 }); 643 return true; 644 }, 645 /** 646 * Processes an AJAX request to load the content of this branch through 647 * AJAX. 648 * 649 * @method ajaxProcessResponse 650 * @param {Int} tid The transaction id. 651 * @param {Object} outcome 652 * @return Boolean 653 */ 654 ajaxProcessResponse : function(tid, outcome) { 655 this.node.removeClass('loadingbranch'); 656 this.node.setAttribute('data-loaded', '1'); 657 try { 658 var object = Y.JSON.parse(outcome.responseText); 659 if (object.error) { 660 Y.use('moodle-core-notification-ajaxexception', function () { 661 return new M.core.ajaxException(object).show(); 662 }); 663 return false; 664 } 665 if (object.children && object.children.length > 0) { 666 var coursecount = 0; 667 for (var i in object.children) { 668 if (typeof(object.children[i])==='object') { 669 if (object.children[i].type === NODETYPE.COURSE) { 670 coursecount++; 671 } 672 this.addChild(object.children[i]); 673 } 674 } 675 if ((this.get('type') === NODETYPE.CATEGORY || this.get('type') === NODETYPE.ROOTNODE || this.get('type') === NODETYPE.MYCATEGORY) 676 && coursecount >= M.block_navigation.courselimit) { 677 this.addViewAllCoursesChild(this); 678 } 679 Y.log('AJAX loading complete.', 'note', 'moodle-block_navigation'); 680 // If this block can dock tell the dock to resize if required and check 681 // the width on the dock panel in case it is presently in use. 682 if (this.get('tree').get('candock') && M.core.dock.notifyBlockChange) { 683 M.core.dock.notifyBlockChange(this.get('tree').id); 684 } 685 return true; 686 } 687 Y.log('AJAX loading complete but there were no children.', 'note', 'moodle-block_navigation'); 688 } catch (error) { 689 if (outcome && outcome.status && outcome.status > 0) { 690 // If we got here then there was an error parsing the result. 691 Y.log('Error parsing AJAX response or adding branches to the navigation tree', 'error', 'moodle-block_navigation'); 692 Y.use('moodle-core-notification-exception', function () { 693 return new M.core.exception(error).show(); 694 }); 695 } 696 697 return false; 698 } 699 // The branch is empty so class it accordingly 700 this.node.replaceClass('branch', 'emptybranch'); 701 return true; 702 }, 703 /** 704 * Turns the branch object passed to the method into a proper branch object 705 * and then adds it as a child of this branch. 706 * 707 * @method addChild 708 * @param {Object} branchobj 709 * @return Boolean 710 */ 711 addChild : function(branchobj) { 712 // Make the new branch into an object 713 var branch = new BRANCH({tree:this.get('tree'), branchobj:branchobj}); 714 if (branch.draw(this.getChildrenUL())) { 715 this.get('tree').branches[branch.get('id')] = branch; 716 branch.wire(); 717 var count = 0, i, children = branch.get('children'); 718 for (i in children) { 719 // Add each branch to the tree 720 if (children[i].type === NODETYPE.COURSE) { 721 count++; 722 } 723 if (typeof(children[i]) === 'object') { 724 branch.addChild(children[i]); 725 } 726 } 727 if ((branch.get('type') === NODETYPE.CATEGORY || branch.get('type') === NODETYPE.MYCATEGORY) 728 && count >= M.block_navigation.courselimit) { 729 this.addViewAllCoursesChild(branch); 730 } 731 } 732 return true; 733 }, 734 735 /** 736 * Add a link to view all courses in a category 737 * 738 * @method addViewAllCoursesChild 739 * @param {BRANCH} branch 740 */ 741 addViewAllCoursesChild: function(branch) { 742 var url = null; 743 if (branch.get('type') === NODETYPE.ROOTNODE) { 744 if (branch.get('key') === 'mycourses') { 745 url = M.cfg.wwwroot + '/my'; 746 } else { 747 url = M.cfg.wwwroot + '/course/index.php'; 748 } 749 } else { 750 url = M.cfg.wwwroot+'/course/index.php?categoryid=' + branch.get('key'); 751 } 752 branch.addChild({ 753 name : M.str.moodle.viewallcourses, 754 title : M.str.moodle.viewallcourses, 755 link : url, 756 haschildren : false, 757 icon : {'pix':"i/navigationitem",'component':'moodle'} 758 }); 759 } 760 }; 761 Y.extend(BRANCH, Y.Base, BRANCH.prototype, { 762 NAME : 'navigation-branch', 763 ATTRS : { 764 /** 765 * The Tree this branch belongs to. 766 * @attribute tree 767 * @type TREE 768 * @required 769 * @writeOnce 770 */ 771 tree : { 772 writeOnce : 'initOnly', 773 validator : Y.Lang.isObject 774 }, 775 /** 776 * The name of this branch. 777 * @attribute name 778 * @type String 779 */ 780 name : { 781 value : '', 782 validator : Y.Lang.isString, 783 setter : function(val) { 784 return val.replace(/\n/g, '<br />'); 785 } 786 }, 787 /** 788 * The title to use for this branch. 789 * @attribute title 790 * @type String 791 */ 792 title : { 793 value : '', 794 validator : Y.Lang.isString 795 }, 796 /** 797 * The ID of this branch. 798 * The ID and Type should always form a unique pair. 799 * @attribute id 800 * @type String 801 */ 802 id : { 803 value : '', 804 validator : Y.Lang.isString, 805 getter : function(val) { 806 if (val === '') { 807 val = 'expandable_branch_'+M.block_navigation.expandablebranchcount; 808 M.block_navigation.expandablebranchcount++; 809 } 810 return val; 811 } 812 }, 813 /** 814 * The key used to identify this branch easily if there is one. 815 * @attribute key 816 * @type String 817 */ 818 key : { 819 value : null 820 }, 821 /** 822 * The type of this branch. 823 * @attribute type 824 * @type Number 825 */ 826 type : { 827 value : null, 828 setter : function(value) { 829 return parseInt(value, 10); 830 } 831 }, 832 /** 833 * The link to use for this branch. 834 * @attribute link 835 * @type String 836 */ 837 link : { 838 value : false 839 }, 840 /** 841 * The Icon to add when displaying this branch. 842 * @attribute icon 843 * @type Object 844 */ 845 icon : { 846 value : false, 847 validator : Y.Lang.isObject 848 }, 849 /** 850 * True if this branch is expandable. 851 * @attribute expandable 852 * @type Boolean 853 */ 854 expandable : { 855 value : false, 856 validator : Y.Lang.isBool 857 }, 858 /** 859 * True if this branch is hidden and should be displayed greyed out. 860 * @attribute hidden 861 * @type Boolean 862 */ 863 hidden : { 864 value : false, 865 validator : Y.Lang.isBool 866 }, 867 /** 868 * True if this branch has any children. 869 * @attribute haschildren 870 * @type Boolean 871 */ 872 haschildren : { 873 value : false, 874 validator : Y.Lang.isBool 875 }, 876 /** 877 * An array of other branches that appear as children of this branch. 878 * @attribute children 879 * @type Array 880 */ 881 children : { 882 value : [], 883 validator : Y.Lang.isArray 884 } 885 } 886 }); 887 888 889 }, '@VERSION@', {"requires": ["base", "io-base", "node", "event-synthetic", "event-delegate", "json-parse"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |