API Docs for: 1.0.0
Show:

File: src/gallery-layout-rows/js/PageLayoutRows.js

"use strict";

var has_no_recalc_auto_bug    = (0 < Y.UA.ie && Y.UA.ie < 8),
	has_explosive_modules_bug = (0 < Y.UA.ie && Y.UA.ie < 8),
	is_borked_dom_access      = (0 < Y.UA.ie && Y.UA.ie < 8);

/**
 * PageLayout plugin for managing vertically stacked rows on a page,
 * sandwiched vertically between header and footer.  Each row contains one
 * or more modules.
 * 
 * @module gallery-layout
 * @submodule gallery-layout-rows
 */

Y.namespace('PageLayoutRows');

// must be done after defining Y.PageLayoutRows

Y.PageLayoutRows.collapse_classes =
{
	vert_parent_class:       Y.PageLayout.module_rows_class,
	horiz_parent_class:      Y.PageLayout.module_class,
	collapse_parent_pattern: Y.PageLayout.expand_vert_nub_class
};

function adjustHeight(
	/* int */		total_height,
	/* object */	children)
{
	var h = total_height;

	if (is_borked_dom_access)
	{
		var access_dom_so_it_will_be_right_next_time = children.bd.get('offsetHeight');
	}

	var b = children.root.get('offsetHeight') - children.bd.get('offsetHeight');

	if (children.hd)
	{
		h -= children.hd.get('offsetHeight');
		b -= children.hd.get('offsetHeight');
	}
	if (children.ft)
	{
		h -= children.ft.get('offsetHeight');
		b -= children.ft.get('offsetHeight');
	}

	h -= b;

	h -= children.bd.vertMarginBorderPadding();

	return Math.max(h, Y.PageLayout.min_module_height);
}

function getWidth(
	/* int */		body_width,
	/* array */		col_widths,
	/* int */		row_index,
	/* int */		col_index,
	/* object */	module,
	/* object */	module_info)
{
	module_info.mbp = module.horizMarginBorderPadding();
	return Math.max(1, Math.floor(body_width * col_widths[ row_index ][ col_index ] / 100.0) - module_info.mbp);
}

Y.PageLayoutRows.resize = function(
	/* enum */			mode,
	/* int */			body_width,
	/* int */			body_height)
{
	var row_count = this.body_info.outers.size();

	// reset module heights
	// adjust for horizontally collapsed or fixed width modules

	var col_widths = [],
		row_widths = [];
	for (var i=0; i<row_count; i++)
	{
		var widths = this.body_info.inner_sizes[i].slice(0);
		col_widths.push(widths);
		row_widths.push(body_width);

		var uncollapsed_count = 0,
			sum               = 0;

		var modules = this.body_info.modules[i];
		var count   = modules.size();
		for (var j=0; j<count; j++)
		{
			var module = modules.item(j);
			module.setStyle('height', 'auto');
			if (module.hasClass(Y.PageLayout.collapsed_horiz_class))
			{
				if (has_no_recalc_auto_bug)
				{
					module.setStyle('display', 'none');
				}
				module.setStyle('width', 'auto');
				if (has_no_recalc_auto_bug)
				{
					module.setStyle('display', 'block');
				}
				widths[j]      = - module.get('offsetWidth');
				row_widths[i] -= module.totalWidth();
			}
			else if (widths[j] > 0)
			{
				uncollapsed_count++;
				sum += widths[j];
			}
		}

		if (uncollapsed_count < count)
		{
			for (var j=0; j<count; j++)
			{
				if (widths[j] > 0)
				{
					widths[j] *= (100.0 / sum);
				}
			}
		}
	}

	// smart fit:  if only one module, fit-to-content until it won't fit inside viewport

	var module_info = {};
	if (this.single_module)
	{
		var module   = this.body_info.modules[0].item(0);
		var children = module._page_layout.children;
		if (children.bd)
		{
			var w  = getWidth(row_widths[0], col_widths, 0, 0, module, module_info);
			var w1 = Math.max(1, w - children.bd.horizMarginBorderPadding());
			this.fire('beforeResizeModule', { bd: children.bd, height: 'auto', width: w1 });
			this._setWidth(children, w);
			children.root.setStyle('height', 'auto');
			children.bd.setStyle('height', 'auto');
		}

		var h = module.totalHeight();
		mode  = (h > body_height ? Y.PageLayout.FIT_TO_VIEWPORT : Y.PageLayout.FIT_TO_CONTENT);

		this.body_container.removeClass('FIT_TO_[A-Z_]+');
	}

	// fit-to-content:  compute height of each row; requires setting module widths
	// fit-to-viewport: adjust for vertically collapsed modules

	if (mode === Y.PageLayout.FIT_TO_CONTENT)
	{
		var row_heights = [];
		for (var i=0; i<row_count; i++)
		{
			this.body_info.outers.item(i).setStyle('height', 'auto');

			var modules    = this.body_info.modules[i];
			var h          = 0;
			var total_w    = 0;
			var open_count = modules.size();
			var count      = open_count;
			for (var j=0; j<count; j++)
			{
				var w      = col_widths[i][j];
				var module = modules.item(j);
				if (w < 0)
				{
					var total_w_hacked = false;
					if (w == Y.PageLayout.unmanaged_size && has_explosive_modules_bug)
					{
						var children = module._page_layout.children;
						if (children.bd)
						{
							var bd_w = children.bd.totalWidth();
							total_w += bd_w + module.horizMarginBorderPadding();
							total_w_hacked = true;

							children.root.setStyle('width', bd_w+'px');
						}
					}

					if (!total_w_hacked)
					{
						total_w += module.totalWidth();
					}
					open_count--;
				}
			}

			var k = 0;
			for (var j=0; j<count; j++)
			{
				var w      = col_widths[i][j];
				var module = modules.item(j);
				if (w < 0)
				{
					if (w == Y.PageLayout.unmanaged_size)
					{
						var children = module._page_layout.children;
						if (children.bd)
						{
							children.root.setStyle('height', 'auto');
							children.bd.setStyle('height', 'auto');
						}

						h = Math.max(h, module.get('offsetHeight'));
					}
					continue;
				}
				k++;

				var children = module._page_layout.children;
				if (children.bd)
				{
					var w    = getWidth(row_widths[i], col_widths, i, j, module, module_info);
					total_w += w + module_info.mbp;

					if (k == open_count)
					{
						w += body_width - total_w;
					}

					var w1 = Math.max(1, w - children.bd.horizMarginBorderPadding());
					this.fire('beforeResizeModule', { bd: children.bd, height: 'auto', width: w1 });
					this._setWidth(children, w);
					children.root.setStyle('height', 'auto');
					children.bd.setStyle('height', 'auto');
				}

				h = Math.max(h, module.get('offsetHeight'));
			}

			row_heights.push(h);
		}
	}
	else
	{
		var row_heights = this.body_info.outer_sizes.slice(0);

		var uncollapsed_count = 0,
			sum               = 0;
		for (var i=0; i<row_count; i++)
		{
			var row       = this.body_info.outers.item(i);
			var collapsed = row.hasClass(Y.PageLayout.collapsed_vert_class);
			if (collapsed || row_heights[i] < 0)
			{
				row_heights[i] = 0;
				if (collapsed)
				{
					row.setStyle('height', 'auto');
				}

				// We cannot compute the height of row directly
				// because the row above might be wrapping.

				body_height -= row.one('*').totalHeight();
				body_height -= row.vertMarginBorderPadding();
			}
			else
			{
				uncollapsed_count++;
				sum += row_heights[i];
			}
		}

		if (uncollapsed_count < row_count)
		{
			for (var i=0; i<row_count; i++)
			{
				row_heights[i] *= (100.0 / sum);
			}
		}
	}

	// set height of each row and size of each module

	for (var i=0; i<row_count; i++)
	{
		if (mode === Y.PageLayout.FIT_TO_CONTENT)
		{
			var h = row_heights[i];
		}
		else
		{
			if (row_heights[i] === 0)
			{
				var module   = this.body_info.modules[i].item(0);
				var children = module._page_layout.children;
				if (children.bd)
				{
					var h1 = children.bd.insideHeight();
					var w  = getWidth(row_widths[i], col_widths, i, 0, module, module_info);
					var w1 = Math.max(1, w - children.bd.horizMarginBorderPadding());
					this.fire('beforeResizeModule', { bd: children.bd, height: h1, width: w1 });
					this._setWidth(children, w);
					this.fire('afterResizeModule', { bd: children.bd, height: h1, width: w1 });
				}
				continue;
			}

			var h = Math.max(1, Math.floor(body_height * row_heights[i] / 100.0) - this.body_info.outers.item(i).vertMarginBorderPadding());
		}
		this.body_info.outers.item(i).setStyle('height', h+'px');

		// adjust for horizontally collapsed or fixed width modules

		var modules    = this.body_info.modules[i];
		var total_w    = 0;
		var open_count = modules.size();
		var count      = open_count;
		for (var j=0; j<count; j++)
		{
			var w      = col_widths[i][j];
			var module = modules.item(j);
			if (w < 0)
			{
				var total_w_hacked = false;
				if (w == Y.PageLayout.unmanaged_size)
				{
					var children = module._page_layout.children;
					if (children.bd)
					{
						var h1 = adjustHeight(h, children);
						var w1 = children.bd.insideWidth();
						this.fire('beforeResizeModule', { bd: children.bd, height: h1, width: w1 });
						children.bd.setStyle('height', h1+'px');

						if (has_explosive_modules_bug)
						{
							var bd_w = children.bd.totalWidth();
							total_w += bd_w + module.horizMarginBorderPadding();
							total_w_hacked = true;

							children.root.setStyle('width', bd_w+'px');
						}

						this.fire('afterResizeModule', { bd: children.bd, height: h1, width: w1 });
					}
				}
				else
				{
					module.setStyle('height', Math.max(1, h - module.vertMarginBorderPadding())+'px');
				}

				if (!total_w_hacked)
				{
					total_w += module.totalWidth();
				}
				open_count--;
			}
		}

		// set the size of each module

		var k = 0;
		for (var j=0; j<count; j++)
		{
			if (col_widths[i][j] < 0)
			{
				continue;
			}
			k++;

			var module   = modules.item(j);
			var children = module._page_layout.children;
			if (children.bd)
			{
				var h1   = adjustHeight(h, children);
				var w    = getWidth(row_widths[i], col_widths, i, j, module, module_info);
				total_w += w + module_info.mbp;

				if (k == open_count)
				{
					w += body_width - total_w;
				}

				var w1 = Math.max(1, w - children.bd.horizMarginBorderPadding());
				if (mode === Y.PageLayout.FIT_TO_VIEWPORT)
				{
					this.fire('beforeResizeModule', { bd: children.bd, height: h1, width: w1 });
					this._setWidth(children, w);
				}

				children.bd.setStyle('height', h1+'px');

				this.fire('afterResizeModule', { bd: children.bd, height: h1, width: w1 });
			}
		}
	}
};