API Docs for: 1.0.0
Show:

File: src/gallery-treeble/js/Treeble.js

/**********************************************************************
 * Treeble displays a tree of data in a table.
 *
 * @module gallery-treeble
 * @main gallery-treeble
 */

/**
 * Extension to DataTable for displaying tree data.
 *
 * @class Treeble
 * @extends DataTable
 * @constructor
 * @param config {Object}
 */
function Treeble()
{
	Treeble.superclass.constructor.apply(this, arguments);
}

Treeble.NAME = "datatable";		// same styling

Treeble.ATTRS =
{
	/**
	 * Object returned by saveOpenState(), used to initialize the open
	 * elements.
	 * 
	 * @attribute openState
	 * @type Object
	 * @writeonce
	 */
	openState:
	{
		writeOnce: true
	},

	/**
	 * Message displayed below the last row if paginating children.  The
	 * message must include `<a href="{href}" class="{css}">` to
	 * provide a link to go to the next page.
	 * 
	 * @attribute moreRowsMessage
	 * @type String
	 */
	moreRowsMessage:
	{
		validator: function(s)
		{
			return (Y.Lang.isString(s) &&
					s.indexOf('<a href="{href}" class="{css}">') >= 0);
		}
	}
};

/**
 * The class added to rows created by this plugin.
 *
 * @property Y.RowExpansion.row_class
 * @type {String}
 * @value "row-expansion"
 */
Treeble.more_row_class = 'row-more-items';

/**
 * Formatter for open/close twistdown.
 *
 * @method twistdownFormatter
 * @static
 * @param send_request {Function} Function that reloads DataTable
 */
Treeble.buildTwistdownFormatter = function(send_request)
{
	return function(o)
	{
		o.td.addClass('treeble-nub');

		var ds  = this.datasource.get('datasource');
		var key = ds.get('root').treeble_config.childNodesKey;

		if (o.data[key])
		{
			var path = o.data._yui_node_path;

			o.td.addClass('row-toggle');
			o.td.replaceClass('row-(open|closed)',
				ds.isOpen(path) ? 'row-open' : 'row-closed');

			YUI.Env.add(o.td.getDOMNode(), 'click', function()
			{
				ds.toggle(path, {}, send_request);
			});

			o.cell.set('innerHTML', '<a class="treeble-expand-nub" href="javascript:void(0);"></a>');
		}

		var more_rows_msg = this.get('moreRowsMessage');
		if (o.rowIndex === 0 && more_rows_msg && ds.get('paginateChildren') &&
			this.paginator && this.paginator.get('paginator').hasNextPage())
		{
			var self  = this,
				tbody = o.td.ancestor('tbody');

			if (this._treeble_more_rows_task)
			{
				this._treeble_more_rows_task.cancel();
			}

			this._treeble_more_rows_task = Y.Lang.later(0, null, function()
			{
				self._treeble_more_rows_task = null;

				var row = tbody.get('lastElementChild'),
					c   = self.getClassName('next-page');

				var row_class =
					row.get('className').indexOf('-even') >= 0 ?
						'yui3-datatable-odd' : 'yui3-datatable-even';

				var more_row = Y.Lang.sub(
					'<tr class="{css}">' +
						'<td colspan="{span}" class="yui3-datatable-cell">{text}</td>' +
					'</tr>',
					{
						css:  row_class + ' ' + Treeble.more_row_class,
						span: row.get('childElementCount'),
						text: Y.Lang.sub(more_rows_msg,
						{
							href: 'javascript:void(0);',
							css:  c
						})
					});

				tbody.append(more_row);

				tbody.one('a.' + c).on('click', function(e)
				{
					e.halt();

					var pg = self.paginator.get('paginator');
					pg.setPage(pg.getCurrentPage() + 1);
				});
			});
		}

		return false;	// discard Y.Node instances
	};
};

/**
 * Default formatter for indented column.
 *
 * @method treeValueFormatter
 * @static
 */
Treeble.treeValueFormatter = function(o)
{
	var depth_class = 'treeble-depth-'+o.data._yui_node_depth;
	o.rowClass     += ' ' + depth_class;
	o.className    += ' treeble-value';
	return '<span class="'+depth_class+'">'+o.value+'</span>';
};

/**
 * Add node id's to an existing openState object.
 *
 * @method augmentOpenState
 * @static
 * @param open_state {Object} opaque object containing the open state of all the nodes
 * @param ids {Array} list of ids to add to the open state
 */
Treeble.augmentOpenState = function(open_state, ids)
{
	if (open_state && Y.Lang.isArray(open_state.ids))
	{
		open_state.ids = open_state.ids.concat(ids);
	}
};

Y.extend(Treeble, Y.DataTable,
{
	plug: function(plugin, config)
	{
		if (plugin.NAME === Y.Plugin.DataTableDataSource.NAME)
		{
			var recordType = this.get('recordType');
			recordType.ATTRS[ config.datasource.get('root').treeble_config.childNodesKey ] = {};
			recordType.ATTRS._yui_node_path  = {};
			recordType.ATTRS._yui_node_depth = {};

			var open_state = this.get('openState');
			if (open_state && Y.Lang.isArray(open_state.ids))
			{
				config.datasource.setOpenNodeIds(open_state.ids);
			}
		}

		Treeble.superclass.plug.apply(this, arguments);
	},

	/**
	 * @method saveOpenState
	 * @return {Object} opaque object containing the open state of all the nodes
	 */
	saveOpenState: function()
	{
		var state =
		{
			ids: this.datasource.get('datasource').getOpenNodeIds()
		};
		return state;
	}
});

Y.Treeble = Treeble;