Show:

File: ia\ui\FeatureCard.js

/** 
 * A class for rendering a feature card.
 *
 * @author J Clare
 * @class ia.FeatureCard
 * @extends ia.EventDispatcher
 * @constructor
 * @param {String} id The id of the feature card.
 */
ia.FeatureCard = function(id)
{		
	ia.FeatureCard.baseConstructor.call(this);

	this.id = id;
	this.displaySelectedDateOnly = false
	this.ignoreThemeIds = [];
	this.ignoreIndicatorIds = [];
	this.displayThemeHeader = false;
	this.displayFeatureHeader = false;
	this.displayMode = "All themes";
	this.dataOrder = "Order data by feature";
	this._renderTimeout = null;
	
	this._featureIds = [];	// A list of feature ids.

	this.container  = $j("<div id='"+id+"' class='ia-feature-card-scrollbox'>");
	this._scrollBox = new ia.ScrollBox(this.container);
	this.$content  = $j("<div>"); // Div to contain the html.
	this.container.append(this.$content);

	// Text substitution.
	this._textSubstitution = new ia.TextSubstitution();

	// Load the html snippet.
	this._snippet = "";	
};
ia.extend(ia.EventDispatcher, ia.FeatureCard);

/** 
 * The id.
 * 
 * @property id
 * @type String
 */
ia.FeatureCard.prototype.id;

/**
 * Specifies a geography.
 * 
 * @property geography
 * @type ia.Geography
 */
ia.FeatureCard.prototype.geography;

/**
 * Specifies a selected indicator.
 * 
 * @property indicator
 * @type ia.Indicator
 */
ia.FeatureCard.prototype.indicator;

/**
 * Display indicators for selected date only?
 * 
 * @property displaySelectedDateOnly
 * @type Boolean
 * @default false
 */
ia.FeatureCard.prototype.displaySelectedDateOnly;

/**
 * The container that holds the object.
 * 
 * @property container
 * @type JQUERY Element
 */
ia.FeatureCard.prototype.container;

/**
 * The themes to ignore.
 * 
 * @property ignoreThemeIds
 * @type String[]
 */
ia.FeatureCard.prototype.ignoreThemeIds;

/**
 * The indicators to ignore.
 * 
 * @property ignoreIndicatorIds
 * @type String[]
 */
ia.FeatureCard.prototype.ignoreIndicatorIds;

/**
 * Should theme headers be displayed.
 * 
 * @property displayThemeHeader
 * @type Boolean
 * @default false
 */
ia.FeatureCard.prototype.displayThemeHeader;

/**
 * Should feature headers be displayed.
 * 
 * @property displayFeatureHeader
 * @type Boolean
 * @default false
 */
ia.FeatureCard.prototype.displayFeatureHeader;

/**
 * The display mode.
 * 
 * @property displayMode
 * @type String
 * @default "All themes"
 */
ia.FeatureCard.prototype.displayMode;

/**
 * The list mode.
 * 
 * @property dataOrder
 * @type String
 * @default "Order data by feature"
 */
ia.FeatureCard.prototype.dataOrder;

/**
 * Sets the snippet.
 *
 * @method setSnippet
 * @param {String} url The path to the html snippet. 
 * @param {Function} callbackFunction Called once snippet has loaded. 
 */
ia.FeatureCard.prototype.setSnippet = function(url, callbackFunction) 
{
	var me = this;
	if (url !== "" && url !== undefined) 
	{
		me._snippet = url;

		// Check for html file - otherwise its a blob of html.
		if (me._snippet.indexOf(".htm") !== -1 && me._snippet.indexOf("href=") === -1)
		{
			ia.File.load(
			{
				url: url,
				dataType: "html", 
				onSuccess:function(data)
				{
					me._snippet = data;
					if (callbackFunction !== undefined) callbackFunction.call(null);
				}
			});
		}
		else if (callbackFunction !== undefined) callbackFunction.call(null);
	}
	else if (callbackFunction !== undefined) callbackFunction.call(null);
};

/**
 * Renders the repeater.
 *
 * @method render
 */
ia.FeatureCard.prototype.render = function() 
{	
	this._renderTimeout = null;
	var me = this;

	if (this._snippet !== "")	
	{
		// Empty the previous content.
		this.$content.empty();
		me._textSubstitution.clearVariables();

		var listByFeature = true;
		if (me.dataOrder !== "Order data by feature") listByFeature = false;

		// Reverse selection so last selected feature is top of list.
		var ids = this._featureIds.concat().reverse();
		if (this.displaySelectedDateOnly) 
		{
			if (listByFeature) data = this.geography.getFeatureData(ids, this.indicator.date);
			else data = this.geography.getIndicatorData(ids, this.indicator.date);
		}
		else 
		{
			if (listByFeature) data = this.geography.getFeatureData(ids);
			else data = this.geography.getIndicatorData(ids);
		}

		if (listByFeature) this._renderFeatureList(data);
		else this._renderIndicatorList(data);
	
		this._scrollBox.refresh();
	}
};

/**
 * Renders the feature list.
 *
 * @method _renderFeatureList
 * @param {JSON} data The JSON data.
 */
ia.FeatureCard.prototype._renderFeatureList = function(data) 
{	
	var me = this;
	me._textSubstitution.setVariable("geog-id", data.id);
	me._textSubstitution.setVariable("geog-name", data.name);

	// Features.
	var features = data.features;
	$j.each(features, function(fIndex, feature)
	{		
		me._textSubstitution.setVariable("feature-id", feature.id);
		me._textSubstitution.setVariable("feature-name", feature.name);
		me._textSubstitution.setVariable("feature-href", feature.href);
		me._textSubstitution.setVariable("feature-index", fIndex);
		$j.each(feature.properties, function(i, prop)
		{
			me._textSubstitution.setVariable(prop.name+"-value", prop.value);
		});

		var $featureCard = $j("<div class='ia-feature-card'>");
		me.$content.append($featureCard);

		// Feature header.
		if (me.displayFeatureHeader)
		{
			var $featureHeader = $j("<div id='"+feature.id+"' class='ia-feature-card-header'>").html(feature.name);
			$featureCard.append($featureHeader);
		}

		// Themes.
		var themes = feature.themes;
		$j.each(themes, function(tIndex, theme)
		{

			var includeTheme = true;
			if (me.displayMode === "Selected theme only") // Test if this is selected theme.
			{	
				if (me.indicator.theme.id !== theme.id) includeTheme = false;
			}
			else // Test if theme is ignored.
			{
				for (var i = 0; i < me.ignoreThemeIds.length; i++) 
				{
					if (theme.id === me.ignoreThemeIds[i])
					{
						includeTheme = false;
						break;
					}
				}
			}

			if (includeTheme)
			{
				me._textSubstitution.setVariable("theme-id", theme.id);
				me._textSubstitution.setVariable("theme-name", theme.name);
				me._textSubstitution.setVariable("theme-index", tIndex);

				if (me.displayThemeHeader && theme.indicators.length > 0)
				{
					// Theme row.
					if (me.displayMode === "Selected indicator only") 
					{
						var containsIndicator = false;
						var indicators = theme.indicators;
						$j.each(indicators, function(iIndex, indicator)
						{
							if (me.indicator.id === indicator.id) containsIndicator = true
						});
						if (containsIndicator === true)
						{
							var $themeHeader = $j("<div id='"+theme.id+"' class='ia-feature-card-sub-header'>").html(theme.name);
							$featureCard.append($themeHeader);
						}
					}
					else
					{
						var $themeHeader = $j("<div id='"+theme.id+"' class='ia-feature-card-sub-header'>").html(theme.name);
						$featureCard.append($themeHeader);
					}
				}

				var $themeContainer = $j("<div class='ia-feature-card-content'>");
				$featureCard.append($themeContainer);

				// Indicators.
				var indicators = theme.indicators;

				// Keep track of dates.
				var dateIndex;
				var prevId = "";

				$j.each(indicators, function(iIndex, indicator)
				{
					var includeIndicator = true;
					if (me.displayMode === "Selected indicator only") // Test if this is selected indicator.
					{	
						if (me.indicator.id !== indicator.id) includeIndicator = false;
					}
					else // Test if indicator is ignored.
					{
						for (var i = 0; i < me.ignoreIndicatorIds.length; i++) 
						{
							if (indicator.id === me.ignoreIndicatorIds[i])
							{
								includeIndicator = false;
								break;
							}
						}
					}

					if (includeIndicator)
					{
						me._textSubstitution.setVariable("indicator-id", indicator.id);
						me._textSubstitution.setVariable("indicator-name", indicator.name);
						me._textSubstitution.setVariable("indicator-index", iIndex);
						me._textSubstitution.setVariable("indicator-type", indicator.type);
						me._textSubstitution.setVariable("indicator-href", indicator.href);
						me._textSubstitution.setVariable("indicator-formatted-value", indicator.formattedValue);
						me._textSubstitution.setVariable("indicator-date", indicator.date);
						if (indicator.id !== prevId)
						{
							prevId = indicator.id;
							dateIndex = 0;
						}
						me._textSubstitution.setVariable("indicator-date-index", dateIndex);
						dateIndex++;

						if ((indicator.value === "null") 
							|| (indicator.value === null) 
							|| (indicator.value === "NaN") 
							|| (indicator.value === "") 
							|| (indicator.value === "No Data") 
							|| (indicator.value === undefined)) 
							me._textSubstitution.setVariable("indicator-value", "");
						else
							me._textSubstitution.setVariable("indicator-value", indicator.value);

						$j.each(indicator.associates, function(i, associate)
						{
							me._textSubstitution.setVariable(associate.name+"-value", associate.value);
							me._textSubstitution.setVariable(associate.name+"-formatted-value", associate.formattedValue);
							me._textSubstitution.setVariable(associate.name+"-type", associate.type);
						});
						$j.each(indicator.properties, function(i, prop)
						{
							me._textSubstitution.setVariable(prop.name+"-value", prop.value);
						});
						if (indicator.lowerLimit) 
						{
							me._textSubstitution.setVariable("lower-limit-value", indicator.lowerLimit.value);
							me._textSubstitution.setVariable("lower-limit-formatted-value", indicator.lowerLimit.formattedValue);
						}
						if (indicator.upperLimit) 
						{
							me._textSubstitution.setVariable("upper-limit-value", indicator.upperLimit.value);
							me._textSubstitution.setVariable("upper-limit-formatted-value", indicator.upperLimit.formattedValue);
						}

						var msg = me._textSubstitution.formatMessage(me._snippet);
						$themeContainer.append(msg);
					}
				});
			}
		});
	});
};

/**
 * Renders the indicator list.
 *
 * @method _renderIndicatorList
 * @param {JSON} data The JSON data.
 */
ia.FeatureCard.prototype._renderIndicatorList = function(data) 
{	
	var me = this;
	me._textSubstitution.setVariable("geog-id", data.id);
	me._textSubstitution.setVariable("geog-name", data.name);

	// Themes.
	var themes = data.themes;
	$j.each(themes, function(tIndex, theme)
	{
		var includeTheme = true;
		if (me.displayMode === "Selected theme only") // Test if this is selected theme.
		{	
			if (me.indicator.theme.id !== theme.id) includeTheme = false;
		}
		else // Test if theme is ignored.
		{
			for (var i = 0; i < me.ignoreThemeIds.length; i++) 
			{
				if (theme.id === me.ignoreThemeIds[i])
				{
					includeTheme = false;
					break;
				}
			}
		}

		if (includeTheme)
		{
			var $featureCard = $j("<div class='ia-feature-card'>");
			me.$content.append($featureCard);

			me._textSubstitution.setVariable("theme-id", theme.id);
			me._textSubstitution.setVariable("theme-name", theme.name);
			me._textSubstitution.setVariable("theme-index", tIndex);

			if (me.displayThemeHeader && theme.indicators.length > 0)
			{
				// Theme row.
				if (me.displayMode === "Selected indicator only") 
				{
					var containsIndicator = false;
					var indicators = theme.indicators;
					$j.each(indicators, function(iIndex, indicator)
					{
						if (me.indicator.id === indicator.id) containsIndicator = true
					});
					if (containsIndicator === true)
					{
						var $themeHeader = $j("<div id='"+theme.id+"' class='ia-feature-card-header'>").html(theme.name);
						$featureCard.append($themeHeader);
					}
				}
				else
				{
					var $themeHeader = $j("<div id='"+theme.id+"' class='ia-feature-card-header'>").html(theme.name);
					$featureCard.append($themeHeader);
				}
			}

			var $themeContainer = $j("<div class='ia-feature-card-content'>");
			$featureCard.append($themeContainer);

			// Indicators.
			var indicators = theme.indicators;

			// Keep track of dates.
			var dateIndex;
			var prevId = "";

			$j.each(indicators, function(iIndex, indicator)
			{
				var includeIndicator = true;
				if (me.displayMode === "Selected indicator only") // Test if this is selected indicator.
				{	
					if (me.indicator.id !== indicator.id) includeIndicator = false;
				}
				else // Test if indicator is ignored.
				{
					for (var i = 0; i < me.ignoreIndicatorIds.length; i++) 
					{
						if (indicator.id === me.ignoreIndicatorIds[i])
						{
							includeIndicator = false;
							break;
						}
					}
				}

				if (includeIndicator)
				{
					// Feature header.
					if (me.displayFeatureHeader)
					{
						var $featureHeader = $j("<div id='"+indicator.id+"' class='ia-feature-card-sub-header'>").html(indicator.name);
						$themeContainer.append($featureHeader);
					}

					me._textSubstitution.setVariable("indicator-id", indicator.id);
					me._textSubstitution.setVariable("indicator-name", indicator.name);
					me._textSubstitution.setVariable("indicator-index", iIndex);
					me._textSubstitution.setVariable("indicator-type", indicator.type);
					me._textSubstitution.setVariable("indicator-href", indicator.href);
					me._textSubstitution.setVariable("indicator-date", indicator.date);
					if (indicator.id !== prevId)
					{
						prevId = indicator.id;
						dateIndex = 0;
					}
					me._textSubstitution.setVariable("indicator-date-index", dateIndex);
					dateIndex++;

					$j.each(indicator.properties, function(i, prop)
					{
						me._textSubstitution.setVariable(prop.name+"-value", prop.value);
					});

					// Features.
					var features = indicator.features;
					$j.each(features, function(fIndex, feature)
					{		
						me._textSubstitution.setVariable("feature-id", feature.id);
						me._textSubstitution.setVariable("feature-name", feature.name);
						me._textSubstitution.setVariable("feature-href", feature.href);
						me._textSubstitution.setVariable("feature-index", fIndex);

						me._textSubstitution.setVariable("indicator-formatted-value", feature.formattedValue);
						if ((feature.value === "null") 
							|| (feature.value === null) 
							|| (feature.value === "NaN") 
							|| (feature.value === "") 
							|| (feature.value === "No Data") 
							|| (feature.value === undefined)) 
							me._textSubstitution.setVariable("indicator-value", "");
						else
							me._textSubstitution.setVariable("indicator-value", feature.value);

						$j.each(feature.properties, function(i, prop)
						{
							me._textSubstitution.setVariable(prop.name+"-value", prop.value);
						});
						$j.each(feature.associates, function(i, associate)
						{
							me._textSubstitution.setVariable(associate.name+"-value", associate.value);
							me._textSubstitution.setVariable(associate.name+"-formatted-value", associate.formattedValue);
							me._textSubstitution.setVariable(associate.name+"-type", associate.type);
						});
						if (feature.lowerLimit) 
						{
							me._textSubstitution.setVariable("lower-limit-value", feature.lowerLimit.value);
							me._textSubstitution.setVariable("lower-limit-formatted-value", feature.lowerLimit.formattedValue);
						}
						if (feature.upperLimit) 
						{
							me._textSubstitution.setVariable("upper-limit-value", feature.upperLimit.value);
							me._textSubstitution.setVariable("upper-limit-formatted-value", feature.upperLimit.formattedValue);
						}

						var msg = me._textSubstitution.formatMessage(me._snippet);
						$themeContainer.append(msg);
					});
				}
			});
		}
	});
};

/** 
 * Triggers a render. Prevents over rendering which results in a frozen browser.
 *
 * @method _triggerRender
 * @private
 */
ia.FeatureCard.prototype._triggerRender = function()
{
	if (!this._renderTimeout) 
	{
		this._renderTimeout = setTimeout(function()
		{
			this.render()
		}.bind(this), 5);
	}
};

/**
 * Selects.
 *
 * @method select
 * @param {String} id The id of the item.
 */
ia.FeatureCard.prototype.select = function(id) 
{
	var index = this._featureIds.indexOf(id);
	if (index === -1) this._featureIds.push(id);
	this._triggerRender();
};

/**
 * Unselects.
 *
 * @method unselect
 * @param {String} id The id of the item.
 */
ia.FeatureCard.prototype.unselect = function(id) 
{
	var index = this._featureIds.indexOf(id);
	if (index !== -1) this._featureIds.splice(index, 1);
	this._triggerRender();
};

/**
 * Clears all selections.
 *
 * @method clearSelection
 */
ia.FeatureCard.prototype.clearSelection = function() 
{	
	this._featureIds = [];
	this._triggerRender();
};

/**
 * Highlights the legend class that contains the given id.
 *
 * @method highlight
 * @param {String} id The id of the item.
 */
ia.FeatureCard.prototype.highlight = function(id) {};

/**
 * Clears all highlights.
 *
 * @method clearHighlight
 */
ia.FeatureCard.prototype.clearHighlight = function() {};