分享

TreeV3等相关导航widget介绍

 tinaroad 2007-05-08

TreeV3等相关导航widget介绍

1.       TreeV3 & TreeNodeV3

l         简介

TreeV3TreeNodeV3分别是原有widgetV3版本,其较大地提高了原版本的操作效率及性能。所以在navigation系列的widget中,如果有带V3后缀的版本,应当使用该版本。TreeV3可以看做移个不可见的rootnode,扮演TreeContainer的功能。

l         如何在网页中创建一个TreeV3 widget

有两种方法在一个页面中创建一个TreeV3:

使用makeup标签:

使用编程创建:在页面中的javascript代码中使用dojo.widget.createWidget()方法:

var tree = dojo.widget.createWidget("TreeV3", {listeners:[controller.widgetId]}); 

var rootNode = dojo.widget.createWidget("TreeNodeV3", {title: "TreeRoot” });

tree.addChild(rootNode);

var node1 = dojo.widget.createWidget("TreeNodeV3", {title: "TreeNode1"});

rootNode.addChild(node1);

var node2 = dojo.widget.createWidget("TreeNodeV3", {title: "TreeNode2"});

rootNode.addChild(node1);

 

 

l         加载过程

当页面中包含了一个TreeV3 widget时,在页面加载时该TreeV3constructor()initialize()方法会一次被调用,从而创建一个TreeV3对象,并初始化其Template,如果该tree包含了多个节点,则接下来会多次调用onAfterChangeTree(), 并最后调用onAfterTreeCreate()

l         一些实用成员变量及方法介绍

addChild()用于为树或者Node节点添加子节点。

TreeV3:

templateCssPath, templateString, makeNodeTemplate(),: 用于设置TreeV3 widget所用模板文件的路径及名称。

isExpanded, DndMode, createNode( data), makeContainerNodeTemplate(), move( child, newParent, index)

TreeNodeV3:

labelClass, contentClass, expandClass: 各种样式类型;

expandNode, labelNode, nodeDocType, isTreeNode, title, isFolder, addedTo( parent, index, dontPublishEvent), collapse(), destroy(), expand(), setTitle( title)

从名字即可看出功用,略之,稍后用到再解释。

另外可以查看源代码中的eventNamesDefault数组,其定义了treev3可以抛出的events

2.       TreeSelectorV3

l         简介

主要用于在其监听的tree上发生了click等事件时,对该click事件的不同情况进行分类处理,并使用publish抛出该select/deselect事件,而对treenode本身不做任何的操作。

l         加载过程

默认情况下,在TreeSelectorV3.js中通过

定义了该selector监听"afterTreeCreate", "afterCollapse", "afterChangeTree",  "afterDetach",  "beforeTreeDestroy"五个事件。例如:当其监听的tree创建后,该tree抛出afterTreeCreate事件,被TreeSelectorV3捕获,并调用onAfterTreeCreate()方法,该方法将tree.domnodeclick等事件与TreeSelectorV3onTreeClick()方法绑定。

l         TreeClick事件处理过程:

在其监听的treenode上发生了click事件时,对该click事件的不同情况进行相应的select/deselect操作,并使用publish抛出该select/deselect事件,而对treenode不做任何的操作。所谓的不同onTreeClick事件可分为:

1)        无效点击:点击处不在任何node或其图标上,此时不做任何处理。

2)        点击上次点击的nodeonTreeClick()— processNode()— checkSpecialEvent()--   checkRecentClick()— setLastClicked().

3)        点击不同的node时:onTreeClick()— processNode()— deselectIfNoMulti()-- checkSpecialEvent()--  deselectAll()—deselect()—setLastClicked()—select()

4)        双击一个node时:随浏览器不同而略有不同,可查看源码,略之。

l         Select函数:

select: function(node) {

var index = dojo.lang.find(this.selectedNodes, node, true);    if (index >=0 ) {

           return; // if the node already selected, return;

       }

       this.selectedNodes.push(node); // else push the selected node

       dojo.event.topic.publish(this.eventNames.select, {node: node} );   // publish the eventNames:select event

    },

 

l         Deselect函数:

deselect: function(node){

   var index = dojo.lang.find(this.selectedNodes, node, true);

   if (index < 0) {

       return; // not selected

   }

   this.selectedNodes.splice(index, 1); //deselect the node

    dojo.event.topic.publish(this.eventNames.deselect,{node: node});

          //publish the eventNames:deselect event;

   },

 

3.       TreeBasicControllerV3

l         简介

对于Tree,不加controller,即可实现expand/collapse功能,但是我想是为了更好地贯彻MVC结构(参见摘自dojobook第四章的Tree over structure节),在TreeV3版本中,将这些的control功能从TreeV3(model)中移除,使用controller来实现。

用于TreeV3Controller主要有三个,其继承关系为TreeBasicController -> TreeLoadingController -> TreeRpcController,他们主要用于对tree进行逻辑控制及定制(树或节点知道该怎样改变及显示其自身,但是对于树及其节点的操作往往还涉及到更高层次的逻辑问题,如expand/collapse以及各节点的包含关系的变动等等,这些就需要controller来控制,这可能跟tree的实现机制有关,它的节点数据都是保存在一个children[]数组中)。而tree并不知道这些controller的存在,这也体现了MVC的设计思想。

我主要研究了TreeBasicController,其他两个较其实现了远程调用的相关功能。

l         加载过程:

TreeSelectorV3类似,在TreeBasicControllerV3.js中通过:

listenTreeEvents: ["afterSetFolder", "afterTreeCreate", "beforeTreeDestroy"],

 

定义了该controller默认监听的事件,developer可以通过自行添加。

在其controltree创建后,其onAfterSetFolder()onAfterTreeCreate()方法会依次被调用来设置树的展开层次及将自身的方法与tree.domnode点击等事件绑定

l         主要成员变量及方法:

listenTreeEvents:设置该controller监听的事件,默认监听"afterSetFolder", "afterTreeCreate", "beforeTreeDestroy"三个事件,可自行添加;

editor, batchExpandTimeoutexpandAll( nodeOrTree)expandToLevel( nodeOrTree, level)expand( node)move( child, newParent, ,... index)onAfterSetFolder( message) collapse( node)等等。

l         onTreeClick

tree被点击时,会出发controlleronTreeClick()方法,一下为处理流程:

l         Expand过程:上图中的expand方法会调用被clicknodeexpand方法(在TreeNodeV3.js中定义),而node.expand()通过调用viewSetExpand()对该node节点的显示样式进行设置(使用dojo.html.setClass…,…)方法),然后使用this. showChildren()对展开后的子节点进行显示。

l         Collapse过程:Expand过程有对应关系,略之。

l         _focusLabel(): 私有方法,用于将节点设置为焦点样式。

4.       Extentions

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

l         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.

l         TreeDocIconExtension

Tree extension, places icon to the left of a node, depening on nodeType property

l         TreeEmphaseOnSelect

Selector extension, highlights currently selected nodes

l         TreeDeselectOnDblselect

Selector extension, deselects a selected node when it is clicked. Usually, one should ctrl-click, or click another node.

l         TreeLinkExtension

Tree extension, turns labels into links, merges object property into tag

 

5.       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.

l         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

l         beforeTreeDestroy

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

source

references to tree

l         beforeNodeDestroy

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

source

references to node

l         afterChangeTree

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

Ø         a node is created

ü         no parent at this stage

Ø         fires in initialize(), so children may be not added yet

ü         a node was moved to another tree widget

oldTree

references previous tree, null if node has been just created

newTree

new(current) tree

node

target node

l         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

l         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

l         (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

l         afterAddChild

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

Also it occurs when a detached node gets attached.

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.

l         afterDetach

Occurs when a node is detached. This may happen in the process of node destruction. Keep in mind, that detaching a node sets its parent to null, but
tree remains same.

child

references to node

parent

references to old parent

index

references to index among children of old parent

l         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

l         afterSetTitle

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

source

target node

oldTitle

replaced node title

6.       Tips

l         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.

l         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.

l         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.

Also, you may want to set actionsDisabled="ADDCHILD" to tree itself, so now children can be added besides the root.

l         How to create a custom tree node ?

First, of course, you may explicitly use createSimple for your widget and declare your widgetType in markup.

But sometimes, tree has to create a node from data object or just from "nothing", e.g in case of createAndEdit.

Then it checks for widgetName property of data object (can be namespaced), and if no widgetName, then tree.defaultChildWidget property should contain node class, e.g mycustom.tree.Node.

Usually, when you override a node, all you need is to adjust defaultChildWidget,

because widgetName uses generic create and hence works slower right now.

l         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.

l         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, large cleanup causes visible delay. I don‘t know a way to evade that.

l         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.
There is also setNodeTypeClass method to update node CSS when its nodeType changes e.g programmatically.

7.       Tree Overall Structure

Sat, 10/07/2006 - 18:26 — ilia

Note: most classes here omitt ‘V3‘ suffix

l         Model + View

The tree itself is a TreeV3 class instance. Hierarchy is maintained in a standard widgety way: through children[] array. Children are usually TreeNodeV3 instances, but you could use your own(overriding?) implementation of course.

TreeV3 instance also represents an ‘invisible root‘ node, so it shares common methods with TreeNodeV3. These methods reside in TreeWithNode mixin.

Model contains data and manipulation methods like "addChild", "detach" .. etc. It also publishes events when modified.

DOM-structure and view is also merged into model.

Various functionality can be hooked on model‘s events: controller, menu, drag‘n‘drop etc.

Model events should help you to integrate tree with application on data-level, so you hook on actual data changes, not the cause (program call, user click etc).

l         Controller

Main controllers are TreeBasicController -> TreeLoadingController -> TreeRpcController

Basically, they are responsible for operating on model and performing most logic, besides model‘s action. It also makes checks / remote calls.

Usually, one should work with controller only and let it process model.

TreeLoadingController and TreeRpcController are known to perform remote calls to server. They use dojo.Deferred and dojo.DeferredList for that purpose.

Most customizations are also about controller.

And, by the way, model has no idea about its controller... It throws events and delivers API to call, that‘s all.

8.   Others

l         Several relating CSS file: treeV3.css which define the css class of the tree and it’s node in different states. Another css file TreeDocIcon.css has define the css class of the icon of tree and nodes. You can modify or add some css class according to needed.

l         Note: Part 1-3 of this document is written by myself base on my program testing (on the firefox browser), while part 4-7 is mainly copied from dojobook.

l         Example project:

This is the dojoTreeV3 demo which has implement such functions as follow:

                         i.              A treeV3 widget can be used to navigate these info displayed in the right-bottom pane.

                        ii.              As to the tree, its nodes can be added/deleted  and expandedToAll with the buttons in the right-top toolbar.

                      iii.              The treeNodes would be emphesized when clicked and expanded/collapsed when double clicked.

                      iv.              Icons and label’s color of nodes will change dynamically with the state of the tree.

 

Some functions are achieved by modify the TreeBasicControllerV3.js and I’ll manage later to implement them in a more reasonable approach as reride the controller by inheriting it.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多