<?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>ajgraham.com</title>
	<atom:link href="http://www.ajgraham.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ajgraham.com</link>
	<description>web developer</description>
	<lastBuildDate>Wed, 12 Jun 2013 14:25:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>Forcing embedded Vimeo videos to show non-HD version</title>
		<link>http://www.ajgraham.com/2012/10/forcing-embedded-vimeo-videos-to-show-non-hd-version/</link>
		<comments>http://www.ajgraham.com/2012/10/forcing-embedded-vimeo-videos-to-show-non-hd-version/#comments</comments>
		<pubDate>Thu, 11 Oct 2012 23:42:20 +0000</pubDate>
		<dc:creator>alex</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.ajgraham.com/?p=590</guid>
		<description><![CDATA[I had a bit of a strange issue crop up with a Vimeo video that had been embedded on a website today. We&#8217;d set the video to default to the HD version via the video settings on Vimeo (which I [...]]]></description>
			<content:encoded><![CDATA[<p>I had a bit of a strange issue crop up with a Vimeo video that had been embedded on a website today. We&#8217;d set the video to default to the HD version via the video settings on Vimeo (which I believe you only get with a Plus or Pro account) to try and have it appear as high quality as possible to users. Unfortunately for the very few people with low bandwidth internet connections this was causing the video to stop/start as it tried to buffer. Sadly, the customer was one of these pesky low bandwidth users. After hearing about this we set the video back to the default non-HD, but if anyone has already seen the video in HD it would stay in HD (I&#8217;m guessing it must set a cookie).</p>
<p>Their is a way to reset this, simply add <strong>hd_off=1</strong> to the following Vimeo embed code on the end of the src URI:</p>
<pre><code class="html">&lt;iframe src="http://player.vimeo.com/video/51120422?title=1&amp;byline=1&amp;portrait=1&amp;hd_off=1" width="500" height="281" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen&gt;&lt;/iframe&gt;</code></pre>
<p>I haven&#8217;t been able to test this exhaustively, but having spent a few minutes testing this fixed the issue.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ajgraham.com/2012/10/forcing-embedded-vimeo-videos-to-show-non-hd-version/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Improving interaction with HTML Forms : dropdown list</title>
		<link>http://www.ajgraham.com/2012/10/improving-interaction-with-html-forms-ui/</link>
		<comments>http://www.ajgraham.com/2012/10/improving-interaction-with-html-forms-ui/#comments</comments>
		<pubDate>Sat, 06 Oct 2012 15:39:12 +0000</pubDate>
		<dc:creator>alex</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.ajgraham.com/?p=582</guid>
		<description><![CDATA[I was recently trying to improve the way a basic form worked, in particular trying to improve the user experience. From my experience forms and pages that contain forms especially Contact pages are often given the least design and development [...]]]></description>
			<content:encoded><![CDATA[<p>I was recently trying to improve the way a basic form worked, in particular trying to improve the user experience. From my experience forms and pages that contain forms especially Contact pages are often given the least design and development consideration despite often being key pages on every website.</p>
<p>One of my personal dislikes is the Dropdown box (or the HTML Select element to give it its proper name). For anything more than a dozen options they become horrible to use on any screen or device. In certain circumstances it can help the user interaction experience to break the options out of the dropdown box and represent them close to the dropdown box. I don&#8217;t recommend hiding the dropdown box for accessibility reasons. </p>
<p>Below is a basic example of a colour picker that could be used in an online shop.</p>
<p><iframe style="width: 100%; height: 300px" src="http://jsfiddle.net/ajgraham/cAZ4Y/1/embedded/result,js,html,css/" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ajgraham.com/2012/10/improving-interaction-with-html-forms-ui/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Blackberry @font-face CSS declaration</title>
		<link>http://www.ajgraham.com/2012/03/blackberry-font-face-css/</link>
		<comments>http://www.ajgraham.com/2012/03/blackberry-font-face-css/#comments</comments>
		<pubDate>Thu, 15 Mar 2012 22:17:47 +0000</pubDate>
		<dc:creator>alex</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[@font-face]]></category>
		<category><![CDATA[blackberry]]></category>
		<category><![CDATA[css]]></category>

		<guid isPermaLink="false">http://www.ajgraham.com/?p=549</guid>
		<description><![CDATA[Had to try and get some custom fonts working on a Blackberry specific website today and couldn&#8217;t find much official guidance or help via Google searches so thought this might help someone. The Blackberry browser on BB OS5, 6 and [...]]]></description>
			<content:encoded><![CDATA[<p>Had to try and get some custom fonts working on a Blackberry specific website today and couldn&#8217;t find much official guidance or help via Google searches so thought this might help someone. The Blackberry browser on BB OS5, 6 and 7 only supports SVG font files (you can use <a href="http://www.fontsquirrel.com/" target="_blank">fontsquirrel</a> to convert from other formats). Unfortunately SVGZ (gzipped SVG) doesn&#8217;t seem to work from my testing.</p>
<pre><code>@font-face {
	font-family: 'TimesModernCondensed';
	src: url('../fonts/timesmodconlightdc-webfont.svg#TimesModernCondensedDCCnLtDC') format('svg');
	font-weight: normal;
	font-style: normal;
}</code></pre>
<p><code> </code></p>
<p>N.B: Don&#8217;t be tempted to change the text after the  &#8216;#&#8217; as this has to reference the embedded font name within the file. Font Squirrel gets this automatically, leave it as it is or you&#8217;ll cause yourself unnecessary pain like I went through&#8230;  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.ajgraham.com/2012/03/blackberry-font-face-css/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Getting an RSS feed from Facebook</title>
		<link>http://www.ajgraham.com/2011/01/data-feed-facebook-rss-jso/</link>
		<comments>http://www.ajgraham.com/2011/01/data-feed-facebook-rss-jso/#comments</comments>
		<pubDate>Mon, 24 Jan 2011 02:13:10 +0000</pubDate>
		<dc:creator>alex</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[RSS]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://www.ajgraham.com/?p=530</guid>
		<description><![CDATA[From my experience Facebook tends to provoke strong reactions, both positive or negative. As a developer who works with Facebook often in one way or another I&#8217;ve had lots of frustrating moments mainly due to poor/incorrect documentation. I spent a [...]]]></description>
			<content:encoded><![CDATA[<p>From my experience Facebook tends to provoke strong reactions, both positive or negative. As a developer who works with Facebook often in one way or another I&#8217;ve had lots of frustrating moments mainly due to poor/incorrect documentation.</p>
<p>I spent a while trying to find the best way to export a public Facebook pages posts in the form of an RSS feed. Facebook don&#8217;t provide an easy way to do this (only on Notifications, e.g. <a href="http://www.facebook.com/notifications.php">facebook.com/notifications.php</a>), although it can be done with a workaround in 2 different ways.</p>
<h3>Via Twitter</h3>
<p>You can connect a Facebook page to Twitter and any new posts will automatically be sent to a Twitter account you specify (you can do this through <a href="http://www.facebook.com/twitter/">facebook.com/twitter/</a>). With this carried out, you can then access the RSS feed of the Twitter account. This works but confines you to the 140 characters limit and will include a link back to the original Facebook post within the tweet.</p>
<h3>The long way round</h3>
<p>Another way would be to make a system to automatically create an RSS feed from the Facebook pages JSON feed (example: https://graph.facebook.com/<em>pagename or id</em>/feed). This has the benefit of displaying your Facebook posts in full. The downside is of course the extra work and complication involved.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ajgraham.com/2011/01/data-feed-facebook-rss-jso/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Social Media: Overview of Facebook, Twitter and LinkedIn</title>
		<link>http://www.ajgraham.com/2010/11/social-media-efficient-marketing-with-facebook-twitter/</link>
		<comments>http://www.ajgraham.com/2010/11/social-media-efficient-marketing-with-facebook-twitter/#comments</comments>
		<pubDate>Tue, 09 Nov 2010 22:30:59 +0000</pubDate>
		<dc:creator>alex</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[linked in]]></category>
		<category><![CDATA[linkedin]]></category>
		<category><![CDATA[marketing]]></category>
		<category><![CDATA[media]]></category>
		<category><![CDATA[social]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[web2.0]]></category>

		<guid isPermaLink="false">http://www.ajgraham.com/?p=420</guid>
		<description><![CDATA[Over the past few years I&#8217;ve watched the way the Internet has gradually changed. The leap from old school websites where all the content and features were served up 100% themselves is so far gone that I can barely remember [...]]]></description>
			<content:encoded><![CDATA[<p>Over the past few years I&#8217;ve watched the way the Internet has gradually changed. The leap from old school websites where all the content and features were served up 100% themselves is so far gone that I can barely remember it existing. Almost every website has some form of external input or aggregation, whether to provide additional niche features or website content that can make the difference between websites/companies being successful or not.</p>
<p>The challenge is to make the correct decisions when adding social media features, it&#8217;s all too easy to add 20 &#8216;sharing&#8217; buttons to a page when trying to cover all the bases and end up creating an awful user experience. The key is to know which social media services demographics best match the demographics and the type of info being shared by a company or organisation. Basically trying to find a best fit, if one exists.</p>
<h3>Facebook</h3>
<p>Facebook over the past 2 years has grown to become a huge social platform. They have 500 million registered members, and 200+ million of those use it through mobile devices and both stats are growing steadily (see <a href="http://www.facebook.com/press/info.php?statistics">www.facebook.com/press/info.php?statistics</a>). A wide variety of age groups use Facebook, although it is heavily slanted towards teenagers and &#8217;20-somethings&#8217;, this is changing gradually though as Facebook becomes synonymous with using the Internet.</p>
<p>Age Range: All (13 y/o&#8217;s and over).<br />
Location: Generally US, Europe and South America have very high use, although it is quickly spreading in Asia, Middle East and beyond.</p>
<p>Marketing with Facebook can be carried out via 2 main methods:<br />
<strong>Fan Pages</strong> allow standard Facebook users to &#8216;Like&#8217; them, which means that anything published to the Fan Page will be seen by everyone who has &#8216;Liked&#8217; it. This creates a valuable communication stream which is best used with weekly/bi-weekly updates to ensure regular contact, although it&#8217;s important to make sure you don&#8217;t spam the user as you&#8217;ll likely dilute the usefulness of the tool and/or lose them as a &#8216;fan&#8217;. There is also a spin-off of this whereby users can allowed to &#8216;Share&#8217; or &#8216;Like&#8217; specific webpages, which is used to good effect on news items, video or other similar individual pieces of content. A good example of this is the ability to share a video on YouTube to your Facebook account.</p>
<p><strong>Facebook Ads</strong> allow an advertiser to focus ads to Facebook users via specific demographics such as age, location and interests. Due to Facebook users supplying this information via their profiles this helps to make advertising as pin-point as is possible on the internet at the moment, which is much more accurate than almost all over alternatives.</p>
<h3>Twitter</h3>
<p>Twitter is similar in some respects to Facebook, but has some key differences. Twitter is designed for much more verbose communication with a 140 character limit, and an emphasis on time sensitivity. Twitter has ~150 million registered users, although its churn rate (the number of users that sign up and don&#8217;t use their account again) is widely regarded as being far higher than Facebook. <a href="http://techcrunch.com/2010/09/02/twitter-stats/">Twitter stats</a>.</p>
<p>Age Range: All (13 y/o&#8217;s and over).<br />
Location: Significant usage almost everywhere.</p>
<p>Marketing is generally best done via encouraging retweeting (which is the equivalent of repeating a specific piece of information, thus adding kudos). This is often described as something &#8216;going viral&#8217; on the internet. Twitter is used to publicise pretty much anything, although it&#8217;s best used as bait (due to the limited number of characters) to link to breaking news or similar situations.</p>
<h3>LinkedIn</h3>
<p>LinkedIn is primarily used for professional contacts to build a network of people they know via employment both past and present. There are 80 million users, although 40 million are based in the US which weaken its appeal outside of the US. <a href="http://press.linkedin.com/">LinkedIn stats</a>.</p>
<p>Age Range: All (18 y/o&#8217;s and over).<br />
Location: Significant usage US mostly, but still common in Europe.</p>
<p>Marketing can be carried out similarily to Facebook, by allowing people to share content to LinkedIn this content would then be visible to all of their contacts. Marketing aimed towards LinkedIn (due to the nature of LinkedIn) is best done for any information that is work related, thus is more niche than what you would share on Facebook.</p>
<h3>Conclusions</h3>
<p>Each service is significantly different, in some cases all 3 may be useful to visitors if a website has a wide range of content but is unlikely. Try not to clog a website with 100 ways to share content when only 2 are really popular as you&#8217;ll sacrifice a lot of page space and confuse some users, not to mention increase page loading times.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ajgraham.com/2010/11/social-media-efficient-marketing-with-facebook-twitter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress Posts Pagination</title>
		<link>http://www.ajgraham.com/2010/08/wordpress-posts-pagination-with/</link>
		<comments>http://www.ajgraham.com/2010/08/wordpress-posts-pagination-with/#comments</comments>
		<pubDate>Thu, 05 Aug 2010 19:42:44 +0000</pubDate>
		<dc:creator>alex</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[global]]></category>
		<category><![CDATA[paginated]]></category>
		<category><![CDATA[paging]]></category>
		<category><![CDATA[post]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.ajgraham.com/?p=460</guid>
		<description><![CDATA[I recently had to find a way of forcing WordPress to display a post that had been paginated using the nextpage quicktag, to display different content on different dynamically generated pages. After some help from StackOverflow.com I found out that [...]]]></description>
			<content:encoded><![CDATA[<p>I recently had to find a way of forcing WordPress to display a post that had been paginated using the nextpage quicktag, to display different content on different dynamically generated pages. After some help from StackOverflow.com I found out that within <a href="http://codex.wordpress.org/The_Loop">The Loop</a> you can access 2 particular variables that WordPress uses: <em>$page</em> and <em>$numpages</em>. </p>
<p>Without having to be a genius <em>$page</em> is the current page number and <em>$numpages</em> is the total number of pages that a post has been converted into by WordPress.</p>
<p>Example: To have something appear only on the first page of a paginated post use:</p>
<pre><code>if($page == 1 || $numpages == 1) {
	//will only appear on first page
}</code></pre>
<p>Example: To have something appear only on the last page of a paginated post use:</p>
<pre><code>if($page == $numpages) {
	//will only appear on last page
}</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ajgraham.com/2010/08/wordpress-posts-pagination-with/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Retrieve Facebook page status with no authenticating or permissions issues</title>
		<link>http://www.ajgraham.com/2010/07/get-facebook-page-stream-simple-easy/</link>
		<comments>http://www.ajgraham.com/2010/07/get-facebook-page-stream-simple-easy/#comments</comments>
		<pubDate>Fri, 02 Jul 2010 21:42:11 +0000</pubDate>
		<dc:creator>alex</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[auth]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[feed]]></category>
		<category><![CDATA[get]]></category>
		<category><![CDATA[key]]></category>
		<category><![CDATA[read]]></category>
		<category><![CDATA[retrieve]]></category>
		<category><![CDATA[RSS]]></category>
		<category><![CDATA[scraping]]></category>
		<category><![CDATA[session]]></category>
		<category><![CDATA[status]]></category>
		<category><![CDATA[stream]]></category>

		<guid isPermaLink="false">http://www.ajgraham.com/?p=451</guid>
		<description><![CDATA[If you&#8217;re just looking to read the &#8216;Stream&#8217; or &#8216;Statuses&#8217; of a Facebook fan page (not a normal Profile page) it can be done very easily. Due to all Fan Pages being public (their are 2 settings: published or unpublished), [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re just looking to read the &#8216;Stream&#8217; or &#8216;Statuses&#8217; of a Facebook fan page (<em>not</em> a normal Profile page) it can be done very easily. Due to all Fan Pages being public (their are 2 settings: published or unpublished), as long as the Fan page is published then you can retrieve any data from it, no authentication, no API, no messing around.</p>
<p>Step 1 &#8211; Find the page feed for the Fan Page<br />
The basic URL format of a Facebook fan page feed is:</p>
<pre><code>https://graph.facebook.com/ID of Page/feed</code></pre>
<p>If you can&#8217;t find your unique Page ID <a target="_blank" rel="nofollow" href="http://help.wildfireapp.com/faqs/tutorials/how-to-find-out-your-facebook-fan-page-public-profile-id">read this guide</a>.<br />
<a target="_blank" rel="nofollow" href="https://graph.facebook.com/ID of Page/feed">Test it by opening the link in another browser window</a>. If you get a whole load of data in square and curly brackets (it&#8217;s JSON) that contains posts from your fan page then you&#8217;re set for Step 2.</p>
<p>*Please note that this URL gets every post from your Wall/Stream limited to about the 50 most recent from what I&#8217;ve seen. This includes everything that other people have posted as well in the form of their posts or comments, etc.</p>
<p>Step 2 &#8211; Extract the last status from the feed URL data</p>
<p>Here comes the basic PHP code, you need to put in the Page ID for the
<pre><code>$pageID</code></pre>
<p> variable:</p>
<pre><code>$pageID = "ID of Page"
$url = "https://graph.facebook.com/". $pageID ."/feed";
$json = file_get_contents($url);
$jsonData = json_decode($json);

foreach($jsonData->data as $val) {
	if($val->from->id == $pageID) { //find the first matching post/status by a fan page admin
		$message = $val->message;
		echo $message;
		break; //stop looping on most recent status posted by page admin
	}
}</code></pre>
<h3>Things to consider</h3>
<p>Extracting the data from Facebook directly using a server-side approach should not be used for production as it&#8217;s really inefficient as it adds a noticeable pause to page loading times and will break if Facebook is slow in responding. I provided a basic demo to show how easy it can be done, but you should expand on this by storing the data extracted in a database or file on your server via CRON jobs. Another alternative would be to do it client-side with JavaScript, it depends on the frequency the Fan page data you want is expected to change and what you&#8217;re doing with it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ajgraham.com/2010/07/get-facebook-page-stream-simple-easy/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JQuery: Open external links in new window</title>
		<link>http://www.ajgraham.com/2010/05/jquery-open-external-links-in-new-window/</link>
		<comments>http://www.ajgraham.com/2010/05/jquery-open-external-links-in-new-window/#comments</comments>
		<pubDate>Mon, 24 May 2010 18:00:29 +0000</pubDate>
		<dc:creator>alex</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[JQuery]]></category>
		<category><![CDATA[rel="external"]]></category>

		<guid isPermaLink="false">http://www.ajgraham.com/?p=396</guid>
		<description><![CDATA[Finally got round to writing a small bit of code to automatically force anchor links to open in new windows if they are for different domains: $(document).ready(function() { var myDomain = ["www.ajgraham.com", "testing.ajgraham.com", "lifestream.ajgraham.com"]; //do NOT include the http:// pls! [...]]]></description>
			<content:encoded><![CDATA[<p>Finally got round to writing a small bit of code to automatically force anchor links to open in new windows if they are for different domains:</p>
<pre><code>$(document).ready(function() {
	var myDomain = ["www.ajgraham.com", "testing.ajgraham.com", "lifestream.ajgraham.com"]; //do NOT include the http:// pls!
	$("a[href^='http://']").each(function() {
		var slicedHref = $(this).attr('href').slice(7);
		var slashPosition = slicedHref.indexOf("/");
		if (slashPosition != -1) {
			slicedHref = slicedHref.slice(0,(slashPosition));
		}
		var matchCounter = 0;
		for (i=0;i&lt;myDomain.length;i++) {
			if (slicedHref.indexOf(myDomain[i]) == -1) {
				matchCounter++;
			}
		}
		if (matchCounter == myDomain.length) {
			$(this).attr("target","_blank").attr("rel","external").append("&lt;img class='new-window-link' alt='new window' src='http://www.ajgraham.com/wp-content/themes/ajgrahampro/images/external.png' style='padding-left:2px' /&gt;");
		}
	});
});</code></pre>
<p><a target="_blank" href="http://www.ajgraham.com/codestore/linksinnewwindow/anchorlinkstest.html">See Demo</a></p>
<p><a href="http://www.ajgraham.com/codestore/linksinnewwindow/newWindowLinks.zip">Download basic example</a></p>
<p>Just remember to change
<pre><code>var myDomain = ["www.ajgraham.com", "testing.ajgraham.com", "lifestream.ajgraham.com"];</code></pre>
<p> to your internal domain(s). You can use as many as you like, just don&#8217;t include the http:// bit.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ajgraham.com/2010/05/jquery-open-external-links-in-new-window/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simple but powerful JQuery Form Validation</title>
		<link>http://www.ajgraham.com/2010/05/simple-but-powerful-jquery-form-validation/</link>
		<comments>http://www.ajgraham.com/2010/05/simple-but-powerful-jquery-form-validation/#comments</comments>
		<pubDate>Thu, 20 May 2010 01:29:46 +0000</pubDate>
		<dc:creator>alex</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[Field]]></category>
		<category><![CDATA[Form]]></category>
		<category><![CDATA[Input]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[JQuery]]></category>
		<category><![CDATA[Validator]]></category>

		<guid isPermaLink="false">http://www.ajgraham.com/?p=363</guid>
		<description><![CDATA[I wrote a relatively simple and intuitive form validation script for a client, which they kindly allowed me to release into the open-source community. Contents The Objective The Basics Including The JavaScript Explaining The Code Core Functions Expanded Functions Options [...]]]></description>
			<content:encoded><![CDATA[<p>I wrote a relatively simple and intuitive form validation script for a client, which they kindly allowed me to release into the open-source community.</p>
<h2>Contents</h2>
<p><a href="#objective">The Objective</a><br />
<a href="#basics">The Basics</a><br />
<a href="#include-the-javascript">Including The JavaScript</a><br />
<a href="#explain-code">Explaining The Code</a><br />
<a href="#core-functions">Core Functions</a><br />
<a href="#expanded-functions">Expanded Functions</a><br />
<a href="#options">Options</a><br />
<a href="#html">HTML</a><br />
<a href="#examples">Examples</a><br />
<a href="#download">Download</a><br />
<a href="#license">License</a><br />
<a href="#to-dos">To-Do&#8217;s</a><br />
<a href="#change-log">Change-log</a></p>
<h2 id="objective">The Objective</h2>
<p>The aim was to develop a simple JavaScript form validator plugin to be:</p>
<ul>
<li>JQuery based</li>
<li>Fast and efficient</li>
<li>Automated (via CSS Classes)</li>
<li>Adjustable (via option settings)</li>
<li>Easily expandable</li>
</ul>
<h2 id="basics">The Basics</h2>
<p>From a simplistic overview, the plugin loops around any form with a submit button and validates input elements based on its CSS classes.<br />
The standard CSS classes it works on are:<br />
<strong>required</strong> &#8211; if an input is marked as &#8216;required&#8217; it simply makes sure the field is not empty.<br />
<strong>email</strong> &#8211; it does a simple regex check to ensure the format is correct.<br />
<strong>digit</strong> &#8211; it checks whether the field only contains numbers 0 to 9.<br />
<strong>alpha</strong> &#8211; checks if the field contains characters a to z and A to Z.</p>
<h2 id="include-the-javascript">Including the JavaScript</h2>
<p>First include JQuery, supports 1.3.2 &#8211; 1.4.2:</p>
<pre><code>&lt;script type=&quot;text/javascript&quot; src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js&quot;&gt;&lt;/script&gt;</code></pre>
<p>Then include our <a href="#download">script</a>:</p>
<pre><code>&lt;script type=&quot;text/javascript&quot; src=&quot;options.validate-form.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;validate-form.js&quot;&gt;&lt;/script&gt;</code></pre>
<h2 id="explain-code">Explaining the Code</h2>
<p>Attaching the code automatically to all Forms is carried out by:</p>
<pre><code>$().ready(function() {
	//attach plugin to all forms with a submit button (except for ignored forms)
	$('form:not('+ formsToIgnore() +')').submit(function() {
		var formId = $(this).attr('id');
		var matchingElements = $('form#'+ formId +' input[type=text], form#'+ formId +' textarea, form#'+ formId +' input[type=checkbox]');
		if (!matchingElements == &quot;&quot;) {
			var formError = validateForm(formId, matchingElements);
			if (formError == true) {
				return false
			} else {
				return true;
			}
		}
	});
});</code></pre>
<p>If you need eager validation (it annoys me, but some people seem to love it #shake-head), set the options variable <em>eagerValidation=true</em> (see script options or examples), or if you don&#8217;t need it, remove it.</p>
<pre><code>//check whether to eagerly validate each field
	if (eagerValidation == true) {
		$('form input[type=text], form textarea, form input[type=checkbox]').focusout(function() {
			var fieldId = $(this).attr('id');
			var formId = $('#'+fieldId).parents('form').attr('id');
			if (validateField(formId, fieldId) == false) {
				removeFieldError(formId, fieldId);
			}
			removeFormError(formId);
			addFormError(formId);
		});
	}</code></pre>
<h2 id="core-functions">Core Functions</h2>
<pre><code>function validateField(formId, fieldId) {
	if (fieldId) {
		removeFieldError(formId, fieldId);

		var element = buildElement(formId, fieldId);
		var fieldValue = jQuery.trim(jQuery(element).val());
		var fieldLength = fieldValue.length;
		var fieldErrorMessage = &quot;&quot;;

		if ($(element).hasClass('text')) {
			if ($(element).hasClass('alpha') &#038;&#038; fieldLength &gt; 0) { // from string start to end, only contains '-' &quot;whitespace&quot; or 'aA'-'zZ'
				if (validateAlpha(fieldValue) == false) {
					fieldErrorMessage = alphaFieldError;
				}
			} else if ($(element).hasClass('digit') &#038;&#038; fieldLength &gt; 0) {
				if (validateDigit(fieldValue) == false) {
					fieldErrorMessage = digitFieldError;
				}
			} else if ($(element).hasClass('email') &#038;&#038; fieldLength &gt; 0) {
				if (validateEmail(fieldValue) == false) {
					fieldErrorMessage = emailFieldError;
				}
			} else if ($(element).hasClass('required') &#038;&#038; fieldLength == 0) {
				fieldErrorMessage = requiredTextError;
			}
		} else if ($(element).is('.textarea.required') &#038;&#038; fieldLength == 0) {
			fieldErrorMessage = requiredTextareaError;
		} else if ($(element).is('.checkbox.required') &#038;&#038; !$(element).is(':checked')) {
			fieldErrorMessage = requiredCheckboxError;
		}

		if (!fieldErrorMessage) {
			return false;
		} else {
			if (customErrorSelectors.length &gt; 0) {
				for (i=0;i&lt;customErrorSelectors.length;i++) { //check for overrides
					if (customErrorSelectors[i] == element) {
						fieldErrorMessage = customErrorMessages[i];
					}
				}
			}
			addFieldError(formId, fieldId, fieldErrorMessage);
			return true;
		}
	}
}

function validateForm(formId, matchingElements) {
	removeAllErrors(formId);

	matchingElements.each(function(index) {
		var elementId = $(this).attr('id');
		var fieldErrorStatus = validateField(formId, elementId);
	});

	if (countFormErrors(formId) &gt; 0) {
		if (focusFirstError == true) {
			focusOnFirstError(formId);
		}
		if (errorSummary == true) {
			addFormError(formId);
		}
		return true;
	} else {
		if (errorSummary == true) {
			removeFormError(formId);
		}
		return false;
	}
}</code></pre>
<h2 id="expanded-functions">Expanded Functions</h2>
<pre><code>function buildElement(formId, fieldId) {
	var element = &quot;form#&quot;+formId+&quot; #&quot;+fieldId;
	return element;
}

function focusOnFirstError(formId) {
	$('form#'+formId+' input.'+inputErrorClass+':first').focus();
}

function formsToIgnore() { //check for forms to ignore
	var formIgnoreItems = &quot;&quot;;
	for (i=0;i&lt;ignoreForms.length;i++) {
		if (i&gt;0) {
			formIgnoreItems += &quot;, &quot;;
		}
		formIgnoreItems += ignoreForms[i];
	}
	return formIgnoreItems;
}

function countFormErrors(formId) {
	var errorCounter = $('form#'+formId+' '+inputWrapper+'.'+inputWrapperErrorClass).size();
	return errorCounter;
}

function addFormError(formId) {
	var formSelector = 'form#'+formId;
	var errorMessageSelector = formSelector+' p.error-summary';
	var errorCounter = countFormErrors(formId);
	if (errorCounter &gt; 0) {
		if ($(errorMessageSelector).length) {
			$(errorMessageSelector).html(errorCounter + ' field(s) are invalid.');
		} else {
			$(formSelector).prepend('&lt;p class=\&quot;error-summary\&quot;&gt;' + errorCounter + ' field(s) are invalid.&lt;/p&gt;');
		}
	}
}

function removeAllErrors(formId) {
	removeFormError(formId);
	removeAllFieldErrors(formId);
}

function removeFormError(formId) {
	$('form#'+formId+' p.error-summary').remove();
}

function removeAllFieldErrors(formId) {
	var formSelector = 'form#'+formId;
	$(formSelector+' '+inputWrapper).removeClass(inputWrapperErrorClass);
	$(formSelector+' input[type=text], '+formSelector+' textarea, '+formSelector+' input[type=checkbox]').removeClass(inputErrorClass);
	$(formSelector+' '+inputWrapper+' p.error-message').remove();
}

function addFieldError(formId, fieldId, fieldErrorMessage) {
	var element = buildElement(formId, fieldId);
	$(element).addClass(inputErrorClass)
			  .parents(inputWrapper).addClass(inputWrapperErrorClass)
									.append('&lt;p class=\&quot;error-message\&quot;&gt;&gt;' + fieldErrorMessage + '&lt;/p&gt;');
}

function removeFieldError(formId, fieldId) {
	var element = buildElement(formId, fieldId);
	$(element).removeClass(inputErrorClass)
			  .parents(inputWrapper).removeClass(inputWrapperErrorClass);
	$(element).parents(inputWrapper).children('p.error-message').remove();
}

function validateAlpha(alpha) {
	var regex = /^[-\sa-zA-Z]+$/
	return regex.test(alpha);
}

function validateDigit(digit) {
	var regex = /^[0-9]+$/
	return regex.test(digit);
}

function validateEmail(email) {
	var regex = /^(([^&lt;&gt;()[\]\\.,;:\s@\&quot;]+(\.[^&lt;&gt;()[\]\\.,;:\s@\&quot;]+)*)|(\&quot;.+\&quot;))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
	return regex.test(email);
}</code></pre>
<h2 id="options">Options</h2>
<pre><code>//Validator options
var eagerValidation = false; //true/false   if set to true, form will eagerly validate each field. False will validate only ever on form submission
var errorSummary = true; //true/false    if set to true will show error summary at the top of the form
var focusFirstError = true; //true/false    if set to true will refocus user input to first error field on form submission
var inputErrorClass = &quot;error&quot;;    //set the class name that will be appended to the form input/textarea when an error is detected
var inputWrapper = &quot;p&quot;;    //set the element type that is used to wrap the form input/textarea in your forms
var inputWrapperErrorClass = &quot;err&quot;;    //set the class name that will be appended to the wrapper of the input/textarea when an error is detected

//Error Messages
var requiredTextError = &quot;cannot be empty&quot;; //Textbox error
var requiredTextareaError = &quot;cannot be empty&quot;; //Textarea error
var requiredCheckboxError = &quot;needs to be ticked&quot;; //Checkbox error
var alphaFieldError = &quot;characters only, no numbers&quot;; //Alpha Textbox error
var digitFieldError = &quot;numbers only, no characters&quot;; //Numeric Textbox error
var emailFieldError = &quot;valid email address only&quot;; //email Textbox error

var ignoreForms = ['#search-form']; //add any forms you need want the form to ignore, e.g search forms, etc. This can be ignored as long as none of the form inputs have 'required' or other validation classes attached

var customErrorSelectors = ['form#testform #el_0','form#testform #el_2']; //include form Id and element Id!
var customErrorMessages = ['this is an error message override, as specified in the config options','this is another error message override']; //Relates directly to customErrorSelectors</code></pre>
<h2 id="html">HTML</h2>
<p>The script assumes an element wrapper is used, and must be included in the options under inputWrapper, the default is &lt;p&gt;. See the examples included for the structure of HTML compatible.</p>
<h2 id="examples">Examples</h2>
<p><a target="_blank" href="http://www.ajgraham.com/codestore/jqueryformvalidator/formvalidation-basic.html">Simple Example</a><br />
<a target="_blank" href="http://www.ajgraham.com/codestore/jqueryformvalidator/formvalidation-complex.html">More Complex Example</a></p>
<h2 id="download">Download</h2>
<p>Options script &#8211; <strong>required for validation script to work</strong></p>
<p><a href="http://www.ajgraham.com/codestore/jqueryformvalidator/jquery.form-validator.zip">Download everything in 1 zipped package</a></p>
<h2 id="license">License</h2>
<p>Released under <a href="http://www.ajgraham.com/codestore/jqueryformvalidator/MIT-LICENSE.txt">MIT License</a>.</p>
<h2 id="to-dos">To Do&#8217;s</h2>
<ul>
<li>Improve the efficiency of the code execution.</li>
<li>Add min-length class options for fields.</li>
</ul>
<h2 id="change-log">Change-log</h2>
<p>2010/05/20: v0.2 released</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ajgraham.com/2010/05/simple-but-powerful-jquery-form-validation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tracking Email Signature click throughs</title>
		<link>http://www.ajgraham.com/2010/05/tracking-analytics-by-email-campaign/</link>
		<comments>http://www.ajgraham.com/2010/05/tracking-analytics-by-email-campaign/#comments</comments>
		<pubDate>Thu, 13 May 2010 21:23:51 +0000</pubDate>
		<dc:creator>alex</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[campaign]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[google analytics]]></category>
		<category><![CDATA[monitoring]]></category>
		<category><![CDATA[tracking]]></category>

		<guid isPermaLink="false">http://www.ajgraham.com/?p=352</guid>
		<description><![CDATA[Update 08/2011: GMail has since added the ability to use HTML within signatures in the online version which simplifies much of what I originally wrote. A while ago I thought about how best to create a more modern and useful [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update 08/2011</strong>: GMail has since added the ability to use HTML within signatures in the online version which simplifies much of what I originally wrote.</p>
<p>A while ago I thought about how best to create a more modern and useful email signature. At the same time I was doing some work with Google Analytics and thought it might be useful to track how many people click on my website link in my signature. I decided to use the following bit of code which would track it:</p>
<pre><code>&lt;a style="color:#353535" title="www.ajgraham.com/" href="http://www.ajgraham.com/?utm_source=Signature&#038;utm_medium=Email&#038;utm_term=Gmail&#038;utm_campaign=Email%2BSignature"&gt;
www.ajgraham.com/
&lt;/a&gt;</code></pre>
<p>The inline colour is used so the line isn&#8217;t the nasty default blue, change the #colour to anything you like.<br />
Change the title attribute to whatever you like, or omit it.</p>
<p>The only problem with using the above is that using it natively within GMail or an online web based email will not process it, and the only way to use it would be to use the full (nasty) URL like:
<pre><code>http://www.ajgraham.com/?utm_source=Signature&#038;utm_medium=Email&#038;utm_term=Gmail&#038;utm_campaign=Email%2BSignature</code></pre>
<p>There&#8217;s a workaround though, but it forces you to use a mail client like Thunderbird or Outlook and use it as part of a signature, which is a bit of a hassle simply to track email signature clicks. Unfortunately, until GMail allows full HTML in its online signatures then this is the only automated way of doing this.</p>
<p>It is interesting how many people click on it though, and the level of potential granularity if you wanted to take it even further to track different sets of email correspondents.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ajgraham.com/2010/05/tracking-analytics-by-email-campaign/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
