## Dojo Tree

### Introduction

This documentation refers to new TreeV3, not to stable Tree widget. Many classes have V3 on the end for TreeV3, but that suffix can be omitted, because it will be removed in dojo 0.5.

Basic things are shown in tests (dojo/tests/widget/treeV3), so you might want to check them first and copy-paste exactly the things you need. The tutorial is meant to provide deeper understanding for those who want to extend/modify tree behavior.

This is just a draft, quite incomplete, but I'd be grateful for your replies.

The contacts are

- IRC: Freenode, #dojo by nick [algo]
- ICQ: 820317
- Dojo mailing lists: "Ilia Kantor" ilia @ dojotoolkit.org

### What's new in TreeV3

#### New HTML/CSS structure

##### Nested divs

Previous tree used a list of divs, each of them was indented with grid and spacers to right level. The new tree uses natural nested divs structure (children' divs inside parent's div). Grid is contigous and structure is displayed correctly for any node/font size

##### All design in CSS through classes and class combinations

All image and size information was removed from JS code. There is a bunch of classes applied to nodes, that may denote node folder state, node type, show if there are children, etc. CSS moves this logical classes into style

##### Different trees be styled with different CSS class families

Want to put 2 differently styled trees on a page? Give them different classPrefix.

##### Multiline content support

Rich content support was incomplete, because list-of-divs model could not handle arbitrary-sized nodes. Now you may have <br>, <p> and any other width/height modifiers.

#### Event system modified

`nodeDOMCreated` event was removed. That's because listeners are bound to tree and may want to modify the new node, but that's only possible when the node is being bound to the tree, not when it was created and hanging around. `afterTreeChange` was introduced to help listeners to (un)bind nodes the right moment

All events were renamed to better reflect the moment of their publishing

`afterExpand`, `afterCollapse` events now fire when the animation (e.g fading in or out) finishes, not when the actual expand/collapse is called.

#### Lazy widget creation

Before TreeV3, all nodes must be widgets. A node is added - hence graphical widget is created. For performance reasons that behavior was altered. Now when you add a node, you may actually add a "data object", containing node data, e.g {title:"new node"}. You may want to add a large nested branch of such data objects, like {title:"new", children:[...data objects..]}.

Data objects will become real members of children array (you may recursively search them, modify etc), but graphical widgets will be created only when visitor expands them.

The compatibility drawback of such behavior is that old code may erroneously call *widget* methods on *data objects* while recursively traversing a tree, e.g with Widget#getDescendants. You should change such code to use TreeCommon#processDescendants, or handle data objects in special way.

There are no special mechanisms to add laziliy instantiated "data objects". You may manipulate them simply modifying `children` array, but no events are thrown until a real widget appears on the scene. In most cases that is fine, but you are free to "disable" lazy widget creation - do not modify `children` directly and enable `tree.eagerWidgetInstantiation`

#### Tree extensions

Many features were moved from core into extensions

- Added TreeDocIconExtension instead of builtin childIcon support
- Selector now only throws events, not doing anything with nodes
- Out-of-the box extensions introduced to be examples and handle well-known requirements

#### Implicit helpers removed

The Tree is actually a pack of loosely coupled components, connected through events. To keep things simple and also for compatibility reasons, such components(controller,selector...) were created implicitly, if not declared. But actually this proved to be a source of questions and misunderstandings. So now nothing is created implicitly, read how-to and declare things.

#### RPC has both sync/async modes

Old callbacks code was removed in favor to dojo.Deferred. Now all operations may be async and run your callbacks at the end.

#### Drag'n'drop changes

##### Multiple selection and multiple drag'n'drop (incomplete)

Sounds simple enough.. Select multiple nodes with ctrl and get them with `selector.selectedNodes`. instead of removed `selectorNode` call.

Currently, multiple drag'n'drop does not work with multiple selection because of dojo bugs. Hopefully will be fixed.

##### Drop of any source, not just tree node

If `treeNode` property is empty, tree will create a new node from the data returned by `source.getTreeNode`, then `source.onDrop` will be called to remove old node.

#### Inline node editing

It became possible to edit nodes inline, using TreeEditor. Base variant uses RichText widget, you can make another wrapper though. Remote calls can be made on save only, or on start/cancel too e.g for locking purposes.

### Features

- Flexible styling
  - All design in CSS through classes and class combinations
  - Different trees be styled with different CSS class families
  - Multiline and rich content support
- Full set of node operations
  - expand/collapse
  - create with JS or markup
  - destroy/move/clone
  - addChild/detach/(de)folderize
  - inline editing
  - multiple selection and drag'n'drop
- Performance
  - batch operations
  - special features
- Lazy loading & RPC features
  - ready to be in-sync with your data
- Rich event system
  - fluently integrates with your app
- Customization
  - change everything through inheritance, events and css
  - out-of-the box extensions
- Tests and demos

### Todo for TreeV3

#### A must, easy to implement

- doClone in RPC should get cloned nodes from server, like createChild

#### Optional enhancements

- Automated unit-testing system based on Selenium
- Optimize all gifs with AGO (advanced gif optimizer) carefully. AGO spoils transparent gifs. It may make single layer LESS than reported image size, that'd lead to background-repeat effect under OS X or Opera.
- Make SortChildren extension to keep nodes sorted
- Make DisableSelection extension to keep node selection
- On Drag'n'drop tree 'wobbles', because node size increases/decreases when it is bordered. Could be nice to evade it, either placing another transparent div with border onto the node or decreasing their size, or using padding divs, or..
- Add checkbox extension. Every node will have checkbox, can save/restore checked state. When parent is checked, all children are marked "grey-checked", user may uncheck grey-checked nodes. grey-checked dependant nodes removed if parent is unchecked. This will require rewrite TreeDocIconExtension ( docIcon -> checkbox ) to allow arbitrary new "thing" left from node.

#### Problems to solve

- Multiple dnd of nodes selected by multiple select work incorrectly. Although all is fine if dragManager uses shift for multiple dnd and TreeSelector uses ctrl. No idea what the reason is.
- Drag'n'drop onDrop errors can't be handled. Need a way to hook on e.g permission denied errors.
- When I expand a large tree and try to move its top (dnd), node starts to move after a pause - a gap in time between I start moving node with my mouse and dragClone appears. Lots of calculations?
- wipe and fade togglers are broken
- can't add subwidgets in title. Seems I need to put them to children, and children property will contain not only subnodes, but also title widgets.. Will need to fix a lot.

### Tree events

There are many classes of events, published with dojo.event.publish mechanism. Every event has a name and message object, containing more precise information about what happened. You may use events to update your data while tree changes, and to perform additional processing of involved objects.

There is a default naming scheme for an event class. E.g for a tree with widgetId='mytree', event of class afterTreeCreate will be named "mytree/afterTreeCreate". You may provide other names in eventNames property of the tree.

#### afterTreeCreate

Event occurs after tree creation is complete. There is an alternative to hook on this action by putting your objects in "listeners" property of the tree. The difference is that listeners are guaranteed to hook before nodes get added, and afterTreeCreate is published after Tree widget is created.

source
  references to tree

#### beforeTreeDestroy

Published right before actual Tree#destroy method is called. Useful for cleanups

source
  references to tree

#### beforeNodeDestroy

Right before TreeNode#destroy is called. Node is detached after this event fired.

source
  references to node

#### afterChangeTree

This event is tightly created with node creation process. It is fired when

- a node is created
- a node moves to another tree widget

oldTree
  references previous tree, null if node has been just created
newTree
  new(current) tree
node
  target node

#### afterSetFolder

Fires when a node obtains "folder" state. That may happen when a first child is added to a leaf, or if a node was initially created with isFolder=true

source
  references to node

#### afterUnsetFolder

Fires when a node obtains looses "folder" state. That may happen when a last child leaves the node, and Tree.unsetFolderOnEmptyis set, or when unsetFolder is called explicitly.

source
  references to node

#### (before|after)Move(From|To)

These events share same arguments and fire when a node is moved. Move process is considered something special. When you move a node, no detach/addChild events get thrown. That allows to tell situations when a node leaves a tree for some time (detached then attached) from situations when a node is simply moved to another location

oldParent
  previous parent
oldTree
  previous tree
oldIndex
  previous index among siblings
newParent
  new parent
newTree
  new tree
newIndex
  new index among siblings
child
  target node

#### afterAddChild

Published when a node is attached to parent. This may happen at the end of creation process, or when a node is lazily instantiated from data object.

child
  references to node
index
  index among siblings
parent
  current parent who adopted a child
childWidgetCreated
  flag is set if child was laziliy instantiated. That is: it resided as data object in children array, but user expanded its parent, so node widget came to life.

#### afterDetach

Occurs when a node is detached. This may happen in the process of node destruction.

child
  references to node
parent
  references to old parent
index
  references to index among children of old parent

#### after(Expand|Collapse)

Fire when a node is expanded/collapsed. Some togglers do nice animation hiding/showing node. This event fires when animation finishes.

source
  target node

#### afterSetTitle

When a node is edited, or explicit setTitle method is called, this event helps to inform interested parts about changes.

source
  target node
title
  new node title

### Performance

Tree was coded with performance in mind. Although, JavaScript itself is a slow language. Flexible model requires some code that slows it down. It's not DOM manipulations, but actually javascript that I couldn't make lighter. Being a part of dojo/widget structure also implies some overhead, but also power.

Almost all operations require small constant time when single node is involved. Depending on your application you may notice slowdown when (most common) creating lots of nodes or performing other batch operations.

In my tests 1000 nodes required 0.7-0.8 sec, growth is linear, depth does not matter, children are created with `createSimple` and added to parent all at once with `setChildren`.

Creation from markup or with standard create/addChild routines is 2-3 times slower, because these routines are generic.

Memory footprint (IE,FF) is about 1M per 100 nodes

#### Comparison

Fast node creation with dojo tree is 2-3 times slower than xtree 1.7, another tree widget, not so featured, but nicely optimized for performance.

### Important

The results described here refer to operations without any lazy features involved. Most of time you will use lazy creation or lazy loading, or both, and operate with 10000 "virtual" nodes with ease.

### Performance tricks

When talking about performance, one should understand, that there are single-node operations that operate on single node... These ones are fast. The examples are: create a node, delete a node, move a node along the tree.

... And there are batch operations that touch a lot of nodes. The examples are: initial tree creation, moving a node from one tree to another which has different listeners, etc.

That performance issues become noticeable at 100-300 tree nodes depending on your trees. All algorithms are linear in worst case, but JS is slow language, DOM is also not that fast.

There is a number of features one could use to get a speedup.

#### Lazy loading

A node can be created with `isFolder=true` flag, but without children. Any node has a `state`, initially UNCHECKED for empty folder, and used by TreeLoadingController.

When a user presses expand, tree controller (supporting lazy loading) will send a request to server asking for nodes, and parse the answer creating children.

The benefit is obvious: you don't have to load/process whole tree at once. You can only load a single node and user will load the rest clicking "expand"

#### Lazy creation

Node/tree keeps array of its children in `children` property. Lazy creation is somewhat a half-way approach to lazy loading. It allows you to put data objects into this array and tree will create widgets of them later, when they are expanded.

For instance, one can call `node.children = [{title:'node1'},{title:'node2'}]`. The objects will be set, but no widgets are created. You can also set children to nested array: `node.children = [{title:'node1', children:[{title:'node2'}] }]`.

You can create tree on server, JSON-serialize it and put to HTML, that is gzip-compressed. Compression will be 6 times or more, so it is not that space hungry.

The benefit comes from postponing almost all real job: widget creation and attaching it to tree will happen in expansion-time.

##### Comparison between lazy creation and lazy loading

- You need web-service for lazy loading, not for lazy creation
- No network waits for lazy creation
- Lazy creation gives you the tree right here. You can search data objects and modify them without spending time and memory on graphical widgets

Sometimes, lazy creation and loading may work together nicely, providing seamless increase in speed and decrease in memory footprint. For instance, server may pass a whole tree branch in JSON to lazy loading controller. Top nodes will be created right along, because user needs them, but the rest of the branch will be postponed relying on lazy creation feature.

There are operations, like "expandAll" where such lazy tricks don't help, because all graphical widgets must be processed. That is why widget creation process is well-optimized itself. `createSimple` is a hacky program-only way to create TreeNodes fast. `setChildren` is a method to assign (and create if needed) all children at once. It helps to evade some extra work happening when children are added one by one.

#### IE image-reloading fixup (!!!)

IE has a well-known bug. If an image was loaded dynamically - with a `new Image()`, or `img.src=` assignment, or even as a background of a new node, it will not be cached. So every time when you create a node, all needed icons get loaded from server (or requested at least). A possible solution is to put a special div into HTML (adjust src to your path):

<div style="display:none">
<!-- IE has a bug: it reloads all dynamically resolved images, no matter, is it
new Image() or CSS background. If you don't specify images like that,
it will reload them every time a new node is created -->
<img src="../../../src/widget/templates/images/TreeV3/i.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/i_half.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/expand_minus.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/expand_plus.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/expand_leaf.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/i_long.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/document.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/open.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/closed.gif"/>
</div>

### Components

Tree
  Tree and TreeNode classes handle both data and view
Controllers
  TreeBasicController
    Controller that provides all capabilities but no server calls
  TreeLoadingController
    Added dynamic node loading from server
  TreeRPCController
    All actions call server
Selector
  TreeSelector handles node selection. Currently, only single node can be selected
Drag'n'Drop
  TreeDragSource, TreeDropTarget and TreeDNDController are classes that allow nodes to be dragged, to be dropped on and mechanism binding that together. Sources are located under src/dnd folder, not among widgets.
Context menu
  TreeContextMenu inherits dojo context menu to provide a lightweight right-click menu. There is a single menu object for all nodes, although it always knows its target
Style & icons
  Tree.css and icons are located under src/widget/templates and provide basic style used by default.
Extensions
  TreeControllerExtension contains additional functions for controller that you might need

### Lazy loading

#### How to load *not* TreeNodes ?

Every data object you send is created with Tree#createNode call.

You want to pass a special object, specify widgetName in widgetName property of your object.

Another option is to change `defaultChildWidget` property of the tree. Helpful in case when you have your own widgets and use them elsewhere instead of TreeNode

### Extensions

Extensions are also called plugins, they can be hooked onto widgets in various combinations and provide wanted options.

Currently there is a couple of extensions

TreeDisableWrapExtension
  Tree extension, disables wrapping for tree nodes. Also it fixes IE bug when an 'unwrappable' node (e.g single word) will move to next line if no space left.
TreeDocIconExtension
  Tree extension, places icon to the left of a node, depening on nodeType property
TreeEmphasizeOnSelect
  Selector extension, highlights currently selected nodes
TreeDeselectOnDblselect
  Selector extension, deselects a selected node when it is clicked. Usually, one should ctrl-click, or click another node.
TreeLinkExtension
  Tree extension, turns labels into links, merges object property into <a> tag

### Node creation

There are few code paths that lead to same purpose: to create a tree node. They differ in effeciency and use patterns

#### Markup creation

You specity a tree and its nodes in HTML, relying upon dojo to parse it and turn into widgets. That is a slowest way, but nice for small trees or if only tree top is specified and the rest is created later.

dojo widget parser walks DOM and creates a special structure. The next pass creates widgets from the structure.

##### widget.create

The generic widget creation routine. It basically runs the operations in order:

1. Mix in widget properties from parameters/markup
2. Register widget in widget.Manager
3. Call `buildRendering` to make fill template and create domNode
4. Call `initialize`
5. Call `postInitialize`. registers widget as a child of its parent and after it creates all subwidgets
6. Call `postCreate`

Note that `initialize` is called in pre-order: parent is initialized before children, `postInitialize` is called in post-order: a child is postCreated before its parent.

#### Manual creation

If you create nodes with javascript, then you run create calls manyally. So parents are naturally created (and postCreated) before children

There seem to be no good way to distinguish betwen markup creation and manual creation. From the one hand its seems good, because allows reuse of generic creation code. From the other hand code paths going through this code are subtly different.

The reliable thing is that `initialize` will process widget after its domNode is built, BUT it should not assume anything about children.

nodeCreate event is fired on initialization also. If you want to know anything about children and do something at this point - check addChild, but not node creation.

#### Input parameters

`children` array may be

- empty
- contain widgets, e.g if created from markup, or someone created them before parent and pushed in
- contain data objects, that will be turned into widgets when parent expands.

`isFolder` comes into play only when there are no children. It allows creation of empty folders, with UNCHECKED state that can be filled later.

### Faq

#### How to make tree unselectable?

To make tree (or its elements) unselectable use dojo.html.disableSelection in nodeCreate and treeCreate hooks. Apply disableSelection to every node you want to make unselectable.

#### How to bind an object to tree node?

There is an "objectId" property and "object" property ready to be filled in from markup or program-way.

#### How to walk all node descendants ?

You may use `dojo.lang.forEach(nodeOrTree.getDescendants(),function(elem) { ... })` to process all descendants, it will walk `children` property recursively.

The safer way would be to call `TreeCommon.prototype.processDescendants(nodeOrTree, filter, func)`, it will process all children with `func`, but will not descend into nodes if `filter(node)` returns false. E.g see `collapseAll` controller method uses it to collapse all widgets, but skip non-folders and data objects.

#### How to evade a situation where all nodes are (re)moved and tree is empty without a way to add new child (no nodes) ?

Make a single root node with actionsDisabled="DETACH;MOVE". User will be unable to remove it, so interface will stay sane.

#### How to make pages open when a user clicks on node?

There are 2 ways. The first one is to attach TreeSelector and hook on "select" event. So when a user clicks, event handler will change url to node.object.href. Of course, you should fill hrefs.

A probably more convinient path would be to employ TreeLinkExtension, which will turn your labelNodes into real links, and apply attrbutes from node object to them.

#### I open very large tree. But navigation away to another page from the tree takes time. What's up?

Dojo performs actions not only when a node is created, but also cleanup when a node is destroyed. Lazy features allow node creation be distributed in time, but when you navigate away from a large tree, cleanup need some time. I don't know a way to evade that.

#### How to add icons to nodes ?

TreeDocIconExtension handles that. You should declare nodeType for your nodes, so they'll get nodeIcon[Your type] CSS class. Default type is Document for leaves and Folder for folders.

### Contributors

Thanks to all dojo contributors, Tree widgets wouldn't be possible without such a nice background.

Also, there are people who contributed their skills to make Tree widget better.

- Ilia Kantor
- Slava Ivanyuk
- Nachoman

In case if someone is left out, message me, please.