<commit_before>AUI.add('tree-node', function(A) {

var L = A.Lang,
	isString = L.isString,
	isBoolean = L.isBoolean,

	ALWAYS_SHOW_HITAREA = 'alwaysShowHitArea',
	BLANK = '',
	BOUNDING_BOX = 'boundingBox',
	CHILDREN = 'children',
	CLEARFIX = 'clearfix',
	COLLAPSED = 'collapsed',
	CONTAINER = 'container',
	CONTENT = 'content',
	CONTENT_BOX = 'contentBox',
	EL = 'el',
	EXPANDED = 'expanded',
	HELPER = 'helper',
	HIDDEN = 'hidden',
	HITAREA = 'hitarea',
	HIT_AREA_EL = 'hitAreaEl',
	ICON = 'icon',
	ICON_EL = 'iconEl',
	ID = 'id',
	LABEL = 'label',
	LABEL_EL = 'labelEl',
	LAST_SELECTED = 'lastSelected',
	LEAF = 'leaf',
	NODE = 'node',
	OVER = 'over',
	OWNER_TREE = 'ownerTree',
	PARENT_NODE = 'parentNode',
	SELECTED = 'selected',
	SPACE = ' ',
	TREE = 'tree',
	TREE_NODE = 'tree-node',

	nodeSetter = function(v) {
		return A.get(v);
	},

	concat = function() {
		return Array.prototype.slice.call(arguments).join(SPACE);
	},

	isTreeNode = function(v) {
		return ( v instanceof A.TreeNode );
	},

	getCN = A.ClassNameManager.getClassName,

	CSS_HELPER_CLEARFIX = getCN(HELPER, CLEARFIX),
	CSS_TREE_COLLAPSED = getCN(TREE, COLLAPSED),
	CSS_TREE_CONTAINER = getCN(TREE, CONTAINER),
	CSS_TREE_EXPANDED = getCN(TREE, EXPANDED),
	CSS_TREE_HIDDEN = getCN(TREE, HIDDEN),
	CSS_TREE_HITAREA = getCN(TREE, HITAREA),
	CSS_TREE_ICON = getCN(TREE, ICON),
	CSS_TREE_LABEL = getCN(TREE, LABEL),
	CSS_TREE_NODE_CONTENT = getCN(TREE, NODE, CONTENT),
	CSS_TREE_NODE_HIDDEN_HITAREA = getCN(TREE, NODE, HIDDEN, HITAREA),
	CSS_TREE_NODE_LEAF = getCN(TREE, NODE, LEAF),
	CSS_TREE_NODE_OVER = getCN(TREE, NODE, OVER),
	CSS_TREE_NODE_SELECTED = getCN(TREE, NODE, SELECTED),

	HIT_AREA_TPL = '<div class="'+CSS_TREE_HITAREA+'"></div>',
	ICON_TPL = '<div class="'+CSS_TREE_ICON+'"></div>',
	LABEL_TPL = '<div class="'+CSS_TREE_LABEL+'"></div>',
	NODE_CONTAINER_TPL = '<ul></ul>',

	NODE_BOUNDING_TEMPLATE = '<li></li>',
	NODE_CONTENT_TEMPLATE = '<div class="'+concat(CSS_HELPER_CLEARFIX, CSS_TREE_NODE_CONTENT)+'"></div>';

/*
* TreeNode
*/
function TreeNode(config) {
	TreeNode.superclass.constructor.apply(this, arguments);
}

A.mix(TreeNode, {
	NAME: TREE_NODE,

	ATTRS: {
		draggable: {
			value: true,
			validador: isBoolean
		},

		ownerTree: {
			value: null
		},

		label: {
			value: BLANK,
			validador: isString
		},

		expanded: {
			value: false,
			validador: isBoolean
		},

		id: {
			validador: isString,
			setter: function(v) {
				this.get(BOUNDING_BOX).attr(ID, v);

				return v;
			}
		},

		leaf: {
			value: true,
			setter: function(v) {
				// if has children it's not a leaf
				if (v && this.get(CHILDREN).length) {
					return false;
				}

				return v;
			},
			validador: isBoolean
		},

		nextSibling: {
			value: null,
			validador: isTreeNode
		},

		prevSibling: {
			value: null,
			validador: isTreeNode
		},

		parentNode: {
			value: null,
			validador: isTreeNode
		},

		labelEl: {
			setter: nodeSetter,
			valueFn: function() {
				var label = this.get(LABEL);

				return A.Node.create(LABEL_TPL).html(label).unselectable();
			}
		},

		hitAreaEl: {
			setter: nodeSetter,
			valueFn: function() {
				return A.Node.create(HIT_AREA_TPL);
			}
		},

		alwaysShowHitArea: {
			value: true,
			validador: isBoolean
		},

		iconEl: {
			setter: nodeSetter,
			valueFn: function() {
				return A.Node.create(ICON_TPL);
			}
		},

		tabIndex: {
			value: null
		}
	}
});


A.extend(TreeNode, A.TreeData, {
	BOUNDING_TEMPLATE: NODE_BOUNDING_TEMPLATE,
	CONTENT_TEMPLATE: NODE_CONTENT_TEMPLATE,

	/*
	* Lifecycle
	*/
	initializer: function() {
		var instance = this;
		var boundingBox = instance.get(BOUNDING_BOX);

		if (!instance.get(ID)) {
			// add a default unique id for the index
			instance.set( ID, A.guid(TREE_NODE) );
		}

		// invoking TreeData initializer
		TreeNode.superclass.initializer.apply(this, arguments);
	},

	bindUI: function() {
		var instance = this;

		// binding collapse/expand
		instance.publish('collapse', { defaultFn: instance._collapse });
		instance.publish('expand', { defaultFn: instance._expand });

		instance.after('childrenChange', A.bind(instance._afterSetChildren, instance));
	},

	// overloading private _renderUI, don't call this._renderBox method
	// avoid render node on the body
    _renderUI: function(parentNode) {
        this._renderBoxClassNames();
		// this._renderBox(parentNode);
    },

	renderUI: function() {
		var instance = this;

		instance._renderBoundingBox();
		instance._renderContentBox();
	},

	syncUI: function() {
		var instance = this;

		instance._syncHitArea( instance.get( CHILDREN ) );
	},

	_renderContentBox: function(v) {
		var instance = this;
		var contentBox = instance.get(CONTENT_BOX);

		if (instance.isLeaf()) {
			// add leaf css classes
			contentBox.addClass(CSS_TREE_NODE_LEAF);
		}
		else {
			// add folder css classes state
			contentBox.addClass(
				instance.get(EXPANDED) ? CSS_TREE_EXPANDED : CSS_TREE_COLLAPSED
			);
		}

		return contentBox;
	},

	_renderBoundingBox: function() {
		var instance = this;
		var boundingBox = instance.get(BOUNDING_BOX);
		var contentBox = instance.get(CONTENT_BOX);

		if (!instance.isLeaf()) {
			// append hitarea element
			contentBox.append( instance.get(HIT_AREA_EL) );

			// if has children append them to this model
			var nodeContainer = instance._createNodeContainer();
		}

		contentBox.append( instance.get(ICON_EL) );
		contentBox.append( instance.get(LABEL_EL) );

		boundingBox.append(contentBox);

		if (nodeContainer) {
			if (!instance.get(EXPANDED)) {
				nodeContainer.addClass(CSS_TREE_HIDDEN);
			}

			boundingBox.append(nodeContainer);
		}

		return boundingBox;
	},

	_createNodeContainer: function() {
		var instance = this;

		// creating <ul class="aui-tree-container">
		var nodeContainer = instance.get(CONTAINER) || A.Node.create(NODE_CONTAINER_TPL);

		nodeContainer.addClass(CSS_TREE_CONTAINER);

		// when it's not a leaf it has a <ul> container
		instance.set(CONTAINER, nodeContainer);

		instance.eachChildren(function(node) {
			instance.appendChild(node);
		});

		return nodeContainer;
	},

	_syncHitArea: function(children) {
		var instance = this;

		if (instance.get(ALWAYS_SHOW_HITAREA) || children.length) {
			instance.showHitArea();
		}
		else {
			instance.hideHitArea();

			instance.collapse();
		}
	},

	/*
	* Methods
	*/
	appendChild: function() {
		var instance = this;

		if (!instance.isLeaf()) {
			TreeNode.superclass.appendChild.apply(instance, arguments);
		}
	},

	collapse: function() {
		var instance = this;

		if (instance.get(EXPANDED)) {
			var output = instance.getEventOutputMap(instance);

			instance.bubbleEvent('collapse', output);
		}
	},

	_collapse: function(event) {
		// stopActionPropagation while bubbling
		if (event.stopActionPropagation) {
			return false;
		}

		var instance = this;

		if (!instance.isLeaf()) {
			var container = instance.get(CONTAINER);
			var contentBox = instance.get(CONTENT_BOX);

			contentBox.replaceClass(CSS_TREE_EXPANDED, CSS_TREE_COLLAPSED);

			if (container) {
				container.addClass(CSS_TREE_HIDDEN);
			}

			instance.set(EXPANDED, false);
		}
	},

	collapseAll: function() {
		var instance = this;

		TreeNode.superclass.collapseAll.apply(instance, arguments);

		// instance is also a node, so collapse itself
		instance.collapse();
	},

	contains: function(node) {
        return node.isAncestor(this);
	},

	expand: function() {
		var instance = this;

		if (!instance.get(EXPANDED)) {
			var output = instance.getEventOutputMap(instance);

			instance.bubbleEvent('expand', output);
		}
	},

	_expand: function(event) {
		// stopActionPropagation while bubbling
		if (event.stopActionPropagation) {
			return false;
		}

		var instance = this;

		if (!instance.isLeaf()) {
			var container = instance.get(CONTAINER);
			var contentBox = instance.get(CONTENT_BOX);

			contentBox.replaceClass(CSS_TREE_COLLAPSED, CSS_TREE_EXPANDED);

			if (container) {
				container.removeClass(CSS_TREE_HIDDEN);
			}

			instance.set(EXPANDED, true);
		}
	},

	expandAll: function() {
		var instance = this;

		TreeNode.superclass.expandAll.apply(instance, arguments);

		// instance is also a node, so expand itself
		instance.expand();
	},

	getDepth: function() {
		var depth = 0;
		var instance = this;
		var parentNode = instance.get(PARENT_NODE);

		while (parentNode) {
			++depth;
			parentNode = parentNode.get(PARENT_NODE);
		}

		return depth;
	},

	hasChildNodes: function() {
		var instance = this;

		return (!instance.isLeaf() &&
				TreeNode.superclass.hasChildNodes.apply(this, arguments));
	},

	isSelected: function() {
		return this.get(CONTENT_BOX).hasClass(CSS_TREE_NODE_SELECTED);
	},

	isLeaf: function() {
		var instance = this;

		return instance.get(LEAF);
	},

	isAncestor: function(node) {
		var instance = this;
		var parentNode = instance.get(PARENT_NODE);

		while (parentNode) {
			if (parentNode == node) {
				return true;
			}
			parentNode = parentNode.get(PARENT_NODE);
		}

		return false;
	},

	insertAfter: function(node, refNode) {
		var instance = this;

		TreeNode.superclass.insertAfter.apply(this, [node, instance]);
	},

	insertBefore: function(node) {
		var instance = this;

		TreeNode.superclass.insertBefore.apply(this, [node, instance]);
	},

	removeChild: function(node) {
		var instance = this;

		if (!instance.isLeaf()) {
			TreeNode.superclass.removeChild.apply(instance, arguments);
		}
	},

	toggle: function() {
		var instance = this;

		if (instance.get(EXPANDED)) {
			instance.collapse();
		}
		else {
			instance.expand();
		}
	},

	select: function() {
		var instance = this;
		var ownerTree = instance.get(OWNER_TREE);

		if (ownerTree) {
			ownerTree.set(LAST_SELECTED, instance);
		}

		instance.get(CONTENT_BOX).addClass(CSS_TREE_NODE_SELECTED);

		instance.fire('select');
	},

	unselect: function() {
		var instance = this;

		instance.get(CONTENT_BOX).removeClass(CSS_TREE_NODE_SELECTED);

		instance.fire('unselect');
	},

	over: function() {
		this.get(CONTENT_BOX).addClass(CSS_TREE_NODE_OVER);
	},

	out: function() {
		this.get(CONTENT_BOX).removeClass(CSS_TREE_NODE_OVER);
	},

	showHitArea: function() {
		var instance = this;
		var hitAreaEl = instance.get(HIT_AREA_EL);

		hitAreaEl.removeClass(CSS_TREE_NODE_HIDDEN_HITAREA);
	},

	hideHitArea: function() {
		var instance = this;
		var hitAreaEl = instance.get(HIT_AREA_EL);

		hitAreaEl.addClass(CSS_TREE_NODE_HIDDEN_HITAREA);
	},

	/*
	* Listeners
	*/
	_afterSetChildren: function(event) {
		var instance = this;

		instance._syncHitArea(event.newVal);
	}
});

A.TreeNode = TreeNode;


/*
* TreeNodeIO
*/
var isFunction = L.isFunction,

	CACHE = 'cache',
	FORMATTER = 'formatter',
	IO = 'io',
	LOADED = 'loaded',<commit_msg>Partial fix for tree node with YUI3.1 changes. Setters should only be used for formatting set data, but attribute change events are for updating the view elements<commit_after>AUI.add('tree-node', function(A) {

var L = A.Lang,
	isString = L.isString,
	isBoolean = L.isBoolean,

	ALWAYS_SHOW_HITAREA = 'alwaysShowHitArea',
	BLANK = '',
	BOUNDING_BOX = 'boundingBox',
	CHILDREN = 'children',
	CLEARFIX = 'clearfix',
	COLLAPSED = 'collapsed',
	CONTAINER = 'container',
	CONTENT = 'content',
	CONTENT_BOX = 'contentBox',
	EL = 'el',
	EXPANDED = 'expanded',
	HELPER = 'helper',
	HIDDEN = 'hidden',
	HITAREA = 'hitarea',
	HIT_AREA_EL = 'hitAreaEl',
	ICON = 'icon',
	ICON_EL = 'iconEl',
	ID = 'id',
	LABEL = 'label',
	LABEL_EL = 'labelEl',
	LAST_SELECTED = 'lastSelected',
	LEAF = 'leaf',
	NODE = 'node',
	OVER = 'over',
	OWNER_TREE = 'ownerTree',
	PARENT_NODE = 'parentNode',
	SELECTED = 'selected',
	SPACE = ' ',
	TREE = 'tree',
	TREE_NODE = 'tree-node',

	nodeSetter = function(v) {
		return A.get(v);
	},

	concat = function() {
		return Array.prototype.slice.call(arguments).join(SPACE);
	},

	isTreeNode = function(v) {
		return ( v instanceof A.TreeNode );
	},

	getCN = A.ClassNameManager.getClassName,

	CSS_HELPER_CLEARFIX = getCN(HELPER, CLEARFIX),
	CSS_TREE_COLLAPSED = getCN(TREE, COLLAPSED),
	CSS_TREE_CONTAINER = getCN(TREE, CONTAINER),
	CSS_TREE_EXPANDED = getCN(TREE, EXPANDED),
	CSS_TREE_HIDDEN = getCN(TREE, HIDDEN),
	CSS_TREE_HITAREA = getCN(TREE, HITAREA),
	CSS_TREE_ICON = getCN(TREE, ICON),
	CSS_TREE_LABEL = getCN(TREE, LABEL),
	CSS_TREE_NODE_CONTENT = getCN(TREE, NODE, CONTENT),
	CSS_TREE_NODE_HIDDEN_HITAREA = getCN(TREE, NODE, HIDDEN, HITAREA),
	CSS_TREE_NODE_LEAF = getCN(TREE, NODE, LEAF),
	CSS_TREE_NODE_OVER = getCN(TREE, NODE, OVER),
	CSS_TREE_NODE_SELECTED = getCN(TREE, NODE, SELECTED),

	HIT_AREA_TPL = '<div class="'+CSS_TREE_HITAREA+'"></div>',
	ICON_TPL = '<div class="'+CSS_TREE_ICON+'"></div>',
	LABEL_TPL = '<div class="'+CSS_TREE_LABEL+'"></div>',
	NODE_CONTAINER_TPL = '<ul></ul>',

	NODE_BOUNDING_TEMPLATE = '<li></li>',
	NODE_CONTENT_TEMPLATE = '<div class="'+concat(CSS_HELPER_CLEARFIX, CSS_TREE_NODE_CONTENT)+'"></div>';

/*
* TreeNode
*/
function TreeNode(config) {
	TreeNode.superclass.constructor.apply(this, arguments);
}

A.mix(TreeNode, {
	NAME: TREE_NODE,

	ATTRS: {
		draggable: {
			value: true,
			validador: isBoolean
		},

		ownerTree: {
			value: null
		},

		label: {
			value: BLANK,
			validador: isString
		},

		expanded: {
			value: false,
			validador: isBoolean
		},

		id: {
			validador: isString
		},

		leaf: {
			value: true,
			setter: function(v) {
				// if has children it's not a leaf
				if (v && this.get(CHILDREN).length) {
					return false;
				}

				return v;
			},
			validador: isBoolean
		},

		nextSibling: {
			value: null,
			validador: isTreeNode
		},

		prevSibling: {
			value: null,
			validador: isTreeNode
		},

		parentNode: {
			value: null,
			validador: isTreeNode
		},

		labelEl: {
			setter: nodeSetter,
			valueFn: function() {
				var label = this.get(LABEL);

				return A.Node.create(LABEL_TPL).html(label).unselectable();
			}
		},

		hitAreaEl: {
			setter: nodeSetter,
			valueFn: function() {
				return A.Node.create(HIT_AREA_TPL);
			}
		},

		alwaysShowHitArea: {
			value: true,
			validador: isBoolean
		},

		iconEl: {
			setter: nodeSetter,
			valueFn: function() {
				return A.Node.create(ICON_TPL);
			}
		},

		tabIndex: {
			value: null
		}
	}
});


A.extend(TreeNode, A.TreeData, {
	BOUNDING_TEMPLATE: NODE_BOUNDING_TEMPLATE,
	CONTENT_TEMPLATE: NODE_CONTENT_TEMPLATE,

	/*
	* Lifecycle
	*/
	initializer: function() {
		var instance = this;
		var boundingBox = instance.get(BOUNDING_BOX);

		if (!instance.get(ID)) {
			// add a default unique id for the index
			instance.set( ID, A.guid(TREE_NODE) );
		}

		// invoking TreeData initializer
		TreeNode.superclass.initializer.apply(this, arguments);
	},

	bindUI: function() {
		var instance = this;

		// binding collapse/expand
		instance.publish('collapse', { defaultFn: instance._collapse });
		instance.publish('expand', { defaultFn: instance._expand });

		instance.after('childrenChange', A.bind(instance._afterSetChildren, instance));
		instance.after('idChange', instance._afterSetId, instance);
	},

	// overloading private _renderUI, don't call this._renderBox method
	// avoid render node on the body
    _renderUI: function(parentNode) {
        this._renderBoxClassNames();
		// this._renderBox(parentNode);
    },

	renderUI: function() {
		var instance = this;

		instance._renderBoundingBox();
		instance._renderContentBox();
	},

	syncUI: function() {
		var instance = this;

		instance._syncHitArea( instance.get( CHILDREN ) );
	},

	_renderContentBox: function(v) {
		var instance = this;
		var contentBox = instance.get(CONTENT_BOX);

		if (instance.isLeaf()) {
			// add leaf css classes
			contentBox.addClass(CSS_TREE_NODE_LEAF);
		}
		else {
			// add folder css classes state
			contentBox.addClass(
				instance.get(EXPANDED) ? CSS_TREE_EXPANDED : CSS_TREE_COLLAPSED
			);
		}

		return contentBox;
	},

	_renderBoundingBox: function() {
		var instance = this;
		var boundingBox = instance.get(BOUNDING_BOX);
		var contentBox = instance.get(CONTENT_BOX);

		if (!instance.isLeaf()) {
			// append hitarea element
			contentBox.append( instance.get(HIT_AREA_EL) );

			// if has children append them to this model
			var nodeContainer = instance._createNodeContainer();
		}

		contentBox.append( instance.get(ICON_EL) );
		contentBox.append( instance.get(LABEL_EL) );

		boundingBox.append(contentBox);

		if (nodeContainer) {
			if (!instance.get(EXPANDED)) {
				nodeContainer.addClass(CSS_TREE_HIDDEN);
			}

			boundingBox.append(nodeContainer);
		}

		return boundingBox;
	},

	_createNodeContainer: function() {
		var instance = this;

		// creating <ul class="aui-tree-container">
		var nodeContainer = instance.get(CONTAINER) || A.Node.create(NODE_CONTAINER_TPL);

		nodeContainer.addClass(CSS_TREE_CONTAINER);

		// when it's not a leaf it has a <ul> container
		instance.set(CONTAINER, nodeContainer);

		instance.eachChildren(function(node) {
			instance.appendChild(node);
		});

		return nodeContainer;
	},

	_syncHitArea: function(children) {
		var instance = this;

		if (instance.get(ALWAYS_SHOW_HITAREA) || children.length) {
			instance.showHitArea();
		}
		else {
			instance.hideHitArea();

			instance.collapse();
		}
	},

	/*
	* Methods
	*/
	appendChild: function() {
		var instance = this;

		if (!instance.isLeaf()) {
			TreeNode.superclass.appendChild.apply(instance, arguments);
		}
	},

	collapse: function() {
		var instance = this;

		if (instance.get(EXPANDED)) {
			var output = instance.getEventOutputMap(instance);

			instance.bubbleEvent('collapse', output);
		}
	},

	_collapse: function(event) {
		// stopActionPropagation while bubbling
		if (event.stopActionPropagation) {
			return false;
		}

		var instance = this;

		if (!instance.isLeaf()) {
			var container = instance.get(CONTAINER);
			var contentBox = instance.get(CONTENT_BOX);

			contentBox.replaceClass(CSS_TREE_EXPANDED, CSS_TREE_COLLAPSED);

			if (container) {
				container.addClass(CSS_TREE_HIDDEN);
			}

			instance.set(EXPANDED, false);
		}
	},

	collapseAll: function() {
		var instance = this;

		TreeNode.superclass.collapseAll.apply(instance, arguments);

		// instance is also a node, so collapse itself
		instance.collapse();
	},

	contains: function(node) {
        return node.isAncestor(this);
	},

	expand: function() {
		var instance = this;

		if (!instance.get(EXPANDED)) {
			var output = instance.getEventOutputMap(instance);

			instance.bubbleEvent('expand', output);
		}
	},

	_expand: function(event) {
		// stopActionPropagation while bubbling
		if (event.stopActionPropagation) {
			return false;
		}

		var instance = this;

		if (!instance.isLeaf()) {
			var container = instance.get(CONTAINER);
			var contentBox = instance.get(CONTENT_BOX);

			contentBox.replaceClass(CSS_TREE_COLLAPSED, CSS_TREE_EXPANDED);

			if (container) {
				container.removeClass(CSS_TREE_HIDDEN);
			}

			instance.set(EXPANDED, true);
		}
	},

	expandAll: function() {
		var instance = this;

		TreeNode.superclass.expandAll.apply(instance, arguments);

		// instance is also a node, so expand itself
		instance.expand();
	},

	getDepth: function() {
		var depth = 0;
		var instance = this;
		var parentNode = instance.get(PARENT_NODE);

		while (parentNode) {
			++depth;
			parentNode = parentNode.get(PARENT_NODE);
		}

		return depth;
	},

	hasChildNodes: function() {
		var instance = this;

		return (!instance.isLeaf() &&
				TreeNode.superclass.hasChildNodes.apply(this, arguments));
	},

	isSelected: function() {
		return this.get(CONTENT_BOX).hasClass(CSS_TREE_NODE_SELECTED);
	},

	isLeaf: function() {
		var instance = this;

		return instance.get(LEAF);
	},

	isAncestor: function(node) {
		var instance = this;
		var parentNode = instance.get(PARENT_NODE);

		while (parentNode) {
			if (parentNode == node) {
				return true;
			}
			parentNode = parentNode.get(PARENT_NODE);
		}

		return false;
	},

	insertAfter: function(node, refNode) {
		var instance = this;

		TreeNode.superclass.insertAfter.apply(this, [node, instance]);
	},

	insertBefore: function(node) {
		var instance = this;

		TreeNode.superclass.insertBefore.apply(this, [node, instance]);
	},

	removeChild: function(node) {
		var instance = this;

		if (!instance.isLeaf()) {
			TreeNode.superclass.removeChild.apply(instance, arguments);
		}
	},

	toggle: function() {
		var instance = this;

		if (instance.get(EXPANDED)) {
			instance.collapse();
		}
		else {
			instance.expand();
		}
	},

	select: function() {
		var instance = this;
		var ownerTree = instance.get(OWNER_TREE);

		if (ownerTree) {
			ownerTree.set(LAST_SELECTED, instance);
		}

		instance.get(CONTENT_BOX).addClass(CSS_TREE_NODE_SELECTED);

		instance.fire('select');
	},

	unselect: function() {
		var instance = this;

		instance.get(CONTENT_BOX).removeClass(CSS_TREE_NODE_SELECTED);

		instance.fire('unselect');
	},

	over: function() {
		this.get(CONTENT_BOX).addClass(CSS_TREE_NODE_OVER);
	},

	out: function() {
		this.get(CONTENT_BOX).removeClass(CSS_TREE_NODE_OVER);
	},

	showHitArea: function() {
		var instance = this;
		var hitAreaEl = instance.get(HIT_AREA_EL);

		hitAreaEl.removeClass(CSS_TREE_NODE_HIDDEN_HITAREA);
	},

	hideHitArea: function() {
		var instance = this;
		var hitAreaEl = instance.get(HIT_AREA_EL);

		hitAreaEl.addClass(CSS_TREE_NODE_HIDDEN_HITAREA);
	},

	/*
	* Listeners
	*/
	_afterSetChildren: function(event) {
		var instance = this;

		instance._syncHitArea(event.newVal);
	},

	_afterSetId: function(event) {
		var instance = this;

		instance.get(BOUNDING_BOX).attr(ID, event.newVal);
	}
});

A.TreeNode = TreeNode;


/*
* TreeNodeIO
*/
var isFunction = L.isFunction,

	CACHE = 'cache',
	FORMATTER = 'formatter',
	IO = 'io',
	LOADED = 'loaded',
{'fraction_non_alphanumeric': 0.13790557068352793, 'fraction_numerical': 0.0001846125444223935, 'mean_word_length': 3.9290263876251137, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5601292', 'n_tokens_mistral': 8770, 'n_tokens_neox': 7864, 'n_words': 1475}