<?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>Dawn Budge</title>
	<atom:link href="http://www.dawnbudge.co.uk/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dawnbudge.co.uk</link>
	<description>Front-end / client-side / user interface development</description>
	<lastBuildDate>Thu, 21 Mar 2013 18:16:15 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Hacking the  tag &#8211; implications for search engines</title>
		<link>http://www.dawnbudge.co.uk/index.php/2013/03/hacking-the-tag-implications-for-search-engines/</link>
		<comments>http://www.dawnbudge.co.uk/index.php/2013/03/hacking-the-tag-implications-for-search-engines/#comments</comments>
		<pubDate>Thu, 21 Mar 2013 18:16:15 +0000</pubDate>
		<dc:creator>Dawn Budge</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[seo]]></category>

		<guid isPermaLink="false">http://www.dawnbudge.co.uk/?p=181</guid>
		<description><![CDATA[Bilawal Hameed recently posted up Hacking the &#60;a&#62; tag in 100 characters, where he uses JavaScript to capture a click event on a link and then redirects it to another page entirely. Knowing that search engine crawlers have limited JavaScript support, I went to see if Google thinks his page links to paypal or not. [...]]]></description>
				<content:encoded><![CDATA[<p>Bilawal Hameed recently posted up <a href="http://bilaw.al/2013/03/17/hacking-the-a-tag-in-100-characters.html">Hacking the &lt;a&gt; tag in 100 characters</a>, where he uses JavaScript to capture a click event on a link and then redirects it to another page entirely.</p>
<p>Knowing that search engine crawlers have limited JavaScript support, I went to see if Google thinks his page links to paypal or not.</p>
<p>If you search in google for <code>link:www.paypal.co.uk site:bilaw.al</code>, you will see that his post shows up.</p>
<p>To check I wasn&#8217;t getting a false positive, I tried a slightly different URL.</p>
<p>If you search for <code>link:www.paypal.com site:bilaw.al</code> instead, you get no results.</p>
<p>Is it a problem? Can it be exploited for profit?  Not as far as I&#8217;m aware, beyond damaging the quality of Google&#8217;s search engine data.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dawnbudge.co.uk/index.php/2013/03/hacking-the-tag-implications-for-search-engines/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Accessible select box (dropdown) change events that work cross-browser, including IE, Chrome and touch devices</title>
		<link>http://www.dawnbudge.co.uk/index.php/2012/06/accessible-select-box-dropdown-change-events-that-work-cross-browser-including-ie-chrome-and-touch-devices/</link>
		<comments>http://www.dawnbudge.co.uk/index.php/2012/06/accessible-select-box-dropdown-change-events-that-work-cross-browser-including-ie-chrome-and-touch-devices/#comments</comments>
		<pubDate>Thu, 21 Jun 2012 11:33:13 +0000</pubDate>
		<dc:creator>Dawn Budge</dc:creator>
				<category><![CDATA[accessibility]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.dawnbudge.co.uk/?p=171</guid>
		<description><![CDATA[There&#8217;s a well-know issue with select elements where if you listen for the change event, it will trigger differently between browsers, and on IE it will trigger in a way that makes it inaccessible. Take the following example: user tabs onto a select element and then uses the arrow key to move through the list. [...]]]></description>
				<content:encoded><![CDATA[<p>There&#8217;s a well-know issue with select elements where if you listen for the change event, it will trigger differently between browsers, and on IE it will trigger in a way that makes it inaccessible.  </p>
<p>Take the following example: user tabs onto a select element and then uses the arrow key to move through the list. In IE (tested versions 7-9), this triggers the change event whereas other browsers will wait until you&#8217;ve moved off the element.  </p>
<p>Try this <a href="http://jsfiddle.net/debugwand/twkQu/">demo on jsfiddle</a>, it will alert the value of the option you&#8217;ve selected when &#8216;change&#8217; event gets fired.</p>
<p>If you are using your select element for navigating to another page, the keyboard user will never be able to get past the first and second item in your list.  If you are using the select element for loading in more content via AJAX (e.g. updating other field items based on a select box selection is quite common), then you are going to be hitting your server far more than necessary.</p>
<p>The solution is to bind to blur, click and keydown for IE and change for everything else (should include touch devices), and then a) filter out keypresses that aren&#8217;t spacebar or enter and b) check to see if the selected option has actually changed.  The below code uses jQuery, but it is all possible via native JS or other libraries.  Sadly it relies on checking the browser&#8217;s user agent as there isn&#8217;t a feature you can test for (if I&#8217;ve overlooked something I&#8217;d love to hear about it).</p>
<p>Have a look at the <a href="http://jsfiddle.net/debugwand/zz3DQ/">accessibile version on jsfiddle</a></p>
<pre>

var somemodule = (function () {
  var obj = {
    //some code
    bindDOM: function () {
      var evts = "";
      //accessibility workaround: onchange is good for non-ie; keydown, click and blur is good for ie (but not for chrome)
      //unfortunately we cannot detect this with feature support so must rely on browser support
      if ($jQ.browser.msie) {
        evts = "keydown click blur";
      }
      else {
        evts = "change";
      }
      this.elem.on(evts, $jQ.proxy(this.onFooChange, this));
    },
    onFooChange: function (e) {
      var id;
      if (e.type !== "keydown" || (e.which === 13 || e.which === 32)) {
        id = $jQ(e.target).val();
        if (id !== this.currentFoo) {
          this.currentFoo = id;
          this.getBar(id);
        }
      }
    },
  };
  
  //more code
  return obj;
}());

</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.dawnbudge.co.uk/index.php/2012/06/accessible-select-box-dropdown-change-events-that-work-cross-browser-including-ie-chrome-and-touch-devices/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Webaim screenreader user survey</title>
		<link>http://www.dawnbudge.co.uk/index.php/2012/06/webaim-screenreader-user-survey/</link>
		<comments>http://www.dawnbudge.co.uk/index.php/2012/06/webaim-screenreader-user-survey/#comments</comments>
		<pubDate>Wed, 06 Jun 2012 17:28:53 +0000</pubDate>
		<dc:creator>Dawn Budge</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.dawnbudge.co.uk/?p=167</guid>
		<description><![CDATA[The annual screenreader user survey is out, at http://webaim.org/projects/screenreadersurvey4/ If you&#8217;ve not seen it before, it is definitely worth the five minutes it will take you to scan through. Its results contradict a lot of received wisdom about screenreader behaviour, and highlight which features are actually really helpful (and which aren&#8217;t). Main takeaways: Screenereader users [...]]]></description>
				<content:encoded><![CDATA[<p>The annual screenreader user survey is out, at <a href="http://webaim.org/projects/screenreadersurvey4/">http://webaim.org/projects/screenreadersurvey4/</a></p>
<p>If you&#8217;ve not seen it before, it is definitely worth the five minutes it will take you to scan through.  Its results contradict a lot of received wisdom about screenreader behaviour, and highlight which features are actually really helpful (and which aren&#8217;t).</p>
<p>Main takeaways:</p>
<ul>
<li>Screenereader users love headings for navigating around a page</li>
<li>1.4% don’t have JS on, so your biggest user base without JS is going to be search bots.</li>
<li>82.7% update their software</li>
<li>JAWS is still dominant, but decreasing due to uptake in NVDA (free) and VoiceOver (Mac, iOS)</li>
<li>CAPTCHA is still a massive pain. Only Flash is worse for difficulty</li>
<li>Quite a lot are using mobiles with screenreaders</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.dawnbudge.co.uk/index.php/2012/06/webaim-screenreader-user-survey/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery UI sortable incorrectly positioned on drag when page is scrolled</title>
		<link>http://www.dawnbudge.co.uk/index.php/2012/01/jquery-ui-sortable-incorrectly-positioned-on-drag-when-page-is-scrolled/</link>
		<comments>http://www.dawnbudge.co.uk/index.php/2012/01/jquery-ui-sortable-incorrectly-positioned-on-drag-when-page-is-scrolled/#comments</comments>
		<pubDate>Fri, 13 Jan 2012 17:51:31 +0000</pubDate>
		<dc:creator>Dawn Budge</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.dawnbudge.co.uk/?p=160</guid>
		<description><![CDATA[While this issue is a bit odd, there&#8217;s not much in the way of information online and I suspect it will become more common as people start adding support for smaller screens and mobiles to their sites. Here was our problem: When dragging a sortable element, positioning was fine unless you were scrolled down the [...]]]></description>
				<content:encoded><![CDATA[<p>While this issue is a bit odd, there&#8217;s not much in the way of information online and I suspect it will become more common as people start adding support for smaller screens and mobiles to their sites.</p>
<p>Here was our problem:<br />
When dragging a sortable element, positioning was fine unless you were scrolled down the page a little.</p>
<p>After some trial and error, we found it was created by a combination of body{offset-x: hidden;} and position:relative on one of the parent elements of the sortable widget.</p>
<p>Now we don&#8217;t want to go removing things from other people&#8217;s pages to fix our work, because it will almost certainly break something else (these are templates, so the risk is high and regression testing a big task).  The solution was to put offset-x: auto on the same element that gets scrollable applied to it.</p>
<p>This is due to get fixed in jQuery UI 2 as they rewrite the sortable plugin.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dawnbudge.co.uk/index.php/2012/01/jquery-ui-sortable-incorrectly-positioned-on-drag-when-page-is-scrolled/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Android apps with PhoneGap &#8211; the missing basic steps</title>
		<link>http://www.dawnbudge.co.uk/index.php/2011/09/android-apps-with-phonegap-the-missing-basic-steps/</link>
		<comments>http://www.dawnbudge.co.uk/index.php/2011/09/android-apps-with-phonegap-the-missing-basic-steps/#comments</comments>
		<pubDate>Tue, 20 Sep 2011 16:24:18 +0000</pubDate>
		<dc:creator>Dawn Budge</dc:creator>
				<category><![CDATA[mobile]]></category>
		<category><![CDATA[offline apps]]></category>

		<guid isPermaLink="false">http://www.dawnbudge.co.uk/?p=156</guid>
		<description><![CDATA[The getting started guide for Android apps on Phonegap misses out a few key pieces of information. Don&#8217;t install your Android SDK in Program Files, or any other folder with a space in it. Eclipse will fail on the build, and uninstalling and reinstalling the SDK somewhere else is just a pain. If you want [...]]]></description>
				<content:encoded><![CDATA[<p>The <a href="http://www.phonegap.com/start#android">getting started guide for Android apps on Phonegap</a> misses out a few key pieces of information.</p>
<ol>
<li>Don&#8217;t install your Android SDK in Program Files, or any other folder with a space in it. Eclipse will fail on the build, and uninstalling and reinstalling the SDK somewhere else is just a pain.</li>
<li>If you want to deploy to your device in developer mode and you&#8217;re on windows, you&#8217;ll need the USB driver. This is buried in the Android SDK installation guide</li>
<li>Another way to deploy to your device is plain old file transfer.  Unlike iOS, you don&#8217;t need a specific developer or enterprise license to do this.  This involves exporting a signed app, which is a bit more involved.
<ul>
<li>Luckily <a href="http://www.androiddevelopment.org/2009/01/19/signing-an-android-application-for-real-life-mobile-device-usage-installation/">http://www.androiddevelopment.org/2009/01/19/signing-an-android-application-for-real-life-mobile-device-usage-installation/</a> tells you all you need to know.  You can now however create a signed application through Eclipse export, so the last step can be missed. </li>
<li>Once you have a signed app, all you need to do is connect your device to your PC, go into file transfer mode and copy across the apk file.</li>
<li>To install it, you&#8217;ll finally need to find the .apk file in My files and click to install. Job done. You can delete the apk file and open the application as normal from the Applications screen.</li>
</ul>
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.dawnbudge.co.uk/index.php/2011/09/android-apps-with-phonegap-the-missing-basic-steps/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cleaning up Excel-generated HTML with sed on Mac Terminal</title>
		<link>http://www.dawnbudge.co.uk/index.php/2011/06/cleaning-up-excel-generated-html-with-sed-on-mac-terminal/</link>
		<comments>http://www.dawnbudge.co.uk/index.php/2011/06/cleaning-up-excel-generated-html-with-sed-on-mac-terminal/#comments</comments>
		<pubDate>Fri, 03 Jun 2011 12:13:05 +0000</pubDate>
		<dc:creator>Dawn Budge</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[sed]]></category>

		<guid isPermaLink="false">http://www.dawnbudge.co.uk/?p=142</guid>
		<description><![CDATA[Not so long ago, a client gave us an Excel spreadsheet to work from as a temporary measure while the database got set up. Excel exports to HTML but fills it with rubbish. Using regular expression-based find and replace in my IDE is normally fine, but with a file this large it froze. Command line [...]]]></description>
				<content:encoded><![CDATA[<p>Not so long ago, a client gave us an Excel spreadsheet to work from as a temporary measure while the database got set up.</p>
<p>Excel exports to HTML but fills it with rubbish.  Using regular expression-based find and replace in my IDE is normally fine, but with a file this large it froze.  Command line is the only solution in such a case.</p>
<p>On the mac Terminal, the sed command is a little bit different from what you might use on *nix (and totally different from what you would do with  a PC).</p>
<p>After manually cleaning up the head section, the following 3 commands cleaned up the table cells in my export:</p>
<p><code>sed -i '' 's/class=xl[0-9]*//g' Table.htm<br />
sed -i '' 's/width=[0-9]*//g' Table.htm<br />
sed -i '' 's/height=[0-9]*//g' Table.htm</code></p>
<p>sed is a stream editor, the -i switch makes it edit in place, the &#8221; is where Mac differs.  It requires a backup file name even if that is blank (therefore overwriting the original file) whereas for *nix it is optional.</p>
<p>The next bit is the regular expression and these particular ones are tailored to remove the class, width and height attributes that Excel adds to all the &lt;td&gt; elements.  Finally, the name of the file to edit goes in.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dawnbudge.co.uk/index.php/2011/06/cleaning-up-excel-generated-html-with-sed-on-mac-terminal/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Saving form input when you&#8217;re offline using localStorage</title>
		<link>http://www.dawnbudge.co.uk/index.php/2011/02/saving-form-input-when-youre-offline-using-localstorage/</link>
		<comments>http://www.dawnbudge.co.uk/index.php/2011/02/saving-form-input-when-youre-offline-using-localstorage/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 00:50:30 +0000</pubDate>
		<dc:creator>Dawn Budge</dc:creator>
				<category><![CDATA[html5]]></category>
		<category><![CDATA[offline apps]]></category>
		<category><![CDATA[web apps]]></category>

		<guid isPermaLink="false">http://www.dawnbudge.co.uk/?p=105</guid>
		<description><![CDATA[Leading on from the work I did with the application cache, I became interested in using local storage to allow me to input data into a form and save it offline, ready for synching later on when I was online. I&#8217;ve made use of JSON.js for handling JSON and jQuery in the code below for [...]]]></description>
				<content:encoded><![CDATA[<p>Leading on from the work I did with the application cache, I became interested in using local storage to allow me to input data into a form and save it offline, ready for synching later on when I was online.</p>
<p>I&#8217;ve made use of JSON.js for handling JSON and jQuery in the code below for some convenience, you should be able to swap out for your library of choice.</p>
<p>Some caveats:</p>
<ul>
<li> potential for data collisions if you edit on another device or browser between saving offline and synching.
<ul>
<li>you could feasibly solve this by dynamically building duplicate form fields that sit next to the server version and contain the local data.  A button to copy across from one field to another is quite a simple trick.</li>
</ul>
</li>
<li> you get 5MB of localstorage per domain, meaning it isn&#8217;t suitable for documents over 5000 characters (including input names and syntax) or for saving a vast amount of forms without synchronising.  There&#8217;s a warning provided but it happens at a stage where the storage is already refusing to save, so the user has to copy their content to another file</li>
<li> local storage only handles text in key-value strings, so you can&#8217;t save your data as a JSON object, you have to stringify it.</li>
<li>Try&#8230;Catch is not my favourite way of handling detection or errors, but in the 2 cases below it is the only practical option</li>
</ul>
<p>Inspiration:</p>
<ul>
<li><a href="http://diveintohtml5.org/storage.html">http://diveintohtml5.org/storage.html</a></li>
<li><a href="http://paperkilledrock.com/2010/05/html5-localstorage-part-one/">http://paperkilledrock.com/2010/05/html5-localstorage-part-one/</a></li>
</ul>
<pre>

/*
OnOffApp makes use of local storage to save form input locally when a user is offline and allow them to synchronise it when they are back online again.
Dependencies:	json.js http://www.json.org/
				jQuery http://www.jquery.com/
Config:			when calling init, there are 5 items that can be optionally configured
				id
					unique identifier for the form to be used in local storage as the key
				field_id
					jQuery object of the field that supplies the id, used to find the parent form, otherwise form defaults to all forms on page
				synchMsg
					HTML to display to inform the user they have items to be synchronised to the server
				synchBtn
					HTML for synchronising button
				warnMsg
					HTML for the message to show the user when local storage is full and data cannot be saved
*/

OnOffApp = (function(){
	
	//variables available throughout the function
	var UID;
	var postForm = $(&quot;form&quot;);
	var holder = $(&quot;&lt;div id=\&quot;synchMsg\&quot;&gt;&lt;/div&gt;&quot;);
	var config = {};
	
	//initialiser function
	//@argument usrconfig: an object of config options
	var init = function(usrconfig){
		setup_config(usrconfig);
		var submit_button = postForm.delegate(&quot;input[type=submit]&quot;, &quot;click&quot;, submit_click);
		if(retrieveLocalData() === true){
			synchMessage();
		}
		$(window).bind(&quot;online&quot;, synchMessage);
		$(window).bind(&quot;offline&quot;, synchMessage_remove);
	};
	
	//set-up defaults for user configurable messages and overwrite where specified
	//@arguments usrconfig: object of user-set options
	//@returns the config object
	var setup_config = function(usrconfig){
		var id = location.href;
		config.synchMsg = &quot;&lt;p class=\&quot;synch\&quot;&gt;Locally saved data can be synchronised now&lt;/p&gt;&quot;;
		config.synchBtn = &quot;&lt;input type=\&quot;submit\&quot; value=\&quot;Synch\&quot; class=\&quot;synch\&quot; /&gt;&quot;;
		config.warnMsg = &quot;&lt;p class=\&quot;warn\&quot;&gt;Local storage is full.&lt;/p&gt;&quot;;
		 for(var i in usrconfig){
			if(i === &quot;id&quot;){
				id = usrconfig[i].val();
				continue;
			}
			else if(i === &quot;field_id&quot;){
				postForm = usrconfig[i].closest(&quot;form&quot;);
				continue;
			}
			config[i] = usrconfig[i];
		 }
		 UID = &quot;uID-&quot; + id;
		 return config;
	};
	
	//submit button clicked
	//detect if we are online.  If so, grab any saved data as well as existing data and save via AJAX, if not save to local storage
	var submit_click = function(e){
		e.preventDefault();
		var data = getFormInput();
		var savedData = $.parseJSON(getLocalData());
		if(navigator.onLine){
			saveToServer($.extend({},savedData,data));
		}
		else{
			setLocalData(JSON.stringify(data));
		}
	};
	
	//get the form inputs and put into object notation
	//@returns an object
	var getFormInput = function(){
		var formArray = postForm.serializeArray(),
			o = {};
			$.each(formArray, function(){
				o[this.name] = this.value;
			});
		return o;
	};
	
	//get localStorage data
	//@returns string of locally stored data or an empty string
	var getLocalData = function(){
		return localStorage.getItem(UID) || &quot;&quot;;
	};
	
	//set localStorage data, if out of space add a warning instead
	var setLocalData = function(data){
		try {
			localStorage.setItem(UID, data);
		}
		catch (e) {
			if (e == QUOTA_EXCEEDED_ERR) {
				postForm.prepend(config.warnMsg);
			}
		}
	};
	
	//get the data from localStorage and add saved values into the relevant fields
	//@returns true or false depending on whether there was locally stored data
	var retrieveLocalData = function(){
		var oldData = getLocalData();
		if(oldData !== &quot;&quot;){
			var fields = $.parseJSON(oldData),
				field;
			$.each(fields, function(key, val){
				field = $(&quot;[name=&quot; + key + &quot;]&quot;);
				if(field.length &gt; 0){
					if(field.is(&quot;:checkbox&quot;) || field.is(&quot;:radio&quot;)){
						field.attr(&quot;checked&quot;, &quot;checked&quot;);
					}
					else{
						field.val(val);
					}
				}
			});
			return true;
		}
		return false;
	};
	
	//if you have localStorage data and you are online, prompt the user to synchronise their data (i.e. save it to the server)
	var synchMessage = function(){
		if(navigator.onLine &amp;&amp; getLocalData() !== &quot;&quot;){
			if($(&quot;#synchMsg&quot;).length === 0){
				holder.append(config.synchMsg).append(config.synchBtn);
				postForm.prepend(holder);
			}
			else{
				holder.show();
			}
		}
	};
	
	//remove the synch message
	var synchMessage_remove = function(){
		holder.hide();
	};
	
	//save form data to the server via AJAX
	var saveToServer = function(data){
		var url = postForm.attr(&quot;action&quot;);
		var params = $.param(data);
		var me = this;
		$.ajax({
			method: &quot;post&quot;,
			url: url,
			data: params,
			success: savedSuccess(data)
		});
	};
	
	//after data saved to server, remove the saved data from localStorage and remove the synchronise message
	var savedSuccess = function(){
		localStorage.removeItem(UID);
		synchMessage_remove();
	};
	
	//interfacing methods and properties
	return {
		init: init
	};
}());


//For the purposes of the demo, there is a hidden input with id &quot;post_id&quot; with the unique identifier for the post (like WordPress)
$(document).ready(function(){
	try {
		if('localStorage' in window &amp;&amp; window['localStorage'] !== null){
			OnOffApp.init({
				&quot;id_field&quot; : $(&quot;#post_id&quot;),
				&quot;id&quot; : $(&quot;#post_id&quot;).val(),
				&quot;warnMsg&quot; : &quot;&lt;p class=\&quot;warn\&quot;&gt;Sorry, your local storage is full up.  Please copy and save your latest work to a text file and go online to synchronise your work as soon as you can.&lt;/p&gt;&quot;,
				&quot;synchMsg&quot; : &quot;&lt;p class=\&quot;synch\&quot;&gt;You have locally saved data that you can now synchronise with the live server&lt;/p&gt;&quot;
			});
		}
	}
	catch(e) {
		return false;
	}
});
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.dawnbudge.co.uk/index.php/2011/02/saving-form-input-when-youre-offline-using-localstorage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A better application cache manifest</title>
		<link>http://www.dawnbudge.co.uk/index.php/2011/02/a-better-application-cache-manifest/</link>
		<comments>http://www.dawnbudge.co.uk/index.php/2011/02/a-better-application-cache-manifest/#comments</comments>
		<pubDate>Wed, 16 Feb 2011 13:38:24 +0000</pubDate>
		<dc:creator>Dawn Budge</dc:creator>
				<category><![CDATA[html5]]></category>
		<category><![CDATA[offline apps]]></category>
		<category><![CDATA[web apps]]></category>
		<category><![CDATA[cache]]></category>

		<guid isPermaLink="false">http://www.dawnbudge.co.uk/?p=99</guid>
		<description><![CDATA[I&#8217;ve recently been messing around with offline application caching.  At a simple static level it is pretty basic, but once you start thinking about what might actually happen in real life it gets a lot more ugly. The following sources got me started with offline caching in the first place.  If you need more background [...]]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve recently been messing around with offline application caching.  At a simple static level it is pretty basic, but once you start thinking about what might actually happen in real life it gets a lot more ugly.</p>
<p>The following sources got me started with offline caching in the first place.  If you need more background to what application cache is, you should read these first.</p>
<ul>
<li><a href="http://jonathanstark.com/blog/2009/09/27/debugging-html-5-offline-application-cache/">http://jonathanstark.com/blog/2009/09/27/debugging-html-5-offline-application-cache/</a></li>
<li><a href="http://diveintohtml5.org/offline.html">http://diveintohtml5.org/offline.html</a></li>
<li><a href="http://www.slideshare.net/jonathanstark/offline-application-cache">http://www.slideshare.net/jonathanstark/offline-application-cache</a></li>
</ul>
<p>My main problem with it is that every time I make a change to my files, I have to go into my cache.manifest file and update a comment somewhere.  Why? Because the application cache is checked for updates first.  If there are no updates, it just stops.  It doesn&#8217;t check any of the underlying files for updates.</p>
<p>That&#8217;s efficient in terms of client-server communication by reducing the amount of calls to check whether cached versions can be used or need updated, but its also really dumb, and a nuisance to work with.  You start relying on people to remember on these little jobs, and that introduces a risk of human error.  It&#8217;s not an acceptable risk because it is an avoidable risk.</p>
<p>Luckily we can use server-side technology to generate our cache manifests and grab the file update timestamp.  Here&#8217;s what I&#8217;ve learned thus far:</p>
<ol>
<li>the manifest attribute on the html element doesn&#8217;t have to point to a *.manifest file.  It can point to a manifest.php file (for example).</li>
<li>in the dynamic page, set your header to serve up the right mime type.  In PHP, this is<br />
<code>&lt;? php header("Content-Type: text/cache-manifest;charset=utf-8"); ?&gt;</code></li>
<li>find the most recently updated file date and echo it out in a comment. If there&#8217;s not been a change, the comment will remain the same in the generated code as it is in the cached version.   In my example below I&#8217;m statically setting which files I want to be in the cache. <a href="http://www.slideshare.net/jonathanstark/offline-application-cache"> Jonathan Stark shows a way of going through the file system to cache all files</a> if you&#8217;d rather.  You&#8217;d just add the timestamp bits in where required.</li>
</ol>
<pre>
&lt;?php
	header(&quot;Content-Type: text/cache-manifest;charset=utf-8&quot;);
	$cache_files = array(
					&quot;testhtml5.htm&quot;,
					&quot;testinvisdyn.php&quot;,
					&quot;testhtml5.css&quot;,
					&quot;testhtml5.js&quot;,
					&quot;jquery.js&quot;,
					&quot;json.js&quot;
					);
	$fallback_files = array(
						&quot;/&quot; =&gt; &quot;fallback/testhtml5fall.htm&quot;
					   );
?&gt;
CACHE MANIFEST
NETWORK:
*
CACHE:
&lt;?php
	$cache_mod = 0;
	foreach($cache_files as $f){
		echo &quot;$f \n&quot;;
		$last_mod = filemtime($f);
		if($last_mod &gt; $cache_mod){
			$cache_mod = $last_mod;
		}
	}
	unset($f);
	
	echo &quot;# $cache_mod \n&quot;;
?&gt;

FALLBACK:
&lt;?php
	$cache_mod = 0;
	foreach($fallback_files as $d =&gt; $f){
		echo &quot;$d $f \n&quot;;
		$last_mod = filemtime($f);
		if($last_mod &gt; $cache_mod){
			$cache_mod = $last_mod;
		}
	}
	unset($f);
	unset($d);
	
	echo &quot;# $cache_mod \n&quot;;
?&gt;
</pre>
<p>Disclaimer: I&#8217;m not a PHP developer, its not one of my professional competencies.  If the above code sucks, please respond in the comments and I&#8217;ll fix it up.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dawnbudge.co.uk/index.php/2011/02/a-better-application-cache-manifest/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Interface Developer&#8217;s quality checklist</title>
		<link>http://www.dawnbudge.co.uk/index.php/2009/11/interface-developer-quality-checklist/</link>
		<comments>http://www.dawnbudge.co.uk/index.php/2009/11/interface-developer-quality-checklist/#comments</comments>
		<pubDate>Wed, 11 Nov 2009 13:41:23 +0000</pubDate>
		<dc:creator>Dawn Budge</dc:creator>
				<category><![CDATA[accessibility]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[standards]]></category>

		<guid isPermaLink="false">http://www.dawnbudge.co.uk/?p=83</guid>
		<description><![CDATA[Towards the end of a project or sprint, time to delivery can sometimes get crushed due to any number of reasons (late wireframe or design delivery, too many iterations, staff illness, contractors leaving, underestimation, overdelivering, changing business needs, etc.), and sadly it is usually testing time that cops it. This checklist should help you check [...]]]></description>
				<content:encoded><![CDATA[<p>Towards the end of a project or sprint, time to delivery can sometimes get crushed due to any number of reasons (late wireframe or design delivery, too many iterations, staff illness, contractors leaving, underestimation, overdelivering, changing business needs, etc.), and sadly it is usually testing time that cops it.</p>
<p>This checklist should help you check you&#8217;ve got your main bases covered.</p>
<h3>Tools you&#8217;ll need</h3>
<ul>
<li>Firefox
<ul>
<li><a href="http://chrispederick.com/work/web-developer/">Web developer toolbar</a></li>
<li><a href="http://getfirebug.com/">Firebug</a></li>
<li><a href="http://developer.yahoo.com/yslow/">YSlow</a></li>
</ul>
</li>
<li>IE
<ul>
<li><a href="http://www.microsoft.com/DownLoads/details.aspx?familyid=E59C3964-672D-4511-BB3E-2D5E1DB91038&amp;displaylang=en">IE developer toolbar</a></li>
<li><a href="http://www.webaim.org/articles/ais/">AIS web accessibility toolbar</a></li>
<li>Virtual PC for various IE versions.   There&#8217;s no permanent URL for this, so search microsoft.com for the latest version.</li>
</ul>
</li>
</ul>
<h3>Checklist</h3>
<ol>
<li>Having stable, valid code will save you a lot of debugging pain.  If you know your code is sound, then it is most likely a browser fault that is the cause of any further bugs from here onwards
<ol>
<li>Run the W3C HTML validator on all pages and correct</li>
<li>Run the W3C CSS validator on all pages and correct</li>
<li>Run the WAI tool on all pages.</li>
<li>Run your JavaScript code through JSLint</li>
<li>If you are hoping to have good coverage on mobiles, run <a href="http://validator.w3.org/mobile/">mobileOK</a> on your pages</li>
</ol>
</li>
<li>Check the static text content for spelling and grammar.  Mistakes here will just make you look stupid and unprofessional.</li>
<li>Check you&#8217;ve done a full run-through of the site in each supported browser.  You do have an agreed <a href="http://developer.yahoo.com/yui/articles/gbs/">browser matrix</a> don&#8217;t you?</li>
<li>View your site without CSS, can you still read everything?</li>
<li>Open up each template in a new tab and run through them using CTRL+Tab to check your layouts are all the same &#8211; do the edges of the main layout boxes sit at the same position on each page or do they jump a few pixels? Is the main heading at the same position (presuming your design intends that)?</li>
<li>Run through all pages at 1024&#215;768 resolution (or 800&#215;600 if you are required to support it), do you have to scroll horizontally?</li>
<li>Try using your site without JavaScript.   If you can&#8217;t then non-JS users will not be able to use your site and search bots will not be able to index all your content</li>
<li>Have you remembered your print stylesheet? Print preview your pages and actually print the most likely to be printed (e.g. an article template).  Sometimes the preview lies.</li>
<li>If you are using flash, check your non-flash fall-back works.  You do have a fall-back right?</li>
<li>If you are using embedded media, check there is a fall-back for those without it and a link to the vendor site to download the plugin.</li>
<li>If you have static links in the site, run a linkchecker.  I&#8217;ve used Xenu in the past which is fairly good, and free.</li>
<li>Run your pages through YSlow to find any major issues</li>
<li>If you are using XMLHttpRequest (often referred to as AJAX), test what happens when the server returns a failure (e.g. a 404 or 500 rather than 200 OK)</li>
<li>Accessibility checklist (this isn&#8217;t a definitive list, if for example your navigation is inconsistent between pages then you&#8217;ve a problem that requires the team going back to the drawing board to solve)
<ol>
<li>Your content is in a sensible order in the HTML.  If you are not sure, looking at the page with CSS off will help you decide.
<ul>
<li>e.g. you do not break up your main content paragraphs to line up your right hand promo boxes</li>
</ul>
</li>
<li>Go through a few pages with a screenreader and keyboard.
<ul>
<li>Can you get to all your links and form fields without the mouse?</li>
<li> Can you hear all your content?</li>
<li>Is hidden content still &#8216;perceivable&#8217;?  If you are hiding with display none or visibility hidden, screenreaders will ignore that content, but if you use position absolute with left being a large negative number, it will still get read out to the user.</li>
</ul>
</li>
<li>Test all your interactive features (e.g. accordions or sliders) with a keyboard, also is the screenreader able to read the information in them? (see my previous <a href="http://www.dawnbudge.co.uk/index.php/2009/09/get-some-focus-keyboard-and-mouse-events/">post about focus</a>)</li>
<li>Page sections are marked out with headings</li>
<li>Headings do not skip levels.  This should be picked up in the HTML validation.</li>
<li>Have a &#8216;skip to content&#8217; link at the top of your page</li>
<li>You can pause any animation or movement that is on by default</li>
<li>All forms have a submit button
<ul>
<li>that especially includes select field (dropdown) navigation, it should never be executed from the onchange or onselect events</li>
</ul>
</li>
<li>Text can be resized in all browsers, IE6 does it differently so be sure to test if you support it</li>
<li>All form fields have explicit labels (i.e. you use the for attribute to refer to the field&#8217;s ID rather than wrapping the field inside the label element)</li>
<li>Missing alt attributes is a common mistake, but will be picked up in your HTML validation</li>
<li>Foreground and background colours have sufficient <a href="http://juicystudio.com/services/luminositycontrastratio.php">contrast</a></li>
<li>Testing for seizure-causing animation is difficult, but the safest course of action is not to flash anything more than 3 times in 1 second.</li>
<li>Image maps have their links duplicated underneath as a list</li>
<li>Any static links have sensible link text that indicates where the link will go on its own without the rest of the paragraph text around it.</li>
<li>Any linked images have sensible alt text that indicates on its own where the link will go</li>
<li>Specify what language the page is in.  The HTML validator will pick it up if it is missing.</li>
<li>Tables of data have a summary and scope for each column and each row is defined</li>
</ol>
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.dawnbudge.co.uk/index.php/2009/11/interface-developer-quality-checklist/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Mobile web developments &#8211; a bit like the number 73 bus.</title>
		<link>http://www.dawnbudge.co.uk/index.php/2009/11/mobile-web-developments-a-bit-like-the-number-73-bus/</link>
		<comments>http://www.dawnbudge.co.uk/index.php/2009/11/mobile-web-developments-a-bit-like-the-number-73-bus/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 22:55:47 +0000</pubDate>
		<dc:creator>Dawn Budge</dc:creator>
				<category><![CDATA[mobile]]></category>

		<guid isPermaLink="false">http://www.dawnbudge.co.uk/?p=75</guid>
		<description><![CDATA[A number of interesting things related to mobile web have come up recently: First, Phil Archer from the W3C presented Mobile Best Practice at London Web Standards Group It&#8217;s an excellent presentation and worth a full read, but the gist of it is: think about mobile users not mobile devices.  if nothing else, mobile devices [...]]]></description>
				<content:encoded><![CDATA[<p>A number of interesting things related to mobile web have come up recently:</p>
<p>First, <a href="http://philarcher.org/">Phil Archer</a> from the W3C presented <a href="http://www.w3.org/2009/Talks/phila-lws/#(1)">Mobile Best Practice</a> at London Web Standards Group</p>
<p>It&#8217;s an excellent presentation and worth a full read, but the gist of it is:</p>
<ul>
<li>think about mobile users not mobile devices.  if nothing else, mobile devices are developing and improving their user experience as a fast rate which will probably get faster</li>
<li>you don&#8217;t have to give mobile users the exact same page only tiny, if you stick to the theme of your content you&#8217;ll be helping them (compare <a href="http://news.bbc.co.uk/">http://news.bbc.co.uk/</a> on PC and mobile, or try <a href="http://news.bbc.co.uk/mobile">http://news.bbc.co.uk/mobile</a> which BBC news redirects to) BUT don&#8217;t make them remember a special mobile URL.  Detect and redirect your user.</li>
<li>w3c have a very cool validator called <a href="http://validator.w3.org/mobile/">mobileOK</a> that estimates how well your page will perform on mobiles</li>
<li>secondary windows including popups, frames, tables and image maps will cause mobile users inconvenience</li>
<li>Progressive enhancement will pay off hugely</li>
<li>That said, various mobile browser vendors don&#8217;t play well with @media=&#8221;handheld&#8221;.  See <a href="http://www.bushidodesigns.net/blog/?p=72 ">http://www.bushidodesigns.net/blog/?p=72</a> for the best way to serve up CSS for all devices</li>
</ul>
<p>Then Firefox announced accelerometer detection (the thing in your iphone/nokia/laptop/wii that detects motion and direction) for 3.6.  Firefox has yet to crack the mobile devices platform, so this is a signal of intent.</p>
<p>Serendipity then took me to PPK&#8217;s <a href="http://www.quirksmode.org/webkit.html">Great Webkit Comparison table</a> whose family now includes the browsers for android, iphone, bolt, palm pre and <a href="http://www.downloadsquad.com/2009/08/24/mobile-minute-webkit-based-iris-browser-coming-to-blackberry/">possibly blackberry in the near future.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.dawnbudge.co.uk/index.php/2009/11/mobile-web-developments-a-bit-like-the-number-73-bus/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
