bgx:components logo
© 2004 -2005
Bernhard Gaul



FTree Example
Flash MX, ActionScript 1.0

The following is an example of how to bind Xml data to the Flash FTree component. It allows n levels of folders, stores Xml node data with the FTree nodes and makes it available on selection.

It also assigns double-click open/close action to tree nodes. It saves the tree state in a Shared Object on the client and restores it whenever the tree is loaded, e.g. at a later visit to the same page.

Note: There is also an example available of how to bind XML to the Flash MX 2004 Tree component using the BGX Serialization Classes

Links

Download sample files

View the Xml used for this example

The Code


/* ===========
 * Description
 * ===========
 * An instance of the FTree component is already placed on the stage,
 * as well as textfileds and movieclips for description, icon display 
 * and load button. The FTree instance is called "bgTree".
 * 
 * The tree data comes from explorer.xml. Once it is loaded it gets 
 * bound to the tree via the buildTree() function. For each node a 
 * new object (NodeData) is created and used as the tree node data.
 * 
 * When a node is selected, the object is retrieved via bgTreeCall() and
 * the display updated using the defined methods for the NodeData object.
 * 
 * To correspond with usual tree behaviour, double-click will load samples 
 * and open/close folders. The state of opened/closed folders gets saved 
 * locally using a Shared Object to restore the tree when viewed next time.
 * 
 * © Bernhard Gaul, 2002
 * ===========
 */ 


//initialise display
var nodeDescription = "";
var dTitle = "Loading..."; 
loadButton._visible = false;
var fileInfo = "";
with (iconClip) {
    gotoAndStop(1);
} 

//paramaters to check for double-click
var lastClick = 0;
var lastSelected; 
var dClick = false; 

//define shared object for storage of tree status
bg_so = SharedObject.getLocal("bgTree");

//initialise tree
var t = _level0.bgTree;
var rootNode;
t.setNodeExpansionHandler("saveBranches", _root);
t.setChangeHandler("bgTreeCall", _root);

//current data depository for selected tree node
//also accessed by the load button
//which calls _level0.cD.loadSample();
var cD;

//load XML
treeXML = new XML();
treeXML.onLoad = buildTree; 
treeXML.load("explorer.xml"); 

function buildTree() {
	getRoot();
	parseTreeNode(rootNode,"0");
	//restore the tree to last saved state
	setBranches();
	dTitle = "Description";
	nodeDescription = descDefault;
}


function parseTreeNode(node,level) {
	var parentTreeNode;	
	thisObject = new NodeData(node);
	
	//set rootnode
	if(t.getTreeLength() == 0 ) {
		t.setRootNode(new FTreeNode(thisObject.label, thisObject));
	} else {
		//trace(level);
		parentTreeNode = t.getRootNode();
	
		/*
		check levels: as long as there is only one level
		below the root we use 
			parentTreeNode = t.getRootNode();
		after that parentTreeNode.getChildNodes() can be 
		used recursively.
		*/
		var levelArray = level.split(".");
		
		if (levelArray.length > 2) {
			for (var i=1; i < levelArray.length -1; i++) {
				var pChildren = parentTreeNode.getChildNodes();
				parentTreeNode = pChildren[levelArray[i]];			
			}
		}
		
		t.addNode(parentTreeNode, new FTreeNode(thisObject.label, thisObject));
	}
	//loop through children
	if(node.hasChildNodes()) {
		var childArray = node.childNodes;
		var childNode = node.firstChild;
		for (var z = 0; z < childArray.length; z++) {
			var childLevel = level + "." + z;
			parseTreeNode(childNode,childLevel);
			childNode = childNode.nextSibling;			
		}		
	}
}

//check if the firstChild is indeed the root, otherwise 
//skip over comments and DTD declarations...
//this was necessary with Flash 5, seems OK with MX
//but leave it in for the moment
function getRoot() { 
  rootNode = treeXML.firstChild;
  rootName = rootNode.nodeName;
  var x = 0;
  var y = treeXML.childNodes;
  while (x < y.length) {
    if (rootName == "myRoot") {
      break;
    }
    rootNode = rootNode.nextSibling;
    rootName = rootNode.nodeName;
    x++;
  }
}

//NodeData Class constructor
//creates the NodeData object based on the 
//XML node submitted
//called from buildTree()
function NodeData(sNode) {
  this.type = sNode.nodeName;
  this.label = sNode.attributes["label"];
  this.description = sNode.attributes["description"];
  if (this.type == "leaf") {
    this.sampleUrl = sNode.attributes["URL"];
    this.fileinfo = sNode.attributes["fileInf"];
    this.icon = sNode.attributes["icon"];
    this.target = sNode.attributes["target"];
  }
  //create boolean value for hasURL property
  this.hasUrl = ((this.type == "leaf") && (this.sampleUrl.length > 0)); 
}

//Method for NodeData: loadSample()
NodeData.prototype.loadSample = function() {
  getURL(this.sampleUrl,this.target);
}

//Method for NodeData: update()
//this function is called when a tree node gets clicked on 
//unless it is a double-click on a folder, which is
//treated beforehand
NodeData.prototype.update = function() {
  //unlike for branches response to double-click for leaves
  //has to be handled considering the current data as it
  //shall only be executed if the object does have a URL  
  if (dClick) {
    if (this.hasURL) this.loadSample();//load sample on double-click
    return;//display was already updated on first click
  } 
  loadButton._visible = this.hasURL; 
  nodeDescription = this.description;
  fileInfo = this.fileinfo; 
  with (iconClip) {
    gotoAndStop((this.icon.length>0) ? this.icon : 1);
  }
}


//handle tree node selections
function bgTreeCall(component) {
  //identify selected node
  var s = component.getSelectedNode(); 
  //check for double-click
  checkDblClick(s);
  //toggle folder state on double-click
  if (s.isBranch() && dClick) {
    toggleOpen = ((s.isOpen()) ? false : true);
    s.setIsOpen(toggleOpen);
    t.refresh();
    saveBranches();
  } else {
    //get new data on first click
    if (!dClick) cD = s.getData();
    //process data
    cD.update();
  } 
}

//restore tree to last saved state
function setBranches() {
  fL = this.bg_so.data.folderList;
  rO = this.bg_so.data.rootOpen;
  
  if (fL == undefined) {
    //define default state
    t.getRootNode().setIsOpen(true);
  } else {
    t.getRootNode().setIsOpen(rO); 
	var bArray = t.getRootNode().getChildNodes();
	var i = 0;	
   	setBranchesLoop(bArray,fL,i);
  }
  t.refresh();
}

function setBranchesLoop(bArray,fL,i) {
	 for (var j=0; j < bArray.length; j++) {
		 if (bArray[j].isBranch()) {
			 bArray[j].setIsOpen(fl[i]);
			 i++;
     		 var thisChildren =  bArray[j].getChildNodes();
			 i = setBranchesLoop(thisChildren,fL,i);
		 }
    }
	return i;
}

//get tree status when a branch is opened/closed
function saveBranches() {
  rOpen = t.getRootNode().isOpen();
  var bOpen = new Array();
  var bArray = t.getRootNode().getChildNodes();
  saveBranchesLoop(bOpen,bArray);
  //by defining these parameters as properties of the shared 
  //object they get automatically saved if the file gets closed
  this.bg_so.data.folderList = bOpen;
  this.bg_so.data.rootOpen = rOpen;
} 

function saveBranchesLoop(bOpen,bArray){
	for (var j=0; j < bArray.length; j++) {
		if (bArray[j].isBranch()) {
			bOpen.push(bArray[j].isOpen());
			var thisChildren =  bArray[j].getChildNodes();
			saveBranchesLoop(bOpen,thisChildren);
		}
  	}
}

//check if a tree node was double-clicked 
//set dClick to true if it was
function checkDblClick(s) {
  var clickTime = getTimer();
  dClick = ((clickTime-lastClick<300) && (lastSelected == s));
  lastClick = clickTime;
  lastSelected = s; 
}

function loadButtonCall() {
	cD.loadSample();	
}
			

Background

The FTree component is one of the standard UI components that come with Flash MX.

This example shows how to loop through Xml loaded from an external file and build a tree structure based on that Xml information.