001 
002 /*
003  *  JScripter Standard 1.0 - To Script In Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package jsx.ui;
021 
022 import js.ArrayLike;
023 import js.Id;
024 import js.Js;
025 import js.Vars;
026 import jsx.Configurable;
027 import jsx.Template;
028 import jsx.core.ArrayLikes;
029 import jsx.dom.Markups;
030 import jsx.event.Handle;
031 import jsx.ui.event.OnRender;
032 import jsx.ui.event.Render;
033 
034 /**
035  * <p>A base class for tree widgets.</p>
036  * <p>A {@link Tree} is a {@link Widget} that provides tree-structured UI 
037  * representation of tree-structured data.</p>
038  * <p>A {@link Tree} widget is {@link Configurable} and is also an event source which 
039  * fires {@link Widget.Event} events. It is meanwhile an event listener that handles 
040  * events fired from its underlying component.</p>
041  * 
042  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
043  */
044 public class Tree extends Widget implements OnRender
045 {
046     /**
047      * <p>The default constructor.</p>
048      * <p>This constructor simply invokes the default constructor of this class.</p>
049      * @since 1.0
050      */
051     public Tree() {
052         super(new Component(Markups.UL));
053         addClasses();
054         ini(this).var(ITEMS, new Vars<Component>().var());
055         unwrap().addListener(Render.class, this);
056     }
057 
058     private final static Id<ArrayLike<Component>> ITEMS = new Id<ArrayLike<Component>>();
059     private final static Id<Tree> SUBTREE = new Id<Tree>();
060 
061     /**
062      * <p>Appends the given HTML text as a tree node.</p>
063      * @param node The HTML text for the new node.
064      * @return The new node of component.
065      * @since 1.0
066      */
067     public Component add(String node) {
068         Component item = new Component(Template.apply(
069                 Template.LI,
070                 node
071         ));
072         ArrayLikes.push(ini(this).var(ITEMS), item);
073         Component.addClasses(item, subs("item"));
074         return item;
075     }
076 
077     /**
078      * <p>Appends the given HTML text as a tree node with a given sub tree.</p>
079      * @param node The HTML text for the new node.
080      * @param sub The sub tree attached to the new node.
081      * @return The new node of component.
082      * @since 1.0
083      */
084     public Component add(String node, Tree sub) {
085         Component item = add(node).unwrap();
086         Component.addClasses(item, subs("node"));
087         ini(item).var(SUBTREE, sub);
088         return item;
089     }
090 
091     /**
092      * <p>Performs an action on the dispatched event.</p>
093      * <p>This method sets up mouse event handlers for the underlying HTML element on the 
094      * browser level.</p>
095      * @param evt The event dispatched to this listener.
096      * @since 1.0
097      */
098     public void onEvent(Render evt) {
099         ArrayLike<Component> items = ini(this).var(ITEMS);
100         for (int i = 0, len = ArrayLikes.length(items); i < len; i++) {
101             Component item = items.get(i);
102             Component.appendChild(unwrap(), item);
103             item.handle("click", Handle.CANCELBUBBLE.var());
104             Tree sub = ini(item).var(SUBTREE);
105             if (Js.be(sub)) {
106                 Component subc = sub.unwrap();
107                 Component.appendChild(item, subc);
108                 item.pseudo(COLLAPSE, "collapse").toggle(item, "click");
109                 subc.pseudo(COLLAPSE, "collapse").toggle(item, "click");
110             }
111         }
112     }
113 }