<extension>
	<title>Guerric's Extensions</title>
	<label>G's</label>
	<description>This extension contains functions created by Guerric.</description>
	<uri.help>http://wiki.developer.mindtouch.com/User:Guerric</uri.help>
	<namespace>GS</namespace>


	<function>
		<name>msn</name>
		<description>MSN Email Link</description>
		<param name="email" type="str">MSN Email</param>
		<param name="text" type="str">Link Text</param>
		<return>
			<html xmlns:eval="http://mindtouch.com/2007/dekiscript">
				<body>
					<a eval:href="'msnim:add?contact=' .. args.email" rel="custom"><eval:expr>args.text</eval:expr></a>
				</body>
			</html>
		</return>
	</function>

	<function>
		<name>iframeLink</name>
		<description>Allows a link to be embedded that opens in an iframe</description>
		<param name="href" type="str">Url</param>
		<param name="text" type="str" optional="true">Link Text (default: args.href)</param>
		<param name="width" type="num" optional="true">Width of the iframe (default: 700)</param>
		<param name="height" type="num" optional="true">Height of the iframe (default: 500)</param>
		<return>
			<html xmlns:eval="http://mindtouch.com/2007/dekiscript">
				<head>
					<script type="text/javascript" src="/skins/common/jquery/thickbox/thickbox.js"></script>
				</head>
				<body>
					<a onclick="tb_show(this.title, this.href, false); return false;" eval:href="uri.appendquery(args.href, {'KeepThis':'true','TB_iframe':'true','height':args.height ?? 500,'width':args.width ?? 700})" eval:title="args.text ?? args.href" rel="false"><eval:expr>args.text ?? args.href</eval:expr></a>
				</body>
			</html>
		</return>
	</function>

	<function>
		<name>sectionExpand</name>
		<description>Hides section contents until the section heading is clicked. (Side-effect: disables section editing)</description>
		<param name="tag" type="str" optional="true">Defines which heading elements should be collapsed. (default: "h3")</param>
		<param name="useStyles" type="bool" optional="true">If set to "false" then no styles are inlined allowing custom styles. (default: "true")</param>
		<return>
			<html xmlns:eval="http://mindtouch.com/2007/dekiscript">
				<head>
					<script type="text/javascript">
						var GS = GS ? GS : [];
						GS.sectionExpand = function(tag)
						{
							// set allowed tags here
							if (!String(tag).match('h[1-6]'))
							{
								tag = 'h3'; // default
							}
							// create some new dom elements
							DekiWiki.$('#page-top ' + tag).each(function()
							{
								var $This = DekiWiki.$(this);

								// create the new element
								var el = document.createElement(tag);
								var title = $This.find('span:first').text();
								if (title == '')
								{
									title = $This.text();
								}
								// need to build the dom for no-edit state
								DekiWiki.$(el).append('&lt;span /&gt;')
									.find('*:first').text(title).addClass('gs-sectionExpander')
									.parent().addClass('gs-sectionExpand');
								// don't show the normal heading
								$This.hide();
								// add the new heading
								this.parentNode.parentNode.insertBefore(el, this.parentNode);

								// create the new div element
								el = document.createElement('div');
								el.setAttribute('class', 'gs-sectionExpand');
								$This.parent().wrap(el).parent().hide();
							});

							// attach an event listener to the heading elements
							DekiWiki.$('#page-top '+ tag +'.gs-sectionExpand').click(function()
							{
								DekiWiki.$(this).toggleClass('gs-sectionExpanded').next('div.gs-sectionExpand').toggle();
							});
						};
					</script>
					
					<eval:if test="args.useStyles ?? true">
						<style type="text/css">
							div.gs-sectionExpand {
								cursor: default;
								background: none;
							}
							h1.gs-sectionExpand,
							h2.gs-sectionExpand,
							h3.gs-sectionExpand,
							h4.gs-sectionExpand,
							h5.gs-sectionExpand,
							h6.gs-sectionExpand {
								cursor: pointer;
							}

							.gs-sectionExpand span.gs-sectionExpander {
								padding-right: 20px;
								background: transparent url('/skins/common/images/nav-parent-open.gif') no-repeat center right;
							}
							.gs-sectionExpanded span.gs-sectionExpander {
								background: transparent url('/skins/common/images/nav-parent-docked.gif') no-repeat center right;
							}
						</style>
					</eval:if>
				</head>
				<body />
				<tail>
					<script type="text/javascript">
						GS.sectionExpand(<eval:js>args.tag ?? ''</eval:js>);
					</script>
				</tail>
			</html>
		</return>
	</function>

	<function transform="p,div">
		<name>blockCollapse</name>
		<description>Hides an entire block element's contents.</description>
		<param name="element" type="str">Do not invoke this method directly. Use it as a transformation unless you are running prelyons.</param>
		<param name="prelyons" type="bool" optional="true">If you set this to true, then you must invoke this function on the page. (Default: false)</param>
		<return>
			<html xmlns:eval="http://mindtouch.com/2007/dekiscript">
				<head>
					<style type="text/css">
						.gs-blockCollapse {
							border-right: solid 2px #ccc;
							border-bottom: solid 2px #ccc;
							background: transparent url('/skins/common/images/nav-parent-open.gif') no-repeat top left;

							padding-top: 8px;
							cursor: pointer;
						}

						.gs-blockCollapse-expanded {
							background: transparent url('/skins/common/images/nav-parent-docked.gif') no-repeat top left;
						}

						.gs-blockCollapse-element {
							display: none;
						}
					</style>
				</head>
				<body>
					<eval:if test="!(args.prelyons ?? false)">
						<div eval:id="@expand" class="gs-blockCollapse">
							<eval:expr>web.html(addClass(args.element, 'gs-blockCollapse-element'));</eval:expr>
						</div>
					</eval:if>
				</body>
				<tail>
					<script type="text/javascript">
						<eval:if test="(args.prelyons ?? false)">
							// create the wrapping divs around paragrpahs with class="collapse"
							var el = document.createElement('div');
							DekiWiki.$(el).addClass('gs-blockCollapse');

							DekiWiki.$('p.collapse').addClass('gs-blockCollapse-element').wrap(el);
						</eval:if>

						// hook the expand/contract event to interested parties
						DekiWiki.$('.gs-blockCollapse').click(function()
						{
							DekiWiki.$(this).toggleClass('gs-blockCollapse-expanded')
								.children(':first').toggle();
						});
					</script>
				</tail>
			</html>
		</return>
	</function>


	<function transform="table">
		<name>tableChart</name>
		<description>Converts a simple table into a line chart (Requires open-flash-chart 2.0)</description>
		<param name="table" type="str">Table markup to build a chart against</param>
		<param name="chartWidth" type="num" optional="true">Defines the chart width (default: 100%)</param>
		<return>
			<html xmlns:eval="http://mindtouch.com/2007/dekiscript">
				<head>
					<script type="text/javascript" src="/deki/gui/ofc/swfobject.js"></script>
					<script type="text/javascript">
						var GS = GS ? GS : [];
						GS.tableChart = function(sChartId, sTableId, sTable)
						{
							// create the table in the DOM
							var elTable = document.getElementById(sTableId);
							elTable.innerHTML = sTable;
							
							// create the chart
							swfobject.embedSWF(
								"/deki/gui/ofc/open-flash-chart.swf", sChartId,
								<eval:js>args.chartWidth ?? '100%'</eval:js>, "400", 
								"9.0.0",
								"expressInstall.swf",
								{"get-data": "GS.buildTableData", 'id': sTableId}
							);
						};

						GS.buildTableData = function(sId)
						{
							var aLabelsX = [];
							var aLabelsY = [];
							var aColorsY = [];
							// 2-dim array for each line
							var aValues = [];

							var oTable = DekiWiki.$('#' + sId).find('table');
							
							// get details from the table
							var sTitle = oTable.find('caption').text();

							// regex for parsing the rgb notation
							var rRgb = /rgb\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/;
							oTable.find('tr th').each(function(i)
							{
								// first column is X values
								if (i != 0)
								{
									aLabelsY[i-1] = $(this).text();
									sColor = $(this).find('span').css('color');

									if (sColor &amp;&amp; String(sColor).substring(0, 3) == 'rgb')
									{
										// parse the RGB css notation
										aSplit = rRgb.exec(sColor);
										if (aSplit.length == 4)
										{
											sColor = '#' +
												GS.decToHex(aSplit[1]) +
												GS.decToHex(aSplit[2]) +
												GS.decToHex(aSplit[3]);
										}
									}
									aColorsY[i-1] = sColor;
								}
							});

							// create 2-dim array by expanding the values array to the number of lines
							for (var i = 0, nLines = oTable.find('tr:first').children().length - 1; i &lt; nLines; i++)
							{
								aValues[i] = [];
							}

							// get data from the table
							oTable.find('tr:has(td)').each(function(i)
							{
								$(this).find('td').each(function(j)
								{
									if (j == 0)
									{
										// get the label
										aLabelsX[i] = $(this).text();
									}
									else
									{
										// convert the cell value to a number
										sTemp = $(this).text();
										val = parseFloat(sTemp.replace(',', ''));

										aValues[j-1][i] = val;
									}
								});
							});

							// process the data retrieved
							var nMax = -1;
							for (var i = 0; i &lt; aValues.length; i++)
							{
								nTemp = GS.findArrayMax(aValues[i]);
								if (nTemp > nMax)
								{
									nMax = nTemp;
								}
							}
							// increase the max by a fractional amount
							nMax = nMax * 1.05;
							var nSteps = parseInt(nMax / 10);
							
							// create the elements array from the values
							var aElements = [];
							for (var i = 0; i &lt; aValues.length; i++)
							{
								aElements[i] = {
									'type': 'line_dot',
									'text': aLabelsY[i],
									'colour': aColorsY[i] ? aColorsY[i] : '',
									'values': aValues[i]
								};
							}

							var oData = {
								'title': {
									'text': sTitle
								},

								'elements': aElements,

								'x_axis': {
									'labels': aLabelsX
								},

								//'y_legend': {
								//	'text': ''
								//},

								'y_axis': {
									'max': nMax,
									'steps': nSteps
								}
							};

							return YAHOO.lang.JSON.stringify(oData);
						};

						GS.decToHex = function(d)
						{
							n = parseInt(d).toString(16);

							return String(n).length &lt; 2 ? '0'+n : n;
						};

						GS.findArrayMax = function(array)
						{
							return Math.max.apply(Math, array);
						};

						GS.findArrayMin = function(array)
						{
							return Math.min.apply(Math, array);
						};
					</script>
				</head>
				<body>
					<div eval:id="@chartId"></div>
					<div eval:id="@tableId"></div>
				</body>
				<tail>
					<script type="text/javascript">
						GS.tableChart(<eval:js>@chartId</eval:js>, <eval:js>@tableId</eval:js>, <eval:js>args.table</eval:js>);
					</script>
				</tail>
			</html>
		</return>
	</function>

	<function transform="li">
		<name>youDoIt</name>
		<description>Let other people know what to do.</description>
		<param name="element" type="str">Should be the html node.</param>
		<param name="delim" type="str" optional="true">Defines the user/task delim for transformed elements (default: ":")</param>
		<return>
			<html xmlns:eval="http://mindtouch.com/2007/dekiscript">
				<head>
					<script type="text/javascript">
						var GS = GS || {};
						GS.youDoIt = {};
						GS.youDoIt.sDelim = ':';
						GS.youDoIt.sUserName = String(<eval:js>user.name</eval:js>).toUpperCase();
	
						DekiWiki.$(document).ready(function()
						{
							var aHtml = [];

							var sMessage = 'or else';

							aHtml.push('&lt;div class="youDoIt"&gt;');
							aHtml.push('&lt;span&gt;' + <eval:js>user.name</eval:js> + ', take care of these... '+ sMessage +'&lt;/span&gt;');
							aHtml.push('&lt;ul&gt;');
							DekiWiki.$('.gs-youDoIt-task').each(function()
							{
								var $this = DekiWiki.$(this);
								// determine the user name for this task
								var text = String($this.text()).replace(/&lt;&#91;^&gt;&#93;*&gt;/g, '');
								var split = text.indexOf(GS.youDoIt.sDelim);
								if (split == -1)
								{
									return;
								}

								u = text.substr(0, split);
								//t = text.substr(split+1, text.length);
								//console.log('Checking user: ' + u);
								if (String(u).toUpperCase() == GS.youDoIt.sUserName)
								{
									aHtml.push('&lt;li&gt;' + $this.text() + '&lt;/li&gt;');
								}
							});
							aHtml.push('&lt;/ul&gt;');
							aHtml.push('&lt;/div&gt;');

							DekiWiki.$('#pageText').prepend(aHtml.join(''));
						});
					</script>
				</head>
				<body>
						<eval:expr>web.html(addClass(args.element, 'gs-youDoIt-task'));</eval:expr>
				</body>
				<tail>
					<eval:if test="args.delim ?? false">
						<script type="text/javascript">GS.youDoIt.sDelim = <eval:js>args.delim</eval:js>;</script>
					</eval:if>
				</tail>
			</html>
		</return>
	</function>

	<function>
		<name>addClass</name>
		<description>Adds a class to an html node (string).</description>
		<param name="element" type="str">Should be the html node.</param>
		<param name="class" type="str">The CSS class to add to the node.</param>
		<return>
			<html xmlns:eval="http://mindtouch.com/2007/dekiscript">
				<body>
					<eval:expr>
						let tagOpen = string.indexOf(args.element, '&gt;');
						let classStart = string.indexOf(args.element, 'class="');

						if (classStart == -1)
						{
							web.html(string.insert(args.element, 'class="' .. args.class .. '"', tagOpen));
						}
						else
						{
							web.html(string.insert(args.element, args.class .. ' ', classStart+7));
						}
					</eval:expr>
				</body>
			</html>
		</return>
	</function>

</extension>