Page Menu
Home
Code
Search
Configure Global Search
Log In
Files
F884428
Tree.js
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
27 KB
Subscribers
None
Tree.js
View Options
if
(
!
dojo
.
_hasResource
[
"dijit.Tree"
]){
//_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo
.
_hasResource
[
"dijit.Tree"
]
=
true
;
dojo
.
provide
(
"dijit.Tree"
);
dojo
.
require
(
"dojo.fx"
);
dojo
.
require
(
"dijit._Widget"
);
dojo
.
require
(
"dijit._Templated"
);
dojo
.
require
(
"dijit._Container"
);
dojo
.
require
(
"dojo.cookie"
);
dojo
.
declare
(
"dijit._TreeNode"
,
[
dijit
.
_Widget
,
dijit
.
_Templated
,
dijit
.
_Container
,
dijit
.
_Contained
],
{
// summary
// Single node within a tree
// item: dojo.data.Item
// the dojo.data entry this tree represents
item
:
null
,
isTreeNode
:
true
,
// label: String
// Text of this tree node
label
:
""
,
isExpandable
:
null
,
// show expando node
isExpanded
:
false
,
// state: String
// dynamic loading-related stuff.
// When an empty folder node appears, it is "UNCHECKED" first,
// then after dojo.data query it becomes "LOADING" and, finally "LOADED"
state
:
"UNCHECKED"
,
templateString
:
"<div class=\"dijitTreeNode dijitTreeExpandLeaf dijitTreeChildrenNo\" waiRole=\"presentation\"\n\t><span dojoAttachPoint=\"expandoNode\" class=\"dijitTreeExpando\" waiRole=\"presentation\"\n\t></span\n\t><span dojoAttachPoint=\"expandoNodeText\" class=\"dijitExpandoText\" waiRole=\"presentation\"\n\t></span\n\t>\n\t<div dojoAttachPoint=\"contentNode\" class=\"dijitTreeContent\" waiRole=\"presentation\">\n\t\t<div dojoAttachPoint=\"iconNode\" class=\"dijitInline dijitTreeIcon\" waiRole=\"presentation\"></div>\n\t\t<span dojoAttachPoint=\"labelNode\" class=\"dijitTreeLabel\" wairole=\"treeitem\" tabindex=\"-1\"></span>\n\t</div>\n</div>\n"
,
postCreate
:
function
(){
// set label, escaping special characters
this
.
setLabelNode
(
this
.
label
);
// set expand icon for leaf
this
.
_setExpando
();
// set icon and label class based on item
this
.
_updateItemClasses
(
this
.
item
);
if
(
this
.
isExpandable
){
dijit
.
setWaiState
(
this
.
labelNode
,
"expanded"
,
this
.
isExpanded
);
}
},
markProcessing
:
function
(){
// summary: visually denote that tree is loading data, etc.
this
.
state
=
"LOADING"
;
this
.
_setExpando
(
true
);
},
unmarkProcessing
:
function
(){
// summary: clear markup from markProcessing() call
this
.
_setExpando
(
false
);
},
_updateItemClasses
:
function
(
item
){
// summary: set appropriate CSS classes for item (used to allow for item updates to change respective CSS)
this
.
iconNode
.
className
=
"dijitInline dijitTreeIcon "
+
this
.
tree
.
getIconClass
(
item
);
this
.
labelNode
.
className
=
"dijitTreeLabel "
+
this
.
tree
.
getLabelClass
(
item
);
},
_updateLayout
:
function
(){
// summary: set appropriate CSS classes for this.domNode
var
parent
=
this
.
getParent
();
if
(
parent
&&
parent
.
isTree
&&
parent
.
_hideRoot
){
/* if we are hiding the root node then make every first level child look like a root node */
dojo
.
addClass
(
this
.
domNode
,
"dijitTreeIsRoot"
);
}
else
{
dojo
.
toggleClass
(
this
.
domNode
,
"dijitTreeIsLast"
,
!
this
.
getNextSibling
());
}
},
_setExpando
:
function
(
/*Boolean*/
processing
){
// summary: set the right image for the expando node
// apply the appropriate class to the expando node
var
styles
=
[
"dijitTreeExpandoLoading"
,
"dijitTreeExpandoOpened"
,
"dijitTreeExpandoClosed"
,
"dijitTreeExpandoLeaf"
];
var
idx
=
processing
?
0
:
(
this
.
isExpandable
?
(
this
.
isExpanded
?
1
:
2
)
:
3
);
dojo
.
forEach
(
styles
,
function
(
s
){
dojo
.
removeClass
(
this
.
expandoNode
,
s
);
},
this
);
dojo
.
addClass
(
this
.
expandoNode
,
styles
[
idx
]);
// provide a non-image based indicator for images-off mode
this
.
expandoNodeText
.
innerHTML
=
processing
?
"*"
:
(
this
.
isExpandable
?
(
this
.
isExpanded
?
"-"
:
"+"
)
:
"*"
);
},
expand
:
function
(){
// summary: show my children
if
(
this
.
isExpanded
){
return
;
}
// cancel in progress collapse operation
if
(
this
.
_wipeOut
.
status
()
==
"playing"
){
this
.
_wipeOut
.
stop
();
}
this
.
isExpanded
=
true
;
dijit
.
setWaiState
(
this
.
labelNode
,
"expanded"
,
"true"
);
dijit
.
setWaiRole
(
this
.
containerNode
,
"group"
);
this
.
_setExpando
();
this
.
_wipeIn
.
play
();
},
collapse
:
function
(){
if
(
!
this
.
isExpanded
){
return
;
}
// cancel in progress expand operation
if
(
this
.
_wipeIn
.
status
()
==
"playing"
){
this
.
_wipeIn
.
stop
();
}
this
.
isExpanded
=
false
;
dijit
.
setWaiState
(
this
.
labelNode
,
"expanded"
,
"false"
);
this
.
_setExpando
();
this
.
_wipeOut
.
play
();
},
setLabelNode
:
function
(
label
){
this
.
labelNode
.
innerHTML
=
""
;
this
.
labelNode
.
appendChild
(
document
.
createTextNode
(
label
));
},
_setChildren
:
function
(
/* Object[] */
childrenArray
){
// summary:
// Sets the children of this node.
// Sets this.isExpandable based on whether or not there are children
// Takes array of objects like: {label: ...} (_TreeNode options basically)
// See parameters of _TreeNode for details.
this
.
destroyDescendants
();
this
.
state
=
"LOADED"
;
var
nodeMap
=
{};
if
(
childrenArray
&&
childrenArray
.
length
>
0
){
this
.
isExpandable
=
true
;
if
(
!
this
.
containerNode
){
// maybe this node was unfolderized and still has container
this
.
containerNode
=
this
.
tree
.
containerNodeTemplate
.
cloneNode
(
true
);
this
.
domNode
.
appendChild
(
this
.
containerNode
);
}
// Create _TreeNode widget for each specified tree node
dojo
.
forEach
(
childrenArray
,
function
(
childParams
){
var
child
=
new
dijit
.
_TreeNode
(
dojo
.
mixin
({
tree
:
this
.
tree
,
label
:
this
.
tree
.
getLabel
(
childParams
.
item
)
},
childParams
));
this
.
addChild
(
child
);
var
identity
=
this
.
tree
.
store
.
getIdentity
(
childParams
.
item
);
nodeMap
[
identity
]
=
child
;
if
(
this
.
tree
.
persist
){
if
(
this
.
tree
.
_openedItemIds
[
identity
]){
this
.
tree
.
_expandNode
(
child
);
}
}
},
this
);
// note that updateLayout() needs to be called on each child after
// _all_ the children exist
dojo
.
forEach
(
this
.
getChildren
(),
function
(
child
,
idx
){
child
.
_updateLayout
();
});
}
else
{
this
.
isExpandable
=
false
;
}
if
(
this
.
_setExpando
){
// change expando to/form dot or + icon, as appropriate
this
.
_setExpando
(
false
);
}
if
(
this
.
isTree
&&
this
.
_hideRoot
){
// put first child in tab index if one exists.
var
fc
=
this
.
getChildren
()[
0
];
var
tabnode
=
fc
?
fc
.
labelNode
:
this
.
domNode
;
tabnode
.
setAttribute
(
"tabIndex"
,
"0"
);
}
// create animations for showing/hiding the children (if children exist)
if
(
this
.
containerNode
&&
!
this
.
_wipeIn
){
this
.
_wipeIn
=
dojo
.
fx
.
wipeIn
({
node
:
this
.
containerNode
,
duration
:
150
});
this
.
_wipeOut
=
dojo
.
fx
.
wipeOut
({
node
:
this
.
containerNode
,
duration
:
150
});
}
return
nodeMap
;
},
_addChildren
:
function
(
/* object[] */
childrenArray
){
// summary:
// adds the children to this node.
// Takes array of objects like: {label: ...} (_TreeNode options basically)
// See parameters of _TreeNode for details.
var
nodeMap
=
{};
if
(
childrenArray
&&
childrenArray
.
length
>
0
){
dojo
.
forEach
(
childrenArray
,
function
(
childParams
){
var
child
=
new
dijit
.
_TreeNode
(
dojo
.
mixin
({
tree
:
this
.
tree
,
label
:
this
.
tree
.
getLabel
(
childParams
.
item
)
},
childParams
)
);
this
.
addChild
(
child
);
nodeMap
[
this
.
tree
.
store
.
getIdentity
(
childParams
.
item
)]
=
child
;
},
this
);
dojo
.
forEach
(
this
.
getChildren
(),
function
(
child
,
idx
){
child
.
_updateLayout
();
});
}
return
nodeMap
;
},
deleteNode
:
function
(
/* treeNode */
node
){
node
.
destroy
();
var
children
=
this
.
getChildren
();
if
(
children
.
length
==
0
){
this
.
isExpandable
=
false
;
this
.
collapse
();
}
dojo
.
forEach
(
children
,
function
(
child
){
child
.
_updateLayout
();
});
},
makeExpandable
:
function
(){
//summary
// if this node wasn't already showing the expando node,
// turn it into one and call _setExpando()
this
.
isExpandable
=
true
;
this
.
_setExpando
(
false
);
}
});
dojo
.
declare
(
"dijit.Tree"
,
dijit
.
_TreeNode
,
{
// summary
// This widget displays hierarchical data from a store. A query is specified
// to get the "top level children" from a data store, and then those items are
// queried for their children and so on (but lazily, as the user clicks the expand node).
//
// Thus in the default mode of operation this widget is technically a forest, not a tree,
// in that there can be multiple "top level children". However, if you specify label,
// then a special top level node (not corresponding to any item in the datastore) is
// created, to father all the top level children.
// store: String||dojo.data.Store
// The store to get data to display in the tree
store
:
null
,
// query: String
// query to get top level node(s) of tree (ex: {type:'continent'})
query
:
null
,
// childrenAttr: String
// one ore more attributes that holds children of a tree node
childrenAttr
:
[
"children"
],
templateString
:
"<div class=\"dijitTreeContainer\" style=\"\" waiRole=\"tree\"\n\tdojoAttachEvent=\"onclick:_onClick,onkeypress:_onKeyPress\">\n\t<div class=\"dijitTreeNode dijitTreeIsRoot dijitTreeExpandLeaf dijitTreeChildrenNo\" waiRole=\"presentation\"\n\t\tdojoAttachPoint=\"rowNode\"\n\t\t><span dojoAttachPoint=\"expandoNode\" class=\"dijitTreeExpando\" waiRole=\"presentation\"\n\t\t></span\n\t\t><span dojoAttachPoint=\"expandoNodeText\" class=\"dijitExpandoText\" waiRole=\"presentation\"\n\t\t></span\n\t\t>\n\t\t<div dojoAttachPoint=\"contentNode\" class=\"dijitTreeContent\" waiRole=\"presentation\">\n\t\t\t<div dojoAttachPoint=\"iconNode\" class=\"dijitInline dijitTreeIcon\" waiRole=\"presentation\"></div>\n\t\t\t<span dojoAttachPoint=\"labelNode\" class=\"dijitTreeLabel\" wairole=\"treeitem\" tabindex=\"0\"></span>\n\t\t</div>\n\t</div>\n</div>\n"
,
isExpandable
:
true
,
isTree
:
true
,
// persist: Boolean
// enables/disables use of cookies for state saving.
persist
:
true
,
// dndController: String
// class name to use as as the dnd controller
dndController
:
null
,
//parameters to pull off of the tree and pass on to the dndController as its params
dndParams
:
[
"onDndDrop"
,
"itemCreator"
,
"onDndCancel"
,
"checkAcceptance"
,
"checkItemAcceptance"
],
//declare the above items so they can be pulled from the tree's markup
onDndDrop
:
null
,
itemCreator
:
null
,
onDndCancel
:
null
,
checkAcceptance
:
null
,
checkItemAcceptance
:
null
,
_publish
:
function
(
/*String*/
topicName
,
/*Object*/
message
){
// summary:
// Publish a message for this widget/topic
dojo
.
publish
(
this
.
id
,
[
dojo
.
mixin
({
tree
:
this
,
event
:
topicName
},
message
||
{})]);
},
postMixInProperties
:
function
(){
this
.
tree
=
this
;
this
.
lastFocused
=
this
.
labelNode
;
this
.
_itemNodeMap
=
{};
this
.
_hideRoot
=
!
this
.
label
;
if
(
!
this
.
store
.
getFeatures
()[
'dojo.data.api.Identity'
]){
throw
new
Error
(
"dijit.tree requires access to a store supporting the dojo.data Identity api"
);
}
if
(
!
this
.
cookieName
){
this
.
cookieName
=
this
.
id
+
"SaveStateCookie"
;
}
// if the store supports Notification, subscribe to the notification events
if
(
this
.
store
.
getFeatures
()[
'dojo.data.api.Notification'
]){
this
.
connect
(
this
.
store
,
"onNew"
,
"_onNewItem"
);
this
.
connect
(
this
.
store
,
"onDelete"
,
"_onDeleteItem"
);
this
.
connect
(
this
.
store
,
"onSet"
,
"_onSetItem"
);
}
},
postCreate
:
function
(){
// load in which nodes should be opened automatically
if
(
this
.
persist
){
var
cookie
=
dojo
.
cookie
(
this
.
cookieName
);
this
.
_openedItemIds
=
{};
if
(
cookie
){
dojo
.
forEach
(
cookie
.
split
(
','
),
function
(
item
){
this
.
_openedItemIds
[
item
]
=
true
;
},
this
);
}
}
// make template for container node (we will clone this and insert it into
// any nodes that have children)
var
div
=
document
.
createElement
(
'div'
);
div
.
style
.
display
=
'none'
;
div
.
className
=
"dijitTreeContainer"
;
dijit
.
setWaiRole
(
div
,
"presentation"
);
this
.
containerNodeTemplate
=
div
;
if
(
this
.
_hideRoot
){
this
.
rowNode
.
style
.
display
=
"none"
;
}
this
.
inherited
(
"postCreate"
,
arguments
);
// load top level children
this
.
_expandNode
(
this
);
if
(
this
.
dndController
){
if
(
dojo
.
isString
(
this
.
dndController
)){
this
.
dndController
=
dojo
.
getObject
(
this
.
dndController
);
}
var
params
=
{};
for
(
var
i
=
0
;
i
<
this
.
dndParams
.
length
;
i
++
){
if
(
this
[
this
.
dndParams
[
i
]]){
params
[
this
.
dndParams
[
i
]]
=
this
[
this
.
dndParams
[
i
]];
}
}
this
.
dndController
=
new
this
.
dndController
(
this
,
params
);
}
this
.
connect
(
this
.
domNode
,
dojo
.
isIE
?
"onactivate"
:
"onfocus"
,
"_onTreeFocus"
);
},
////////////// Data store related functions //////////////////////
mayHaveChildren
:
function
(
/*dojo.data.Item*/
item
){
// summary
// User overridable function to tell if an item has or may have children.
// Controls whether or not +/- expando icon is shown.
// (For efficiency reasons we may not want to check if an element has
// children until user clicks the expando node)
return
dojo
.
some
(
this
.
childrenAttr
,
function
(
attr
){
return
this
.
store
.
hasAttribute
(
item
,
attr
);
},
this
);
},
getItemChildren
:
function
(
/*dojo.data.Item*/
parentItem
,
/*function(items)*/
onComplete
){
// summary
// User overridable function that return array of child items of given parent item,
// or if parentItem==null then return top items in tree
var
store
=
this
.
store
;
if
(
parentItem
==
null
){
// get top level nodes
store
.
fetch
({
query
:
this
.
query
,
onComplete
:
onComplete
});
}
else
{
// get children of specified node
var
childItems
=
[];
for
(
var
i
=
0
;
i
<
this
.
childrenAttr
.
length
;
i
++
){
childItems
=
childItems
.
concat
(
store
.
getValues
(
parentItem
,
this
.
childrenAttr
[
i
]));
}
// count how many items need to be loaded
var
_waitCount
=
0
;
dojo
.
forEach
(
childItems
,
function
(
item
){
if
(
!
store
.
isItemLoaded
(
item
)){
_waitCount
++
;
}
});
if
(
_waitCount
==
0
){
// all items are already loaded. proceed..
onComplete
(
childItems
);
}
else
{
// still waiting for some or all of the items to load
function
onItem
(
item
){
if
(
--
_waitCount
==
0
){
// all nodes have been loaded, send them to the tree
onComplete
(
childItems
);
}
}
dojo
.
forEach
(
childItems
,
function
(
item
){
if
(
!
store
.
isItemLoaded
(
item
)){
store
.
loadItem
({
item
:
item
,
onItem
:
onItem
});
}
});
}
}
},
getItemParentIdentity
:
function
(
/*dojo.data.Item*/
item
,
/*Object*/
parentInfo
){
// summary
// User overridable function, to return id of parent (or null if top level).
// It's called with args from dojo.store.onNew
return
this
.
store
.
getIdentity
(
parentInfo
.
item
);
// String
},
getLabel
:
function
(
/*dojo.data.Item*/
item
){
// summary: user overridable function to get the label for a tree node (given the item)
return
this
.
store
.
getLabel
(
item
);
// String
},
getIconClass
:
function
(
/*dojo.data.Item*/
item
){
// summary: user overridable function to return CSS class name to display icon
},
getLabelClass
:
function
(
/*dojo.data.Item*/
item
){
// summary: user overridable function to return CSS class name to display label
},
_onLoadAllItems
:
function
(
/*_TreeNode*/
node
,
/*dojo.data.Item[]*/
items
){
// sumary: callback when all the children of a given node have been loaded
var
childParams
=
dojo
.
map
(
items
,
function
(
item
){
return
{
item
:
item
,
isExpandable
:
this
.
mayHaveChildren
(
item
)
};
},
this
);
dojo
.
mixin
(
this
.
_itemNodeMap
,
node
.
_setChildren
(
childParams
));
this
.
_expandNode
(
node
);
},
/////////// Keyboard and Mouse handlers ////////////////////
_onKeyPress
:
function
(
/*Event*/
e
){
// summary: translates keypress events into commands for the controller
if
(
e
.
altKey
){
return
;
}
var
treeNode
=
dijit
.
getEnclosingWidget
(
e
.
target
);
if
(
!
treeNode
){
return
;
}
// Note: On IE e.keyCode is not 0 for printables so check e.charCode.
// In dojo charCode is universally 0 for non-printables.
if
(
e
.
charCode
){
// handle printables (letter navigation)
// Check for key navigation.
var
navKey
=
e
.
charCode
;
if
(
!
e
.
altKey
&&
!
e
.
ctrlKey
&&
!
e
.
shiftKey
&&
!
e
.
metaKey
){
navKey
=
(
String
.
fromCharCode
(
navKey
)).
toLowerCase
();
this
.
_onLetterKeyNav
(
{
node
:
treeNode
,
key
:
navKey
}
);
dojo
.
stopEvent
(
e
);
}
}
else
{
// handle non-printables (arrow keys)
var
map
=
this
.
_keyHandlerMap
;
if
(
!
map
){
// setup table mapping keys to events
map
=
{};
map
[
dojo
.
keys
.
ENTER
]
=
"_onEnterKey"
;
map
[
dojo
.
keys
.
LEFT_ARROW
]
=
"_onLeftArrow"
;
map
[
dojo
.
keys
.
RIGHT_ARROW
]
=
"_onRightArrow"
;
map
[
dojo
.
keys
.
UP_ARROW
]
=
"_onUpArrow"
;
map
[
dojo
.
keys
.
DOWN_ARROW
]
=
"_onDownArrow"
;
map
[
dojo
.
keys
.
HOME
]
=
"_onHomeKey"
;
map
[
dojo
.
keys
.
END
]
=
"_onEndKey"
;
this
.
_keyHandlerMap
=
map
;
}
if
(
this
.
_keyHandlerMap
[
e
.
keyCode
]){
this
[
this
.
_keyHandlerMap
[
e
.
keyCode
]](
{
node
:
treeNode
,
item
:
treeNode
.
item
}
);
dojo
.
stopEvent
(
e
);
}
}
},
_onEnterKey
:
function
(
/*Object*/
message
){
this
.
_publish
(
"execute"
,
{
item
:
message
.
item
,
node
:
message
.
node
}
);
this
.
onClick
(
message
.
item
,
message
.
node
);
},
_onDownArrow
:
function
(
/*Object*/
message
){
// summary: down arrow pressed; get next visible node, set focus there
var
returnNode
=
this
.
_navToNextNode
(
message
.
node
);
if
(
returnNode
&&
returnNode
.
isTreeNode
){
returnNode
.
tree
.
focusNode
(
returnNode
);
return
returnNode
;
}
},
_onUpArrow
:
function
(
/*Object*/
message
){
// summary: up arrow pressed; move to previous visible node
var
nodeWidget
=
message
.
node
;
var
returnWidget
=
nodeWidget
;
// if younger siblings
var
previousSibling
=
nodeWidget
.
getPreviousSibling
();
if
(
previousSibling
){
nodeWidget
=
previousSibling
;
// if the previous nodeWidget is expanded, dive in deep
while
(
nodeWidget
.
isExpandable
&&
nodeWidget
.
isExpanded
&&
nodeWidget
.
hasChildren
()){
returnWidget
=
nodeWidget
;
// move to the last child
var
children
=
nodeWidget
.
getChildren
();
nodeWidget
=
children
[
children
.
length
-
1
];
}
}
else
{
// if this is the first child, return the parent
// unless the parent is the root of a tree with a hidden root
var
parent
=
nodeWidget
.
getParent
();
if
(
!
(
this
.
_hideRoot
&&
parent
===
this
)){
nodeWidget
=
parent
;
}
}
if
(
nodeWidget
&&
nodeWidget
.
isTreeNode
){
returnWidget
=
nodeWidget
;
}
if
(
returnWidget
&&
returnWidget
.
isTreeNode
){
returnWidget
.
tree
.
focusNode
(
returnWidget
);
return
returnWidget
;
}
},
_onRightArrow
:
function
(
/*Object*/
message
){
// summary: right arrow pressed; go to child node
var
nodeWidget
=
message
.
node
;
var
returnWidget
=
nodeWidget
;
// if not expanded, expand, else move to 1st child
if
(
nodeWidget
.
isExpandable
&&
!
nodeWidget
.
isExpanded
){
this
.
_expandNode
(
nodeWidget
);
}
else
if
(
nodeWidget
.
hasChildren
()){
nodeWidget
=
nodeWidget
.
getChildren
()[
0
];
}
if
(
nodeWidget
&&
nodeWidget
.
isTreeNode
){
returnWidget
=
nodeWidget
;
}
if
(
returnWidget
&&
returnWidget
.
isTreeNode
){
returnWidget
.
tree
.
focusNode
(
returnWidget
);
return
returnWidget
;
}
},
_onLeftArrow
:
function
(
/*Object*/
message
){
// summary: left arrow pressed; go to parent
var
node
=
message
.
node
;
var
returnWidget
=
node
;
// if not collapsed, collapse, else move to parent
if
(
node
.
isExpandable
&&
node
.
isExpanded
){
this
.
_collapseNode
(
node
);
}
else
{
node
=
node
.
getParent
();
}
if
(
node
&&
node
.
isTreeNode
){
returnWidget
=
node
;
}
if
(
returnWidget
&&
returnWidget
.
isTreeNode
){
returnWidget
.
tree
.
focusNode
(
returnWidget
);
return
returnWidget
;
}
},
_onHomeKey
:
function
(){
// summary: home pressed; get first visible node, set focus there
var
returnNode
=
this
.
_navToRootOrFirstNode
();
if
(
returnNode
){
returnNode
.
tree
.
focusNode
(
returnNode
);
return
returnNode
;
}
},
_onEndKey
:
function
(
/*Object*/
message
){
// summary: end pressed; go to last visible node
var
returnWidget
=
message
.
node
.
tree
;
var
lastChild
=
returnWidget
;
while
(
lastChild
.
isExpanded
){
var
c
=
lastChild
.
getChildren
();
lastChild
=
c
[
c
.
length
-
1
];
if
(
lastChild
.
isTreeNode
){
returnWidget
=
lastChild
;
}
}
if
(
returnWidget
&&
returnWidget
.
isTreeNode
){
returnWidget
.
tree
.
focusNode
(
returnWidget
);
return
returnWidget
;
}
},
_onLetterKeyNav
:
function
(
message
){
// summary: letter key pressed; search for node starting with first char = key
var
node
=
startNode
=
message
.
node
;
var
key
=
message
.
key
;
do
{
node
=
this
.
_navToNextNode
(
node
);
//check for last node, jump to first node if necessary
if
(
!
node
){
node
=
this
.
_navToRootOrFirstNode
();
}
}
while
(
node
!==
startNode
&&
(
node
.
label
.
charAt
(
0
).
toLowerCase
()
!=
key
));
if
(
node
&&
node
.
isTreeNode
){
// no need to set focus if back where we started
if
(
node
!==
startNode
){
node
.
tree
.
focusNode
(
node
);
}
return
node
;
}
},
_onClick
:
function
(
/*Event*/
e
){
// summary: translates click events into commands for the controller to process
var
domElement
=
e
.
target
;
// find node
var
nodeWidget
=
dijit
.
getEnclosingWidget
(
domElement
);
if
(
!
nodeWidget
||
!
nodeWidget
.
isTreeNode
){
return
;
}
if
(
domElement
==
nodeWidget
.
expandoNode
||
domElement
==
nodeWidget
.
expandoNodeText
){
// expando node was clicked
if
(
nodeWidget
.
isExpandable
){
this
.
_onExpandoClick
({
node
:
nodeWidget
});
}
}
else
{
this
.
_publish
(
"execute"
,
{
item
:
nodeWidget
.
item
,
node
:
nodeWidget
}
);
this
.
onClick
(
nodeWidget
.
item
,
nodeWidget
);
this
.
focusNode
(
nodeWidget
);
}
dojo
.
stopEvent
(
e
);
},
_onExpandoClick
:
function
(
/*Object*/
message
){
// summary: user clicked the +/- icon; expand or collapse my children.
var
node
=
message
.
node
;
if
(
node
.
isExpanded
){
this
.
_collapseNode
(
node
);
}
else
{
this
.
_expandNode
(
node
);
}
},
onClick
:
function
(
/* dojo.data */
item
,
/*TreeNode*/
node
){
// summary: user overridable function for executing a tree item
},
_navToNextNode
:
function
(
node
){
// summary: get next visible node
var
returnNode
;
// if this is an expanded node, get the first child
if
(
node
.
isExpandable
&&
node
.
isExpanded
&&
node
.
hasChildren
()){
returnNode
=
node
.
getChildren
()[
0
];
}
else
{
// find a parent node with a sibling
while
(
node
&&
node
.
isTreeNode
){
returnNode
=
node
.
getNextSibling
();
if
(
returnNode
){
break
;
}
node
=
node
.
getParent
();
}
}
return
returnNode
;
},
_navToRootOrFirstNode
:
function
(){
// summary: get first visible node
if
(
!
this
.
_hideRoot
){
return
this
;
}
else
{
var
returnNode
=
this
.
getChildren
()[
0
];
if
(
returnNode
&&
returnNode
.
isTreeNode
){
return
returnNode
;
}
}
},
_collapseNode
:
function
(
/*_TreeNode*/
node
){
// summary: called when the user has requested to collapse the node
if
(
node
.
isExpandable
){
if
(
node
.
state
==
"LOADING"
){
// ignore clicks while we are in the process of loading data
return
;
}
if
(
this
.
lastFocused
){
// are we collapsing a descendant with focus?
if
(
dojo
.
isDescendant
(
this
.
lastFocused
.
domNode
,
node
.
domNode
)){
this
.
focusNode
(
node
);
}
else
{
// clicking the expando node might have erased focus from
// the current item; restore it
this
.
focusNode
(
this
.
lastFocused
);
}
}
node
.
collapse
();
if
(
this
.
persist
&&
node
.
item
){
delete
this
.
_openedItemIds
[
this
.
store
.
getIdentity
(
node
.
item
)];
this
.
_saveState
();
}
}
},
_expandNode
:
function
(
/*_TreeNode*/
node
){
// summary: called when the user has requested to expand the node
// clicking the expando node might have erased focus from the current item; restore it
var
t
=
node
.
tree
;
if
(
t
.
lastFocused
){
t
.
focusNode
(
t
.
lastFocused
);
}
if
(
!
node
.
isExpandable
){
return
;
}
var
store
=
this
.
store
;
var
getValue
=
this
.
store
.
getValue
;
switch
(
node
.
state
){
case
"LOADING"
:
// ignore clicks while we are in the process of loading data
return
;
case
"UNCHECKED"
:
// need to load all the children, and then expand
node
.
markProcessing
();
var
_this
=
this
;
var
onComplete
=
function
(
childItems
){
node
.
unmarkProcessing
();
_this
.
_onLoadAllItems
(
node
,
childItems
);
};
this
.
getItemChildren
(
node
.
item
,
onComplete
);
break
;
default
:
// data is already loaded; just proceed
if
(
node
.
expand
){
// top level Tree doesn't have expand() method
node
.
expand
();
if
(
this
.
persist
&&
node
.
item
){
this
.
_openedItemIds
[
this
.
store
.
getIdentity
(
node
.
item
)]
=
true
;
this
.
_saveState
();
}
}
break
;
}
},
////////////////// Miscellaneous functions ////////////////
blurNode
:
function
(){
// summary
// Removes focus from the currently focused node (which must be visible).
// Usually not called directly (just call focusNode() on another node instead)
var
node
=
this
.
lastFocused
;
if
(
!
node
){
return
;
}
var
labelNode
=
node
.
labelNode
;
dojo
.
removeClass
(
labelNode
,
"dijitTreeLabelFocused"
);
labelNode
.
setAttribute
(
"tabIndex"
,
"-1"
);
this
.
lastFocused
=
null
;
},
focusNode
:
function
(
/* _tree.Node */
node
){
// summary
// Focus on the specified node (which must be visible)
// set focus so that the label will be voiced using screen readers
node
.
labelNode
.
focus
();
},
_onBlur
:
function
(){
// summary:
// We've moved away from the whole tree. The currently "focused" node
// (see focusNode above) should remain as the lastFocused node so we can
// tab back into the tree. Just change CSS to get rid of the dotted border
// until that time
if
(
this
.
lastFocused
){
var
labelNode
=
this
.
lastFocused
.
labelNode
;
dojo
.
removeClass
(
labelNode
,
"dijitTreeLabelFocused"
);
}
},
_onTreeFocus
:
function
(
evt
){
var
node
=
dijit
.
getEnclosingWidget
(
evt
.
target
);
if
(
node
!=
this
.
lastFocused
){
this
.
blurNode
();
}
var
labelNode
=
node
.
labelNode
;
// set tabIndex so that the tab key can find this node
labelNode
.
setAttribute
(
"tabIndex"
,
"0"
);
dojo
.
addClass
(
labelNode
,
"dijitTreeLabelFocused"
);
this
.
lastFocused
=
node
;
},
//////////////// Events from data store //////////////////////////
_onNewItem
:
function
(
/*Object*/
item
,
parentInfo
){
//summary: callback when new item has been added to the store.
var
loadNewItem
;
// should new item be displayed in tree?
if
(
parentInfo
){
var
parent
=
this
.
_itemNodeMap
[
this
.
getItemParentIdentity
(
item
,
parentInfo
)];
// If new item's parent item not in tree view yet, can safely ignore.
// Also, if a query of specified parent wouldn't return this item, then ignore.
if
(
!
parent
||
dojo
.
indexOf
(
this
.
childrenAttr
,
parentInfo
.
attribute
)
==
-
1
){
return
;
}
}
var
childParams
=
{
item
:
item
,
isExpandable
:
this
.
mayHaveChildren
(
item
)
};
if
(
parent
){
if
(
!
parent
.
isExpandable
){
parent
.
makeExpandable
();
}
if
(
parent
.
state
==
"LOADED"
||
parent
.
isExpanded
){
var
childrenMap
=
parent
.
_addChildren
([
childParams
]);
}
}
else
{
// top level node
var
childrenMap
=
this
.
_addChildren
([
childParams
]);
}
if
(
childrenMap
){
dojo
.
mixin
(
this
.
_itemNodeMap
,
childrenMap
);
//this._itemNodeMap[this.store.getIdentity(item)]=child;
}
},
_onDeleteItem
:
function
(
/*Object*/
item
){
//summary: delete event from the store
//since the object has just been deleted, we need to
//use the name directly
var
identity
=
this
.
store
.
getIdentity
(
item
);
var
node
=
this
.
_itemNodeMap
[
identity
];
if
(
node
){
var
parent
=
node
.
getParent
();
parent
.
deleteNode
(
node
);
this
.
_itemNodeMap
[
identity
]
=
null
;
}
},
_onSetItem
:
function
(
/*Object*/
item
){
//summary: set data event on an item in the store
var
identity
=
this
.
store
.
getIdentity
(
item
);
node
=
this
.
_itemNodeMap
[
identity
];
if
(
node
){
node
.
setLabelNode
(
this
.
getLabel
(
item
));
node
.
_updateItemClasses
(
item
);
}
},
_saveState
:
function
(){
//summary: create and save a cookie with the currently expanded nodes identifiers
if
(
!
this
.
persist
){
return
;
}
var
ary
=
[];
for
(
var
id
in
this
.
_openedItemIds
){
ary
.
push
(
id
);
}
dojo
.
cookie
(
this
.
cookieName
,
ary
.
join
(
","
));
}
});
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 6, 10:29 (2 w, 2 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25534
Default Alt Text
Tree.js (27 KB)
Attached To
rZEDHG ZedLegacy
Event Timeline
Log In to Comment