<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Foliotek Development Blog</title>
	<atom:link href="http://www.foliotek.com/devblog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.foliotek.com/devblog</link>
	<description></description>
	<lastBuildDate>Fri, 20 Jan 2012 21:47:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>Copy Images from Clipboard in Javascript</title>
		<link>http://www.foliotek.com/devblog/copy-images-from-clipboard-in-javascript/</link>
		<comments>http://www.foliotek.com/devblog/copy-images-from-clipboard-in-javascript/#comments</comments>
		<pubDate>Fri, 20 Jan 2012 16:24:41 +0000</pubDate>
		<dc:creator>Aaron</dc:creator>
				<category><![CDATA[AJAX]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://www.foliotek.com/devblog/?p=1348</guid>
		<description><![CDATA[One of the pretty common in a Windows environment is copy/pasting image data across programs. In recent versions of chrome, this is now possible in the browser. Here is a quick demo of the javascript we&#8217;ll be starting from &#8212; you can copy image data from anywhere (Paint, Word, Screenshot, etc) and paste it into [...]]]></description>
			<content:encoded><![CDATA[<p>One of the pretty common in a Windows environment is copy/pasting image data across programs. In recent versions of chrome, this is now possible in the browser. Here is a quick demo of the javascript we&#8217;ll be starting from &#8212; you can copy image data from anywhere (Paint, Word, Screenshot, etc) and paste it into the div to have it appended.</p>
<p><a href="http://jsfiddle.net/H9wgv/">http://jsfiddle.net/H9wgv/</a></p>
<p>This just appends an image that looks something like:</p>
<pre class="brush:xml">&lt;img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIkAAAAqCAYAAACHr...C"&gt;</pre>
<p>Which is pretty powerful in it&#8217;s own right, but it&#8217;s not terribly well supported across browsers &#8211; for Foliotek Presentation, ideally we would create a file they can manage just like any of their other files from the paste data, so, with a quick change to the reader.onload, we&#8217;ll upload the image to the server:</p>
<pre class="brush:js">reader.onload = function(evt) {

var result = evt.target.result;
var arr = result.split(",");
var data = arr[1]; // raw base64
var contentType = arr[0].split(";")[0].split(":")[1]; // image/png, image/gif, etc

$.post("imageupload", {
    data: data,
    contenttype: contentType,
}, function (ev) {
    var img = $("&lt;img style='display:none;' src='" + ev.URL + "' /&gt;");
    img[0].onload = function () {
        var width = img.width();
        var height = img.height();
        var src = "&lt;img src='" + ev.URL + "' width='" + width + "' height='" + height + "' /&gt;";
        div.append($(src));
        img.remove();
    };

    $("body").append(img);
});

};</pre>
<p>And the content of the &#8220;imageupload&#8221; server route is pretty straightforward, and not too different than what you&#8217;d have for uploading an image from Post data:</p>
<pre class="brush:c#">
public JsonResult imageupload(string data, string contenttype)
{
    byte[] bytes = Convert.FromBase64String(data);
    var ms = new MemoryStream(bytes, 0, bytes.Length);
    UserFile file = SaveByteArrayAsUserFile(User, bytes, contentType); // saves the content as a file associated with that user
    return Json(new {
        file.Name,
        file.URL
    });
}
 </pre>
<p>Pretty powerful, and definitely one further step in making web-apps feel like native OS apps.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.foliotek.com/devblog/copy-images-from-clipboard-in-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iText SimSun Degree Symbol Spacing</title>
		<link>http://www.foliotek.com/devblog/itext-simsun-degree-symbol-spacing/</link>
		<comments>http://www.foliotek.com/devblog/itext-simsun-degree-symbol-spacing/#comments</comments>
		<pubDate>Thu, 29 Dec 2011 14:17:06 +0000</pubDate>
		<dc:creator>Andrew Miller</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Asian]]></category>
		<category><![CDATA[PDF]]></category>
		<category><![CDATA[SimSun]]></category>
		<category><![CDATA[iText]]></category>

		<guid isPermaLink="false">http://www.foliotek.com/devblog/?p=1325</guid>
		<description><![CDATA[I had a rather odd issue come up a few weeks ago for a client that generates data sheets for it&#8217;s Chinese distributors. These data sheets are generated via iText pdf using the SimSun font. Below is a screen shot of the issue that came up when SimSun renders the degree symbol notice the trailing [...]]]></description>
			<content:encoded><![CDATA[<p>I had a rather odd issue come up a few weeks ago for a client that generates data sheets for it&#8217;s Chinese distributors. These data sheets are generated via iText pdf using the SimSun font. </p>
<p>Below is a screen shot of the issue that came up when SimSun renders the degree symbol notice the trailing white space.</p>
<p><a href="http://www.foliotek.com/devblog/wp-content/uploads/2011/12/SimSunDegreeSpace.png"><img src="http://www.foliotek.com/devblog/wp-content/uploads/2011/12/SimSunDegreeSpace-300x198.png" alt="" title="SimSunDegreeSpace" width="300" height="198" class="aligncenter size-medium wp-image-1326" /></a></p>
<p>Since this was an actual issue with the font and the client requested that we not change the font due to Chinese standards I came up with the following solution.</p>
<p>SimSun supports the &#8216;Masculine Ordinal&#8217; symbol. This symbol does not have the trailing white space that the &#8216;degree&#8217; symbol does. So on the fly when it comes time for iText to generate a Chinese Datasheet I replace all Degree symbols with Masculine Ordinals. A little hacky but def the best solution available at the time. </p>
<pre class="brush: csharp; ">

myString.Replace(&#039;\u00B0&#039;, &#039;\u00BA&#039;); //replace degree with masculine ordinal
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.foliotek.com/devblog/itext-simsun-degree-symbol-spacing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Selenium 2 Tips</title>
		<link>http://www.foliotek.com/devblog/selenium2tips/</link>
		<comments>http://www.foliotek.com/devblog/selenium2tips/#comments</comments>
		<pubDate>Fri, 11 Nov 2011 16:00:57 +0000</pubDate>
		<dc:creator>Luke Daffron</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Functional Testing]]></category>
		<category><![CDATA[Regression Testing]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[Selenium 2]]></category>
		<category><![CDATA[selenium server]]></category>
		<category><![CDATA[selenium2]]></category>
		<category><![CDATA[webdriver]]></category>

		<guid isPermaLink="false">http://www.foliotek.com/devblog/?p=1309</guid>
		<description><![CDATA[In previous posts, I described our use of Selenium for functional and regression testing &#8211; and I included some tips on how to use it effectively.   We used the Firefox plugin Selenium IDE to run our tests. Since that time, we&#8217;ve moved on to use Selenium 2 (now, Selenium Server) &#8211; which uses a [...]]]></description>
			<content:encoded><![CDATA[<p>In previous posts, I described our use of Selenium for functional and regression testing &#8211; and I included some tips on how to use it effectively.   We used the Firefox plugin Selenium IDE to run our tests.</p>
<p>Since that time, we&#8217;ve moved on to use Selenium 2 (now, Selenium Server) &#8211; which uses a completely different architecture built on top of a merged project called WebDriver.  Now, instead of the custom &#8216;selenese&#8217; scripts &#8211; our tests are driven with C#.  This allows for much more effective branching, looping, etc. scenarios that are sometimes necessary for robust testing.</p>
<p>Some of the tips for selenese tests still apply, but in addition here are some specific Selenium 2 Server pointers:</p>
<ol>
<li>If you are having trouble getting an element clicked, sometimes it helps to have the test explicitly move the mouse to the element beforehand. Use:
<pre class="brush:csharp">new OpenQA.Selenium.Interaction.Actions(thewebdriver).MoveToElement(theelement).Perform();</pre>
</li>
<li>Selenium 2 will not interact with elements that are hidden or off screen.  Because of this &#8211; each click/etc action implicitly performs a scroll-to-element action.  Usually, this makes things easier, but occasionally it breaks.  If you have a scrollable element with tight spaces, it might scroll it just out of range before the click, and it will silently fail.  There currently isn&#8217;t a great way around this in the test &#8211; you can attempt to change your site to deal with it instead (by giving more room, or locking scrolling, etc).</li>
<li>It can be a hassle to deal with nested frames.
<ol>
<li>Things will fail if you don&#8217;t keep the Selenium context updated.  XPath selections in FireFox will throw exceptions, and events won&#8217;t fire.  Make sure you do the following to always use the proper context:
<pre class="brush:csharp">Driver.SwitchTo().DefaultContent().SwitchTo().Frame("fremename");</pre>
</li>
</ol>
</li>
<li>When things are failing differently on different machines, there are a couple of things to try:
<ol>
<li>Set a consistent resolution at the beginning of the test:
<pre class="brush:csharp">((IJavaScriptExecutor)Driver).ExecuteScript("window.moveTo(0, 1); window.resizeTo(1200,1000);");</pre>
</li>
<li>Retry clicks until success.  This tends to be necessary right after a iframe context change.  Hacky, but this psuedocode handles some performance/timing issues:
<pre class="brush:csharp">do{click;sleep;}while(testforchange){}</pre>
</li>
</ol>
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.foliotek.com/devblog/selenium2tips/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Datagrid Checkbox Column</title>
		<link>http://www.foliotek.com/devblog/datagrid-checkbox-column/</link>
		<comments>http://www.foliotek.com/devblog/datagrid-checkbox-column/#comments</comments>
		<pubDate>Wed, 26 Oct 2011 20:23:04 +0000</pubDate>
		<dc:creator>Dustin Smith</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Checkbox]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[checkbox column]]></category>
		<category><![CDATA[datagrid]]></category>
		<category><![CDATA[select all]]></category>

		<guid isPermaLink="false">http://www.foliotek.com/devblog/?p=1262</guid>
		<description><![CDATA[In Foliotek, there are a lot of instances where we have a table with a check box column that allows users to select rows and do some sort of action to them. This leads to a lot of redundancy in our markup and code. For example, here is what our datagrids looked like when we [...]]]></description>
			<content:encoded><![CDATA[<p>In Foliotek, there are a lot of instances where we have a table with a check box column that allows users to select rows and do some sort of action to them.  This leads to a lot of redundancy in our markup and code.  For example, here is what our datagrids looked like when we placed a checkbox in them (we&#8217;re using a custom server control for our datagrid):</p>
<h2>Datagrid with a checkbox</h2>
<pre class="brush: xml; ">

&lt;Components:ExtendedDataGrid runat=&quot;server&quot; id=&quot;dgItems&quot;&gt;
	&lt;Columns&gt;
		&lt;asp:TemplateColumn&gt;
			&lt;HeaderTemplate&gt;
				&lt;input class=&quot;check&quot; onclick=&quot;FLTK.checkbox.selectAll(this.checked, &#039;chkSelect&#039;);&quot; type=&quot;checkbox&quot; /&gt;
			&lt;/HeaderTemplate&gt;
			&lt;ItemTemplate&gt;
				&lt;input class=&quot;check&quot; type=&quot;checkbox&quot; id=&quot;chkSelect&quot; runat=&quot;server&quot; /&gt;
			&lt;/ItemTemplate&gt;
		&lt;/asp:TemplateColumn&gt;
		&lt;asp:TemplateColumn&gt;
			&lt;ItemTemplate&gt;
				&lt;%# Eval(&quot;ItemName&quot;) %&gt;
			&lt;/ItemTemplate&gt;
		&lt;/asp:TemplateColumn&gt;
	&lt;/Columns&gt;
&lt;/Components:ExtendedDataGrid&gt;
</pre>
<h2>Check All JS</h2>
<p>Here&#8217;s our javascript code that controls the select/deselect all functionality.  See <a href="http://www.foliotek.com/devblog/extending-jquery-to-select-asp-controls/">this blog post</a> in reference to the :asp() selector, and <a href="http://www.foliotek.com/devblog/jquery-check-all-checkbox/">this post</a> for more information on the select all functionality.</p>
<pre class="brush: javascript; ">

FLTK.checkbox = {
    selectAll: function (checked, endingwith) {
        var $checkboxes = $(&quot;:asp(&quot; + endingwith + &quot;)&quot;);
		// we don&#039;t want to check a box that is hidden on the page
        if (checked) {
            $checkboxes = $checkboxes.filter(&quot;:visible&quot;).not(&quot;:disabled&quot;);
        }
        $checkboxes.attr(&quot;checked&quot;, checked);
    }
}
</pre>
<h2>Get selected rows (C#)</h2>
<p>Then, to get the selected items in the code behind and perform some action on them, we&#8217;d have to do the following:</p>
<pre class="brush: c#; ">

foreach(DataGridItem item in dgItems.Items)
{
	if(((HtmlInputCheckBox)item.FindControl(&quot;chkSelect&quot;)).Checked)
	{
		// perform action
	}
}

// which can also be written as...

foreach(DataGridItem in dgItems.Items.Cast&lt;DataGridItem&gt;().Where(i =&gt; ((HtmlInputCheckBox)i.FindControl(&quot;chkSelect&quot;)).Checked))
{
	// perform action
}
</pre>
<h2>Creating the Custom Datagrid Checkbox Column</h2>
<p>Since the above code and markup is used so frequently in Foliotek, we wanted to abstract this logic into something that was easier to use.  As I stated above, we use a custom server control that extends the datagrid control, but if you don&#8217;t have a custom server control it shouldn&#8217;t be hard to create one.  </p>
<p>I would suggest reading up on <a href="http://msdn.microsoft.com/en-us/library/zt27tfhy.aspx">custom server controls</a>, if you&#8217;re interested in how the following code works.</p>
<p>Below is our server controls for the custom DataGrid, CheckBoxColumn, and CheckBoxTemplate.  Keep in mind the Checked and VisibilityDataField on the CheckBoxColumn are optional.</p>
<pre class="brush: c#; ">

namespace Components
{
	// here is our custom datagrid control
    public class ExtendedDataGrid : DataGrid
    {
		public IEnumerable&lt;DataGridItem&gt; GetSelectedItems()
        {
            if (!this.Columns.Cast&lt;DataGridColumn&gt;().Any(c =&gt; c is CheckBoxColumn))
            {
                throw new Exception(&quot;ExtendedDataGrid must have a &#039;CheckBoxColumn&#039; in order to use GetSelectedItems&quot;);
            }

            return this.Items.Cast&lt;DataGridItem&gt;().Where(i =&gt; ((CheckBox)i.FindControl(&quot;cb_&quot; + this.ID)).Checked);
        }
    }

	// Usage: &lt;Components:CheckBoxColumn Checked=&quot;false&quot; VisibilityDataField=&quot;Show&quot;&gt;&lt;/Components:CheckBoxColumn&gt;
	// Alternative Usage: VisiblityDataField=&quot;!Hide&quot;
	public class CheckBoxColumn : TemplateColumn
    {
        public string VisibilityDataField { get; set; }
        public bool Checked { get; set; }

        public CheckBoxColumn() : base()
        {
        }

        public override void InitializeCell(TableCell cell, int columnIndex, ListItemType itemType)
        {
            if (this.Owner != null)
            {
                this.HeaderTemplate = new CheckBoxTemplate(this.Owner.ID, VisibilityDataField, true, Checked);
                this.ItemTemplate = new CheckBoxTemplate(this.Owner.ID, VisibilityDataField, false, Checked);
            }
            base.InitializeCell(cell, columnIndex, itemType);
        }
    }

    public class CheckBoxTemplate : ITemplate
    {
        private string _tableID;
        private bool _isHeader;
        private string _visibilityDataField;
        private bool _isChecked;

        public CheckBoxTemplate(string tableID, string visibilityDataField, bool isHeader, bool isChecked)
        {
            _tableID = tableID;
            _isHeader = isHeader;
            _visibilityDataField = visibilityDataField;
            _isChecked = isChecked;
        }

        public void InstantiateIn(Control c)
        {
            if (_isHeader)
            {
				// If the template container is the header, then we need to add the check all functionality to the checkbox
                HtmlInputCheckBox input = new HtmlInputCheckBox();
                input.Attributes[&quot;onclick&quot;] = &quot;FLTK.checkbox.selectAll(this.checked, &#039;cb_&quot; + this._tableID + &quot;&#039;);&quot;; // This id is determined below.
                input.Checked = _isChecked; // Set the checked status by default
                c.Controls.Add(input);
            }
            else
            {
                CheckBox cb = new CheckBox();
                cb.ID = &quot;cb_&quot; + this._tableID;
                if (!String.IsNullOrEmpty(_visibilityDataField))
                {
                    cb.DataBinding += new EventHandler(cb_DataBinding); // doing this in the databind event allows us to access properties in the dataitem.
                }
                cb.Checked = _isChecked;
                c.Controls.Add(cb);
            }
        }

        void cb_DataBinding(object sender, EventArgs e)
        {
            var cb = (CheckBox)sender;
            var dataitem = ((DataGridItem)cb.NamingContainer).DataItem;

            bool show = true;
            if (!String.IsNullOrEmpty(this._visibilityDataField))
            {
                bool not = this._visibilityDataField.StartsWith(&quot;!&quot;);
                show = (bool)DataBinder.Eval(dataitem, (not ? this._visibilityDataField.Substring(1) : this._visibilityDataField));

                show = not ? !show : show;
            }

            cb.Visible = show;
        }
    }
}
</pre>
<h2>New markup and code behind</h2>
<p>Here&#8217;s our new markup.  Notice how we only have one line now for the checkbox column, compared to 8 lines before.</p>
<pre class="brush: xml; ">

&lt;Components:ExtendedDataGrid runat=&quot;server&quot; id=&quot;dgItems&quot;&gt;
	&lt;Columns&gt;
		&lt;Components:CheckBoxColumn&gt;&lt;/Components:CheckBoxColumn&gt;
		&lt;asp:TemplateColumn&gt;
			&lt;ItemTemplate&gt;
				&lt;%# Eval(&quot;ItemName&quot;) %&gt;
			&lt;/ItemTemplate&gt;
		&lt;/asp:TemplateColum&gt;
	&lt;/Columns&gt;
&lt;/Components:ExtendedDataGrid&gt;
</pre>
<p>&#8230; and our code behind, which definitely simplifies the prior statement&#8230;</p>
<pre class="brush: c#; ">

foreach(DataGridItem item in dgItems.GetSelectedItems())
{
	//perform action
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.foliotek.com/devblog/datagrid-checkbox-column/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simplifying C# Selenium 2 Tests for ASP.NET WebForms</title>
		<link>http://www.foliotek.com/devblog/simplifying-c-selenium-2-tests-for-asp-net-webforms/</link>
		<comments>http://www.foliotek.com/devblog/simplifying-c-selenium-2-tests-for-asp-net-webforms/#comments</comments>
		<pubDate>Thu, 20 Oct 2011 16:15:50 +0000</pubDate>
		<dc:creator>John Pasquet</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Selenium 2]]></category>
		<category><![CDATA[methods]]></category>
		<category><![CDATA[selenium]]></category>
		<category><![CDATA[webforms]]></category>

		<guid isPermaLink="false">http://www.foliotek.com/devblog/?p=1248</guid>
		<description><![CDATA[Our company uses Selenium to automate regression testing of important functionality on our products. One of the products uses ASP.NET Web Forms. Since the ID for controls gets changed from &#8220;txtName&#8221; to something like &#8220;ct100$contentMain$txtName&#8221;, we were using the xPath methods (ClickByXPath(), sendKeysByXPath(), anyByXPath(), etc). The code looked like this: Previous Test Code Tester.Driver.clickByXPath(&#34;//input[contains(@id, &#039;btnSearch&#039;)]&#34;); [...]]]></description>
			<content:encoded><![CDATA[<p>Our company uses Selenium to automate regression testing of important functionality on our products.  One of the products uses ASP.NET Web Forms.  Since the ID for controls gets changed from &#8220;txtName&#8221; to something like &#8220;ct100$contentMain$txtName&#8221;, we were using the xPath methods (ClickByXPath(), sendKeysByXPath(), anyByXPath(), etc).</p>
<p>The code looked like this:</p>
<h2>Previous Test Code</h2>
<pre class="brush: c#; ">

Tester.Driver.clickByXPath(&quot;//input[contains(@id, &#039;btnSearch&#039;)]&quot;);
Tester.Driver.clickByXPath(&quot;//select[contains(@id, &#039;drpPrograms&#039;)]/option[contains(text(), &#039;&quot; + programName + &quot;&#039;)]&quot;);
Tester.Driver.clickByXPath(&quot;//input[contains(@id, &#039;rblOption_2&#039;)]&quot;);
Tester.Driver.clickByXPath(&quot;//input[contains(@id, &#039;cbOption_1&#039;)]&quot;);
Tester.Driver.sendKeysByXPath(&quot;//input[contains(@id, &#039;txtName&#039;)]&quot;, name);

Tester.Driver.clickByLinkText(&quot;Next&quot;);
</pre>
<p>Writing xPath may be enjoyable for some, but for me it got a bit tedious.  So, I created some wrapper methods to make this a lot easier to create and read.</p>
<h2>New Test Code</h2>
<pre class="brush: c#; ">

ClickButton(&quot;btnSearch&quot;);
SelectDropDownOption(&quot;drpPrograms&quot;, optionName);
SelectRadio(&quot;rblOption_2&quot;);
SelectCheckBox(&quot;cbOption_1&quot;);
EnterTextBox(&quot;txtName&quot;, name);
</pre>
<h2>Wrapper Methods</h2>
<pre class="brush: c#; ">

/// Select a RadioButton or an option on a RadioButtonList.
/// If optionText is specified for a RadioButtonList, this will select that option.  Otherwise it works for native RadioButtons
/// prefix = html filter e.g.  &quot;p/&quot; or &quot;tr/td/&quot;
public void SelectRadio(string radioButtonID, string optionText = &quot;&quot;, string prefix = &quot;&quot;)
{
    string path = &quot;//&quot; + prefix + &quot;input[contains(@id, &#039;&quot; + radioButtonID + &quot;&#039;)]&quot;;

    if (optionText != &quot;&quot;)
        path += &quot;/option[contains(text(), &#039;&quot; + optionText + &quot;&#039;)]&quot;;

    ClickByXPath(path);
}

/// Select a CheckBox
/// prefix = html filter e.g.  &quot;p/&quot; or &quot;tr/td/&quot;
public void SelectCheckbox(string checkboxID, string prefix = &quot;&quot;)
{
    string path = &quot;//&quot; + prefix + &quot;input[contains(@id, &#039;&quot; + checkboxID + &quot;&#039;)]&quot;;

    ClickByXPath(path);
}

/// Select an option on a DropDownList
/// prefix = html filter e.g.  &quot;p/&quot; or &quot;tr/td/&quot;
public void SelectDropDownOption(string dropdownID, string optionText = &quot;&quot;, string prefix = &quot;&quot;)
{
    string path = &quot;//&quot; + prefix + &quot;select[contains(@id, &#039;&quot; + dropdownID + &quot;&#039;)]&quot;;

    if (optionText != &quot;&quot;)
        path += &quot;/option[contains(text(), &#039;&quot; + optionText + &quot;&#039;)]&quot;;

    ClickByXPath(path);
}

/// Enter text into a TextBox and optionally clear it out first.
public void EnterTextBox(string txtName, string value, bool clearField = false)
{
    Tester.Driver.sendKeysByXPath(&quot;//input[contains(@id,&#039;&quot; + txtName + &quot;&#039;)]&quot;, value, clearField);
}

/// Confirm if a condition is true.  If it is, output the confirmationMessage.
public void ConfirmTrue(bool test, string confirmationMessage)
{
    Tester.Assert(test, confirmationMessage);
}

/// Test to see if a control exists on the page.
/// Control type = input, div, td or whatever
public bool ControlExists(string controlType, string controlID)
{
    string path = &quot;//&quot; + controlType + &quot;[contains(@id,&#039;&quot; + controlID + &quot;&#039;)]&quot;;
    return Tester.Driver.anyByXPath(path);
}

/// Click a Button
public void ClickButton(string buttonName, string prefix = &quot;&quot;)
{
    string path = &quot;//&quot; + prefix + &quot;input[contains(@id, &#039;&quot; + buttonName + &quot;&#039;)]&quot;;

    ClickByXPath(path);
}

public void ClickByXPath(string xPath)
{
    Tester.Driver.ClickByXPath(xPath);
}

public void ClickByLinkText(string linkText)
{
    Tester.Driver.clickByLinkText(linkText);
}
</pre>
<p>For more posts, see <a href="http://www.foliotek.com/devblog/selenium-tips-and-tricks/">Tips and Tricks</a> or <a href="http://www.foliotek.com/devblog/realwebtesting/">Functional Regression Testing</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.foliotek.com/devblog/simplifying-c-selenium-2-tests-for-asp-net-webforms/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Color Scheme Generator in JavaScript</title>
		<link>http://www.foliotek.com/devblog/color-scheme-generator-in-javascript/</link>
		<comments>http://www.foliotek.com/devblog/color-scheme-generator-in-javascript/#comments</comments>
		<pubDate>Fri, 23 Sep 2011 17:53:42 +0000</pubDate>
		<dc:creator>Brian Grinstead</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[colors]]></category>
		<category><![CDATA[css]]></category>

		<guid isPermaLink="false">http://www.foliotek.com/devblog/?p=1232</guid>
		<description><![CDATA[ColorStash is a tiny web app I built for the 10K Apart contest. The goal of the contest is to build an application in under 10 Kilobytes. This includes all HTML, JavaScript, CSS, and images. This is a tight limit, but luckily you can include jQuery and not have it count against your size quota. [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://briangrinstead.com/colorstash/'>ColorStash</a> is a tiny web app I built for the <a href='http://10k.aneventapart.com/'>10K Apart contest</a>.  The goal of the contest is to build an application in under 10 Kilobytes.  This includes all HTML, JavaScript, CSS, and images.  This is a tight limit, but luckily you can include jQuery and not have it count against your size quota.</p>
<p>The main goal is to provide an easy way for to choose a nice color or scheme, and output those colors in a variety of formats.  It supports hex, css names, rgb, hsv, and hsl as input and output formats.  You don&#8217;t really need to know anything about these formats to use the colorpicker or built in image eyedropper.</p>
<p>I started learning about color when working on the template editor and color schemes</p>
<p>You can read more <a href='http://www.briangrinstead.com/blog/colorstash'>http://www.briangrinstead.com/blog/colorstash</a>, check out the <a href='http://10k.aneventapart.com/Entry/Details/578/'>10K entry</a>, or see the more permanent (and possibly bigger than 10K as I make updates) app here: <a href=''http://briangrinstead.com/colorstash/">http://briangrinstead.com/colorstash/</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.foliotek.com/devblog/color-scheme-generator-in-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Flash Streaming MP4 file in Umbraco</title>
		<link>http://www.foliotek.com/devblog/flash-streaming-mp4-file-in-umbraco/</link>
		<comments>http://www.foliotek.com/devblog/flash-streaming-mp4-file-in-umbraco/#comments</comments>
		<pubDate>Fri, 23 Sep 2011 14:50:25 +0000</pubDate>
		<dc:creator>Luke Daffron</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Umbraco]]></category>
		<category><![CDATA[flash streaming]]></category>
		<category><![CDATA[flv]]></category>
		<category><![CDATA[mp4 flash]]></category>
		<category><![CDATA[umbraco]]></category>

		<guid isPermaLink="false">http://www.foliotek.com/devblog/?p=1227</guid>
		<description><![CDATA[In our old website, we had a script that would take an mp4 file and automatically respond with the proper flash header for it in addition to sending the proper content if flash requests a certain position.  I adapted that code for Umbraco, and made it so that a request for /media/MEDIA_PATH/stream.flv would automatically do [...]]]></description>
			<content:encoded><![CDATA[<p>In our old website, we had a script that would take an mp4 file and automatically respond with the proper flash header for it in addition to sending the proper content if flash requests a certain position.  I adapted that code for Umbraco, and made it so that a request for /media/MEDIA_PATH/stream.flv would automatically do this for Umbraco media.  The strategy is very similar to my <a title="last post" href="helper-razor-scripts-for-umbraco-cms/">last post</a> that does this for a /css/media/MEDIA_PATH type url.</p>
<p>To use this, add a  rewrite rule to UrlRewriting.config:</p>
<pre class="brush:xml">virtualUrl="^~/media/(.*)/stream.flv"
          rewriteUrlParameter="ExcludeFromClientQueryString"
          destinationUrl="~/mp4streamer?path=$1"
          ignoreCase="true" /&gt;</pre>
<p>&nbsp;</p>
<p>Add a new scripting file (and macro) called &#8220;MP4Streamer&#8221;</p>
<pre class="brush:csharp">@using uComponents.Core
   @using umbraco.cms.businesslogic.media
   @using uComponents.Core.uQueryExtensions
   @{

        byte[] _flvheader = { 0x46, 0x4c, 0x56, 0x01, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09 };

          try{
                int pos;
                int length;

                    string filename = Server.MapPath("~/media/"+Request.QueryString["path"]);
                    using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)){
                        // Check start parameter if present
                        string qs = Request.Params["start"];

                        if (string.IsNullOrEmpty(qs)){
                            pos = 0;
                            length = Convert.ToInt32(fs.Length);
                        }
                        else{
                            pos = Convert.ToInt32(qs);
                            length = Convert.ToInt32(fs.Length - pos) + _flvheader.Length;
                        }

                        // Add HTTP header stuff: cache, content type and length
                       Response.Cache.SetCacheability(HttpCacheability.Public);
                       Response.Cache.SetLastModified(DateTime.Now);

                        Response.AppendHeader("Content-Type", "video/x-flv");
                        Response.AppendHeader("Content-Length", length.ToString());

                        // Append FLV header when sending partial file
                        if (pos &gt; 0){
                            Response.OutputStream.Write(_flvheader, 0, _flvheader.Length);
                            fs.Position = pos;
                        }

                        // Read buffer and write stream to the response stream
                        const int buffersize = 16384;
                        byte[] buffer = new byte[buffersize];

                        int count = fs.Read(buffer, 0, buffersize);
                        while (count &gt; 0) {
                            if (Response.IsClientConnected) {
                                Response.OutputStream.Write(buffer, 0, count);
                                Response.Flush();

                                count = fs.Read(buffer, 0, buffersize);
                            }
                            else{
                                count = -1;
                            }
                        }
                    }

            }
            catch (Exception ex)
            {
            }

  }</pre>
<p>Add a new &#8220;MP4Streamer&#8221; template that uses the macro:</p>
<pre class="brush:xml">&lt;%@ Master Language="C#" MasterPageFile="~/umbraco/masterpages/default.master" AutoEventWireup="true" %&gt;</pre>
<p>And, finally, add a new page called MP4Streamer to the root of your site that uses the macro.</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.foliotek.com/devblog/flash-streaming-mp4-file-in-umbraco/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Weebly Automatically Generated Left Menu via jQuery</title>
		<link>http://www.foliotek.com/devblog/weebly-left-menu-via-jquery/</link>
		<comments>http://www.foliotek.com/devblog/weebly-left-menu-via-jquery/#comments</comments>
		<pubDate>Thu, 08 Sep 2011 14:02:11 +0000</pubDate>
		<dc:creator>John Pasquet</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[automatically generated]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[left menu]]></category>
		<category><![CDATA[side menu]]></category>
		<category><![CDATA[weebly]]></category>

		<guid isPermaLink="false">http://www.foliotek.com/devblog/?p=1219</guid>
		<description><![CDATA[I&#8217;ve helped a few people put together websites using Weebly, since it&#8217;s a tool that non-technical people can easily use to manage and maintain their sites. However, Weebly currently does not offer the option of a left menu. I don&#8217;t particularly like all the moving dropdown menus. It just seems to busy for me. So, [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve helped a few people put together websites using Weebly, since it&#8217;s a tool that non-technical people can easily use to manage and maintain their sites.  However, Weebly currently does not offer the option of a left menu.  I don&#8217;t particularly like all the moving dropdown menus.  It just seems to busy for me.</p>
<p>So, here&#8217;s my solution to generate a left menu based based on the structure of the site.  Basically, I grab the dropdown links and copy them into a side menu structure.  I will note that you should be aware when you&#8217;re creating a site that the content will be shifted over.  I have not adjusted the css to represent this myself, because it doesn&#8217;t really matter to me.</p>
<p>To see an example of this in action, go to <a href="http://www.highquest.info">www.highquest.info</a></p>
<h2>Reference jQuery</h2>
<p>Add a link to jQuery in the <head> section on index.html:</p>
<pre class="brush: javascript; ">

&lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js&quot;&gt;&lt;/script&gt;
</pre>
<h2>The JavaScript</h2>
<p>Add the following javascript code to the index.html page type html, probably at the bottom but inside the body tag. (or any other page types you&#8217;ve defined.  You could actually have this for every page but the main page to keep left menus off that if you want.)<br />
  (Click Design => Edit HTML/CSS => index.html)</p>
<pre class="brush: javascript; ">

&lt;script type=&quot;text/javascript&quot;&gt;
      // You need this since Weebly uses another JavaScript library
      jQuery.noConflict();        

      function AddMenu() {

        // Find active link
        var activeLink = jQuery(&quot;#active&quot;);
        if (activeLink.length == 0) {
          activeLink = jQuery(&quot;.wsite-nav-current&quot;);
        }       

        var linkParent = activeLink;

        //find root page
        while (linkParent.parent().parent().hasClass(&quot;wsite-menu-wrap&quot;)) {
          linkParent = linkParent.parent().parent().parent();
        }

        // add menus when there are sub items to the root page -- but don&#039;t when there are no children (main page)
        if (linkParent .find(&quot;div&quot;).length &gt; 0) {
          var contentDiv = jQuery(&quot;#wsite-content&quot;);

          //I add a table structure, which I know isn&#039;t the best, but it works well here.
          contentDiv.html(&quot;&lt;table class=&#039;leftmenupage&#039;&gt;&lt;tr&gt;&lt;td class=&#039;leftmenu&#039;&gt;&quot; + linkParent.html()
                          + &quot;&lt;/td&gt;&lt;td class=&#039;rightcontent&#039;&gt;&quot; + contentDiv.html()+ &quot;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&quot;);

          jQuery(&quot;.leftmenu div&quot;).show();
        }

        // Mark main nav link with id=&quot;active&quot;
        var linkHref = linkParent.find(&quot;a&quot;).attr(&quot;href&quot;);
        var navLinks = jQuery(&quot;#navigation a&quot;);
        for (var i = 0; i &lt; navLinks.length; i++) {
          if (navLinks.eq(i).attr(&quot;href&quot;) == linkHref) {
            navLinks.eq(i).parent().attr(&quot;id&quot;, &quot;active&quot;);
          }
        }

      } 

      AddMenu();

 &lt;/script&gt;
</pre>
<h2>The CSS</h2>
<pre class="brush: css; ">

ul.wsite-menu li { padding-bottom: 5px; } 

.leftmenupage { margin-left: -15px; width:850px; } 

td.leftmenu {
  width: 200px;
  white-space: nowrap;
  padding: 7px 7px;
  vertical-align: top;
  border-radius: 15px;
  background: #ddd;
  color: #333;
  padding: 12px 12px;
  min-width: 200px;
  min-height: 250px;
} 

td.leftmenu li { padding-bottom: 7px; }
td.leftmenu a {
  color: #333;
  font-size: 1.33em;
  padding: 5px 0px;
  display: block;
}
td.leftmenu a:hover {text-decoration: underline; }

td.leftmenu li a { font-size: 1em; }

td.leftmenu li{
  color: #333;
  font-size: 1em;
  padding: 2px 0px;
}
td.leftmenu li li {
  color: #333;
  font-size: 1em;
  padding: 2px 0 2px 15px;
} 

td.rightcontent {
  width: 75%;
  padding-left:25px;
  width: 650px;
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.foliotek.com/devblog/weebly-left-menu-via-jquery/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>A couple of handy helper razor scripts for Umbraco CMS</title>
		<link>http://www.foliotek.com/devblog/helper-razor-scripts-for-umbraco-cms/</link>
		<comments>http://www.foliotek.com/devblog/helper-razor-scripts-for-umbraco-cms/#comments</comments>
		<pubDate>Thu, 01 Sep 2011 14:45:53 +0000</pubDate>
		<dc:creator>Luke Daffron</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[media]]></category>
		<category><![CDATA[rewrite]]></category>
		<category><![CDATA[umbraco]]></category>
		<category><![CDATA[umbraco css image]]></category>
		<category><![CDATA[umbraco css media]]></category>
		<category><![CDATA[umbraco image]]></category>

		<guid isPermaLink="false">http://www.foliotek.com/devblog/?p=1212</guid>
		<description><![CDATA[I&#8217;ve recently started a project for a new marketing site for our projects.  One of the biggest issues with our current marketing site is that it was developed as an application &#8211; so changes need to go through a developer and be deployed.  This basically resulted in the site being stagnant for a couple of [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently started a project for a new marketing site for our projects.  One of the biggest issues with our current marketing site is that it was developed as an application &#8211; so changes need to go through a developer and be deployed.  This basically resulted in the site being stagnant for a couple of years.  This is bad &#8211; there are lots of things we offer now that we didn&#8217;t 2 years ago &#8211; and there are many opportunities where a page that speaks to a particular system, market, or feature could be very good for business/SEO.</p>
<p>I decided to use a CMS to allow anyone in our business edit and add content.  Since we were a web consulting firm before we built products &#8211; we&#8217;ve had a number of custom solutions over the years for managing site content.  I didn&#8217;t want to create that maintenance pain again, so I looked for another maintained solution I could use.  I settled on Umbraco &#8211; it&#8217;s free, open source, has a great plugin architecture using the .NET/Razor architecture we already know &#8211; so it was a perfect fit.</p>
<p>I wanted to share a couple of handy scripts I came up with to make Umbraco even better:</p>
<h2>Add &#8220;/edit&#8221; redirect to all pages:</h2>
<p>To use this, add a couple of rewrite rules to UrlRewriting.config:</p>
<pre class="brush:xml">&lt;add name="editrewrite"
          virtualUrl="^~/(.*)/edit/?"
          rewriteUrlParameter="ExcludeFromClientQueryString"
          destinationUrl="~/editredirect?path=foliotek/$1"
          ignoreCase="true" /&gt;
        &lt;add name="edithomerewrite"
          virtualUrl="^~/edit/?"
          rewriteUrlParameter="ExcludeFromClientQueryString"
          destinationUrl="~/editredirect?path=foliotek"
          ignoreCase="true" /&gt;</pre>
<p>Add a new scripting file (and macro) called &#8220;EditRedirect&#8221;</p>
<pre class="brush:csharp">@using uComponents.Core
   @using umbraco.presentation.nodeFactory
   @using uComponents.Core.uQueryExtensions
   @{

   Node n = null;

   var path = Request.QueryString["path"].Split("/".ToCharArray());

   for(int i=0; i&lt;path.Length; i++)
   {
     if(n==null)
     {
       n = uQuery.GetRootNode().GetChildNodes().Where(x=&gt;x.Name.ToLower()== path[i].Trim().ToLower()).First();
     }
     else
     {
       var name = path[i].Trim();
       if(i==path.Length-1 &amp;&amp; name.IndexOf(".")&gt;0)
       {
         name=name.Substring(0,name.LastIndexOf("."));
       }
       n = n.GetDescendantNodes().First(c=&gt;c.Name.ToLower()==name.ToLower());
     }
    }

   Response.Redirect("/umbraco/actions/editContent.aspx?id="+n.Id);

   }</pre>
<p>Add a new &#8220;EditRedirect&#8221; template that uses the macro:</p>
<pre class="brush:xml">&lt;%@ Master Language="C#" MasterPageFile="~/umbraco/masterpages/default.master" AutoEventWireup="true" %&gt;

&lt;asp:Content ContentPlaceHolderID="ContentPlaceHolderDefault" runat="server"&gt;
  &lt;umbraco:Macro runat="server"   Alias="EditRedirect" /&gt;
&lt;/asp:Content&gt;</pre>
<p>And, finally, add a new page called EditRedirect to the root of your site that uses the macro.   Now you can hit http://site/anydirectory/anypage/edit and it will take you to the editor screen of that page.</p>
<p>&nbsp;</p>
<h2>Simple path to access media by url and in css files</h2>
<p>The abstraction umbraco allows for media is great &#8211; your editors can create a media item and replace the file later to their hearts content.  Unfortunately, it&#8217;s not very simple to pull this media in scripts, templates, simple html, and especially css files.  I wrote a macro/script to handle this too.  Set up is pretty much like the edit redirect:</p>
<p>The script:</p>
<p>&nbsp;</p>
<pre class="brush:csharp">@using uComponents.Core
   @using umbraco.cms.businesslogic.media
   @using uComponents.Core.uQueryExtensions
   @{

   Media m = null;
   if(!( Model.Media is umbraco.MacroEngines.DynamicNull || (Model.Media is string &amp;&amp; Model.Media=="")))
   {
     m = uQuery.GetMedia(Model.Media);
    }
  else
   {
     var path = Request.QueryString["path"].Split("/".ToCharArray());

     for(int i=0; i&lt;path.Length; i++)
     {
       if(m==null)
       {
         m = uQuery.GetMediaByName( path[i].Trim()).First();
       }
       else
       {
         var name = path[i].Trim();
         if(i==path.Length-1 &amp;&amp; name.IndexOf(".")&gt;0)
         {
           name=name.Substring(0,name.LastIndexOf("."));
         }
         m = m.GetChildMedia().First(c=&gt;c.Text==name);
       }
      }
   }

   Response.Clear();
   Response.ContentType = GetContentType(m.GetProperty&lt;string&gt;("umbracoExtension"));
   Response.TransmitFile(m.GetProperty&lt;string&gt;("umbracoFile"));

   }

   @functions{
     protected string GetContentType(string ext)
     {
   var contentTypes = new Dictionary&lt;string, string&gt;
                               {
                                   {"3dm", "x-world/x-3dmf"},
                                   {"3dmf", "x-world/x-3dmf"},
                                   {"a", "application/octet-stream"},
                                   {"aab", "application/x-authorware-bin"},
                                   {"aam", "application/x-authorware-map"},
                                   {"aas", "application/x-authorware-seg"},
                                   {"abc", "text/vnd.abc"},
                                   {"acgi", "text/html"},
                                   {"afl", "video/animaflex"},
                                   {"ai", "application/postscript"},
                                   {"aif", "audio/aiff"},
                                   {"aifc", "audio/aiff"},
                                   {"aiff", "audio/aiff"},
                                   {"aim", "application/x-aim"},
                                   {"aip", "text/x-audiosoft-intra"},
                                   {"ani", "application/x-navi-animation"},
                                   {"aos", "application/x-nokia-9000-communicator-add-on-software"},
                                   {"aps", "application/mime"},
                                   {"arc", "application/octet-stream"},
                                   {"arj", "application/arj"},
                                   {"art", "image/x-jg"},
                                   {"asf", "video/x-ms-asf"},
                                   {"asm", "text/x-asm"},
                                   {"asp", "text/asp"},
                                   {"asx", "application/x-mplayer2"},
                                   {"au", "audio/basic"},
                                   {"avi", "video/avi"},
                                   {"avs", "video/avs-video"},
                                   {"bcpio", "application/x-bcpio"},
                                   {"bin", "application/octet-stream"},
                                   {"bm", "image/bmp"},
                                   {"bmp", "image/bmp"},
                                   {"boo", "application/book"},
                                   {"book", "application/book"},
                                   {"boz", "application/x-bzip2"},
                                   {"bsh", "application/x-bsh"},
                                   {"bz", "application/x-bzip"},
                                   {"bz2", "application/x-bzip2"},
                                   {"c", "text/plain"},
                                   {"c++", "text/plain"},
                                   {"cat", "application/vnd.ms-pki.seccat"},
                                   {"cc", "text/plain"},
                                   {"ccad", "application/clariscad"},
                                   {"cco", "application/x-cocoa"},
                                   {"cdf", "application/cdf"},
                                   {"cer", "application/pkix-cert"},
                                   {"cha", "application/x-chat"},
                                   {"chat", "application/x-chat"},
                                   {"class", "application/java"},
                                   {"com", "application/octet-stream"},
                                   {"conf", "text/plain"},
                                   {"cpio", "application/x-cpio"},
                                   {"cpp", "text/x-c"},
                                   {"cpt", "application/x-cpt"},
                                   {"crl", "application/pkcs-crl"},
                                   {"css", "text/css"},
                                   {"def", "text/plain"},
                                   {"der", "application/x-x509-ca-cert"},
                                   {"dif", "video/x-dv"},
                                   {"dir", "application/x-director"},
                                   {"dl", "video/dl"},
                                   {"doc", "application/msword"},
                                   {"dot", "application/msword"},
                                   {"dp", "application/commonground"},
                                   {"drw", "application/drafting"},
                                   {"dump", "application/octet-stream"},
                                   {"dv", "video/x-dv"},
                                   {"dvi", "application/x-dvi"},
                                   {"dwf", "drawing/x-dwf (old)"},
                                   {"dwg", "application/acad"},
                                   {"dxf", "application/dxf"},
                                   {"eps", "application/postscript"},
                                   {"es", "application/x-esrehber"},
                                   {"etx", "text/x-setext"},
                                   {"evy", "application/envoy"},
                                   {"exe", "application/octet-stream"},
                                   {"f", "text/plain"},
                                   {"f90", "text/x-fortran"},
                                   {"fdf", "application/vnd.fdf"},
                                   {"fif", "image/fif"},
                                   {"fli", "video/fli"},
                                   {"for", "text/x-fortran"},
                                   {"fpx", "image/vnd.fpx"},
                                   {"g", "text/plain"},
                                   {"g3", "image/g3fax"},
                                   {"gif", "image/gif"},
                                   {"gl", "video/gl"},
                                   {"gsd", "audio/x-gsm"},
                                   {"gtar", "application/x-gtar"},
                                   {"gz", "application/x-compressed"},
                                   {"h", "text/plain"},
                                   {"help", "application/x-helpfile"},
                                   {"hgl", "application/vnd.hp-hpgl"},
                                   {"hh", "text/plain"},
                                   {"hlp", "application/x-winhelp"},
                                   {"htc", "text/x-component"},
                                   {"htm", "text/html"},
                                   {"html", "text/html"},
                                   {"htmls", "text/html"},
                                   {"htt", "text/webviewhtml"},
                                   {"htx", "text/html"},
                                   {"ice", "x-conference/x-cooltalk"},
                                   {"ico", "image/x-icon"},
                                   {"idc", "text/plain"},
                                   {"ief", "image/ief"},
                                   {"iefs", "image/ief"},
                                   {"iges", "application/iges"},
                                   {"igs", "application/iges"},
                                   {"ima", "application/x-ima"},
                                   {"imap", "application/x-httpd-imap"},
                                   {"inf", "application/inf"},
                                   {"ins", "application/x-internett-signup"},
                                   {"ip", "application/x-ip2"},
                                   {"isu", "video/x-isvideo"},
                                   {"it", "audio/it"},
                                   {"iv", "application/x-inventor"},
                                   {"ivr", "i-world/i-vrml"},
                                   {"ivy", "application/x-livescreen"},
                                   {"jam", "audio/x-jam"},
                                   {"jav", "text/plain"},
                                   {"java", "text/plain"},
                                   {"jcm", "application/x-java-commerce"},
                                   {"jfif", "image/jpeg"},
                                   {"jfif-tbnl", "image/jpeg"},
                                   {"jpe", "image/jpeg"},
                                   {"jpeg", "image/jpeg"},
                                   {"jpg", "image/jpeg"},
                                   {"jps", "image/x-jps"},
                                   {"js", "application/x-javascript"},
                                   {"jut", "image/jutvision"},
                                   {"kar", "audio/midi"},
                                   {"ksh", "application/x-ksh"},
                                   {"la", "audio/nspaudio"},
                                   {"lam", "audio/x-liveaudio"},
                                   {"latex", "application/x-latex"},
                                   {"lha", "application/lha"},
                                   {"lhx", "application/octet-stream"},
                                   {"list", "text/plain"},
                                   {"lma", "audio/nspaudio"},
                                   {"log", "text/plain"},
                                   {"lsp", "application/x-lisp"},
                                   {"lst", "text/plain"},
                                   {"lsx", "text/x-la-asf"},
                                   {"ltx", "application/x-latex"},
                                   {"lzh", "application/octet-stream"},
                                   {"lzx", "application/lzx"},
                                   {"m", "text/plain"},
                                   {"m1v", "video/mpeg"},
                                   {"m2a", "audio/mpeg"},
                                   {"m2v", "video/mpeg"},
                                   {"m3u", "audio/x-mpequrl"},
                                   {"man", "application/x-troff-man"},
                                   {"map", "application/x-navimap"},
                                   {"mar", "text/plain"},
                                   {"mbd", "application/mbedlet"},
                                   {"mc$", "application/x-magic-cap-package-1.0"},
                                   {"mcd", "application/mcad"},
                                   {"mcf", "image/vasa"},
                                   {"mcp", "application/netmc"},
                                   {"me", "application/x-troff-me"},
                                   {"mht", "message/rfc822"},
                                   {"mhtml", "message/rfc822"},
                                   {"mid", "audio/midi"},
                                   {"midi", "audio/midi"},
                                   {"mif", "application/x-frame"},
                                   {"mime", "message/rfc822"},
                                   {"mjf", "audio/x-vnd.audioexplosion.mjuicemediafile"},
                                   {"mjpg", "video/x-motion-jpeg"},
                                   {"mm", "application/base64"},
                                   {"mme", "application/base64"},
                                   {"mod", "audio/mod"},
                                   {"moov", "video/quicktime"},
                                   {"mov", "video/quicktime"},
                                   {"movie", "video/x-sgi-movie"},
                                   {"mp2", "audio/mpeg"},
                                   {"mp3", "audio/mpeg3"},
                                   {"mpa", "audio/mpeg"},
                                   {"mpc", "application/x-project"},
                                   {"mpe", "video/mpeg"},
                                   {"mpeg", "video/mpeg"},
                                   {"mpg", "video/mpeg"},
                                   {"mpga", "audio/mpeg"},
                                   {"mpp", "application/vnd.ms-project"},
                                   {"mpt", "application/x-project"},
                                   {"mpv", "application/x-project"},
                                   {"mpx", "application/x-project"},
                                   {"mrc", "application/marc"},
                                   {"ms", "application/x-troff-ms"},
                                   {"mv", "video/x-sgi-movie"},
                                   {"my", "audio/make"},
                                   {"mzz", "application/x-vnd.audioexplosion.mzz"},
                                   {"nap", "image/naplps"},
                                   {"naplps", "image/naplps"},
                                   {"nc", "application/x-netcdf"},
                                   {"ncm", "application/vnd.nokia.configuration-message"},
                                   {"nif", "image/x-niff"},
                                   {"niff", "image/x-niff"},
                                   {"nix", "application/x-mix-transfer"},
                                   {"nsc", "application/x-conference"},
                                   {"nvd", "application/x-navidoc"},
                                   {"o", "application/octet-stream"},
                                   {"oda", "application/oda"},
                                   {"omc", "application/x-omc"},
                                   {"omcd", "application/x-omcdatamaker"},
                                   {"omcr", "application/x-omcregerator"},
                                   {"p", "text/x-pascal"},
                                   {"p10", "application/pkcs10"},
                                   {"p12", "application/pkcs-12"},
                                   {"p7a", "application/x-pkcs7-signature"},
                                   {"p7c", "application/pkcs7-mime"},
                                   {"pas", "text/pascal"},
                                   {"pbm", "image/x-portable-bitmap"},
                                   {"pcl", "application/vnd.hp-pcl"},
                                   {"pct", "image/x-pict"},
                                   {"pcx", "image/x-pcx"},
                                   {"pdf", "application/pdf"},
                                   {"pfunk", "audio/make"},
                                   {"pgm", "image/x-portable-graymap"},
                                   {"pic", "image/pict"},
                                   {"pict", "image/pict"},
                                   {"pkg", "application/x-newton-compatible-pkg"},
                                   {"pko", "application/vnd.ms-pki.pko"},
                                   {"pl", "text/plain"},
                                   {"plx", "application/x-pixclscript"},
                                   {"pm", "image/x-xpixmap"},
                                   {"png", "image/png"},
                                   {"pnm", "application/x-portable-anymap"},
                                   {"pot", "application/mspowerpoint"},
                                   {"pov", "model/x-pov"},
                                   {"ppa", "application/vnd.ms-powerpoint"},
                                   {"ppm", "image/x-portable-pixmap"},
                                   {"pps", "application/mspowerpoint"},
                                   {"ppt", "application/mspowerpoint"},
                                   {"ppz", "application/mspowerpoint"},
                                   {"pre", "application/x-freelance"},
                                   {"prt", "application/pro_eng"},
                                   {"ps", "application/postscript"},
                                   {"psd", "application/octet-stream"},
                                   {"pvu", "paleovu/x-pv"},
                                   {"pwz", "application/vnd.ms-powerpoint"},
                                   {"py", "text/x-script.phyton"},
                                   {"pyc", "applicaiton/x-bytecode.python"},
                                   {"qcp", "audio/vnd.qcelp"},
                                   {"qd3", "x-world/x-3dmf"},
                                   {"qd3d", "x-world/x-3dmf"},
                                   {"qif", "image/x-quicktime"},
                                   {"qt", "video/quicktime"},
                                   {"qtc", "video/x-qtc"},
                                   {"qti", "image/x-quicktime"},
                                   {"qtif", "image/x-quicktime"},
                                   {"ra", "audio/x-pn-realaudio"},
                                   {"ram", "audio/x-pn-realaudio"},
                                   {"ras", "application/x-cmu-raster"},
                                   {"rast", "image/cmu-raster"},
                                   {"rexx", "text/x-script.rexx"},
                                   {"rf", "image/vnd.rn-realflash"},
                                   {"rgb", "image/x-rgb"},
                                   {"rm", "application/vnd.rn-realmedia"},
                                   {"rmi", "audio/mid"},
                                   {"rmm", "audio/x-pn-realaudio"},
                                   {"rmp", "audio/x-pn-realaudio"},
                                   {"rng", "application/ringing-tones"},
                                   {"rnx", "application/vnd.rn-realplayer"},
                                   {"roff", "application/x-troff"},
                                   {"rp", "image/vnd.rn-realpix"},
                                   {"rpm", "audio/x-pn-realaudio-plugin"},
                                   {"rt", "text/richtext"},
                                   {"rtf", "text/richtext"},
                                   {"rtx", "application/rtf"},
                                   {"rv", "video/vnd.rn-realvideo"},
                                   {"s", "text/x-asm"},
                                   {"s3m", "audio/s3m"},
                                   {"saveme", "application/octet-stream"},
                                   {"sbk", "application/x-tbook"},
                                   {"scm", "application/x-lotusscreencam"},
                                   {"sdml", "text/plain"},
                                   {"sdp", "application/sdp"},
                                   {"sdr", "application/sounder"},
                                   {"sea", "application/sea"},
                                   {"set", "application/set"},
                                   {"sgm", "text/sgml"},
                                   {"sgml", "text/sgml"},
                                   {"sh", "application/x-bsh"},
                                   {"shtml", "text/html"},
                                   {"sid", "audio/x-psid"},
                                   {"sit", "application/x-sit"},
                                   {"skd", "application/x-koan"},
                                   {"skm", "application/x-koan"},
                                   {"skp", "application/x-koan"},
                                   {"skt", "application/x-koan"},
                                   {"sl", "application/x-seelogo"},
                                   {"smi", "application/smil"},
                                   {"smil", "application/smil"},
                                   {"snd", "audio/basic"},
                                   {"sol", "application/solids"},
                                   {"spc", "application/x-pkcs7-certificates"},
                                   {"spl", "application/futuresplash"},
                                   {"spr", "application/x-sprite"},
                                   {"sprite", "application/x-sprite"},
                                   {"src", "application/x-wais-source"},
                                   {"ssi", "text/x-server-parsed-html"},
                                   {"ssm", "application/streamingmedia"},
                                   {"sst", "application/vnd.ms-pki.certstore"},
                                   {"step", "application/step"},
                                   {"stl", "application/sla"},
                                   {"stp", "application/step"},
                                   {"sv4cpio", "application/x-sv4cpio"},
                                   {"sv4crc", "application/x-sv4crc"},
                                   {"svf", "image/vnd.dwg"},
                                   {"svr", "application/x-world"},
                                   {"swf", "application/x-shockwave-flash"},
                                   {"t", "application/x-troff"},
                                   {"talk", "text/x-speech"},
                                   {"tar", "application/x-tar"},
                                   {"tbk", "application/toolbook"},
                                   {"tcl", "application/x-tcl"},
                                   {"tcsh", "text/x-script.tcsh"},
                                   {"tex", "application/x-tex"},
                                   {"texi", "application/x-texinfo"},
                                   {"texinfo", "application/x-texinfo"},
                                   {"text", "text/plain"},
                                   {"tgz", "application/x-compressed"},
                                   {"tif", "image/tiff"},
                                   {"tr", "application/x-troff"},
                                   {"tsi", "audio/tsp-audio"},
                                   {"tsp", "audio/tsplayer"},
                                   {"tsv", "text/tab-separated-values"},
                                   {"turbot", "image/florian"},
                                   {"txt", "text/plain"},
                                   {"uil", "text/x-uil"},
                                   {"uni", "text/uri-list"},
                                   {"unis", "text/uri-list"},
                                   {"unv", "application/i-deas"},
                                   {"uri", "text/uri-list"},
                                   {"uris", "text/uri-list"},
                                   {"ustar", "application/x-ustar"},
                                   {"uu", "application/octet-stream"},
                                   {"vcd", "application/x-cdlink"},
                                   {"vcs", "text/x-vcalendar"},
                                   {"vda", "application/vda"},
                                   {"vdo", "video/vdo"},
                                   {"vew", "application/groupwise"},
                                   {"viv", "video/vivo"},
                                   {"vivo", "video/vivo"},
                                   {"vmd", "application/vocaltec-media-desc"},
                                   {"vmf", "application/vocaltec-media-file"},
                                   {"voc", "audio/voc"},
                                   {"vos", "video/vosaic"},
                                   {"vox", "audio/voxware"},
                                   {"vqe", "audio/x-twinvq-plugin"},
                                   {"vqf", "audio/x-twinvq"},
                                   {"vql", "audio/x-twinvq-plugin"},
                                   {"vrml", "application/x-vrml"},
                                   {"vrt", "x-world/x-vrt"},
                                   {"vsd", "application/x-visio"},
                                   {"vst", "application/x-visio"},
                                   {"vsw", "application/x-visio"},
                                   {"w60", "application/wordperfect6.0"},
                                   {"w61", "application/wordperfect6.1"},
                                   {"w6w", "application/msword"},
                                   {"wav", "audio/wav"},
                                   {"wb1", "application/x-qpro"},
                                   {"wbmp", "image/vnd.wap.wbmp"},
                                   {"web", "application/vnd.xara"},
                                   {"wiz", "application/msword"},
                                   {"wk1", "application/x-123"},
                                   {"wmf", "windows/metafile"},
                                   {"wml", "text/vnd.wap.wml"},
                                   {"wmlc", "application/vnd.wap.wmlc"},
                                   {"wmls", "text/vnd.wap.wmlscript"},
                                   {"wmlsc", "application/vnd.wap.wmlscriptc"},
                                   {"word", "application/msword"},
                                   {"wp", "application/wordperfect"},
                                   {"wp5", "application/wordperfect"},
                                   {"wp6", "application/wordperfect"},
                                   {"wpd", "application/wordperfect"},
                                   {"wq1", "application/x-lotus"},
                                   {"wri", "application/mswrite"},
                                   {"wrl", "application/x-world"},
                                   {"wrz", "model/vrml"},
                                   {"wsc", "text/scriplet"},
                                   {"wsrc", "application/x-wais-source"},
                                   {"wtk", "application/x-wintalk"},
                                   {"xbm", "image/x-xbitmap"},
                                   {"xdr", "video/x-amt-demorun"},
                                   {"xgz", "xgl/drawing"},
                                   {"xif", "image/vnd.xiff"},
                                   {"xl", "application/excel"},
                                   {"xla", "application/excel"},
                                   {"xlb", "application/excel"},
                                   {"xlc", "application/excel"},
                                   {"xld", "application/excel"},
                                   {"xlk", "application/excel"},
                                   {"xll", "application/excel"},
                                   {"xlm", "application/excel"},
                                   {"xls", "application/excel"},
                                   {"xlt", "application/excel"},
                                   {"xlv", "application/excel"},
                                   {"xlw", "application/excel"},
                                   {"xm", "audio/xm"},
                                   {"xml", "text/xml"},
                                   {"xmz", "xgl/movie"},
                                   {"xpix", "application/x-vnd.ls-xpix"},
                                   {"xpm", "image/x-xpixmap"},
                                   {"x-png", "image/png"},
                                   {"xsr", "video/x-amt-showrun"},
                                   {"xwd", "image/x-xwd"},
                                   {"xyz", "chemical/x-pdb"},
                                   {"z", "application/x-compress"},
                                   {"zip", "application/x-compressed"},
                                   {"zoo", "application/octet-stream"},
                                   {"zsh", "text/x-script.zsh"}
                               };

   if(contentTypes[ext]==null)
   {
     return "application/octet-stream";

   }
       return contentTypes[ext];
     }
   }</pre>
<p>&nbsp;</p>
<p>The template:</p>
<p>&nbsp;</p>
<pre class="brush:xml">&lt;%@ Master Language="C#" MasterPageFile="~/umbraco/masterpages/default.master" AutoEventWireup="true" %&gt;

&lt;asp:Content ContentPlaceHolderID="ContentPlaceHolderDefault" runat="server"&gt;
  &lt;umbraco:Macro runat="server"  MediaID="[#media]" Alias="getMedia" /&gt;
&lt;/asp:Content&gt;</pre>
<p>&nbsp;</p>
<p>The redirect rule:</p>
<p>&nbsp;</p>
<pre class="brush:xml">        &lt;add name="cssmediarewrite"
          virtualUrl="^~/css/media/(.*)"
          rewriteUrlParameter="ExcludeFromClientQueryString"
          destinationUrl="~/cssmedia?path=$1"
          ignoreCase="true" /&gt;</pre>
<p>&nbsp;</p>
<p>Finally, add a page called CssMedia that uses the template.  Now, you can reference /css/media/mediapath/medianame.fileextension  to get the item.  This also means that your css files can use media/mediapath/medianame.fileextension to reference Umbraco media.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.foliotek.com/devblog/helper-razor-scripts-for-umbraco-cms/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Scrollable DataGrid table with Fixed Header with jQuery</title>
		<link>http://www.foliotek.com/devblog/scrollable-datagrid-table-with-fixed-header-with-jquery/</link>
		<comments>http://www.foliotek.com/devblog/scrollable-datagrid-table-with-fixed-header-with-jquery/#comments</comments>
		<pubDate>Thu, 25 Aug 2011 18:39:56 +0000</pubDate>
		<dc:creator>John Pasquet</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[datagrid]]></category>
		<category><![CDATA[fixed header]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[scrollable]]></category>
		<category><![CDATA[scrollable datagrid table]]></category>
		<category><![CDATA[table]]></category>

		<guid isPermaLink="false">http://www.foliotek.com/devblog/?p=1191</guid>
		<description><![CDATA[Problem Implement scrolling on a table, but make the header fixed. I had a really long table and wanted to make it scrollable, but keep the header in place. I saw a few examples of this, but with very little explanation to go with it. So, I just did it myself. Sample Markup &#60;div&#62; &#60;table [...]]]></description>
			<content:encoded><![CDATA[<h2>Problem</h2>
<p>Implement scrolling on a table, but make the header fixed.</p>
<p>I had a really long table and wanted to make it scrollable, but keep the header in place.  I saw a few examples of this, but with very little explanation to go with it.  So, I just did it myself.</p>
<h2>Sample Markup</h2>
<pre class="brush: html; ">

&lt;div&gt;

  &lt;table id=&quot;MyDataRows&quot;&gt;

    &lt;thead&gt;
      &lt;tr class=&quot;grid_header&quot;&gt;
        &lt;th&gt;Col1&lt;/th&gt;
        &lt;th&gt;Col2&lt;/th&gt;
        &lt;th&gt;Col3&lt;/th&gt;
      &lt;/tr&lt;&gt;
    &lt;/thead&gt;

    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;Data&lt;/td&gt;
        &lt;td&gt;Data&lt;/td&gt;
         &lt;td&gt;Data&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;

&lt;/div&gt;
</pre>
<h2>First Attempt</h2>
<p>So, the first option I saw online was to add &#8220;overflow-y: auto; display: block; height: 330px;&#8221; to the tbody tag.  I saw somewhere where this could work with a single column, but with multiple columns, the header is pushed to the right, and the table rows are pushed to the left.  I played with this awhile, but never could get it to work.<span style="font-size: 15px; font-weight: bold;"><br />
</span></p>
<h2>Solution</h2>
<p>While not as elegant as I would like, this solution does work.  Of course, if you isolate the header and then wrap the data rows in a div with the overflow-y stuff, that would work.  However, a datagrid populates the header automatically.  You could build another datagrid and mess with that, but jQuery quickly solves the issue.  Here&#8217;s the plan:</p>
<ul>
<li>Add a place for the header to be moved outside of the table with the rows where the overflow-y will be used</li>
<li>Move the header</li>
<li>Realign the columns</li>
</ul>
<h2>New Markup</h2>
<p>This is pretty basic.  I added a table just before the table with data in it.  This will hold the header.  I also styled the div to allow for scrolling.</p>
<pre class="brush: html; ">

&lt;table id=&quot;MyHeader&quot;&gt;&lt;/table&gt;

&lt;div style=&quot;overflow-y: auto; height: 330px;&quot;&gt;

  &lt;table id=&quot;MyDataRows&quot;&gt;

    &lt;thead&gt;
      &lt;tr class=&quot;grid_header&quot;&gt;
        &lt;th&gt;Col1&lt;/th&gt;
        &lt;th&gt;Col2&lt;/th&gt;
        &lt;th&gt;Col3&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;

    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;Data&lt;/td&gt;
        &lt;td&gt;Data&lt;/td&gt;
        &lt;td&gt;Data&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;

&lt;/div&gt;
</pre>
<h2>jQuery Code</h2>
<pre class="brush: javascript; ">

&lt;script type=&quot;text/javascript&quot;&gt;// &lt;![CDATA[
$(function () {
    /* move the table header from the datagrid outside, so it doesn&#039;t scroll&quot; */
    $(&quot;#MyHeader&quot;).append($(&quot;#StudentData thead&quot;));
    $(&quot;#MyDataRows&quot;).css(&quot;margin-bottom&quot;, &quot;0&quot;);

    var ths = $(&quot;#MyHeader th&quot;);
    var tds = $(&quot;#MyDataRows tr:first td&quot;);

    /* Reset the padding of the th&#039;s to match the td&#039;s */
    ths.css(&quot;padding-left&quot;, tds.first().css(&quot;padding-left&quot;));
    ths.css(&quot;padding-right&quot;, tds.first().css(&quot;padding-right&quot;));

    /* Set the widths of all the th&#039;s (except the last to acccount for scroll bar) to the corresponding td width */
    for (var i = 0; i &lt; tds.length - 1; i++) {
        ths.eq(i).width(tds.eq(i).width());
    }
});
// ]]&gt;&lt;/script&gt;
</pre>
<h2>Final Markup</h2>
<p>So, the end result is two tables whose column widths match but which function as a scrollable datagrid table with a fixed header.</p>
<pre class="brush: html; ">

&lt;table id=&quot;MyHeader&quot;&gt;
  &lt;thead&gt;
    &lt;tr class=&quot;grid_header&quot;&gt;
      &lt;th&gt;Col1&lt;/th&gt;
      &lt;th&gt;Col2&lt;/th&gt;
      &lt;th&gt;Col3&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
&lt;/table&gt;

&lt;div style=&quot;overflow-y: auto; height: 330px;&quot;&gt;

  &lt;table id=&quot;MyDataRows&quot;&gt;

    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;Data&lt;/td&gt;
        &lt;td&gt;Data&lt;/td&gt;
        &lt;td&gt;Data&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;

  &lt;/table&gt;

&lt;/div&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.foliotek.com/devblog/scrollable-datagrid-table-with-fixed-header-with-jquery/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

