[ 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 230 this.id = parseInt(config.id, 10); 231 232 var node = Y.one('#inst'+config.id); 233 234 // Can't find the block instance within the page 235 if (node === null) { 236 return; 237 } 238 239 // Delegate event to toggle expansion 240 Y.delegate('click', this.toggleExpansion, node.one('.block_tree'), '.tree_item.branch', this); 241 Y.delegate('actionkey', this.toggleExpansion, node.one('.block_tree'), '.tree_item.branch', this); 242 243 // Gather the expandable branches ready for initialisation. 244 var expansions = []; 245 if (config.expansions) { 246 expansions = config.expansions; 247 } else if (window['navtreeexpansions'+config.id]) { 248 expansions = window['navtreeexpansions'+config.id]; 249 } 250 // Establish each expandable branch as a tree branch. 251 for (var i in expansions) { 252 var branch = new BRANCH({ 253 tree:this, 254 branchobj:expansions[i], 255 overrides : { 256 expandable : true, 257 children : [], 258 haschildren : true 259 } 260 }).wire(); 261 M.block_navigation.expandablebranchcount++; 262 this.branches[branch.get('id')] = branch; 263 } 264 // Create siteadmin branch. 265 if (window.siteadminexpansion) { 266 var siteadminbranch = new BRANCH({ 267 tree: this, 268 branchobj: window.siteadminexpansion, 269 overrides : { 270 expandable : true, 271 children : [], 272 haschildren : true 273 } 274 }).wire(); 275 M.block_navigation.expandablebranchcount++; 276 this.branches[siteadminbranch.get('id')] = siteadminbranch; 277 // Remove link on site admin with JS to keep old UI. 278 if (siteadminbranch.node) { 279 var siteadminlinknode = siteadminbranch.node.get('childNodes').item(0); 280 if (siteadminlinknode) { 281 var siteadminnode = Y.Node.create('<span tabindex="0">'+siteadminlinknode.get('innerHTML')+'</span>'); 282 siteadminbranch.node.replaceChild(siteadminnode, siteadminlinknode); 283 } 284 } 285 } 286 if (M.block_navigation.expandablebranchcount > 0) { 287 // Delegate some events to handle AJAX loading. 288 Y.delegate('click', this.fire_branch_action, node.one('.block_tree'), '.tree_item.branch[data-expandable]', this); 289 Y.delegate('actionkey', this.fire_branch_action, node.one('.block_tree'), '.tree_item.branch[data-expandable]', this); 290 } 291 }, 292 /** 293 * Fire actions for a branch when an event occurs. 294 * @method fire_branch_action 295 * @param {EventFacade} event 296 */ 297 fire_branch_action : function(event) { 298 var id = event.currentTarget.getAttribute('id'); 299 var branch = this.branches[id]; 300 branch.ajaxLoad(event); 301 }, 302 /** 303 * This is a callback function responsible for expanding and collapsing the 304 * branches of the tree. It is delegated to rather than multiple event handles. 305 * @method toggleExpansion 306 * @param {EventFacade} e 307 * @return Boolean 308 */ 309 toggleExpansion : function(e) { 310 // First check if they managed to click on the li iteslf, then find the closest 311 // LI ancestor and use that 312 313 if (e.target.test('a') && (e.keyCode === 0 || e.keyCode === 13)) { 314 // A link has been clicked (or keypress is 'enter') don't fire any more events just do the default. 315 e.stopPropagation(); 316 return; 317 } 318 319 // Makes sure we can get to the LI containing the branch. 320 var target = e.target; 321 if (!target.test('li')) { 322 target = target.ancestor('li'); 323 } 324 if (!target) { 325 return; 326 } 327 328 // Toggle expand/collapse providing its not a root level branch. 329 if (!target.hasClass('depth_1')) { 330 if (e.type === 'actionkey') { 331 switch (e.action) { 332 case 'expand' : 333 target.removeClass('collapsed'); 334 target.set('aria-expanded', true); 335 break; 336 case 'collapse' : 337 target.addClass('collapsed'); 338 target.set('aria-expanded', false); 339 break; 340 default : 341 target.toggleClass('collapsed'); 342 target.set('aria-expanded', !target.hasClass('collapsed')); 343 } 344 e.halt(); 345 } else { 346 target.toggleClass('collapsed'); 347 target.set('aria-expanded', !target.hasClass('collapsed')); 348 } 349 } 350 351 // If the accordian feature has been enabled collapse all siblings. 352 if (this.get('accordian')) { 353 target.siblings('li').each(function(){ 354 if (this.get('id') !== target.get('id') && !this.hasClass('collapsed')) { 355 this.addClass('collapsed'); 356 this.set('aria-expanded', false); 357 } 358 }); 359 } 360 361 // If this block can dock tell the dock to resize if required and check 362 // the width on the dock panel in case it is presently in use. 363 if (this.get('candock') && M.core.dock.notifyBlockChange) { 364 M.core.dock.notifyBlockChange(this.id); 365 } 366 return true; 367 368 } 369 }; 370 // The tree extends the YUI base foundation. 371 Y.extend(TREE, Y.Base, TREE.prototype, { 372 NAME : 'navigation-tree', 373 ATTRS : { 374 /** 375 * True if the block can dock. 376 * @attribute candock 377 * @type Boolean 378 */ 379 candock : { 380 validator : Y.Lang.isBool, 381 value : false 382 }, 383 /** 384 * If set to true nodes will be opened/closed in an accordian fashion. 385 * @attribute accordian 386 * @type Boolean 387 */ 388 accordian : { 389 validator : Y.Lang.isBool, 390 value : false 391 }, 392 /** 393 * The nodes that get shown. 394 * @attribute expansionlimit 395 * @type Number 396 */ 397 expansionlimit : { 398 value : 0, 399 setter : function(val) { 400 val = parseInt(val, 10); 401 if (val !== EXPANSIONLIMIT_EVERYTHING && 402 val !== EXPANSIONLIMIT_COURSE && 403 val !== EXPANSIONLIMIT_SECTION && 404 val !== EXPANSIONLIMIT_ACTIVITY) { 405 val = EXPANSIONLIMIT_EVERYTHING; 406 } 407 return val; 408 } 409 }, 410 /** 411 * The navigation tree block instance. 412 * 413 * @attribute instance 414 * @default false 415 * @type Number 416 */ 417 instance : { 418 value : false, 419 setter : function(val) { 420 return parseInt(val, 10); 421 } 422 } 423 } 424 }); 425 426 /** 427 * The Branch class. 428 * 429 * This class is used to manage a tree branch, in particular its ability to load 430 * its contents by AJAX. 431 * 432 * @namespace M.block_navigation 433 * @class Branch 434 * @constructor 435 * @extends Base 436 */ 437 BRANCH = function() { 438 BRANCH.superclass.constructor.apply(this, arguments); 439 }; 440 BRANCH.prototype = { 441 /** 442 * The node for this branch (p) 443 * @property node 444 * @type Node 445 * @protected 446 */ 447 node : null, 448 /** 449 * Initialises the branch when it is first created. 450 * @method initializer 451 * @param {Object} config 452 */ 453 initializer : function(config) { 454 var i, 455 children; 456 if (config.branchobj !== null) { 457 // Construct from the provided xml 458 for (i in config.branchobj) { 459 this.set(i, config.branchobj[i]); 460 } 461 children = this.get('children'); 462 this.set('haschildren', (children.length > 0)); 463 } 464 if (config.overrides !== null) { 465 // Construct from the provided xml 466 for (i in config.overrides) { 467 this.set(i, config.overrides[i]); 468 } 469 } 470 // Get the node for this branch 471 this.node = Y.one('#'+this.get('id')); 472 var expansionlimit = this.get('tree').get('expansionlimit'); 473 var type = this.get('type'); 474 if (expansionlimit !== EXPANSIONLIMIT_EVERYTHING && type >= expansionlimit && type <= EXPANSIONLIMIT_ACTIVITY) { 475 this.set('expandable', false); 476 this.set('haschildren', false); 477 } 478 }, 479 /** 480 * Draws the branch within the tree. 481 * 482 * This function creates a DOM structure for the branch and then injects 483 * it into the navigation tree at the correct point. 484 * 485 * @method draw 486 * @chainable 487 * @param {Node} element 488 * @return Branch 489 */ 490 draw : function(element) { 491 492 var isbranch = (this.get('expandable') || this.get('haschildren')); 493 var branchli = Y.Node.create('<li></li>'); 494 var link = this.get('link'); 495 var branchp = Y.Node.create('<p class="tree_item"></p>').setAttribute('id', this.get('id')); 496 if (!link) { 497 //add tab focus if not link (so still one focus per menu node). 498 // it was suggested to have 2 foci. one for the node and one for the link in MDL-27428. 499 branchp.setAttribute('tabindex', '0'); 500 } 501 if (isbranch) { 502 branchli.addClass('collapsed').addClass('contains_branch'); 503 branchli.set('aria-expanded', false); 504 branchp.addClass('branch'); 505 } 506 507 // Prepare the icon, should be an object representing a pix_icon 508 var branchicon = false; 509 var icon = this.get('icon'); 510 if (icon && (!isbranch || this.get('type') === NODETYPE.ACTIVITY)) { 511 branchicon = Y.Node.create('<img alt="" />'); 512 branchicon.setAttribute('src', M.util.image_url(icon.pix, icon.component)); 513 branchli.addClass('item_with_icon'); 514 if (icon.alt) { 515 branchicon.setAttribute('alt', icon.alt); 516 } 517 if (icon.title) { 518 branchicon.setAttribute('title', icon.title); 519 } 520 if (icon.classes) { 521 for (var i in icon.classes) { 522 branchicon.addClass(icon.classes[i]); 523 } 524 } 525 } 526 527 if (!link) { 528 var branchspan = Y.Node.create('<span></span>'); 529 if (branchicon) { 530 branchspan.appendChild(branchicon); 531 } 532 branchspan.append(this.get('name')); 533 if (this.get('hidden')) { 534 branchspan.addClass('dimmed_text'); 535 } 536 branchp.appendChild(branchspan); 537 } else { 538 var branchlink = Y.Node.create('<a title="'+this.get('title')+'" href="'+link+'"></a>'); 539 if (branchicon) { 540 branchlink.appendChild(branchicon); 541 } 542 branchlink.append(this.get('name')); 543 if (this.get('hidden')) { 544 branchlink.addClass('dimmed'); 545 } 546 branchp.appendChild(branchlink); 547 } 548 549 branchli.appendChild(branchp); 550 element.appendChild(branchli); 551 this.node = branchp; 552 return this; 553 }, 554 /** 555 * Attaches required events to the branch structure. 556 * 557 * @chainable 558 * @method wire 559 * @return {BRANCH} This function is chainable, it always returns itself. 560 */ 561 wire : function() { 562 this.node = this.node || Y.one('#'+this.get('id')); 563 if (!this.node) { 564 return this; 565 } 566 if (this.get('expandable')) { 567 this.node.setAttribute('data-expandable', '1'); 568 this.node.setAttribute('data-loaded', '0'); 569 } 570 return this; 571 }, 572 /** 573 * Gets the UL element that children for this branch should be inserted into. 574 * @method getChildrenUL 575 * @return Node 576 */ 577 getChildrenUL : function() { 578 var ul = this.node.next('ul'); 579 if (!ul) { 580 ul = Y.Node.create('<ul></ul>'); 581 this.node.ancestor().append(ul); 582 } 583 return ul; 584 }, 585 /** 586 * Load the content of the branch via AJAX. 587 * 588 * This function calls ajaxProcessResponse with the result of the AJAX 589 * request made here. 590 * 591 * @method ajaxLoad 592 * @param {EventFacade} e 593 * @return Bool 594 */ 595 ajaxLoad : function(e) { 596 if (e.type === 'actionkey' && e.action !== 'enter') { 597 e.halt(); 598 } else { 599 e.stopPropagation(); 600 } 601 if ((e.type === 'actionkey' && e.action === 'enter') || e.target.test('a')) { 602 // No ajaxLoad for enter. 603 this.node.setAttribute('data-expandable', '0'); 604 this.node.setAttribute('data-loaded', '1'); 605 return true; 606 } 607 608 if (this.node.hasClass('loadingbranch')) { 609 // Already loading. Just skip. 610 return true; 611 } 612 613 if (this.node.getAttribute('data-loaded') === '1') { 614 // We've already loaded this stuff. 615 return true; 616 } 617 this.node.addClass('loadingbranch'); 618 619 var params = { 620 elementid : this.get('id'), 621 id : this.get('key'), 622 type : this.get('type'), 623 sesskey : M.cfg.sesskey, 624 instance : this.get('tree').get('instance') 625 }; 626 627 var ajaxfile = '/lib/ajax/getnavbranch.php'; 628 // For siteadmin navigation get tree from getsiteadminbranch.php. 629 if (this.get('type') === NODETYPE.SITEADMIN) { 630 ajaxfile = '/lib/ajax/getsiteadminbranch.php'; 631 } 632 633 Y.io(M.cfg.wwwroot + ajaxfile, { 634 method:'POST', 635 data: build_querystring(params), 636 on: { 637 complete: this.ajaxProcessResponse 638 }, 639 context:this 640 }); 641 return true; 642 }, 643 /** 644 * Processes an AJAX request to load the content of this branch through 645 * AJAX. 646 * 647 * @method ajaxProcessResponse 648 * @param {Int} tid The transaction id. 649 * @param {Object} outcome 650 * @return Boolean 651 */ 652 ajaxProcessResponse : function(tid, outcome) { 653 this.node.removeClass('loadingbranch'); 654 this.node.setAttribute('data-loaded', '1'); 655 try { 656 var object = Y.JSON.parse(outcome.responseText); 657 if (object.error) { 658 Y.use('moodle-core-notification-ajaxexception', function () { 659 return new M.core.ajaxException(object).show(); 660 }); 661 return false; 662 } 663 if (object.children && object.children.length > 0) { 664 var coursecount = 0; 665 for (var i in object.children) { 666 if (typeof(object.children[i])==='object') { 667 if (object.children[i].type === NODETYPE.COURSE) { 668 coursecount++; 669 } 670 this.addChild(object.children[i]); 671 } 672 } 673 if ((this.get('type') === NODETYPE.CATEGORY || this.get('type') === NODETYPE.ROOTNODE || this.get('type') === NODETYPE.MYCATEGORY) 674 && coursecount >= M.block_navigation.courselimit) { 675 this.addViewAllCoursesChild(this); 676 } 677 // If this block can dock tell the dock to resize if required and check 678 // the width on the dock panel in case it is presently in use. 679 if (this.get('tree').get('candock') && M.core.dock.notifyBlockChange) { 680 M.core.dock.notifyBlockChange(this.get('tree').id); 681 } 682 return true; 683 } 684 } catch (error) { 685 if (outcome && outcome.status && outcome.status > 0) { 686 // If we got here then there was an error parsing the result. 687 Y.use('moodle-core-notification-exception', function () { 688 return new M.core.exception(error).show(); 689 }); 690 } 691 692 return false; 693 } 694 // The branch is empty so class it accordingly 695 this.node.replaceClass('branch', 'emptybranch'); 696 return true; 697 }, 698 /** 699 * Turns the branch object passed to the method into a proper branch object 700 * and then adds it as a child of this branch. 701 * 702 * @method addChild 703 * @param {Object} branchobj 704 * @return Boolean 705 */ 706 addChild : function(branchobj) { 707 // Make the new branch into an object 708 var branch = new BRANCH({tree:this.get('tree'), branchobj:branchobj}); 709 if (branch.draw(this.getChildrenUL())) { 710 this.get('tree').branches[branch.get('id')] = branch; 711 branch.wire(); 712 var count = 0, i, children = branch.get('children'); 713 for (i in children) { 714 // Add each branch to the tree 715 if (children[i].type === NODETYPE.COURSE) { 716 count++; 717 } 718 if (typeof(children[i]) === 'object') { 719 branch.addChild(children[i]); 720 } 721 } 722 if ((branch.get('type') === NODETYPE.CATEGORY || branch.get('type') === NODETYPE.MYCATEGORY) 723 && count >= M.block_navigation.courselimit) { 724 this.addViewAllCoursesChild(branch); 725 } 726 } 727 return true; 728 }, 729 730 /** 731 * Add a link to view all courses in a category 732 * 733 * @method addViewAllCoursesChild 734 * @param {BRANCH} branch 735 */ 736 addViewAllCoursesChild: function(branch) { 737 var url = null; 738 if (branch.get('type') === NODETYPE.ROOTNODE) { 739 if (branch.get('key') === 'mycourses') { 740 url = M.cfg.wwwroot + '/my'; 741 } else { 742 url = M.cfg.wwwroot + '/course/index.php'; 743 } 744 } else { 745 url = M.cfg.wwwroot+'/course/index.php?categoryid=' + branch.get('key'); 746 } 747 branch.addChild({ 748 name : M.str.moodle.viewallcourses, 749 title : M.str.moodle.viewallcourses, 750 link : url, 751 haschildren : false, 752 icon : {'pix':"i/navigationitem",'component':'moodle'} 753 }); 754 } 755 }; 756 Y.extend(BRANCH, Y.Base, BRANCH.prototype, { 757 NAME : 'navigation-branch', 758 ATTRS : { 759 /** 760 * The Tree this branch belongs to. 761 * @attribute tree 762 * @type TREE 763 * @required 764 * @writeOnce 765 */ 766 tree : { 767 writeOnce : 'initOnly', 768 validator : Y.Lang.isObject 769 }, 770 /** 771 * The name of this branch. 772 * @attribute name 773 * @type String 774 */ 775 name : { 776 value : '', 777 validator : Y.Lang.isString, 778 setter : function(val) { 779 return val.replace(/\n/g, '<br />'); 780 } 781 }, 782 /** 783 * The title to use for this branch. 784 * @attribute title 785 * @type String 786 */ 787 title : { 788 value : '', 789 validator : Y.Lang.isString 790 }, 791 /** 792 * The ID of this branch. 793 * The ID and Type should always form a unique pair. 794 * @attribute id 795 * @type String 796 */ 797 id : { 798 value : '', 799 validator : Y.Lang.isString, 800 getter : function(val) { 801 if (val === '') { 802 val = 'expandable_branch_'+M.block_navigation.expandablebranchcount; 803 M.block_navigation.expandablebranchcount++; 804 } 805 return val; 806 } 807 }, 808 /** 809 * The key used to identify this branch easily if there is one. 810 * @attribute key 811 * @type String 812 */ 813 key : { 814 value : null 815 }, 816 /** 817 * The type of this branch. 818 * @attribute type 819 * @type Number 820 */ 821 type : { 822 value : null, 823 setter : function(value) { 824 return parseInt(value, 10); 825 } 826 }, 827 /** 828 * The link to use for this branch. 829 * @attribute link 830 * @type String 831 */ 832 link : { 833 value : false 834 }, 835 /** 836 * The Icon to add when displaying this branch. 837 * @attribute icon 838 * @type Object 839 */ 840 icon : { 841 value : false, 842 validator : Y.Lang.isObject 843 }, 844 /** 845 * True if this branch is expandable. 846 * @attribute expandable 847 * @type Boolean 848 */ 849 expandable : { 850 value : false, 851 validator : Y.Lang.isBool 852 }, 853 /** 854 * True if this branch is hidden and should be displayed greyed out. 855 * @attribute hidden 856 * @type Boolean 857 */ 858 hidden : { 859 value : false, 860 validator : Y.Lang.isBool 861 }, 862 /** 863 * True if this branch has any children. 864 * @attribute haschildren 865 * @type Boolean 866 */ 867 haschildren : { 868 value : false, 869 validator : Y.Lang.isBool 870 }, 871 /** 872 * An array of other branches that appear as children of this branch. 873 * @attribute children 874 * @type Array 875 */ 876 children : { 877 value : [], 878 validator : Y.Lang.isArray 879 } 880 } 881 }); 882 883 884 }, '@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 |