<?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>Tech Blog &#187; JavaScript</title>
	<atom:link href="http://assanka.net/content/tech/tag/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>http://assanka.net/content/tech</link>
	<description>Just another Arb-assk2009003.turmeric.assanka.com Blogs weblog</description>
	<lastBuildDate>Mon, 29 Aug 2011 19:00:46 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>FastClick: native-like tapping for touch apps</title>
		<link>http://assanka.net/content/tech/2011/08/26/fastclick-native-like-tapping-for-touch-apps/</link>
		<comments>http://assanka.net/content/tech/2011/08/26/fastclick-native-like-tapping-for-touch-apps/#comments</comments>
		<pubDate>Fri, 26 Aug 2011 08:44:46 +0000</pubDate>
		<dc:creator>Matt Caruana Galizia</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[events]]></category>
		<category><![CDATA[fastclick]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[touch]]></category>
		<category><![CDATA[UI]]></category>

		<guid isPermaLink="false">http://assanka.net/content/tech/?p=227</guid>
		<description><![CDATA[The JavaScript APIs for handling touch events and gestures in JavaScript are simple and intuitive enough to grasp on first try, and the increasingly excellent support for web standards in Webkit browsers means we can create highly touch optimised web apps that look and feel like native apps.   But that doesn’t mean there [...]]]></description>
			<content:encoded><![CDATA[<p>The JavaScript APIs for handling touch events and gestures in JavaScript are simple and intuitive enough to grasp on first try, and the increasingly excellent support for web standards in Webkit browsers means we can create highly touch optimised web apps that look and feel like native apps.   But that doesn’t mean there won’t be any hitches when you get deeper into web app development, and one of those hitches only becomes apparent when users stop thinking of your app as a website.</p>
<p>Probably because touchscreen devices weren’t nearly as popular in 1995 as they are today, JavaScript DOM events tend to reflect the mouse ‘click’ paradigm, where each event neatly corresponds to a single, deliberate click of the button. Take the onClick event, for example. How does that translate to a touchscreen device? Not easily, as it turns out.</p>
<p>Treating a ‘tap’ as a ‘click’ is the practical approach. On iOS at least, there’s no onTap event &#8211; <code>onClick</code> has been repurposed for that role. But in order to properly handle multiple-touch gestures like pinching or even double-taps, some compromises have to be made. One of these is the roughly 300ms delay between a tap and the firing of a click event, which can make your apps feel laggy and unresponsive even when it’s not technically so.</p>
<p>The technique we use to get around this problem is to track all <code>TouchStart</code> events in our app and fire a click event as soon as we receive a <code>TouchEnd</code> event (unless some application-specific exception is satisfied).</p>
<p>As we refined our fast-clicking code, we turned it into a small and efficient library, which we call <strong>FastClick</strong>. This code has been tried and tested by hundreds of thousands of users, and so far has proved to be very robust.  We’d love to know what others are doing to address this challenge and find ways of improving our own approach, and to help kick off that process, we’re open-sourcing FastClick today.  We’d encourage you to try it out, and let us know what you think.</p>
<p>To use FastClick, instantiate it on the layer you’d like to be fast-clickable &#8211; we use <code>document.body</code> because we want all our buttons and links to receive fast clicks. In your event listeners, ‘click’ events synthesised by FastClick will have the <code>forwardedTouchEvent</code> property set to true.</p>
<p>If you use buttons and iOS-style menus in your app then there’s a good chance your interface feels unresponsive on touchscreen devices. Here’s a simple example of how we solve that problem for a single button by instantiating FastClick on it:</p>
<pre class="brush: xml;">
&lt;button class=”fastclick” onclick=”someHandler()”&gt;Fast click&lt;/button&gt;
&lt;button onclick=”someHandler()”&gt;Slow click&lt;/button&gt;
&lt;script type='text/javascript'&gt;
var button = document.querySelector(&quot;.fastclick&quot;);
new FastClick(button);
&lt;/script&gt;
</pre>
<p>In the example, the button with a <code>fastclick</code> class will have its click handler called as soon as your finger is lifted off the screen, while tapping on any other buttons on the page will trigger the same handler after a noticeable delay. Try the <a href="http://assanka.net/content/tech/files/2011/08/fastclickdemo.html">live demo</a>.</p>
<p>Unfortunately, the <code>select</code> element doesn&#8217;t behave normally when receiving (synthesised) programmatic clicks, so if you apply FastClick to an element that contains selects, FastClick will ignore clicks on the select and allow the normal click event to fire.</p>
<p>If you want any other elements (besides selects) in your FastClick layer to receive non-programmatic clicks, you&#8217;ll need to use one of two classes: <code>clickevent</code> or <code>touchandclickevent</code>. For any clickable element in a FastClick layer, tapping the element will cause different effects depending on how you use these classes:</p>
<ul>
<li>No class: The element will receive only a programmatic click from FastClick.  The default click event triggered by the user will be suppressed.</li>
<li><code>clickevent</code>: The element will receive only the default click event, and will be ignored by FastClick</li>
<li><code>touchandclickevent</code>: The element will receive both the default click event AND a programmatic click from FastClick (the FastClick one will be triggered first). This is only safe if your handler&#8217;s action is idempotent.</li>
</ul>
<p>Here&#8217;s an example of all three:</p>
<pre class="brush: xml;">
&lt;div class=&quot;fastclick&quot;&gt;
	&lt;button onclick=&quot;someHandler()&quot;&gt;
		Will receive programmatic click event
	&lt;/button&gt;
	&lt;button class=&quot;clickevent&quot; onclick=&quot;someHandler()&quot;&gt;
		Will receive non-programmatic click event
	&lt;/button&gt;
	&lt;button class=&quot;touchandclickevent&quot; onclick=&quot;someHandler()&quot;&gt;
		Will receive both click events
	&lt;/button&gt;
&lt;/div&gt;
&lt;script type='text/javascript'&gt;
var button = document.querySelector(&quot;.fastclick&quot;);
new FastClick(button);
&lt;/script&gt;
</pre>
<p>When is this useful? Try the <a href="http://assanka.net/content/tech/files/2011/08/fastclickdemo-input.html">other live demo</a> we&#8217;ve built using a click event handler that attempts to trigger focus on an <code>input</code> element. iOS will only allow focus to be triggered on other elements within a handler function if the event that triggered it was non-programmatic.</p>
<p>We’ll be posting updates and answering questions on this blog. If the interest reaches a stage where FastClick could benefit from the developer community, we’ll move to a public repository host. But for now, concentrate on giving your users the best response time they can get &#8211; <a href="http://assanka.net/content/tech/files/2011/08/fastclick.js">download FastClick</a> (or <a href="http://assanka.net/content/tech/files/2011/08/fastclick.min_.js">minified</a>) and give it a go. Its free to use in all your apps, and licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://assanka.net/content/tech/2011/08/26/fastclick-native-like-tapping-for-touch-apps/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Tips for better fragment navigation</title>
		<link>http://assanka.net/content/tech/2011/02/16/tips-for-better-fragment-navigation/</link>
		<comments>http://assanka.net/content/tech/2011/02/16/tips-for-better-fragment-navigation/#comments</comments>
		<pubDate>Wed, 16 Feb 2011 10:05:07 +0000</pubDate>
		<dc:creator>Andrew Betts</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[fragments]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[keyboard]]></category>
		<category><![CDATA[Scrolling]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[User experience]]></category>

		<guid isPermaLink="false">http://assanka.net/content/tech/?p=170</guid>
		<description><![CDATA[Fragment navigation is becoming more and more popular.  Facebook practically runs their entire site on it, twitter search uses it, and Google recently defined a standard for making it crawl-able.  JavaScript framework evangelists have rushed to produce plug-ins for their favourite tool-kit to make fragment navigation easier to implement.  Here I&#8217;ll discuss [...]]]></description>
			<content:encoded><![CDATA[<p>Fragment navigation is becoming more and more popular.  Facebook practically runs their entire site on it, twitter search uses it, and Google recently defined a <a href="http://code.google.com/web/ajaxcrawling/docs/getting-started.html">standard for making it crawl-able</a>.  JavaScript framework evangelists have rushed to produce plug-ins for their favourite tool-kit to make fragment navigation easier to implement.  Here I&#8217;ll discuss some of the issues we&#8217;ve dealt with as we started to use fragment navigation more often.</p>
<p><img src="http://assanka.net/content/tech/files/2010/08/new-1.png" alt="" title="Facebook example of fragment navigation" width="590" height="72" class="alignnone size-full wp-image-178" /></p>
<p>The details of how fragment navigation (also hash navigation or hash fragment navigation) works have been <a href="http://www.novatek.com.au/news/fragment-navigation">covered</a> <a href="http://yensdesign.com/2008/11/creating-ajax-websites-based-on-anchor-navigation/">extensively</a> by <a href="http://msdn.microsoft.com/en-us/library/cc891506(VS.85).aspx">others</a>, and have been abstracted into various frameworks and toolkits.  A number are available for jQuery, such as:</p>
<ul>
<li><a href="http://plugins.jquery.com/project/history">History</a></li>
<li><a>BBQ</a> (<a href="http://mattfrear.com/2010/03/20/enabling-browser-back-button-on-cascading-dropdowns-with-jquery-bbq-plugin/">tutorial</a>)</li>
<li><a href="http://www.asual.com/jquery/address/">Address</a></li>
</ul>
<p>However, fragment navigation comes with a new set of challenges that we found ourselves having to address, so these will be the focus of this post.</p>
<h2>Full page alternatives</h2>
<p>Rather than changing all links to the form <code>&lt;a href="#!fragment/path/for/ajax"&gt;Link&lt;/a&gt;</code> and then detecting and acting upon fragment changes in javascript, we wanted to ensure that our links worked when they were copied and pasted into a new browser window, shared by email, or used with javascript disabled.  This meant making them into real URL links, and then progressively enhancing using a Javascript onclick handler to cancel the normal navigation action:</p>
<pre class="brush: xml;">
&lt;a href=&quot;/path/works/as/fragment/or/normal/page&quot; class=&quot;fragnav&quot;&gt;Link&lt;/a&gt;
</pre>
<p>And some jQuery to hook the onclick handler on these fragment-navigation-compatible links, and convert them so that rather than navigating to the specified href, the browser changes it&#8217;s hash instead:</p>
<pre class="brush: jscript;">
$(&quot;a.fragnav&quot;).click(function() {
  var href = this.href.replace(/^https?:\/\/[a-z0-9\.]+\/(.*\#\!)?/, '');
  location.hash = this.href;
  return false;
});
</pre>
<p>Now you can either click the link with javascript enabled and get a dynamic AJAX behaviour, or right click then &#8216;Open in new window&#8217; (or click with javascript disabled) to get the full URL of the link to load normally.</p>
<h2>Caching</h2>
<p>When your user presses &#8216;back&#8217;, you can detect the fragment change and reload appropriate content &#8211; great.  But this is not as good as what you get from browsers&#8217; normal back button behaviour.  Normally, the previous page is cached, so it reappears almost instantly.  In the AJAX version, unless your fragment is just switching between different versions of content that are all preloaded, you may fire an AJAX request to load the content again.</p>
<p>It shouldn&#8217;t be necessary to reimplement caching yourself, since AJAX requests are subject to the same browser caching as normal page loads, but it&#8217;s easy to forget that you should include appropriate cache headers with your AJAX responses.  There are four HTTP headers that generally modify a browser&#8217;s caching behaviour:</p>
<ul>
<li>Cache-Control (<a href='http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9'>Docs</a>)</li>
<li>Expires (<a href='http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21'>Docs</a>)</li>
<li>ETag (<a href='http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19'>Docs</a>)</li>
<li>Last-Modified (<a href='http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.29'>Docs</a>)</li>
</ul>
<p>Cache-Control and Expires are cache directive headers, telling the browser whether and for how long it may cache the resource.  Typically we set only Cache-Control, as it is more powerful and flexible, and Expires is generally unnecessary.</p>
<p>ETag and Last Modified are validators.  These allow the browser to make a conditional request to the server to find out if the resource has changed, and allow the server to respond with a simple 304 Not Modified if it hasn&#8217;t.  It&#8217;s often the case that your web server will add these automatically, and we prefer to avoid them entirely, relying on a single Cache-Control header to determine browser behaviour.</p>
<pre class="brush: xml;">
Cache-Control: max-age:60, public
</pre>
<p>A nice trick for content that is personalised to an authenticated user is to include the <code>private</code> directive in your Cache-Control header, which allows the page to be cached, but only by the browser, not by any proxies along the way.</p>
<h2>Scroll position</h2>
<p>One of the things we found to be most difficult was managing scroll position.  Consider the default behaviour of a browser when navigating normally.  If you scroll down a page and click a link somewhere near the bottom, the browser loads the new page and displays it starting at the top.  However, if you then press the back button, it redisplays the last page you viewed and <strong>restores your scroll position for that page</strong>.  You may not have even noticed this, but if it stopped behaving this way you&#8217; get pretty annoyed soon enough!</p>
<p>So, if a user clicks one of your fragment links low down on your page, and the change you make to the page as a result would appear to the user to constitute a new page (obviously the point at which perception of &#8216;a new page&#8217; is triggered is subjective), consider scrolling the browser window back to the top.</p>
<p>But, you should not do this if the back button is used, because the browser will restore the user&#8217;s previous scroll position all by itself.  However, this becomes more complex if navigating forwards has considerably shortened the page content, and restoring the scroll position on back would require you to restore the content first in order for the necessary scroll offset to actually exist.  This is a bit confusing.  Here&#8217;s an illustration:</p>
<p><img src="http://assanka.net/content/tech/files/2011/01/ajaxnavgraphic1.png" alt="Illustration of problems with scroll position when using AJAX navigation" title="Illustration of problems with scroll position when using AJAX navigation" class="aligncenter size-full wp-image-197" /></p>
<p>So the solution we use is to remember the scroll position on every navigation action, and then restore it after repopulating the content if it looks like a backwards step.  You need to ensure you have got your caching rules right to support this otherwise the delay in refetching the content will make the browser reposition the scroll position twice &#8211; once by itself immediately, and again triggered by your JavaScript after the content has loaded.</p>
<h2>Loading pause</h2>
<p>Normally, the process of clicking a link and navigating to a new page involves the current page <strong>remaining on screen</strong> while the new page is being requested.  The browser only blanks it out when content starts to arrive for the new page.  The browser does provide some progress feedback immediately though, in the form of a wait mouse cursor or spinner in the browser chrome.</p>
<p>We aimed to replicate this experience for our AJAX-loaded views.  This means avoiding what seems like an obvious solution &#8211; empty the container when the link is clicked, and populate it when the AJAX response is received &#8211; because you&#8217;ll get a flash of blankness between the old content disappearing and new content replacing it.  Instead, the old content should remain, and the new content should simply replace it when the AJAX completes.</p>
<p>But this doesn&#8217;t provide progress feedback.  The risk is, the user will think nothing&#8217;s happened and will click the link again.  This tends to happen after about 2-3 seconds for most users, but AJAX calls normally don&#8217;t take anywhere near that long.  So we implemented a timeout that, after 250ms, would blank out the container, replacing the old content with a loading spinner.  If the AJAX completes within that time, it cancels the timer.</p>
<p>So, in most cases the user clicks a link and sees an almost immediate cut from old content to new with no flash of blankness.  In some cases they see the old content vanish and a loading spinner to reassure them that something is happening while we wait for the new content to come back.</p>
<p>If you regularly have edge cases where content takes more than a few seconds to load, you should consider moving on to a different kind of progress feedback, to avoid hitting that &#8220;it hasn&#8217;t worked&#8221; perception boundary.  The aim is to keep pushing that boundary back, keeping the user&#8217;s expectations in line with the performance that they&#8217;re getting from the site.  I like to think of this like a timeline:</p>
<p><img src="http://assanka.net/content/tech/files/2011/01/ajaxnavgraphic2.png" alt="Timeline of user perception when waiting for a navigation action to complete" title="Timeline of user perception when waiting for a navigation action to complete" width="515" height="169" class="aligncenter size-full wp-image-199" /></p>
<p>By providing better progress feedback, you can expand the &#8216;Expectation&#8217; phase and avoid the &#8216;Frustration&#8217; phase.  However, it&#8217;s also equally important that you don&#8217;t display a big piece of progress feedback for the entire operation to then complete in under 250ms &#8211; the feedback will be on screen for such a short period that the user will potentially be unsure about what happened and get anxious.  So be aware of the &#8216;instant&#8217; phase, when you should present no feedback at all.</p>
<h2>Inline Javascript</h2>
<p>Sometimes, it&#8217;s convenient to get both new HTML code and new Javascript when your user clicks a fragment link.  In our case, we wanted to set some Javascript globals in the response to allow javascript code already loaded on the page to better understand the content that had just been loaded.  Say the user has requested a page with a fragment that loads some search results.  We also want to tell the browser the search query that produced the results so that it can cache them, or populate the query into a search field that&#8217;s outside the fragment container, or something.</p>
<p>Normally, if you load content from a server using AJAX and append it to the DOM using innerHTML, any &lt;script&gt; sections in the HTML are not parsed by the browser&#8217;s JavaScript engine.  However, to make it do this is as simple as searching the returned source for &lt;script&gt; sections, and evaling them.  Make sure you properly filter and escape end user input before allowing it to be evaled though, otherwise you&#8217;re opening up your site to XSS attacks.</p>
<pre class="brush: jscript;">
$('#main script').each(function() { eval(this.text); });
</pre>
<h2>Command, Control and Shift modifier keys</h2>
<p>Power users like to open links in new tabs or windows.  In fact when faced with a list of links I often hold down Control and hit each link to turn to start preloading all the results into tabs which I can then review in turn without having to wait for each one to load.  To avoid annoying users, you need to ensure that whereever possible, control-click (or command-click) and shift-click (normally &#8216;new tab&#8217; and &#8216;new window&#8217; respectively) still work.</p>
<p>It&#8217;s easy to get lulled into a false sense of security by right clicking on your links and using the context menu to select &#8216;Open in new tab&#8217;.  This won&#8217;t run your onclick handler, so most likely will work if your link has a non-JavaScript href.  But using the keyboard CTRL key while clicking the link will fire the onclick event, and if you are cancelling the normal link navigation action by returning false, you&#8217;ll also be cancelling the new tab or new window request.  Ensuring that you don&#8217;t is quite straightforward (remember to include e.metaKey to detect the Command key on Macs):</p>
<pre class="brush: jscript;">
if (e.shiftKey || e.ctrlKey || e.metaKey) return true;
</pre>
<h2>Focus rectangles</h2>
<p>In most browsers, when you click a link, you get a small dotted rectangle around it.  This focus rectangle also appears if you tab through the actionable items on a page, to indicate which one would be followed if you pressed enter.  The problem is that if your link fires an AJAX action, and the link itself remains on screen after the action has completed, you&#8217;re left with a focus rectangle that you probably don&#8217;t want.</p>
<p>A bad way of dealing with this is to simply use CSS to set <code>outline:none</code> on all A tags.  This will certainly solve your problem, but kill all hope of keyboard navigation of your site.  Better is to study the way that this interaction happens normally, and then mimic it for your Ajax actions.  This is actually fairly easy to do generically:</p>
<pre class="brush: jscript;">
(function() {

  // Keep track of which link element last had the focus (if browser does not support document.activeElement)
  if (!document.activeElement) {
    $(&quot;a&quot;).live('focus', function() {
      document.activeElement = this;
    });
  }

  // When any AJAX operation completes, blur any focused link
  $.ajaxSetup({complete:function(xhr, textStatus) {
    if (document.activeElement &amp;&amp; document.activeElement.is('a')) document.activeElement.blur();
  }});
}());
</pre>
<p>Drop the above snippet into your javascript and you should find that focus rectangles still appear and stay visible while the ajax is running, but then vanish once it completes &#8211; perfect replica of the effect the user has learned to expect.  If your links don&#8217;t perform any AJAX, you&#8217;ll have to deal with those separately.</p>
<h2>Conclusion</h2>
<p>With all this to think about, you&#8217;d be forgiven for concluding that AJAX navigation simply isn&#8217;t worth the bother.  But bear with it &#8211; the benefits of being able to trivilally maintain state and load small fragments of content really makes a difference, both to the quality of the user experience and the load on your servers.</p>
]]></content:encoded>
			<wfw:commentRss>http://assanka.net/content/tech/2011/02/16/tips-for-better-fragment-navigation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Thoughts on CSS transitions in Firefox</title>
		<link>http://assanka.net/content/tech/2010/05/20/thoughts-on-css-transitions-in-firefox/</link>
		<comments>http://assanka.net/content/tech/2010/05/20/thoughts-on-css-transitions-in-firefox/#comments</comments>
		<pubDate>Thu, 20 May 2010 14:36:05 +0000</pubDate>
		<dc:creator>Andrew Betts</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[Animation]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Future Tech]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://assanka.net/content/tech/?p=129</guid>
		<description><![CDATA[To produce the CSS3 ticker plugin for jQuery that I&#8217;ve been working on recently, I used CSS3 transitions.  These are the magic new properties in CSS that make a browser animate elements without using JavaScript.
The logic for implementing native animations in the browser is a no-brainer, particularly if you try and use a site [...]]]></description>
			<content:encoded><![CDATA[<p>To produce the <a href="/content/tech/2010/03/14/smooth-css3-ticker-jquery-plugin/">CSS3 ticker plugin for jQuery</a> that I&#8217;ve been working on recently, I used <a href="http://webkit.org/blog/138/css-animation/">CSS3 transitions</a>.  These are the magic new properties in CSS that make a browser animate elements without using JavaScript.</p>
<p>The logic for implementing native animations in the browser is a no-brainer, particularly if you try and use a site that implements scrolling tickers by incrementing an element&#8217;s <code>left</code> or <code>margin-left</code> properties every few milliseconds.   Watch your interactions with the rest of the page slow down to a sluggish crawl and realise that animating the positioning of DOM elements in JavaScript can sometimes be pretty slow.</p>
<p>With animation increasingly important to creating rich and usable user interfaces, the chance to start optimising the performance of animation in the browser via native implementation is a great step forward.  Unfortunately, this is currently only supported by Webkit based browsers.  In developing the ticker, I wanted to see if support in Firefox would be possible.</p>
<p>From version 1.9.3 of Gecko, the <code>-moz-transition</code> family of CSS properties have been added, so I tried grabbing the latest version of <a href='http://www.mozilla.org/projects/minefield/'>Minefield</a> (the pre-release codename for Firefox) and running the ticker plugin.</p>
<p>It doesn&#8217;t work.  Specifically, it doesn&#8217;t work for these reasons:</p>
<ol>
<li>It doesn&#8217;t seem to be possible to act on position properties.  <code>left</code>, <code>right</code>, <code>top</code> and <code>bottom</code> do not appear to animate.  It might be possible to work around this by switching to animating margins rather than absolute positioning, but hopefully it will be possible to animate these before the Firefox 3.7 release.</li>
<li>It doesn&#8217;t appear to fire the <code>mozTransitionEnd</code> event, which you&#8217;d expect from a full implementation of the standard.  As a result, my ticker can&#8217;t loop.</li>
<li>It doesn&#8217;t seem to be possible to change animation properties (such as the duration) from JavaScript.  I need this to disable animation while repositioning the ticker for the next loop.</li>
</ol>
<p>This is clearly an early pre-release version, and it&#8217;s encouraging to see support starting to emerge from the Firefox camp.  I think I might have retired by the time this kind of feature hits Internet Explorer!</p>
]]></content:encoded>
			<wfw:commentRss>http://assanka.net/content/tech/2010/05/20/thoughts-on-css-transitions-in-firefox/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Smooth CSS3 ticker jQuery plugin</title>
		<link>http://assanka.net/content/tech/2010/03/14/smooth-css3-ticker-jquery-plugin/</link>
		<comments>http://assanka.net/content/tech/2010/03/14/smooth-css3-ticker-jquery-plugin/#comments</comments>
		<pubDate>Sun, 14 Mar 2010 11:50:26 +0000</pubDate>
		<dc:creator>Andrew Betts</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Tickers]]></category>
		<category><![CDATA[UI Design]]></category>

		<guid isPermaLink="false">http://assanka.net/content/tech/?p=105</guid>
		<description><![CDATA[I&#8217;ve recently been building a status display for the Assanka office, which shows us information like current Zabbix monitoring triggers, support requests from clients, Pingdom status alerts, and even naming and shaming Assankans who&#8217;ve failed to file their time-sheets on time.
In the process, I was pointed at the gorgeous Panic status board.  Our objectives [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently been building a status display for the Assanka office, which shows us information like current Zabbix monitoring triggers, support requests from clients, Pingdom status alerts, and even naming and shaming Assankans who&#8217;ve failed to file their time-sheets on time.</p>
<p>In the process, I was pointed at the gorgeous <a href="http://www.panic.com/blog/2010/03/the-panic-status-board/">Panic status board</a>.  Our objectives were similar and I was attracted to the idea of adding the scrolling tickers (at least, we assume they are scrolling from Panic&#8217;s photograph), which run along the bottom of their board.  I was reminded of the kind of tickers you get on 24 hour news channels (here&#8217;s one from BBC World):</p>
<p><img src="/content/tech/files/2010/03/bbcworldcap42.jpg" alt="BBC World screen capture showing scrolling ticker" /></p>
<p>Tickers in web browsers are difficult for a number of reasons.  First, continuously animating the <code>left</code> or <code>margin-left</code> properties of an element in JavaScript is computationally expensive, particularly if you want to reposition the element often enough to create a properly smooth animation.  Sites that use Javascript for tickers in this manner tend to hog your computer&#8217;s CPU and feel slow and laggy as a result.  Many sites give up on the traditional ticker and go for something that&#8217;s easier for the browser to animate, like a &#8216;type in&#8217; reveal (eg the BBC News homepage ticker), or a vertical &#8217;scroll up&#8217; ticker.</p>
<p><img src="/content/tech/files/2010/05/Capture.jpg" alt="BBC News online ticker" /></p>
<p>Another issue with continuous tickers is making them loop properly.  When your animation reaches the end of the text, you have to scroll it all the way off the left edge of the screen before it can be repositioned and re-enter the frame from the right.  This leaves an ugly gap in your ticker.</p>
<p>Finally, if your ticker is updating with new information in real time, making changes that are noticeable in the visible portion of the ticker is amateur hour stuff.  You rarely see TV tickers suddenly change mid-scroll, and yet stories are seamlessly added and removed as necessary, <em>outside of the visible frame</em>.</p>
<p>Since Panic didn&#8217;t release any code (boo), I set out to produce a jQuery plugin that would enable news tickers to be easily added to a page, using CSS3 animation effects.  If it&#8217;s working for you, you should see a couple of tickers scrolling away right here:</p>
<div class="iframe-wrapper">
  <iframe src="/content/tech/files/2010/05/webkitscroller.html" frameborder="0" style="height:85px;width:590px;">Please upgrade your browser</iframe>
</div>
<p>If it&#8217;s not working, you&#8217;re probably not using a browser that supports CSS3 transitions.  Try it in Chrome, or Safari.  Support should be added to Firefox pretty soon.  But the objective here is not to get universal compatibility, since I can easily dictate which browser our status board will use.</p>
<p>With CSS3 transitions, we substantially improve the performance issue of tickers.  And this will improve further with browsers implementing these effects at an increasingly lower level.  This leaves the looping and updating issues to resolve before we can claim a properly news-grade ticker.</p>
<h2>Looping</h2>
<p>There are two possible solutions to the looping problem.  The first is to target segments of the ticker just after they have left the frame on the left, and move them to the end of the ticker on the right.  The second is to make several copies of your ticker content, and when you get to the end of the second copy, reposition the entire ticker element so that the first copy lines up with where the second copy had got to, then scroll on into the second copy again and repeat.</p>
<p>I chose the second approach, because you need several copies of the ticker anyway if it&#8217;s too short to fill the width of the frame with enough left over to sort the looping out.</p>
<h2>Updates</h2>
<p>In order to enable the ticker to be updated dynamically, and yet not suffer any noticeable changes in the visible portion, I added some public methods &#8211; addMessage() and removeMessage(), which allow you to pass a list element and have it queued for addition or removal at an appropriate moment.</p>
<p>This does require breaking a rather holy tenet of jQuery, namely returning a reference to the ticker rather than returning the jQuery chain, so you have an object on which you can call the public methods.</p>
<p>Every time the ticker hits the end of the text, it is  repositioned with the penultimate copy in view, all copies of the ticker text are updated to match the copy to their right, and the final copy (the original set of elements) is updated with the queued additions and removals (out of view).   As a result, when you call the add or remove methods, you may have to wait some time before you see the effect, but the ticker will never judder or change while it is visible to the user.</p>
<h2>How to use</h2>
<p>Your ticker must be a block element containing a UL.  This is because the ticker needs a frame to mask the content as it slides through.</p>
<pre class="brush: xml;">
&lt;div id='ticker1'&gt;
  &lt;ul&gt;
    &lt;li&gt;Headline one&lt;/li&gt;
    &lt;li&gt;Headline two&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
  var ticker = $('#ticker1').ticker();
  var newid = ticker.addMsg('Headline three');
  setTimeout(function() {
    ticker.removeMsg(newid);
  }, 60000);
&lt;/script&gt;
</pre>
<h2>Settings and methods</h2>
<p>The following settings are available, which can be passed to the <code>ticker()</code> function in a standard json object:</p>
<ul>
<li><strong>pxpersec</strong>: Speed of the ticker in pixels per second (optional; default is 30)</li>
</ul>
<p>Calls to the <code>ticker()</code> function return a reference to the ticker, not the jQuery chain.  The ticker reference exposes the following methods:</p>
<ul>
<li><strong>string addMsg(<em>msg</em>)</strong>: Add a new message to the ticker.  Can be a jQuery object or raw list item element (which will be moved from its current location in the DOM), or a plain text string.  Returns a string identifier for the message (to enable you to remove it later).  If you pass an element that already has an ID attribute, that ID is used (and returned).</li>
<li><strong>void removeMsg(<em>msg</em>)</strong>: Remove a message from the ticker.  Can be a jQuery object or raw list item element (which must be in the ticker already), or a string identifier returned from the addMsg call that added the message to the ticker. Returns nothing.</li>
</ul>
<h2>Get the code</h2>
<ul>
<li><a href="/content/tech/files/2010/05/jquery.ticker.js">Download development</a> (commented, 7KB)</li>
<li><a href="/content/tech/files/2010/05/jquery.ticker.min.js">Download production</a> (minified, 4KB)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://assanka.net/content/tech/2010/03/14/smooth-css3-ticker-jquery-plugin/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Blocking events with blocker lists</title>
		<link>http://assanka.net/content/tech/2009/12/07/blocking-events-with-blocker-lists/</link>
		<comments>http://assanka.net/content/tech/2009/12/07/blocking-events-with-blocker-lists/#comments</comments>
		<pubDate>Mon, 07 Dec 2009 14:42:35 +0000</pubDate>
		<dc:creator>Andrew Betts</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Scrolling]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[User experience]]></category>

		<guid isPermaLink="false">http://assanka.net/content/tech/?p=56</guid>
		<description><![CDATA[It&#8217;s often useful to be able to detect scroll events using the onscroll event handler in JavaScript.  For example, every time a user scrolls to nearly the bottom of the page, you load more content to create an &#8216;endless&#8217; page.  In my case, I have two DIVs set to overflow: auto, with chat [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s often useful to be able to detect scroll events using the onscroll event handler in JavaScript.  For example, every time a user scrolls to nearly the bottom of the page, you load more content to create an &#8216;endless&#8217; page.  In my case, I have two DIVs set to overflow: auto, with chat histories in each, where the chats have been taking place simultaneously.  I want to detect when the user scrolls one of the DIVs (either one) and then scroll the other one to keep the two in sync.  That is to say, we want messages that are currently vertically in the middle of DIV 1 to have been posted at around the same time as the messages at the same vertical viewport offset in DIV 2.</p>
<p>Try scrolling either of the panels in this example:</p>
<div class="iframe-wrapper">
  <iframe src="/content/tech/files/2009/12/testcase_blockerlist11.html" frameborder="0" style="height:220px;width:450px;">Please upgrade your browser</iframe>
</div>
<p>You should find it scrolls madly and unpredictably until you press stop.</p>
<p>The first problem is that onscroll is not simply fired when you finish scrolling.  It fires like a machine gun continuously while the mouse cursor is moving on the scroll handle.  The solution to this is a watchdog.  A watchdog is a timer that will execute action A if action B does not happen within X seconds.  So every time onscroll fires, we reset the timer, and if it gets to zero we know that the user has finished scrolling (or at least has paused for long enough for us to do something about it).</p>
<div class="iframe-wrapper">
  <iframe src="/content/tech/files/2009/12/testcase_blockerlist2.html" frameborder="0" style="height:220px;width:450px;">Please upgrade your browser</iframe>
</div>
<p>You&#8217;ll find that although it&#8217;s not quite as crazed, the panels do keep scrolling, one after the other.</p>
<p>The problem now is that when you scroll DIV 1, and this causes an automatic scroll of DIV 2, that automatic scroll ALSO triggers the onscroll event and so we then scroll DIV 1 again.  The solution is to have a variable that flags whether we are currently paying attention to scroll events, and turn it off when we don&#8217;t want to detect scrolling (ie just before the auto-scroll) and then on again after the scroll has completed (I&#8217;m using an animation library so the scroll takes around half a second to complete).  Try this (don&#8217;t click the button yet, just scroll the panels):</p>
<div class="iframe-wrapper">
  <iframe src="/content/tech/files/2009/12/testcase_blockerlist3.html" frameborder="0" style="height:220px;width:550px;">Please upgrade your browser</iframe>
</div>
<p>Success.  However, this approach is a bit short-sighted.</p>
<p>You also need to turn off scroll detection when adding or removing content from either DIV, because changing the height of the content within the element can also fire the onscroll event.  So if this is a chat window, and we&#8217;re adding and removing content in the DIVs, we have to disable scroll detection while we&#8217;re doing that and then turn it on again afterwards.</p>
<p>Sadly, our scroll detection flag is crude &#8211; it&#8217;s a sheer yes/no, and if it&#8217;s already set to no (say in order to execute a lengthy scrolling animation), and in the meantime we need to do something quick (say adding a line to one of the DIVs) then that quick operation is going to disable scroll detection (unnecessarily, as it&#8217;s already disabled) and then crucially enable it again before the scroll animation has finished.  Click the button in the example above to demonstrate this (and then scroll).  You should, intermittently, get the unwanted cascade effect you saw in example 2.</p>
<p>What we need is a list, not a flag.  Enter the blocker list &#8211; an object that collates tokens from each procedure in the script that is currently blocking scroll detection.  So if a procedure wants to disable scrolling for a period of time, it adds its token to the blocker list, and then removes its token when it&#8217;s done.  When a scroll event fires, we now only need to know whether there are any items in the blocker list, and then we can work out if it&#8217;s ok to process the event.</p>
<p>It&#8217;s also worth noting that there&#8217;s no need to actually count the number of items in the blocker list &#8211; it&#8217;s enough simply to know that there is at least one item in there.  And as a further optimisation, we don&#8217;t actually need to compute this when scroll events fire (frequently), because the value will only change when some function wants to add or remove its token from the list (less frequent).  So we can have enableScrollDetection and disableScrollDetection functions that deal with the blocker list, and which ultimately simply change the old scrolldetection flag to true or false.</p>
<div class="iframe-wrapper">
  <iframe src="/content/tech/files/2009/12/testcase_blockerlist4.html" frameborder="0" style="height:220px;width:550px;">Please upgrade your browser</iframe>
</div>
<p>There might be a neater way of achieving this, but this certainly works for me.  I&#8217;d welcome any comments or suggestions.  The sources for all these demos are available in the iframes above.</p>
]]></content:encoded>
			<wfw:commentRss>http://assanka.net/content/tech/2009/12/07/blocking-events-with-blocker-lists/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Disappearing text cursor in Firefox</title>
		<link>http://assanka.net/content/tech/2009/11/25/disappearing-text-cursor-in-firefox/</link>
		<comments>http://assanka.net/content/tech/2009/11/25/disappearing-text-cursor-in-firefox/#comments</comments>
		<pubDate>Wed, 25 Nov 2009 13:03:15 +0000</pubDate>
		<dc:creator>Andrew Betts</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[User experience]]></category>

		<guid isPermaLink="false">http://assanka.net/content/tech/?p=43</guid>
		<description><![CDATA[Do you ever find that sometimes when you try and type into a textbox, there is no cursor there, but it still accepts your input and the text appears as if there is a cursor?  I came across this problem in Firefox 3 and searching online revealed only solutions to an earlier problem that [...]]]></description>
			<content:encoded><![CDATA[<p>Do you ever find that sometimes when you try and type into a textbox, there is no cursor there, but it still accepts your input and the text appears as if there is a cursor?  I came across this problem in Firefox 3 and searching online revealed only <a href="http://www.nestedelements.com/2008/02/26/firefoxs-disappearing-cursor/">solutions</a> <a href="http://www.webdeveloper.com/forum/showthread.php?t=150640">to</a> <a href="http://blog.tremend.ro/2007/01/22/mouse-cursor-disappears-in-firefox/">an</a> <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=167801">earlier</a> <a href="http://www.fleegix.org/articles/2007-02-14-mystery-of-the-disappearing-cursor-caret">problem</a> that affected Firefox 2, in which the overflow configuration of the INPUT&#8217;s containing element would affect whether the cursor appeared in the input or not.</p>
<p>But this was clearly not my problem, and various sources suggested that this had in any case been fixed for Firefox 3.  I discovered that my problem was rather simpler.  If you disable an element that has focus, and then re-enable it, you don&#8217;t get the cursor back.</p>
<p>Solution: blur (remove focus from) the element before you disable it.  Those sources that do refer to this specific problem tend to suggest that you focus a different element before you disable the text box.  But this is not necessary &#8211; you can just blur the element that has focus and leave the page with nothing focused.</p>
<h2>Problem test case</h2>
<p>Try clicking and typing in the field below &#8211; if your browser exhibits this problem, the text cursor will not appear.  If it does, then your browser does not have this problem.</p>
<div class="iframe-wrapper">
  <iframe src="/content/tech/files/2009/12/testcase_ffcursor1.html" frameborder="0" style="height:35px;width:300px;">Please upgrade your browser</iframe>
</div>
<p>This demo has a single text field which, when you click into it, is briefly disabled, and then enabled again.  The disabling of the field while it has focus triggers this problem, so the text cursor does not appear (but you can still type into the field!).</p>
<h2>Solution test case</h2>
<p>Now try typing in this field &#8211; the cursor should appear consistently.</p>
<div class="iframe-wrapper">
  <iframe src="/content/tech/files/2009/12/testcase_ffcursor2.html" frameborder="0" style="height:35px;width:300px;">Please upgrade your browser</iframe>
</div>
<p>This demo still briefly disables and re-enables the text field when it gets focus, but this time it blurs it right before it&#8217;s disabled, then focuses it again after re-enabling it.  The result is that when you place your mouse cursor in the field to manually give it focus, the text cursor appears as normal.</p>
]]></content:encoded>
			<wfw:commentRss>http://assanka.net/content/tech/2009/11/25/disappearing-text-cursor-in-firefox/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JSON2.js vs Prototype</title>
		<link>http://assanka.net/content/tech/2009/09/02/json2-js-vs-prototype/</link>
		<comments>http://assanka.net/content/tech/2009/09/02/json2-js-vs-prototype/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 16:24:23 +0000</pubDate>
		<dc:creator>Andrew Betts</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Prototype]]></category>

		<guid isPermaLink="false">http://assanka.net/content/tech/?p=5</guid>
		<description><![CDATA[We use Douglas Crockford&#8217;s json2.js frequently in our web apps.  Its stringify method allows JavaScript data structures to be trivially serialised before submission via AJAX to a web service.   It works by descending through the structure, calling the toJSON() method on anything it finds.  It also creates toJSON methods for data [...]]]></description>
			<content:encoded><![CDATA[<p>We use <a title="Douglas Crockford" rel="homepage" href="http://crockford.com/">Douglas Crockford</a>&#8217;s json2.js frequently in our web apps.  Its stringify method allows JavaScript data structures to be trivially serialised before submission via AJAX to a web service.   It works by descending through the structure, calling the <code>toJSON()</code> method on anything it finds.  It also creates <code>toJSON</code> methods for data types that do not already have them, on the basis that future browsers will introduce <code>toJSON()</code> support &#8211; at which point the native implementation can be used because it&#8217;s likely to be a lot faster.</p>
<p>Recently I needed to use this method to serialise some data in a JavaScript library that might be used in &#8216;foreign&#8217; web pages.  My own library was nicely encapsulated, and didn&#8217;t interfere with any other JavaScript that might be running on the page, and it included Douglas Crockford&#8217;s JSON2.js implementation.</p>
<p>But on one of our clients&#8217; sites, it didn&#8217;t work.  I got this:</p>
<pre class="brush: jscript;">
{&quot;key&quot;:&quot;val&quot;,[\{\&quot;key\&quot;:\&quot;val\&quot;\},\{\&quot;key\&quot;:\&quot;val\&quot;\}]}
</pre>
<p>What&#8217;s happened here is that any arrays in my data structure have been stringified twice.  This didn&#8217;t happen in my dev environment.  I narrowed down the differences and realised what was causing this effect.  They&#8217;re using <a href="http://prototypejs.org">Prototype</a>.  We&#8217;re not.</p>
<p>Prototype modifies a number of JavaScript&#8217;s native objects, including the Array object, and&#8230; you guessed it, adds a <code>toJSON()</code> method to it. Unfortunately it does not return what Crockford&#8217;s <a title="JSON" rel="homepage" href="http://json.org/">JSON</a> implementation is expecting.  From the docs for json2:</p>
<blockquote><p>A toJSON method does not serialize: it returns the value represented by the name/value pair that should be serialized, or undefined if nothing should be serialized.</p></blockquote>
<p>Prototype&#8217;s <code>toJSON()</code> <em>is</em> serialising.  There don&#8217;t seem to be any sensible solutions to this online, but it&#8217;s actually relatively simple to solve using a replacer function, allowed for in the json2 API:</p>
<pre class="brush: jscript;">
var reqdata = JSON.stringify(req, function(key, value) {
	if (typeof this[key] == 'object' &amp;&amp; Object.prototype.toString.apply(this[key]) === '[object Array]') {
		return this[key];
	} else {
		return value;
	}
});
</pre>
<p>Essentially this says &#8216;for each key in the data structure, if the value is an array, use the raw value, otherwise use the value you gave me&#8217;.  This makes sense when you look at the sequence of steps that stringify() goes through for each key it encounters:</p>
<ol>
<li>If the value has a toJSON() method, call it.</li>
<li>If a replacer function has been given, call it.</li>
<li>If the remaining value is a scalar, return it.</li>
<li>If the remaining value is an object, stringify each member, then concatenate keys and values within braces {key:val,key:val}</li>
<li>If the remaining value is an array, stringify each element, then concatenate values within brackets [val,val,val]</li>
</ol>
<p>So, <code>stringify()</code> has already called Prototype&#8217;s <code>toJSON()</code> method by the time it executes the replacer function, but we can use the replacer function to restore the original value, allowing <code>stringify()</code> to then deal with the array by calling itself recursively.</p>
<p>The result is that we can ensure that even if a <code>toJSON()</code> method does exist on the Array object, its output is ignored, and we then get the JSON string that we wanted.</ol>
]]></content:encoded>
			<wfw:commentRss>http://assanka.net/content/tech/2009/09/02/json2-js-vs-prototype/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Auto growing textareas</title>
		<link>http://assanka.net/content/tech/2009/05/04/auto-growing-textareas/</link>
		<comments>http://assanka.net/content/tech/2009/05/04/auto-growing-textareas/#comments</comments>
		<pubDate>Mon, 04 May 2009 16:24:52 +0000</pubDate>
		<dc:creator>Andrew Betts</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[User experience]]></category>
		<category><![CDATA[User input]]></category>

		<guid isPermaLink="false">http://assanka.net/content/tech/?p=3</guid>
		<description><![CDATA[This feels like a topic that&#8217;s been explored to death already, but I really don&#8217;t like most implementations of this technique, so here&#8217;s how we do it.
First, in case anyone has just arrived from Mars, or even more unlikely, isn&#8217;t familiar with Facebook, the auto-growing textarea is a text box that gets bigger as you [...]]]></description>
			<content:encoded><![CDATA[<p>This feels like a topic that&#8217;s been explored to death already, but I really don&#8217;t like most implementations of this technique, so here&#8217;s how we do it.</p>
<p>First, in case anyone has just arrived from Mars, or even more unlikely, isn&#8217;t familiar with Facebook, the auto-growing textarea is a text box that gets bigger as you type into it, so that you never see a scroll bar (unless you&#8217;re typing war and peace).</p>
<p>There are lots of ways of doing each part of this.  The parts I&#8217;ll look at are (a) what triggers a review of the text box&#8217;s size, (b) how to determine whether a resize is required, and (c) how to perform a resize.</p>
<h2>Triggering a review</h2>
<p>There are four ways this is typically done:</p>
<ol>
<li> On an interval, say every 50ms</li>
<li> On keypress</li>
<li> On change</li>
<li> On keyup</li>
</ol>
<p>I&#8217;m staggered by how many scripts insist on doing this kind of thing on an interval.  Setting up interval timers for no good reason is a shortcut to terrible performance and memory leaks galore.  So we won&#8217;t be doing that.  onkeypress and onchange events are triggered before the box is updated with the latest keypress, so we want to avoid those, as the latest keypress might have been the one to bring us onto a new line.  That leaves onkeyup, which is fired after the box is updated with the new character, and allows us to inspect it and decide whether to increase its size.</p>
<h2>To resize or not to resize</h2>
<p>How to determine whether to resize the box comes in three flavours:</p>
<ol>
<li> Count the number of newline characters in the textarea&#8217;s value, and see if that matches the number of rows the textarea has.</li>
<li> Create a &#8217;shadow&#8217; DIV which is off screen (eg. margin-left: -10000px) and has no height declared, but otherwise has the same style properties as the textarea, fill it with the textarea&#8217;s content, measure the subsequent height of the DIV, then see if that height matches the current height of the textarea.</li>
<li> Check whether scrollHeight (the height of the scollable content of the box) &gt; clientHeight (the height of the box itself).</li>
</ol>
<p>In this case I was suprised at the number of implementations that favoured counting newlines.  This only works if combined with counting the number of characters in the textarea&#8217;s value, AND a monospaced font, AND knowing the number of columns in the textarea.  In short, er, it&#8217;s mad.</p>
<p>Second option, and the one favoured by a lot of the framework plugins due to the ease with which you can create shadow elements in the likes of jQuery, is to create a shadow DIV. This has the advantage of telling you the actual pixel height of the text, even where it is LESS than the height of the textarea box.  Otherwise, you&#8217;re limited to measuring clientHeight and scrollHeight, which are exactly the same if the textarea isn&#8217;t scrolling, regardless of how much space you&#8217;ve got to spare at the bottom.  My issue with this method is that it basically requires use of a framework to not be painful, and even then it&#8217;s non-trivial amounts of code, and adds needless pollution to the DOM.</p>
<p>So that leaves relying on scrollHeight and clientHeight.  These are well supported and efficient to read, so provided that you work around the issue of scrollHeight always being at least equal to clientHeight, this offers a very lightweight solution.  The features that you can achieve with a shadow DIV that you can&#8217;t do by simply reading scrollHeight and clientHeight are (a) you can ensure there is always a blank line at the bottom of your textarea, and (b) you can shrink the textarea if the user deletes text from it.  I&#8217;m personally of the view that neither of these is actually particularly desirable.  There&#8217;s potentially an argument for leaving a blank line at the bottom, but equally the uer might feel like they&#8217;re just being pressured to write more.</p>
<h2>How to resize the box</h2>
<p>OK, so if you&#8217;ve concluded that the user is writing chapter and verse and the textarea is in need of a bit more space, how do we go about doing it?</p>
<ol>
<li> Animate the CSS height property</li>
<li> Add some height via the CSS height property</li>
<li> Add 1 to the rows attribute</li>
</ol>
<p>A fair few of the framework plugins use their framework&#8217;s animation capabilities to animate the grow effect.  I don&#8217;t like this.  Just because you have an animation effect available doesn&#8217;t mean it&#8217;s appropriate to use it, and there are many situations where the end user just doesn&#8217;t want to wait 300ms for the privilege of using a fresh line.</p>
<p>Simply adding height to the CSS property is a fair way of doing it, but unless you do some maths on the user&#8217;s line height (or hard code some magic numbers), you can&#8217;t necessarily guarantee that the resulting height will be a multiple of the textarea&#8217;s line height.</p>
<p>Easiest, most efficient solution: add one to the rows attribute of the textarea.  rows is part of XHTML as well as HTML 4.01, and has universal support going back yonks.</p>
<h2>Pasting</h2>
<p>Watch out for pastes.  If the user pastes in a large quantity of text, they will trigger only one keyup event, but will have added many lines to the textarea.  Make sure that if a resize is required, you trigger another review after the resize is complete.</p>
<h2>Max height: the war and peace scenario</h2>
<p>If the user really does seem to be writing a novel, we probably should call it a day on growing the textarea at some stage, and certainly <strong>before it gets to be taller than the viewport</strong>.  You can check the height against the viewport height, though I typically just restrict it to an arbitrary height, say 30 rows.</p>
<h2>The code</h2>
<p>You&#8217;ll need a textarea element with an ID of <code>mytextarea</code> to make this code sample work, and obviously you can easily modify it to use selectors from your favourite framework rather than the native <code>document.getElementById</code>.</p>
<pre class="brush: jscript;">
document.getElementById('mytextarea').onkeyup = function() {
	var ta = document.getElementById('mytextarea');
	var maxrows = 30;
	var lh = ta.clientHeight / ta.rows;
	while (ta.scrollHeight &amp;gt; ta.clientHeight &amp;amp;&amp;amp; !window.opera &amp;amp;&amp;amp; ta.rows &amp;lt; maxrows) {
		ta.style.overflow = 'hidden';
		ta.rows += 1;
	}
	if (ta.scrollHeight &amp;gt; ta.clientHeight) ta.style.overflow = 'auto';
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://assanka.net/content/tech/2009/05/04/auto-growing-textareas/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

