XUL:Tree

From MozillaWiki
Jump to: navigation, search

Editable Tree

The following properties and methods are added for editable tree support. To enable editing of a tree, set the editable attribute on the <tree> to true.

For content trees, the editable attribute may be set to false on a specific <treecell> to disable editing of that cell.

RDF Built trees do not currently support editing.

Editable trees do not work in Firefox 2, they work in Firefox 3 though.

Properties

editingRow 
The integer row index of the cell currently being edited, or -1 if no cell is being edited.
editingColumn 
The TreeColumn of the cell currently being edited, or null if no cell is being edited.

Methods

startEditing ( row , column ) 
Start editing a cell at a given row index and column.
stopEditing ( shouldAccept ) 
Stop editing a cell. If shouldAccept is true, the cell label is changed to the edited value. If shouldAccept is false, the cell label is not changed.

Usage

 <tree editable="true" flex="1">
   <treecols>
     <treecol id="sender" label="Sender" flex="1"/>
     <treecol id="subject" label="Subject" flex="2"/>
   </treecols>
   <treechildren>
     <treeitem>
       <treerow>
         <treecell label="joe@somewhere.com"/>
         <treecell label="Top secret plans" editable="false"/>
       </treerow>
     </treeitem>
   </treechildren>
 </tree>

JSON-based tree

Component Sample Source

you can use that component to feed your tree with some JSON.

in order to do this, you will need at least to provide the data (a list with uniform json objects) and a list of functions which plays the role of columnmodels, sending the value to be shown on each column for each row.

/**
 * Small and simple model able to feed a tree with some custom JSON
 * 
 * @param params
 *            associative array containing some parameters.
 * @param param.tree
 *            referece element for the tree.
 * @param param.model
 *            a list containing data to present.
 * @param param.columnModel
 *            array of funcions which will render (at least) labels for each
 *            cell. what exactly those models will do is related to cellCreator;
 *            the default implementation will simply add the label property for
 *            each cell.
 * @param param.cellCreator
 *            funcion which creates treecell elements and handle the data
 *            generated by each funcion of columnModel.
 * @param param.columnTitle
 *            labels for the columns.
 * 
 * Note that cellCreator and columnTitle are nullable, we have default
 * implementation for cellCreator and can assume that treecols already exists
 * inside xul tree.
 */
function SimpleTreeModel(params) {

	if (!params)// must have params
		throw {
			message :"invalid parameters"
		};

	if (!params.tree)
		throw {
			message :"must pass a tree"
		};
	var tree = params.tree;

	if (!params.model)
		throw {
			message :"must pass a list with some data"
		};
	var model = params.model;

	if (!params.columnModel)
		throw {
			message :"must pass a list of columnModels"
		};
	var columnModel = params.columnModel;

	var cellCreator;
	if (params.crellCreator)
		cellCreator = params.crellCreator;
	else {// fallback to a default cellCreator...
		cellCreator = function(vFunc, data) {
			var cell = document.createElement("treecell");
			cell.setAttribute("label", vFunc(data));
			return cell;
		}
	}

	var columnTitle;
	if (params.columnTitle)
		columnTitle = params.columnTitle;

	if (columnTitle) {
		var treecols = tree.getElementsByTagName("treecols")[0];
		if (!treecols) {
			treecols = document.createElement("treecols");
			treecols.id = tree.id + "cols";
			tree.appendChild(treecols);
		}

		var listTreeCols = treecols.getElementsByTagName("treecol");
		// fix if we don't have enough treecol elements
		var x = columnTitle.length - listTreeCols.length;
		while (x-- > 0) {
			var tc = document.createElement("treecol");
			treecols.appendChild(tc);
		}
		// again...
		listTreeCols = treecols.getElementsByTagName("treecol");
		x = -1;
		while (++x < listTreeCols.length) {
			listTreeCols[x].setAttribute("label", columnTitle[x]);
			if (!listTreeCols[x].flex)// let's default the flex too.
				listTreeCols[x].setAttribute("flex", 1);
		}
	}

	var children = tree.getElementsByTagName("treechildren")[0];
	if (!children) {
		children = document.createElement("treechildren");
		children.id = tree.id + "children";
		children.alternatingbackground = true;
		tree.appendChild(children);
	}

	/**
	 * this method is able to update the list used as model later and forces
	 * redwaw of entire tree. usually it also fires some select events.
	 */
	this.update = function(_model) {
		if (_model)
			model = _model;
		while (children.childNodes.length > 0) {
			children.removeChild(children.firstChild);
		}
		for ( var i = 0; i < model.length; i++) {
			var item = document.createElement("treeitem");
			item.id = children.id + "treeitem" + i;
			var linha = document.createElement("treerow");
			linha.id = item.id + "treerow" + i;
			for ( var j = 0; j < columnModel.length; j++) {
				var cell = cellCreator(columnModel[j], model[i]);
				cell.id = linha.id + "treecell" + j;
				linha.appendChild(cell);
			}
			item.appendChild(linha);
			children.appendChild(item);
		}
	}
}

Usage

Usually you can use some funcion to instantiate it; it handles perfectly state, so keep the component instace alive if you want to change some data.

Here comes a small usage for that component:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
	title="Sample JSON-Based Tree" sizemode="normal"
	onload="new SampleState();" width="640px" height="480px">
	<script type="text/javascript" src="SimpleTreeModel.js"></script>
	<script type="text/javascript"> 
		function SampleState(){ 
			
			//reference for the tree
			var tContacts = document.getElementById("contacts");
			
			//some ordinary data
			var data = [
				{"sender":"joe@somewhere.com","subject":"Top secret plans"},
				{"sender":"mel@whereever.com","subject":"Let's do lunch"}
			];
			
			//a basic columnModel
			var cModel = [
				function(data){
					return data.sender;
				},
				function(data){
					return data.subject;
				}
			];
			
			//our instance Model
			var model = new SimpleTreeModel({
				"tree":tContacts,
				"model":data,
				"columnModel":cModel
			});
			
			//let's draw the tree
			model.update();
		}
	</script>
	<tree flex="1" hidecolumnpicker="true"
		seltype="single" id="contacts">
		<treecols>
			<treecol id="sender" label="Sender" flex="1" />
			<treecol id="subject" label="Subject" flex="2" />
		</treecols>
	</tree>
</window>