[ Index ] |
|
Code source de Serendipity 1.2 |
1 /* 2 Copyright (c) 2006 Yahoo! Inc. All rights reserved. 3 version 0.9.0 4 */ 5 6 /** 7 * @class Contains the tree view metadata and the root node. This is an 8 * ordered tree; child nodes will be displayed in the order created, and 9 * there currently is no way to change this. 10 * 11 * @constructor 12 * @todo prune, graft, reload, repaint 13 * @param {string} id The id of the element that the tree will be inserted 14 * into. 15 */ 16 YAHOO.widget.TreeView = function(id) { 17 if (id) { this.init(id); } 18 }; 19 20 YAHOO.widget.TreeView.prototype = { 21 22 /** 23 * The id of tree container element 24 * 25 * @type String 26 */ 27 id: null, 28 29 /** 30 * Flat collection of all nodes in this tree 31 * 32 * @type YAHOO.widget.Node[] 33 * @private 34 */ 35 _nodes: null, 36 37 /** 38 * We lock the tree control while waiting for the dynamic loader to return 39 * 40 * @type boolean 41 */ 42 locked: false, 43 44 /** 45 * The animation to use for expanding children, if any 46 * 47 * @type string 48 * @private 49 */ 50 _expandAnim: null, 51 52 /** 53 * The animation to use for collapsing children, if any 54 * 55 * @type string 56 * @private 57 */ 58 _collapseAnim: null, 59 60 /** 61 * The current number of animations that are executing 62 * 63 * @type int 64 * @private 65 */ 66 _animCount: 0, 67 68 /** 69 * The maximum number of animations to run at one time. 70 * 71 * @type int 72 */ 73 _maxAnim: 2, 74 75 /** 76 * Sets up the animation for expanding children 77 * 78 * @param {string} the type of animation (acceptable constants in YAHOO.widget.TVAnim) 79 */ 80 setExpandAnim: function(type) { 81 if (YAHOO.widget.TVAnim.isValid(type)) { 82 this._expandAnim = type; 83 } 84 }, 85 86 /** 87 * Sets up the animation for collapsing children 88 * 89 * @param {string} the type of animation (acceptable constants in YAHOO.widget.TVAnim) 90 */ 91 setCollapseAnim: function(type) { 92 if (YAHOO.widget.TVAnim.isValid(type)) { 93 this._collapseAnim = type; 94 } 95 }, 96 97 /** 98 * Perform the expand animation if configured, or just show the 99 * element if not configured or too many animations are in progress 100 * 101 * @param el {HTMLElement} the element to animate 102 * @return {boolean} true if animation could be invoked, false otherwise 103 */ 104 animateExpand: function(el) { 105 106 if (this._expandAnim && this._animCount < this._maxAnim) { 107 // this.locked = true; 108 var tree = this; 109 var a = YAHOO.widget.TVAnim.getAnim(this._expandAnim, el, 110 function() { tree.expandComplete(); }); 111 if (a) { 112 ++this._animCount; 113 a.animate(); 114 } 115 116 return true; 117 } 118 119 return false; 120 }, 121 122 /** 123 * Perform the collapse animation if configured, or just show the 124 * element if not configured or too many animations are in progress 125 * 126 * @param el {HTMLElement} the element to animate 127 * @return {boolean} true if animation could be invoked, false otherwise 128 */ 129 animateCollapse: function(el) { 130 131 if (this._collapseAnim && this._animCount < this._maxAnim) { 132 // this.locked = true; 133 var tree = this; 134 var a = YAHOO.widget.TVAnim.getAnim(this._collapseAnim, el, 135 function() { tree.collapseComplete(); }); 136 if (a) { 137 ++this._animCount; 138 a.animate(); 139 } 140 141 return true; 142 } 143 144 return false; 145 }, 146 147 /** 148 * Function executed when the expand animation completes 149 */ 150 expandComplete: function() { 151 --this._animCount; 152 // this.locked = false; 153 }, 154 155 /** 156 * Function executed when the collapse animation completes 157 */ 158 collapseComplete: function() { 159 --this._animCount; 160 // this.locked = false; 161 }, 162 163 /** 164 * Initializes the tree 165 * 166 * @parm {string} id the id of the element that will hold the tree 167 * @private 168 */ 169 init: function(id) { 170 171 this.id = id; 172 this._nodes = new Array(); 173 174 // store a global reference 175 YAHOO.widget.TreeView.trees[id] = this; 176 177 // Set up the root node 178 this.root = new YAHOO.widget.RootNode(this); 179 180 181 }, 182 183 /** 184 * Renders the tree boilerplate and visible nodes 185 */ 186 draw: function() { 187 var html = this.root.getHtml(); 188 document.getElementById(this.id).innerHTML = html; 189 this.firstDraw = false; 190 }, 191 192 /** 193 * Nodes register themselves with the tree instance when they are created. 194 * 195 * @param node {YAHOO.widget.Node} the node to register 196 * @private 197 */ 198 regNode: function(node) { 199 this._nodes[node.index] = node; 200 }, 201 202 /** 203 * Returns the root node of this tree 204 * 205 * @return {YAHOO.widget.Node} the root node 206 */ 207 getRoot: function() { 208 return this.root; 209 }, 210 211 /** 212 * Configures this tree to dynamically load all child data 213 * 214 * @param {function} fnDataLoader the function that will be called to get the data 215 */ 216 setDynamicLoad: function(fnDataLoader) { 217 // this.root.dataLoader = fnDataLoader; 218 // this.root._dynLoad = true; 219 this.root.setDynamicLoad(fnDataLoader); 220 }, 221 222 /** 223 * Expands all child nodes. Note: this conflicts with the "multiExpand" 224 * node property. If expand all is called in a tree with nodes that 225 * do not allow multiple siblings to be displayed, only the last sibling 226 * will be expanded. 227 */ 228 expandAll: function() { 229 if (!this.locked) { 230 this.root.expandAll(); 231 } 232 }, 233 234 /** 235 * Collapses all expanded child nodes in the entire tree. 236 */ 237 collapseAll: function() { 238 if (!this.locked) { 239 this.root.collapseAll(); 240 } 241 }, 242 243 /** 244 * Returns a node in the tree that has the specified index (this index 245 * is created internally, so this function probably will only be used 246 * in html generated for a given node.) 247 * 248 * @param {int} nodeIndex the index of the node wanted 249 * @return {YAHOO.widget.Node} the node with index=nodeIndex, null if no match 250 */ 251 getNodeByIndex: function(nodeIndex) { 252 var n = this._nodes[nodeIndex]; 253 return (n) ? n : null; 254 }, 255 256 /** 257 * Returns a node that has a matching property and value in the data 258 * object that was passed into its constructor. Provides a flexible 259 * way for the implementer to get a particular node. 260 * 261 * @param {object} property the property to search (usually a string) 262 * @param {object} value the value we want to find (usuall an int or string) 263 * @return {YAHOO.widget.Node} the matching node, null if no match 264 */ 265 getNodeByProperty: function(property, value) { 266 for (var i in this._nodes) { 267 var n = this._nodes[i]; 268 if (n.data && value == n.data[property]) { 269 return n; 270 } 271 } 272 273 return null; 274 }, 275 276 /** 277 * Abstract method that is executed when a node is expanded 278 * 279 * @param node {YAHOO.widget.Node} the node that was expanded 280 */ 281 onExpand: function(node) { }, 282 283 /** 284 * Abstract method that is executed when a node is collapsed 285 * 286 * @param node {YAHOO.widget.Node} the node that was collapsed. 287 */ 288 onCollapse: function(node) { } 289 290 }; 291 292 /** 293 * Global cache of tree instances 294 * 295 * @type Array 296 * @private 297 */ 298 YAHOO.widget.TreeView.trees = []; 299 300 /** 301 * Global method for getting a tree by its id. Used in the generated 302 * tree html. 303 * 304 * @param treeId {String} the id of the tree instance 305 * @return {TreeView} the tree instance requested, null if not found. 306 */ 307 YAHOO.widget.TreeView.getTree = function(treeId) { 308 var t = YAHOO.widget.TreeView.trees[treeId]; 309 return (t) ? t : null; 310 }; 311 312 YAHOO.widget.TreeView.nodeCount = 0; 313 314 /** 315 * Global method for getting a node by its id. Used in the generated 316 * tree html. 317 * 318 * @param treeId {String} the id of the tree instance 319 * @param nodeIndex {String} the index of the node to return 320 * @param return {YAHOO.widget.Node} the node instance requested, null if not found 321 */ 322 YAHOO.widget.TreeView.getNode = function(treeId, nodeIndex) { 323 var t = YAHOO.widget.TreeView.getTree(treeId); 324 return (t) ? t.getNodeByIndex(nodeIndex) : null; 325 }; 326 327 /** 328 * Adds an event. Replace with event manager when available 329 * 330 * @param el the elment to bind the handler to 331 * @param {string} sType the type of event handler 332 * @param {function} fn the callback to invoke 333 * @param {boolean} capture if true event is capture phase, bubble otherwise 334 */ 335 YAHOO.widget.TreeView.addHandler = function (el, sType, fn, capture) { 336 capture = (capture) ? true : false; 337 if (el.addEventListener) { 338 el.addEventListener(sType, fn, capture); 339 } else if (el.attachEvent) { 340 el.attachEvent("on" + sType, fn); 341 } else { 342 el["on" + sType] = fn; 343 } 344 }; 345 346 /** 347 * Attempts to preload the images defined in the styles used to draw the tree by 348 * rendering off-screen elements that use the styles. 349 */ 350 YAHOO.widget.TreeView.preload = function() { 351 352 var styles = [ 353 "ygtvtn", 354 "ygtvtm", 355 "ygtvtmh", 356 "ygtvtp", 357 "ygtvtph", 358 "ygtvln", 359 "ygtvlm", 360 "ygtvlmh", 361 "ygtvlp", 362 "ygtvlph", 363 "ygtvloading" 364 ]; 365 366 var sb = []; 367 368 for (var i = 0; i < styles.length; ++i) { 369 sb[sb.length] = '<span class="' + styles[i] + '"> </span>'; 370 } 371 372 var f = document.createElement("div"); 373 var s = f.style; 374 s.position = "absolute"; 375 s.top = "-1000px"; 376 s.left = "-1000px"; 377 f.innerHTML = sb.join(""); 378 379 document.body.appendChild(f); 380 }; 381 382 YAHOO.widget.TreeView.addHandler(window, 383 "load", YAHOO.widget.TreeView.preload); 384 385 /* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ 386 387 /** 388 * @class Abstract node class 389 * @constructor 390 * @param oData {object} a string or object containing the data that will 391 * be used to render this node 392 * @param oParent {YAHOO.widget.Node} this node's parent node 393 * @param expanded {boolean} the initial expanded/collapsed state 394 */ 395 YAHOO.widget.Node = function(oData, oParent, expanded) { 396 if (oParent) { this.init(oData, oParent, expanded); } 397 }; 398 399 YAHOO.widget.Node.prototype = { 400 401 /** 402 * The index for this instance obtained from global counter in YAHOO.widget.TreeView. 403 * 404 * @type int 405 */ 406 index: 0, 407 408 /** 409 * This node's child node collection. 410 * 411 * @type YAHOO.widget.Node[] 412 */ 413 children: null, 414 415 /** 416 * Tree instance this node is part of 417 * 418 * @type YAHOO.widget.TreeView 419 */ 420 tree: null, 421 422 /** 423 * The data linked to this node. This can be any object or primitive 424 * value, and the data can be used in getNodeHtml(). 425 * 426 * @type object 427 */ 428 data: null, 429 430 /** 431 * Parent node 432 * 433 * @type YAHOO.widget.Node 434 */ 435 parent: null, 436 437 /** 438 * The depth of this node. We start at -1 for the root node. 439 * 440 * @type int 441 */ 442 depth: -1, 443 444 /** 445 * The href for the node's label. If one is not specified, the href will 446 * be set so that it toggles the node. 447 * 448 * @type string 449 */ 450 href: null, 451 452 /** 453 * The label href target, defaults to current window 454 * 455 * @type string 456 */ 457 target: "_self", 458 459 /** 460 * The node's expanded/collapsed state 461 * 462 * @type boolean 463 */ 464 expanded: false, 465 466 /** 467 * Can multiple children be expanded at once? 468 * 469 * @type boolean 470 */ 471 multiExpand: true, 472 473 /** 474 * Should we render children for a collapsed node? It is possible that the 475 * implementer will want to render the hidden data... @todo verify that we 476 * need this, and implement it if we do. 477 * 478 * @type boolean 479 */ 480 renderHidden: false, 481 482 /** 483 * Flag that is set to true the first time this node's children are rendered. 484 * 485 * @type boolean 486 */ 487 childrenRendered: false, 488 489 /** 490 * This node's previous sibling 491 * 492 * @type YAHOO.widget.Node 493 */ 494 previousSibling: null, 495 496 /** 497 * This node's next sibling 498 * 499 * @type YAHOO.widget.Node 500 */ 501 nextSibling: null, 502 503 /** 504 * We can set the node up to call an external method to get the child 505 * data dynamically. 506 * 507 * @type boolean 508 * @private 509 */ 510 _dynLoad: false, 511 512 /** 513 * Function to execute when we need to get this node's child data. 514 * 515 * @type function 516 */ 517 dataLoader: null, 518 519 /** 520 * This is true for dynamically loading nodes while waiting for the 521 * callback to return. 522 * 523 * @type boolean 524 */ 525 isLoading: false, 526 527 /** 528 * The toggle/branch icon will not show if this is set to false. This 529 * could be useful if the implementer wants to have the child contain 530 * extra info about the parent, rather than an actual node. 531 * 532 * @type boolean 533 */ 534 hasIcon: true, 535 536 /** 537 * Initializes this node, gets some of the properties from the parent 538 * 539 * @param oData {object} a string or object containing the data that will 540 * be used to render this node 541 * @param oParent {YAHOO.widget.Node} this node's parent node 542 * @param expanded {boolean} the initial expanded/collapsed state 543 */ 544 init: function(oData, oParent, expanded) { 545 this.data = oData; 546 this.children = []; 547 this.index = YAHOO.widget.TreeView.nodeCount; 548 ++YAHOO.widget.TreeView.nodeCount; 549 this.expanded = expanded; 550 551 // oParent should never be null except when we create the root node. 552 if (oParent) { 553 this.tree = oParent.tree; 554 this.parent = oParent; 555 this.href = "javascript:" + this.getToggleLink(); 556 this.depth = oParent.depth + 1; 557 this.multiExpand = oParent.multiExpand; 558 559 oParent.appendChild(this); 560 } 561 }, 562 563 /** 564 * Appends a node to the child collection. 565 * 566 * @param node {YAHOO.widget.Node} the new node 567 * @return {YAHOO.widget.Node} the child node 568 * @private 569 */ 570 appendChild: function(node) { 571 if (this.hasChildren()) { 572 var sib = this.children[this.children.length - 1]; 573 sib.nextSibling = node; 574 node.previousSibling = sib; 575 } 576 577 this.tree.regNode(node); 578 this.children[this.children.length] = node; 579 return node; 580 581 }, 582 583 /** 584 * Returns a node array of this node's siblings, null if none. 585 * 586 * @return YAHOO.widget.Node[] 587 */ 588 getSiblings: function() { 589 return this.parent.children; 590 }, 591 592 /** 593 * Shows this node's children 594 */ 595 showChildren: function() { 596 if (!this.tree.animateExpand(this.getChildrenEl())) { 597 if (this.hasChildren()) { 598 this.getChildrenEl().style.display = ""; 599 } 600 } 601 }, 602 603 /** 604 * Hides this node's children 605 */ 606 hideChildren: function() { 607 608 if (!this.tree.animateCollapse(this.getChildrenEl())) { 609 this.getChildrenEl().style.display = "none"; 610 } 611 }, 612 613 /** 614 * Returns the id for this node's container div 615 * 616 * @return {string} the element id 617 */ 618 getElId: function() { 619 return "ygtv" + this.index; 620 }, 621 622 /** 623 * Returns the id for this node's children div 624 * 625 * @return {string} the element id for this node's children div 626 */ 627 getChildrenElId: function() { 628 return "ygtvc" + this.index; 629 }, 630 631 /** 632 * Returns the id for this node's toggle element 633 * 634 * @return {string} the toggel element id 635 */ 636 getToggleElId: function() { 637 return "ygtvt" + this.index; 638 }, 639 640 /** 641 * Returns this node's container html element 642 * 643 * @return {Object} the container html element 644 */ 645 getEl: function() { 646 return document.getElementById(this.getElId()); 647 }, 648 649 /** 650 * Returns the div that was generated for this node's children 651 * 652 * @return {Object} this node's children div 653 */ 654 getChildrenEl: function() { 655 return document.getElementById(this.getChildrenElId()); 656 }, 657 658 /** 659 * Returns the element that is being used for this node's toggle. 660 * 661 * @return {Object} this node's toggel html element 662 */ 663 getToggleEl: function() { 664 return document.getElementById(this.getToggleElId()); 665 }, 666 667 /** 668 * Generates the link that will invoke this node's toggle method 669 * 670 * @return {string} the javascript url for toggling this node 671 */ 672 getToggleLink: function() { 673 return "YAHOO.widget.TreeView.getNode(\'" + this.tree.id + "\'," + 674 this.index + ").toggle()"; 675 }, 676 677 /** 678 * Hides this nodes children (creating them if necessary), changes the 679 * toggle style. 680 */ 681 collapse: function() { 682 // Only collapse if currently expanded 683 if (!this.expanded) { return; } 684 685 if (!this.getEl()) { 686 this.expanded = false; 687 return; 688 } 689 690 // hide the child div 691 this.hideChildren(); 692 this.expanded = false; 693 694 if (this.hasIcon) { 695 this.getToggleEl().className = this.getStyle(); 696 } 697 698 // fire the collapse event handler 699 this.tree.onCollapse(this); 700 }, 701 702 /** 703 * Shows this nodes children (creating them if necessary), changes the 704 * toggle style, and collapses its siblings if multiExpand is not set. 705 */ 706 expand: function() { 707 // Only expand if currently collapsed. 708 if (this.expanded) { return; } 709 710 if (!this.getEl()) { 711 this.expanded = true; 712 return; 713 } 714 715 if (! this.childrenRendered) { 716 this.getChildrenEl().innerHTML = this.renderChildren(); 717 } 718 719 this.expanded = true; 720 if (this.hasIcon) { 721 this.getToggleEl().className = this.getStyle(); 722 } 723 724 // We do an extra check for children here because the lazy 725 // load feature can expose nodes that have no children. 726 727 // if (!this.hasChildren()) { 728 if (this.isLoading) { 729 this.expanded = false; 730 return; 731 } 732 733 if (! this.multiExpand) { 734 var sibs = this.getSiblings(); 735 for (var i=0; i<sibs.length; ++i) { 736 if (sibs[i] != this && sibs[i].expanded) { 737 sibs[i].collapse(); 738 } 739 } 740 } 741 742 this.showChildren(); 743 744 // fire the expand event handler 745 this.tree.onExpand(this); 746 }, 747 748 /** 749 * Returns the css style name for the toggle 750 * 751 * @return {string} the css class for this node's toggle 752 */ 753 getStyle: function() { 754 if (this.isLoading) { 755 return "ygtvloading"; 756 } else { 757 // location top or bottom, middle nodes also get the top style 758 var loc = (this.nextSibling) ? "t" : "l"; 759 760 // type p=plus(expand), m=minus(collapase), n=none(no children) 761 var type = "n"; 762 if (this.hasChildren(true) || this.isDynamic()) { 763 type = (this.expanded) ? "m" : "p"; 764 } 765 766 return "ygtv" + loc + type; 767 } 768 }, 769 770 /** 771 * Returns the hover style for the icon 772 * @return {string} the css class hover state 773 */ 774 getHoverStyle: function() { 775 var s = this.getStyle(); 776 if (this.hasChildren(true) && !this.isLoading) { 777 s += "h"; 778 } 779 return s; 780 }, 781 782 /** 783 * Recursively expands all of this node's children. 784 */ 785 expandAll: function() { 786 for (var i=0;i<this.children.length;++i) { 787 var c = this.children[i]; 788 if (c.isDynamic()) { 789 alert("Not supported (lazy load + expand all)"); 790 break; 791 } else if (! c.multiExpand) { 792 alert("Not supported (no multi-expand + expand all)"); 793 break; 794 } else { 795 c.expand(); 796 c.expandAll(); 797 } 798 } 799 }, 800 801 /** 802 * Recursively collapses all of this node's children. 803 */ 804 collapseAll: function() { 805 for (var i=0;i<this.children.length;++i) { 806 this.children[i].collapse(); 807 this.children[i].collapseAll(); 808 } 809 }, 810 811 /** 812 * Configures this node for dynamically obtaining the child data 813 * when the node is first expanded. 814 * 815 * @param fmDataLoader {function} the function that will be used to get the data. 816 */ 817 setDynamicLoad: function(fnDataLoader) { 818 this.dataLoader = fnDataLoader; 819 this._dynLoad = true; 820 }, 821 822 /** 823 * Evaluates if this node is the root node of the tree 824 * 825 * @return {boolean} true if this is the root node 826 */ 827 isRoot: function() { 828 return (this == this.tree.root); 829 }, 830 831 /** 832 * Evaluates if this node's children should be loaded dynamically. Looks for 833 * the property both in this instance and the root node. If the tree is 834 * defined to load all children dynamically, the data callback function is 835 * defined in the root node 836 * 837 * @return {boolean} true if this node's children are to be loaded dynamically 838 */ 839 isDynamic: function() { 840 var lazy = (!this.isRoot() && (this._dynLoad || this.tree.root._dynLoad)); 841 return lazy; 842 }, 843 844 /** 845 * Checks if this node has children. If this node is lazy-loading and the 846 * children have not been rendered, we do not know whether or not there 847 * are actual children. In most cases, we need to assume that there are 848 * children (for instance, the toggle needs to show the expandable 849 * presentation state). In other times we want to know if there are rendered 850 * children. For the latter, "checkForLazyLoad" should be false. 851 * 852 * @param checkForLazyLoad {boolean} should we check for unloaded children? 853 * @return {boolean} true if this has children or if it might and we are 854 * checking for this condition. 855 */ 856 hasChildren: function(checkForLazyLoad) { 857 return ( this.children.length > 0 || 858 (checkForLazyLoad && this.isDynamic() && !this.childrenRendered) ); 859 }, 860 861 /** 862 * Expands if node is collapsed, collapses otherwise. 863 */ 864 toggle: function() { 865 if (!this.tree.locked && ( this.hasChildren(true) || this.isDynamic()) ) { 866 if (this.expanded) { this.collapse(); } else { this.expand(); } 867 } 868 }, 869 870 /** 871 * Returns the markup for this node and its children. 872 * 873 * @return {string} the markup for this node and its expanded children. 874 */ 875 getHtml: function() { 876 var sb = []; 877 sb[sb.length] = '<div class="ygtvitem" id="' + this.getElId() + '">'; 878 sb[sb.length] = this.getNodeHtml(); 879 sb[sb.length] = this.getChildrenHtml(); 880 sb[sb.length] = '</div>'; 881 return sb.join(""); 882 }, 883 884 /** 885 * Called when first rendering the tree. We always build the div that will 886 * contain this nodes children, but we don't render the children themselves 887 * unless this node is expanded. 888 * 889 * @return {string} the children container div html and any expanded children 890 * @private 891 */ 892 getChildrenHtml: function() { 893 var sb = []; 894 sb[sb.length] = '<div class="ygtvchildren"'; 895 sb[sb.length] = ' id="' + this.getChildrenElId() + '"'; 896 if (!this.expanded) { 897 sb[sb.length] = ' style="display:none;"'; 898 } 899 sb[sb.length] = '>'; 900 901 // Don't render the actual child node HTML unless this node is expanded. 902 if (this.hasChildren(true) && this.expanded) { 903 sb[sb.length] = this.renderChildren(); 904 } 905 906 sb[sb.length] = '</div>'; 907 908 return sb.join(""); 909 }, 910 911 /** 912 * Generates the markup for the child nodes. This is not done until the node 913 * is expanded. 914 * 915 * @return {string} the html for this node's children 916 * @private 917 */ 918 renderChildren: function() { 919 920 921 var node = this; 922 923 if (this.isDynamic() && !this.childrenRendered) { 924 this.isLoading = true; 925 this.tree.locked = true; 926 927 if (this.dataLoader) { 928 setTimeout( 929 function() { 930 node.dataLoader(node, 931 function() { 932 node.loadComplete(); 933 }); 934 }, 10); 935 936 } else if (this.tree.root.dataLoader) { 937 938 setTimeout( 939 function() { 940 node.tree.root.dataLoader(node, 941 function() { 942 node.loadComplete(); 943 }); 944 }, 10); 945 946 } else { 947 return "Error: data loader not found or not specified."; 948 } 949 950 return ""; 951 952 } else { 953 return this.completeRender(); 954 } 955 }, 956 957 /** 958 * Called when we know we have all the child data. 959 * @return {string} children html 960 */ 961 completeRender: function() { 962 var sb = []; 963 964 for (var i=0; i < this.children.length; ++i) { 965 sb[sb.length] = this.children[i].getHtml(); 966 } 967 968 this.childrenRendered = true; 969 970 return sb.join(""); 971 }, 972 973 /** 974 * Load complete is the callback function we pass to the data provider 975 * in dynamic load situations. 976 */ 977 loadComplete: function() { 978 this.getChildrenEl().innerHTML = this.completeRender(); 979 this.isLoading = false; 980 this.expand(); 981 this.tree.locked = false; 982 }, 983 984 /** 985 * Returns this node's ancestor at the specified depth. 986 * 987 * @param {int} depth the depth of the ancestor. 988 * @return {YAHOO.widget.Node} the ancestor 989 */ 990 getAncestor: function(depth) { 991 if (depth >= this.depth || depth < 0) { 992 return null; 993 } 994 995 var p = this.parent; 996 997 while (p.depth > depth) { 998 p = p.parent; 999 } 1000 1001 return p; 1002 }, 1003 1004 /** 1005 * Returns the css class for the spacer at the specified depth for 1006 * this node. If this node's ancestor at the specified depth 1007 * has a next sibling the presentation is different than if it 1008 * does not have a next sibling 1009 * 1010 * @param {int} depth the depth of the ancestor. 1011 * @return {string} the css class for the spacer 1012 */ 1013 getDepthStyle: function(depth) { 1014 return (this.getAncestor(depth).nextSibling) ? 1015 "ygtvdepthcell" : "ygtvblankdepthcell"; 1016 }, 1017 1018 /** 1019 * Get the markup for the node. This is designed to be overrided so that we can 1020 * support different types of nodes. 1021 * 1022 * @return {string} the html for this node 1023 */ 1024 getNodeHtml: function() { 1025 return ""; 1026 } 1027 1028 }; 1029 1030 /* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ 1031 1032 /** 1033 * @class A custom YAHOO.widget.Node that handles the unique nature of 1034 * the virtual, presentationless root node. 1035 * 1036 * @extends YAHOO.widget.Node 1037 * @constructor 1038 */ 1039 YAHOO.widget.RootNode = function(oTree) { 1040 // Initialize the node with null params. The root node is a 1041 // special case where the node has no presentation. So we have 1042 // to alter the standard properties a bit. 1043 this.init(null, null, true); 1044 1045 /** 1046 * For the root node, we get the tree reference from as a param 1047 * to the constructor instead of from the parent element. 1048 * 1049 * @type YAHOO.widget.TreeView 1050 */ 1051 this.tree = oTree; 1052 }; 1053 YAHOO.widget.RootNode.prototype = new YAHOO.widget.Node(); 1054 1055 // overrides YAHOO.widget.Node 1056 YAHOO.widget.RootNode.prototype.getNodeHtml = function() { 1057 return ""; 1058 }; 1059 1060 /* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ 1061 1062 /** 1063 * @class The default node presentation. The first parameter should be 1064 * either a string that will be used as the node's label, or an object 1065 * that has a string propery called label. By default, the clicking the 1066 * label will toggle the expanded/collapsed state of the node. By 1067 * changing the href property of the instance, this behavior can be 1068 * changed so that the label will go to the specified href. 1069 * 1070 * @extends YAHOO.widget.Node 1071 * @constructor 1072 * @param oData {object} a string or object containing the data that will 1073 * be used to render this node 1074 * @param oParent {YAHOO.widget.Node} this node's parent node 1075 * @param expanded {boolean} the initial expanded/collapsed state 1076 */ 1077 YAHOO.widget.TextNode = function(oData, oParent, expanded) { 1078 if (oParent) { 1079 this.init(oData, oParent, expanded); 1080 this.setUpLabel(oData); 1081 } 1082 }; 1083 1084 YAHOO.widget.TextNode.prototype = new YAHOO.widget.Node(); 1085 1086 /** 1087 * The CSS class for the label href. Defaults to ygtvlabel, but can be 1088 * overridden to provide a custom presentation for a specific node. 1089 * 1090 * @type string 1091 */ 1092 YAHOO.widget.TextNode.prototype.labelStyle = "ygtvlabel"; 1093 1094 /** 1095 * The derived element id of the label for this node 1096 * 1097 * @type string 1098 */ 1099 YAHOO.widget.TextNode.prototype.labelElId = null; 1100 1101 /** 1102 * The text for the label. It is assumed that the oData parameter will 1103 * either be a string that will be used as the label, or an object that 1104 * has a property called "label" that we will use. 1105 * 1106 * @type string 1107 */ 1108 YAHOO.widget.TextNode.prototype.label = null; 1109 1110 /** 1111 * Sets up the node label 1112 * 1113 * @param oData string containing the label, or an object with a label property 1114 */ 1115 YAHOO.widget.TextNode.prototype.setUpLabel = function(oData) { 1116 if (typeof oData == "string") { 1117 oData = { label: oData }; 1118 } 1119 this.label = oData.label; 1120 1121 // update the link 1122 if (oData.href) { 1123 this.href = oData.href; 1124 } 1125 1126 // set the target 1127 if (oData.target) { 1128 this.target = oData.target; 1129 } 1130 1131 this.labelElId = "ygtvlabelel" + this.index; 1132 }; 1133 1134 /** 1135 * Returns the label element 1136 * 1137 * @return {object} the element 1138 */ 1139 YAHOO.widget.TextNode.prototype.getLabelEl = function() { 1140 return document.getElementById(this.labelElId); 1141 }; 1142 1143 // overrides YAHOO.widget.Node 1144 YAHOO.widget.TextNode.prototype.getNodeHtml = function() { 1145 var sb = new Array(); 1146 1147 sb[sb.length] = '<table border="0" cellpadding="0" cellspacing="0">'; 1148 sb[sb.length] = '<tr>'; 1149 1150 for (i=0;i<this.depth;++i) { 1151 // sb[sb.length] = '<td class="ygtvdepthcell"> </td>'; 1152 sb[sb.length] = '<td class="' + this.getDepthStyle(i) + '"> </td>'; 1153 } 1154 1155 var getNode = 'YAHOO.widget.TreeView.getNode(\'' + 1156 this.tree.id + '\',' + this.index + ')'; 1157 1158 sb[sb.length] = '<td'; 1159 // sb[sb.length] = ' onselectstart="return false"'; 1160 sb[sb.length] = ' id="' + this.getToggleElId() + '"'; 1161 sb[sb.length] = ' class="' + this.getStyle() + '"'; 1162 if (this.hasChildren(true)) { 1163 sb[sb.length] = ' onmouseover="this.className='; 1164 sb[sb.length] = getNode + '.getHoverStyle()"'; 1165 sb[sb.length] = ' onmouseout="this.className='; 1166 sb[sb.length] = getNode + '.getStyle()"'; 1167 } 1168 sb[sb.length] = ' onclick="javascript:' + this.getToggleLink() + '"> '; 1169 sb[sb.length] = '</td>'; 1170 sb[sb.length] = '<td>'; 1171 sb[sb.length] = '<a'; 1172 sb[sb.length] = ' id="' + this.labelElId + '"'; 1173 sb[sb.length] = ' class="' + this.labelStyle + '"'; 1174 sb[sb.length] = ' href="' + this.href + '"'; 1175 sb[sb.length] = ' target="' + this.target + '"'; 1176 if (this.hasChildren(true)) { 1177 sb[sb.length] = ' onmouseover="document.getElementById(\''; 1178 sb[sb.length] = this.getToggleElId() + '\').className='; 1179 sb[sb.length] = getNode + '.getHoverStyle()"'; 1180 sb[sb.length] = ' onmouseout="document.getElementById(\''; 1181 sb[sb.length] = this.getToggleElId() + '\').className='; 1182 sb[sb.length] = getNode + '.getStyle()"'; 1183 } 1184 sb[sb.length] = ' >'; 1185 sb[sb.length] = this.label; 1186 sb[sb.length] = '</a>'; 1187 sb[sb.length] = '</td>'; 1188 sb[sb.length] = '</tr>'; 1189 sb[sb.length] = '</table>'; 1190 1191 return sb.join(""); 1192 }; 1193 1194 /* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ 1195 1196 /** 1197 * @class menu-specific implementation that differs in that only one sibling 1198 * can be expanded at a time. 1199 * @extends YAHOO.widget.TextNode 1200 * @constructor 1201 */ 1202 YAHOO.widget.MenuNode = function(oData, oParent, expanded) { 1203 if (oParent) { 1204 this.init(oData, oParent, expanded); 1205 this.setUpLabel(oData); 1206 } 1207 1208 // Menus usually allow only one branch to be open at a time. 1209 this.multiExpand = false; 1210 1211 }; 1212 1213 YAHOO.widget.MenuNode.prototype = new YAHOO.widget.TextNode(); 1214 1215 /* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ 1216 1217 /** 1218 * @class This implementation takes either a string or object for the 1219 * oData argument. If is it a string, we will use it for the display 1220 * of this node (and it can contain any html code). If the parameter 1221 * is an object, we look for a parameter called "html" that will be 1222 * used for this node's display. 1223 * 1224 * @extends YAHOO.widget.Node 1225 * @constructor 1226 * @param oData {object} a string or object containing the data that will 1227 * be used to render this node 1228 * @param oParent {YAHOO.widget.Node} this node's parent node 1229 * @param expanded {boolean} the initial expanded/collapsed state 1230 * @param hasIcon {boolean} specifies whether or not leaf nodes should 1231 * have an icon 1232 */ 1233 YAHOO.widget.HTMLNode = function(oData, oParent, expanded, hasIcon) { 1234 if (oParent) { 1235 this.init(oData, oParent, expanded); 1236 this.initContent(oData, hasIcon); 1237 } 1238 }; 1239 1240 YAHOO.widget.HTMLNode.prototype = new YAHOO.widget.Node(); 1241 1242 /** 1243 * The CSS class for the label href. Defaults to ygtvlabel, but can be 1244 * overridden to provide a custom presentation for a specific node. 1245 * 1246 * @type string 1247 */ 1248 YAHOO.widget.HTMLNode.prototype.contentStyle = "ygtvhtml"; 1249 1250 /** 1251 * The generated id that will contain the data passed in by the implementer. 1252 * 1253 * @type string 1254 */ 1255 YAHOO.widget.HTMLNode.prototype.contentElId = null; 1256 1257 /** 1258 * The HTML content to use for this node's display 1259 * 1260 * @type string 1261 */ 1262 YAHOO.widget.HTMLNode.prototype.content = null; 1263 1264 /** 1265 * Sets up the node label 1266 * 1267 * @param {object} html string or object containing a html field 1268 * @param {boolean} hasIcon determines if the node will be rendered with an 1269 * icon or not 1270 */ 1271 YAHOO.widget.HTMLNode.prototype.initContent = function(oData, hasIcon) { 1272 if (typeof oData == "string") { 1273 oData = { html: oData }; 1274 } 1275 1276 this.html = oData.html; 1277 this.contentElId = "ygtvcontentel" + this.index; 1278 this.hasIcon = hasIcon; 1279 }; 1280 1281 /** 1282 * Returns the outer html element for this node's content 1283 * 1284 * @return {Object} the element 1285 */ 1286 YAHOO.widget.HTMLNode.prototype.getContentEl = function() { 1287 return document.getElementById(this.contentElId); 1288 }; 1289 1290 // overrides YAHOO.widget.Node 1291 YAHOO.widget.HTMLNode.prototype.getNodeHtml = function() { 1292 var sb = new Array(); 1293 1294 sb[sb.length] = '<table border="0" cellpadding="0" cellspacing="0">'; 1295 sb[sb.length] = '<tr>'; 1296 1297 for (i=0;i<this.depth;++i) { 1298 sb[sb.length] = '<td class="' + this.getDepthStyle(i) + '"> </td>'; 1299 } 1300 1301 if (this.hasIcon) { 1302 sb[sb.length] = '<td'; 1303 sb[sb.length] = ' id="' + this.getToggleElId() + '"'; 1304 sb[sb.length] = ' class="' + this.getStyle() + '"'; 1305 sb[sb.length] = ' onclick="javascript:' + this.getToggleLink() + '"> '; 1306 if (this.hasChildren(true)) { 1307 sb[sb.length] = ' onmouseover="this.className='; 1308 sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\''; 1309 sb[sb.length] = this.tree.id + '\',' + this.index + ').getHoverStyle()"'; 1310 sb[sb.length] = ' onmouseout="this.className='; 1311 sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\''; 1312 sb[sb.length] = this.tree.id + '\',' + this.index + ').getStyle()"'; 1313 } 1314 sb[sb.length] = '</td>'; 1315 } 1316 1317 sb[sb.length] = '<td'; 1318 sb[sb.length] = ' id="' + this.contentElId + '"'; 1319 sb[sb.length] = ' class="' + this.contentStyle + '"'; 1320 sb[sb.length] = ' >'; 1321 sb[sb.length] = this.html; 1322 sb[sb.length] = '</td>'; 1323 sb[sb.length] = '</tr>'; 1324 sb[sb.length] = '</table>'; 1325 1326 return sb.join(""); 1327 }; 1328 1329 /* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ 1330 1331 /** 1332 * Static factory class for tree view expand/collapse animations 1333 */ 1334 YAHOO.widget.TVAnim = new function() { 1335 /** 1336 * Constant for the fade in animation 1337 * 1338 * @type string 1339 */ 1340 this.FADE_IN = "YAHOO.widget.TVFadeIn"; 1341 1342 /** 1343 * Constant for the fade out animation 1344 * 1345 * @type string 1346 */ 1347 this.FADE_OUT = "YAHOO.widget.TVFadeOut"; 1348 1349 /** 1350 * Returns a ygAnim instance of the given type 1351 * 1352 * @param type {string} the type of animation 1353 * @param el {HTMLElement} the element to element (probably the children div) 1354 * @param callback {function} function to invoke when the animation is done. 1355 * @return {ygAnim} the animation instance 1356 */ 1357 this.getAnim = function(type, el, callback) { 1358 switch (type) { 1359 case this.FADE_IN: return new YAHOO.widget.TVFadeIn(el, callback); 1360 case this.FADE_OUT: return new YAHOO.widget.TVFadeOut(el, callback); 1361 default: return null; 1362 } 1363 }; 1364 1365 /** 1366 * Returns true if the specified animation class is available 1367 * 1368 * @param type {string} the type of animation 1369 * @return {boolean} true if valid, false if not 1370 */ 1371 this.isValid = function(type) { 1372 return ( "undefined" != eval("typeof " + type) ); 1373 }; 1374 }; 1375 1376 /* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ 1377 1378 /** 1379 * 1/2 second fade-in 1380 * 1381 * @constructor 1382 * @param el {HTMLElement} the element to animate 1383 * @param callback {function} function to invoke when the animation is finished 1384 */ 1385 YAHOO.widget.TVFadeIn = function(el, callback) { 1386 /** 1387 * The animation dom ref 1388 */ 1389 this.el = el; 1390 1391 /** 1392 * the callback to invoke when the animation is complete 1393 * 1394 * @type function 1395 */ 1396 this.callback = callback; 1397 1398 /** 1399 * @private 1400 */ 1401 }; 1402 1403 /** 1404 * Performs the animation 1405 */ 1406 YAHOO.widget.TVFadeIn.prototype = { 1407 animate: function() { 1408 var tvanim = this; 1409 1410 var s = this.el.style; 1411 s.opacity = 0.1; 1412 s.filter = "alpha(opacity=10)"; 1413 s.display = ""; 1414 1415 // var dur = ( navigator.userAgent.match(/msie/gi) ) ? 0.05 : 0.4; 1416 var dur = 0.4; 1417 // var a = new ygAnim_Fade(this.el, dur, 1); 1418 // a.setStart(0.1); 1419 // a.onComplete = function() { tvanim.onComplete(); }; 1420 1421 // var a = new YAHOO.util.Anim(this.el, 'opacity', 0.1, 1); 1422 var a = new YAHOO.util.Anim(this.el, {opacity: {from: 0.1, to: 1, unit:""}}, dur); 1423 a.onComplete.subscribe( function() { tvanim.onComplete(); } ); 1424 a.animate(); 1425 }, 1426 1427 /** 1428 * Clean up and invoke callback 1429 */ 1430 onComplete: function() { 1431 this.callback(); 1432 } 1433 }; 1434 1435 /* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ 1436 1437 /** 1438 * 1/2 second fade out 1439 * 1440 * @constructor 1441 * @param el {HTMLElement} the element to animate 1442 * @param callback {Function} function to invoke when the animation is finished 1443 */ 1444 YAHOO.widget.TVFadeOut = function(el, callback) { 1445 /** 1446 * The animation dom ref 1447 */ 1448 this.el = el; 1449 1450 /** 1451 * the callback to invoke when the animation is complete 1452 * 1453 * @type function 1454 */ 1455 this.callback = callback; 1456 1457 /** 1458 * @private 1459 */ 1460 }; 1461 1462 /** 1463 * Performs the animation 1464 */ 1465 YAHOO.widget.TVFadeOut.prototype = { 1466 animate: function() { 1467 var tvanim = this; 1468 // var dur = ( navigator.userAgent.match(/msie/gi) ) ? 0.05 : 0.4; 1469 var dur = 0.4; 1470 // var a = new ygAnim_Fade(this.el, dur, 0.1); 1471 // a.onComplete = function() { tvanim.onComplete(); }; 1472 1473 // var a = new YAHOO.util.Anim(this.el, 'opacity', 1, 0.1); 1474 var a = new YAHOO.util.Anim(this.el, {opacity: {from: 1, to: 0.1, unit:""}}, dur); 1475 a.onComplete.subscribe( function() { tvanim.onComplete(); } ); 1476 a.animate(); 1477 }, 1478 1479 /** 1480 * Clean up and invoke callback 1481 */ 1482 onComplete: function() { 1483 var s = this.el.style; 1484 s.display = "none"; 1485 // s.opacity = 1; 1486 s.filter = "alpha(opacity=100)"; 1487 this.callback(); 1488 } 1489 }; 1490
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sat Nov 24 09:00:37 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |