Jason Cale :: Young Delta Heart Ruby developer :: UI Designer http://jasoncale.com/ Scratch your itch: Tiny apps with Ruby, Rack and Heroku. http://jasoncale.com/articles/2-scratch-your-itch-tiny-apps-with-ruby-rack-and-heroku <h2>A ramble through the bramble.</h2> <h3>Humans like to create artefacts</h3> <p>Either to share with others or to keep a personal record, it helps bring meaning to life and is an important part of that yearning we have to leave a little part of our existence behind. Sometimes when you are dealing with hardship, or just trying to get something done creating a record helps you progress.</p> <h4>It helps us work.</h4> <p>Making lists, writing notes, and sketching on paper. These physical or digital artefacts help gather momentum towards a goal as well as spurring on a feeling of continual creation when travelling towards that goal.</p> <p>Imagine trying to achieve something really substantial keeping everything in your mind, resisting the temptation to deposit knowledge via a physical action you will likely find you don't get very far, or get easily distracted on the little things.</p> <p>Now imagine the scenario when you wake up, still in bed, early morning, tired and not ready to get up. Maybe you try and get your brain in gear thinking about all the things you are going to do once you get out from under the duvet. You make a list in your mind; have a shower, feed the cats, remember some towels for yoga and grind some coffee - oh shit did I run out?</p> <p>&ldquo;Well, I'll remember to pick some up after yoga&rdquo;.</p> <p>If you are anything like me, you spend 10-15 minutes doing this dance, a half baked promise to yourself before physically forcing yourself out from under the warm covers and into the cruel cold room.</p> <p>That somewhat inane situation is a lot like a task without artefacts, your brain cannot hold all of the actions and steps it needs to take towards a distance goal, so you must break these down into actions, steps and decisions. Writing down, or at least saving state helps you move on and progress.</p> <p> <em>I imagine you shaking your head in semi-bored disbelief.</em> </p> <h4>A little help from my friends</h4> <p> Those that know me personally or perhaps follow my tweets should know that <a href ='http://soberjase.heroku.com' title='Sober jase app'>1651 days ago</a> I gave up drinking alcohol. Without detailing the grim circumstances, one can suffice to say a hard thing to do. </p> <p>For me, each days elapse is met with a nice pat on the back, and I wanted a little reminder of that I could call upon when I wanted such a little lift.</p> <p>So I made a tiny app that tells me how many days it has been since I gave up the old vino.</p> <p>Taking approximately 3 minutes to write and deploy it is now accessible from anywhere, on my phone, and in the pub whilst I watch my mates slowly absorb themselves.</p> <h4>I'm a one man guy, is me.</h4> <p>What I would like to share today are the tools I used to get this little app together so quickly and published on the web so easily.</p> <p>Of course, the unspoken tool is HTML/CSS which I output to the browser, with that ticked off the other pieces of the puzzle are as follows:</p> <h4>Ruby</h4> <p>Unless you have been asleep or trapped in a closet, you will undoubtably know what Ruby is; the fantastic programming language that powers the framework that changed the way I wrote web applications, yes you know that one called Rails.</p> <p>This will be my fifth year with Ruby as my language of choice and our relationship is as strong as ever, yet I don't feel the urge to persuade you, this isn't some sales pitch, my friend.</p> <h4>Rack</h4> <p>Rack is basically a very simple interface between web servers and a web framework. For example, the popular Ruby framework Rails now runs on Rack, which means any web server that is Rack compatible will run Rails apps (and means any new servers that appear just need to speak Rack to run Rails and countless other Ruby frameworks).</p> <p> <em>Rack makes me think of boobies, which apparently is sexist.</em> </p> <p>This is very cool, because now we have a common way to interface with lots of different web servers via a simple API.</p> <p>Whilst Rack was designed to be used by web framework authors and not necessarily end users (in this case programmers), the same API that is used by said frameworks is simple enough for you to use to deploy a very small application that doesn't require the overhead of a whole web framework.</p> <p> You can even write software that sits in between your application framework and with Rack itself, this is often referred to as <strong>the middleware</strong> and can take the HTTP request (ie a GET request from a browser) and decide whether to process the response itself or pass it on to the web framework itself. Rails has middleware called <a href ='http://railscasts.com/episodes/150-rails-metal' title='Railscast: Rails Metal'>Metal</a>, which allows a developer to decide (in code) whether to send the request to Rails, or deal with the request there and then. This means you can bypass the potentially slower route of the whole framework and deliver certain end-points fast as your mother likes it. </p> <p>One example of this is to handle caching, instead of having to spawn Rails to decide if you can deliver cached content, you can do this via middleware and deliver the cached content without ever needing to add the expense of bothering your big ol' Rails app.</p> <p> The depth of Rack is beyond the point of this article, but should you want more information a good place to start might be on the <a href ='http://rack.rubyforge.org/' title='visit link: official page'>official page</a>, but google is also your friend. </p> <h4>Heroku</h4> <p> I have a major crush on <a href ='http://heroku.com' title='Heroku - awesome hosting'>Heroku</a>, I'm not dumb enough to try and decipher, or even suggest that a cloud based hosting provider has a gender, but either way I'm smitten for Her(oku) in a big way. </p> <p>Possibly the easiest and most grin inducing hosting platform I have ever used, if you have never seen what the whole thing is about, here is a quick run down.</p> <p>Heroku is a cloud hosting platform, that allows you to deploy you apps via a git workflow. I already use git for versioning my code (which I might add have major love for git (I hear you - oh Jase that is très passé) but being super easy to work with and helping me instead of stabbing me in the face like subversion used to who can blame me. So when I learned I could deploy my code via a git push, it turned my frown upside down.</p> <p>Guess what, Heroku knows what to do with Rack apps, so as long as your app is Rack compliant, it will run on Heroku with no setup needed.</p> <p> It's starting to get a bit too geeky around here, so let me get back on the fence and say: </p> <blockquote>With Heroku you get your idea live very quickly</blockquote> <p>Minimal setup, very little effort, and all for free (low resource apps don't cost anything). It is the perfect solution to launch our little itch apps to the world.</p> <h3>Getting started</h3> <p> Before I dive into the example, I need to cover some of the basics. I'm also going to assume you have <a href ='http://ruby-lang.org' title='visit link: Ruby'>Ruby</a>, and <a href ='http://docs.rubygems.org/' title='visit link: RubyGems'>RubyGems</a> installed on your system. If you have a mac with a recent version of OSX then you will do out the box, but you can also <a href ='http://hivelogic.com/articles/compiling-ruby-rubygems-and-rails-on-snow-leopard/' title='visit link: install it from source'>install it from source</a>. </p> <p>If you are on windows, well I have no idea, poor you etc. If you are on Linux I imagine you know what you are doing so I'll shut up.</p> <p>Also if you are a programmer this might be a chore to read, but I'm also assuming that you are interested, and therefore you need a little primer. Don't get too hung up on the code, the real point of this article is the higher level concept and hopefully getting you to discover the component parts incase they haven't crossed your path before.</p> <h4>Call on me.</h4> <p>A Rack app is required to respond to a method named <code>call()</code> which gets passed some details of the server environment that the HTTP request (that you need to process) has come from.</p> <p> Thankfully the <code>call()</code> method exists in a special type of Ruby object called a <code>Proc</code>, which is basically just a special function that you can create to use later on in your application. If you read <a href ='/articles/1-degradable-interface-elements' title='The fine art of degradable interface elements'>my previous article</a>, you may remember we created a reference to our jQuery widget which was a plugin (fancy name for a function) and applied it to our html via javascript. </p> <p>Back with Ruby and without going too deep, lets look at a very simple example of a <code>Proc</code>:</p> <div class='code_sample'> <ol class='code' start='1'> <li> <code class='tab_0 command'> &gt;&gt; hello_method = Proc.new { |name| &quot;Hello #{name}&quot; } </code> </li> <li> <code class='tab_0 result'> =&gt; #&lt;Proc:0x000000010169a328@(irb):16&gt; </code> </li> <li> <code class='tab_0 command'> &gt;&gt; hello_method.call(&quot;Mom&quot;) </code> </li> <li> <code class='tab_0 result'> =&gt; &quot;Hello Mom&quot; </code> </li> </ol> </div> <p>First we define a variable called <code>hello_method</code> and assign a <code>Proc</code> object to it, we then pass what is known as a <code>block</code> (think of it as a block of code - or closure) into to the <code>initialize()</code> method via <code>Proc.new()</code> which creates an instance we can execute later.</p> <p>Then we use the <code>call()</code> method on our <code>Proc</code> (via the <code>hello_method</code> reference) passing in the string <code>"Mom"</code>, and the block we defined the in the line before is evaluated and returns <code>"Hello"</code> concatenated with whatever we passed into the block (referenced as a local variable called <code>name</code>). This as you can hopefully see returns <code>"Hello Mom"</code>.</p> <h4>Extra credit</h4> <p>If you have ruby installed, try typing <code>irb</code> into your computers terminal and entering the lines that start with <code>&gt;&gt;</code> into the prompt (you don't need to type the actual &gt;&gt; into the prompt). <code>irb</code> is the interactive ruby shell which allows you to execute arbitrary bits of ruby on the fly.</p> <h3>Back to Rack</h3> <p>First you need to install the Rack gem, which will allow us to run our app.</p> <p> <pre><code>gem install rack</code></pre> </p> <p>As we mentioned, Rack expects our application to respond to a method named <code>call()</code>, it also expects that method to return an <code>Array</code> with three elements:</p> <ol class='timid'> <li> <p>HTTP Status response (for example 200 which means the request was successful).</p> </li> <li> <p>A hash of any HTTP headers to return to the server, such as the content type and length.</p> </li> <li> <p>The body of the response (normally a html file, but could be xml or json for example).</p> </li> </ol> <p>Such an array may look like this:</p> <p> <pre><code>[200, {'Content-Type'=>'text/plain'}, "Hello world"]</code></pre> </p> <p>Which would return the text <code>"Hello World"</code> to your browser.</p> <p>Putting this all together into a working Rack app would look like so:</p> <div class='code_sample'> <h3> Hello World App <a href ='/examples/article_2/hello_world.ru' title='Download code'>(download source)</a> </h3> <ol class='code' start='1'> <li> <code class='tab_0'> app = lambda { |env| </code> </li> <li> <code class='tab_2'> [ </code> </li> <li> <code class='tab_3'> 200, </code> </li> <li> <code class='tab_3'> {&#39;Content-Type&#39;=&gt;&#39;text/html&#39;}, </code> </li> <li> <code class='tab_3'> &quot;Hello World&quot; </code> </li> <li> <code class='tab_2'> ] </code> </li> <li> <code class='tab_1'> } </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_0'> run app </code> </li> </ol> </div> <h4>Running the Hello World app.</h4> <ol class='timid'> <li> <p> Download the <a href ='http://localhost:9292/examples/article_2/hello_world.ru' title='visit link: hello_world.ru'>hello_world.ru</a> file from the previous code block. </p> </li> <li> <p>Open up your terminal, such as Terminal.app on the mac.</p> </li> <li> <p> <code>cd /path/to/your/downloads/folder</code> </p> </li> <li> <p> then type <code>rackup hello_world.ru</code> (it will hopefully do nothing, and wait for connections). </p> </li> <li> <p> Visit <a href ='http://localhost:9292' title='visit link: http://localhost:9292'>http://localhost:9292</a> in your web browser of choice. </p> </li> <li> <p>Smile and nod.</p> </li> <li> <p>Close your terminal, or hit ctrl+c inside your Terminal to quit rack.</p> </li> </ol> <h4>Woah there Jase, great but what the hell is that lambda thing?!</h4> <p>Well, for the purposes of sanity, lets just say that lambda is another way of doing <code>Proc.new()</code> - there are slight differences, but none that are relevant in this context so don't worry about that - the important thing is you have seen them both so any other examples you find along the way should make sense.</p> <p>You can also see after our main code block we are calling a method <code>run</code> and passing in our refrence to the <code>Proc</code> via our variable <code>app</code>.</p> <p>This is the actual launch command for Rack which gets your app up and running ready to take requests.</p> <h3>Moving on</h3> <p> So <a href ='http://soberjase.heroku.com' title='visit link: my sober counter app'>my sober counter app</a> is potentially the simplest app ever, it really doesn't deserve to be called an application but it does go some way in showing how easy these kind of development strategies are, and if you have never played with Rack, Heroku or even Ruby then maybe I have piqued your interest. </p> <p> Chances are you don't really care about my how many days I've saved grace, so maybe we'll do something a little closer to home. So how about a one line app that tells us what week of <a href ='http://project52.info/' title='visit link: project52'>project52</a> we are on? </p> <p><em>Hey man, give me a break I got a mind full of blanks.</em></p> <p>The code to work out the current week is:</p> <p> <pre><code>week = DateTime.now.strftime("%V") #=> "02"</code></pre> </p> <p>Which is the ISO-8601 date standard, which may or may not be how people are doing p52 counting, but who cares as long as you are pumping something out at least once a week, right?</p> <p>The only other dependency is a html file that is sucked into the app block and has a placeholder dynamically replaced with the current p52 week.</p> <div class='code_sample'> <h3> The HTML template <a href ='/examples/article_2/index.html' title='Download code'>(download source)</a> </h3> <ol class='code' start='1'> <li> <code class='tab_0'> &lt;!DOCTYPE html&gt; </code> </li> <li> <code class=''> &lt;html&gt; </code> </li> <li> <code class='tab_1'> &lt;head&gt; </code> </li> <li> <code class='tab_2'> &lt;title&gt;What week is Project52 on?&lt;/title&gt; </code> </li> <li> <code class='tab_1'> &lt;/head&gt; </code> </li> <li> <code class='tab_1'> </code> </li> <li> <code class='tab_1'> &lt;style&gt; </code> </li> <li> <code class='tab_2'> body { background: #bebebe; font-family: &quot;Sathu&quot;, &quot;Helvetica&quot;, Arial; color: #333; text-align: center; } </code> </li> <li> <code class='tab_2'> h1 { font-size: 3em; text-shadow: #eee 1px 1px 1px; margin-top: 3em; line-height: 3em; } </code> </li> <li> <code class='tab_2'> h1 span { font-size: 4em; line-height: 0.5em; } </code> </li> <li> <code class='tab_1'> &lt;/style&gt; </code> </li> <li> <code class='tab_0'> </code> </li> <li> <code class='tab_1'> &lt;body&gt; </code> </li> <li> <code class='tab_2'> &lt;h1&gt;Project52 week is &lt;span&gt;[CURRENT_WEEK]&lt;/span&gt;/52.&lt;/h1&gt; </code> </li> <li> <code class='tab_1'> &lt;/body&gt; </code> </li> <li> <code class=''> &lt;/html&gt; </code> </li> </ol> </div> <p>To read in the index.html template file, and replace the placeholder <code>[CURRENT_WEEK]</code> we do:</p> <p> <pre><code>body = File.read('index.html').gsub(/\[CURRENT_WEEK\]/, week)</code></pre> </p> <p> We return the body variable in our code block just like we did with our <a href ='http://localhost:9292/examples/article_2/hello_world.ru' title='visit link: Hello World'>Hello World</a> example, and I have added a few extra headers to the response. </p> <p> <pre><code>"Content-Length" => body.length.to_s</code></pre> </p> <p>Tells the server the expected length of the response, which is the length of our html that resides inside the body variable and</p> <p> <pre><code>'Cache-Control' => 'public, max-age=3600'</code></pre> </p> <p> which caches the result of the page (expiring after 3600 seconds or 1 hour) as this will make subsequent requests to our page nice and fast (the caching is <a href ='http://docs.heroku.com/http-caching' title='visit link: provided by Heroku'>provided by Heroku</a> via <a href ='http://en.wikipedia.org/wiki/Varnish_(software)' title='Varnish on wikipedia'>Varnish</a>). </p> <p>Here is the whole thing:</p> <div class='code_sample'> <h3> Current week app <a href ='/examples/article_2/config.ru' title='Download code'>(download source)</a> </h3> <ol class='code' start='1'> <li> <code class='tab_0'> run lambda { |env| </code> </li> <li> <code class='tab_1'> week = DateTime.now.strftime(&quot;%V&quot;) </code> </li> <li> <code class='tab_1'> body = File.read(&#39;index.html&#39;).gsub(/\[CURRENT_WEEK\]/, week) </code> </li> <li> <code class='tab_1'> [ </code> </li> <li> <code class='tab_2'> 200, { </code> </li> <li> <code class='tab_6'> &#39;Content-Type&#39;=&gt;&#39;text/html&#39;, </code> </li> <li> <code class='tab_6'> &#39;Content-Length&#39; =&gt; body.length.to_s, </code> </li> <li> <code class='tab_6'> &#39;Cache-Control&#39; =&gt; &#39;public, max-age=3600&#39; </code> </li> <li> <code class='tab_2'> }, body </code> </li> <li> <code class='tab_1'> ] </code> </li> <li> <code class=''> } </code> </li> </ol> </div> <p> if you are playing along at home, here is a both the <a href ='/examples/article_2/p52_app.zip' title='visit link: required files as a zip'>required files as a zip</a> for you to run <code>rackup</code> and view in your browser. </p> <h3>Deploying to Heroku</h3> <p> This is the final piece of the puzzle, all you need to do is have a free <a href ='http://heroku.com/signup' title='visit link: account with Heroku'>account with Heroku</a>, give them your <a href ='http://help.github.com/mac-key-setup/' title='visit link: public ssh key'>public ssh key</a> and then install the heroku gem. </p> <p> <pre><code>gem install heroku</code></pre> </p> <p>Lets imagine we have created our application, but as it is a quick app we haven't setup git yet, no bones lets do that now as Heroku requires it (you may need to install git on your system first).</p> <div class='code_sample'> <ol class='code' start='1'> <li> <code class='tab_0'> cd p52_app </code> </li> <li> <code class='tab_0'> git init </code> </li> <li> <code class='tab_0'> git add . </code> </li> <li> <code class='tab_0'> git commit -m &quot;my week counter app&quot; </code> </li> </ol> </div> <p>Without getting bogged down in how to use git, the above basically just initialises your app folder as a git repository, adds all the files inside it to the repository and commits the files with the commit message "my week counter app".</p> <p>With that all set, you are ready to create your app on Heroku which we will call p52week via the command <code>heroku create p52week</code></p> <div class='code_sample'> <ol class='code' start='1'> <li> <code class='tab_0'> $ heroku create p52week </code> </li> <li> <code class='tab_0'> Created http://p52week.heroku.com/ | git@heroku.com:p52week.git </code> </li> </ol> </div> <p>All you need to do now is deploy the app, and get on with your life by typing <code>git push heroku master</code></p> <div class='code_sample'> <ol class='code' start='4'> <li> <code class='tab_0'> $ git push heroku master </code> </li> <li> <code class='tab_0'> Counting objects: 5, done. </code> </li> <li> <code class='tab_0'> Delta compression using up to 2 threads. </code> </li> <li> <code class='tab_0'> Compressing objects: 100% (3/3), done. </code> </li> <li> <code class='tab_0'> Writing objects: 100% (3/3), 311 bytes, done. </code> </li> <li> <code class='tab_0'> Total 3 (delta 1), reused 0 (delta 0) </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_0'> -----&gt; Heroku receiving push </code> </li> <li> <code class='tab_0'> -----&gt; Rack app detected </code> </li> <li> <code class='tab_3'> Compiled slug size is 4K </code> </li> <li> <code class='tab_0'> -----&gt; Launching......... done </code> </li> <li> <code class='tab_3'> http://p52week.heroku.com deployed to Heroku </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_0'> To git@heroku.com:p52week.git </code> </li> <li> <code class='tab_1'> a17392a..44df591 master -&gt; master </code> </li> </ol> </div> <h3>And we are done.</h3> <p>Your little app is ready for the world, just in time for the kettle to boil ready for a nice cuppa.</p> <p> Check it out <a href ='http://p52week.heroku.com/' title='p52 Counter'>http://p52week.heroku.com/</a>, and until next week, I bid thee adieu. </p> Sun, 10 Jan 2010 15:10:07 -0800 http://jasoncale.com/articles/2-scratch-your-itch-tiny-apps-with-ruby-rack-and-heroku Be kind to your friends: <br/> hit return. http://jasoncale.com/articles/5-dont-format-your-css-onto-one-line <h2>Viva multi-line CSS declarations!</h2> <p> For our latest project at <a href ='http://gofreerange.com' title='Software revolutionaries'>Go Free Range</a> we've been handed a few dozen stylesheet updates from an external designer, which means we've had to merge those updates into the work we have been doing. One interesting thing we encountered through this process with a designer whom has a penchant for single line style declarations, is that it makes hard work of collaborative style management&#153;. </p> <p>Now this article is somewhat acute in perspective, your company may well have an in-house style that features one line CSS declarations, or you may just plain love them, hell I know a few friends who work in that way, so I don't begrudge if that works in your remit, but when you are working across multiple teams you may need to consider a few different factors.</p> <h4>One line vs multi-line declarations.</h4> <p>For arguments sake, lets assume there are two potential ways to format your CSS, here is a random declaration from this very site laid out as a single line, and then again over multiple.</p> <div class='code_sample'> <h3> Inline style declarations <a href ='/examples/article_5/example.css' title='Download code'>(download source)</a> </h3> <ol class='code' start='1'> <li> <code class='tab_0'> .article_body img { max-width: 904px; margin: 3em 26px 4em 30px; -webkit-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2); -moz-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2); box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2); background: #eee; padding: 2em; border: 1px solid #e6e6e6; display: block; } </code> </li> </ol> </div> <div class='code_sample'> <h3> Style declarations with line-breaks <a href ='/examples/article_5/example.css' title='Download code'>(download source)</a> </h3> <ol class='code' start='3'> <li> <code class='tab_0'> .article_body img { </code> </li> <li> <code class='tab_1'> max-width: 904px; </code> </li> <li> <code class='tab_1'> margin: 3em 26px 4em 30px; </code> </li> <li> <code class='tab_1'> -webkit-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2); </code> </li> <li> <code class='tab_1'> -moz-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2); </code> </li> <li> <code class='tab_1'> box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2); </code> </li> <li> <code class='tab_1'> background: #eee; </code> </li> <li> <code class='tab_1'> padding: 2em; </code> </li> <li> <code class='tab_1'> border: 1px solid #e6e6e6; </code> </li> <li> <code class='tab_1'> display: block; } </code> </li> </ol> </div> <p>Writing style declarations on one line has never made sense to me, I find them confusing to read and generally unpleasant to work with, however there are long fought, apparently valid, arguments for the former style but there is one downside that makes me think all of that should be tossed in the bin:</p> <blockquote> Stylesheets that have declarations grouped onto one line, are impossible to <a href ='http://en.wikipedia.org/wiki/Diff' title='diff on wikipedia'>diff</a>! </blockquote> <h3>Why is this important?</h3> <p>In this instance it revolves around version managment, and if you don't even do that you should wake up and start, I cannot think of a single reason why in this day and age you wouldn't be, next thing you will tell me you still deploy your websites with FTP. Haha.</p> <p> <em>By version manage I mean something like (hopefully) git, or subversion (dropbox could work to some extent).</em> </p> <p>We all know that one of the advantages of version management is being able to look at two snapshots of a single file during the lifetime of development, and if you version manage well you should have fairly regular commits to draw from for your comparison.</p> <p>Usually to compare these two files you would use a tool such as diff, which will usefully and (if you use the right editor) beautifully mark the differences between the file(version)s into an easily digestible format allowing you to make correct assumptions and intelligent changes as needed.</p> <p>Now imagine you are working in a team with 3 or 4 people writing CSS into single file, each committing changes to their local copies before merging. When you come to do said merge you may need to resolve version conflicts, and using a tool like diff will help you to do this painlessly and quickly.</p> <blockquote>If you have declarations that are all on one line, you cannot diff effectively as the changes are not clearly marked.</blockquote> <p>You have to manually scan across the entire line of declarations as diff will just mark the entire line as being changed, and doing this across a few hundred lines of potential changes means you may as well just look at the stylesheet line by line to work out what has been altered! Something as simple as dropping your declarations onto a line each would prevent the need to practice such methods prone to error.</p> <p> Please, if you are going to be writing CSS to send to others to integrate, please try to place each declaration on it's own line, it will be most appreciated. Maybe you will start to see the joy of diff in your own workflow and you will get two prizes for the cost of one. </p> <p> Alternately you could use a syntax specific CSS tool such as <a href ='http://sass-lang.com/' title='visit link: SASS'>SASS</a> to keep your development CSS in a rigid structure and set the output to create one line declarations so you get the best of both methods. </p> Sun, 07 Feb 2010 10:04:17 -0800 http://jasoncale.com/articles/5-dont-format-your-css-onto-one-line The fine art of degradable interface elements http://jasoncale.com/articles/1-degradable-interface-elements <h2>What is the problem?</h2> <p>When working on a web application, you will ultimately have to deal with preferences, settings or controls to allow your users to modify the application behaviour. The simple route is to create a separate page to house these options, with a table or list of form elements representing the user's settings.</p> <p>However as applications get more complex, and the user interaction becomes more context heavy you may find that separating your preferences outside of the user flow becomes a hinderance to the user experience.</p> <p>Your users are frustrated, and your client is too. Your answer is to place the controls in an accessible place within the user interaction flow.</p> <p>Perhaps you already have the form working on a separate page, so pulling that html into an overlay isn't too hard. You also have a link to the settings on the page you need to incorporate with, so with a bit of javascript you can modify that link to activate your overlay providing a nice enhancement to the user.</p> <p>(If the above statement sounds like it really is too hard, send me an email or message me on twitter about it and maybe I'll write something up for that in a future article)</p> <p>Overlays are fine, but when you have an interface that has multiple settings, or preference modifiers it starts to behave like a jack-in-a-box orgy.</p> <img alt='Early interface sketch' class='bleed' src='http://farm3.static.flickr.com/2776/4246537388_4991871407_o.jpg' /> <h3>Getting inline</h3> <p> Complex inline interface elements, provide you with an excellent opportunity to allow the user to modify complex settings via a simple interface, and one that shouldn't get in the way of the user flow. An example of this that I'm going to cover is taken from an application that I designed and built for a startup called <a href ='http://jaseandtonic.com/the-work' title='visit link: ideapi'>ideapi</a>. </p> <p>The project is still in development, so I can't give too much away, but we needed a way to allow users to manage collaborators on a brief proposal.</p> <p>The following video provides a quick overview of solution I'm currently implementing:</p> <p class='screenr'> <object classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0' width='560' height='345'><param name='movie' value='http://screenr.com/Content/assets/screenr_1116090935.swf' /><param name='flashvars' value='i=37293' /><param name='allowFullScreen' value='true' /><embed src='http://screenr.com/Content/assets/screenr_1116090935.swf' flashvars='i=37293' allowFullScreen='true' width='560' height='345' pluginspage='http://www.macromedia.com/go/getflashplayer'></embed></object> </p> <p>As you can see I have encapsulated a number of fairly complex relationships within a simple interface, this allows the user to quickly update their preferences and get back to what they were doing without breaking flow.</p> <p>Whilst the interface uses javascript and ajax to enhance the experience, if you take these away you will find an widely accessible form element behind it that will allow the user to make the same modifications no matter what their browsing experience is, which is just the way I like it.</p> <img alt='form without js enabled' src='http://farm3.static.flickr.com/2682/4246587372_7b52ac2d5e_o.jpg' /> <p>Now you have a bit of background on what we are trying to achieve lets dive in and get started. Because this article is inevitably going to get a bit code heavy, I'm going to assume that you know all about html, CSS and basic jQuery. Even if you don't, maybe bare with me as I'm sure you will get something out of reading on.</p> <h3>The working example.</h3> <p> For our example application, we need a way of managing our employees. They are rambunctious lot so we shift around the roles quite a lot to keep things interesting. To do this we have created an interface element not unlike the one featured in <a href ='http://jaseandtonic.com/the-work' title='visit link: ideapi'>ideapi</a>. </p> <p class='emphasise'> You can see the finished example <a href='/examples/article_1/example_2.html'>here</a>. </p> <p>Hopefully you want to know how to recreate this, and as luck has it I'm going to try and show you.</p> <h4>Building the form.</h4> <p> First comes the markup, the best place to start really, as it will inform what you can and can't do. Here is a selection of the most important bits, you can always view source on the <a href ='/examples/article_1/example_1.html' title='view example script'>example</a>, which you can also access by clicking on <a href ='/examples/article_1/example_1.html' title='view example script'>download source</a> in the code block. </p> <div class='code_sample'> <h3> Creating the widget form <a href ='/examples/article_1/example_1.html' title='Download code'>(download source)</a> </h3> <ol class='code' start='7'> <li> <code class='tab_1'> &lt;body&gt; </code> </li> <li> <code class='tab_2'> &lt;form action=&quot;&quot; method=&quot;get&quot;&gt; </code> </li> <li> <code class='tab_3'> &lt;h2&gt;Employee settings&lt;/h2&gt; </code> </li> <li> <code class='tab_3'> &lt;ul id=&quot;employee_update_settings&quot;&gt; </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4'> &lt;li class=&quot;employee&quot;&gt; </code> </li> <li> <code class='tab_5'> &lt;img src=&quot;i/avatar.png&quot; alt=&quot;profile image&quot; class=&quot;avatar&quot; /&gt; </code> </li> <li> <code class='tab_5'> &lt;h3&gt;Dave&lt;/h3&gt; </code> </li> <li> <code class='tab_5'> &lt;ul class=&quot;employee_options&quot;&gt; </code> </li> <li> <code class='tab_6'> &lt;li class=&quot;manager&quot;&gt; </code> </li> <li> <code class='tab_7'> &lt;label for=&quot;manager_dave&quot;&gt;Manager&lt;/label&gt; </code> </li> <li> <code class='tab_7'> &lt;input type=&quot;radio&quot; id=&quot;manager_dave&quot; name=&quot;employees[manager][]&quot; value=&quot;dave&quot; checked /&gt; </code> </li> <li> <code class='tab_6'> &lt;/li&gt; </code> </li> <li> <code class='tab_6'> &lt;li class=&quot;assistant&quot;&gt; </code> </li> <li> <code class='tab_7'> &lt;label for=&quot;assistant_dave&quot;&gt;Assistant&lt;/label&gt; </code> </li> <li> <code class='tab_7'> &lt;input type=&quot;checkbox&quot; id=&quot;assistant_dave&quot; name=&quot;employees[assistant][]&quot; value=&quot;dave&quot; /&gt; </code> </li> <li> <code class='tab_6'> &lt;/li&gt; </code> </li> <li> <code class='tab_6'> &lt;li class=&quot;remove&quot;&gt; </code> </li> <li> <code class='tab_7'> &lt;label for=&quot;remove_dave&quot;&gt;Sack?&lt;/label&gt; </code> </li> <li> <code class='tab_7'> &lt;input type=&quot;checkbox&quot; id=&quot;remove_dave&quot; name=&quot;employees[remove][]&quot; value=&quot;dave&quot; /&gt; </code> </li> <li> <code class='tab_6'> &lt;/li&gt; </code> </li> <li> <code class='tab_5'> &lt;/ul&gt; </code> </li> <li> <code class='tab_4'> &lt;/li&gt; </code> </li> <li> <code class='tab_2'> </code> </li> <li> <code class='tab_4'> &lt;li class=&quot;employee&quot;&gt; </code> </li> <li> <code class='tab_5'> &lt;img src=&quot;i/avatar.png&quot; alt=&quot;profile image&quot; class=&quot;avatar&quot; /&gt; </code> </li> <li> <code class='tab_5'> &lt;h3&gt;Sam&lt;/h3&gt; </code> </li> </ol> </div> <p>I've also added the basic CSS, which lays out the form as it would look to any poor soul without javascript enabled or available.</p> <p>Here is a snapshot of the action, with a link for you to peruse the full thing.</p> <div class='code_sample'> <h3> Adding some style <a href ='/examples/article_1/screen.css' title='Download code'>(download source)</a> </h3> <ol class='code' start='23'> <li> <code class='tab_0'> #employee_update_settings { </code> </li> <li> <code class='tab_1'> padding: 0; </code> </li> <li> <code class='tab_1'> margin: 0; </code> </li> <li> <code class='tab_1'> list-style: none; </code> </li> <li> <code class=''> } </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_0'> .employee { </code> </li> <li> <code class='tab_1'> border-bottom: 1px solid #aaa; </code> </li> <li> <code class='tab_1'> background: url(i/panel.png) no-repeat; </code> </li> <li> <code class=''> } </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_0'> .employee img { </code> </li> <li> <code class='tab_1'> width: 40px; </code> </li> <li> <code class='tab_1'> height: 40px; </code> </li> <li> <code class='tab_1'> border: 1px solid #ccc; </code> </li> <li> <code class='tab_1'> margin: 5px 5px 5px 7px; </code> </li> <li> <code class=''> } </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_0'> .employee h3 { </code> </li> <li> <code class='tab_1'> padding: 0; </code> </li> <li> <code class='tab_1'> color: #444; </code> </li> <li> <code class='tab_1'> margin: -35px 0 20px 60px; </code> </li> <li> <code class='tab_1'> text-shadow: 1px 1px 1px #fff; </code> </li> <li> <code class=''> } </code> </li> </ol> </div> <p>Yawnsville is just around the corner, so lets divert our attention to the heart of the matter. The javascript that turns this rather timid little form into a man with it's own little bit of Mick Jagger swagger.</p> <p> If you are a sadist, you can have a look at the <a href ='/examples/article_1/j/jshizzle.js' title='View the javascript'>full source here</a> but baby steps is the way we like to work, so lets break it down a little and look at a few techniques used in the script, which should make things a little clearer. </p> <h3>Wrapping up your code to keep it warm.</h3> <p>Your code is special, so don't just leave it lying round where it could get into trouble. Where possible you should try to encapsulate and there are javascript idioms that allow you to do just that.</p> <p> <pre><code>(function ($) { ... })(jQuery); // useful for encapsulating a reference to jQuery</code></pre> </p> <p>This is the technique that I use for creating a sealed block of code which needs access to jQuery. So I pass a reference to jQuery as a parameter when the function is initialised for use throughout the library.</p> <p>For a simple demonstration of what this does, consider following snippet:</p> <p> <pre><code class='eval'>(function (name) { alert("Hello from " + name); })("Jase")</code></pre> </p> <h4>See for yourself</h4> <p>If you have a browser with a javascript console enabled (for instance firebug or safari with the developer bar enabled) you can copy in the following snippet into the console and it will define a function, and then execute it with whatever you pass into it in the second pair of parenthesis. Alternately you can just click on the snippet above as I've bound it to execute the same script, and hopefully you should see an alert.</p> <h4>Back to jQuery</h4> <p>This idiom is used a lot with jQuery as it allows you to pass in a reference to jQuery into your own closures, which also allows you to use the dollar notation throughout your code library, without worrying about conflicts should another library be introduced to the application that also happens to use the dollar notation (prototype.js for example).</p> <p> <pre><code>(function ($) { $('.div').show(); })(jQuery);</code></pre> </p> <h3>Writing utility functions</h3> <p>Once you start writing an real length of script, you are going to start repeating yourself. Which is fine whilst you are playing around, but if you have any plans to keep that script around for longer than an afternoon you had better start refactoring.</p> <p>Even in this little example, I've created two utility functions that encapsulate a little of bit of code that I need to execute over and over in the body of the main script.</p> <div class='code_sample'> <h3> Create link helper <a href ='/examples/article_1/j/jshizzle.js' title='Download code'>(download source)</a> </h3> <ol class='code' start='16'> <li> <code class='tab_1 comment'> // NOTE: I&#39;m saving a reference to createLink so I can return </code> </li> <li> <code class='tab_1 comment'> // it outside of the wrapper, and use it elsewhere in the </code> </li> <li> <code class='tab_1 comment'> // application, whilst encapsulating its magic. </code> </li> <li> <code class='tab_0'> </code> </li> <li> <code class='tab_1'> var createLink = function (el, linkText, classNames, append) { </code> </li> <li> <code class='tab_2'> if (!linkText) linkText = &#39;&#39;; </code> </li> <li> <code class='tab_2'> if (!classNames) classNames = &#39;&#39;; </code> </li> <li> <code class='tab_1'> </code> </li> <li> <code class='tab_2'> var link = &#39;&lt;a href=&quot;#&quot; class=&quot;&#39;+ classNames +&#39;&quot;&gt;&#39;+ linkText +&#39;&lt;/a&gt;&#39;; </code> </li> <li> <code class='tab_1'> </code> </li> <li> <code class='tab_2'> if (append) { </code> </li> <li> <code class='tab_3'> el.append(link); </code> </li> <li> <code class='tab_3'> return el.find(&#39;a:last-child&#39;); </code> </li> <li> <code class='tab_2'> } else { </code> </li> <li> <code class='tab_3'> el.wrap(link); </code> </li> <li> <code class='tab_3'> return el.parent(); </code> </li> <li> <code class='tab_2'> } </code> </li> <li> <code class='tab_1'> } </code> </li> </ol> </div> <p> As you can hopefully see <code>createLink()</code> is a utility to wrap or append an element with a link .. usually to add behaviour a document element. </p> <p>It will return a jQuery reference to the newly created element so it can be chained or have events bound to it, like so:</p> <p> <pre><code>createLink($('span')).click(function () { $(this).hide() });</code></pre> </p> <p>Which will find any span elements, wrap them in a link, which when clicked will hide the link and its descendants (the original span element).</p> <h4>Optional extras</h4> <p> Passing in strings to <code>linkText</code> and <code>classNames</code> as parameters will place their values into the link html and a boolean to <code>append</code> will somewhat expectedly append the link to the element passed into the function instead of wrapping it. </p> <div class='code_sample'> <h3> Sister input <a href ='/examples/article_1/j/jshizzle.js' title='Download code'>(download source)</a> </h3> <ol class='code' start='35'> <li> <code class='tab_1'> function getSisterInput(element) { </code> </li> <li> <code class='tab_2'> return $(element).siblings(&#39;input:radio, input:checkbox&#39;); </code> </li> <li> <code class='tab_1'> } </code> </li> </ol> </div> <p> The <code>getSisterInput()</code> function is a little contrived, but these two approaches allow you to create helper methods within your application without polluting the overall object space, and by creating a reference to <code>createLink</code> we return a reference to be used in other parts of the application too. </p> <p>You can see where I do this a little further down the script, which I've included below .. But you may have to look at that line in context if you want to get the full gist.</p> <div class='code_sample'> <h3> Returning created methods to the outside world <a href ='/examples/article_1/j/jshizzle.js' title='Download code'>(download source)</a> </h3> <ol class='code' start='118'> <li> <code class='tab_1 comment'> // return our helper method so it can be used outside of this closure. </code> </li> <li> <code class='tab_1'> return { </code> </li> <li> <code class='tab_2'> createLink: createLink </code> </li> <li> <code class='tab_1'> } </code> </li> </ol> </div> <p>As we move onto the widget details, you will see these functions get used, and hopefully you will see their use in context.</p> <h3>An earnest jQuery plugin</h3> <p>Our widget is a standalone bit of code that we want to attach to our list of employees. If you have used jQuery for any length of time, chances are you have used a jQuery plugin or at least the functional level at which they operate. It goes a little bit like this:</p> <p> <pre><code>$('#employee_update_settings').employeeWidget();</code></pre> </p> <p> Hopefully the above looks like something you have seen before, basically we want to encapsulate our behaviour into a nice one-liner to use inside the usual <code>$(document).ready()</code> setup when writing jQuery. It also means we can hide the real meat away into a separate file should we wish, and not scare off any of those 'real designers' with our terribly dreary code. Not to mention refactoring it enough so we could use it across multiple projects! </p> <h4>Defining a plugin</h4> <p>A plugin is just a function that you apply to the jQuery api, which is basically a fancy way of saying this:</p> <p> <pre><code>$.fn.pluginName = function () { ... } ;</code></pre> </p> <p>A practical example below shows how you could create a plugin that when applied to an element, clicking said element would fade it out.</p> <div class='code_sample'> <h3> Simple jQuery plugin <a href ='/examples/article_1/j/simple_plugin.js' title='Download code'>(download source)</a> </h3> <ol class='code' start='1'> <li> <code class='tab_0'> $.fn.hideMe = function () { </code> </li> <li> <code class='tab_1'> $(this).click(function () { </code> </li> <li> <code class='tab_2'> alert(&quot;I&#39;m off, see you later!&quot;); </code> </li> <li> <code class='tab_2'> $(this).fadeOut(); </code> </li> <li> <code class='tab_1'> }); </code> </li> <li> <code class=''> } </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_0'> $(document).ready(function () { </code> </li> <li> <code class='tab_1'> $(&#39;a.hide_me&#39;).hideMe(); </code> </li> <li> <code class=''> }); </code> </li> </ol> </div> <h4>Our example</h4> <p> Taking what we have just learned, look at the following code. It is the main part of the script which transforms the employee widget into the final version, with a little help from our custom helper methods (some of which we are yet to cover), it should make sense how we bind the different events and animations onto the elements within the employee widget. </p> <p> You will notice that I'm using <code>$.fn.extend( { pluginName: function .. })</code> instead of <br /> <code>$.fn.pluginName = function () {}</code> when defining the plugin. It is essentially the same thing, but for more information on the extend method you should consult the <a href ='http://docs.jquery.com/Utilities/jQuery.extend' title='Read about extending objects'>jQuery documentation</a>. </p> <div class='code_sample'> <h3> The employee widget plugin <a href ='/examples/article_1/j/jshizzle.js' title='Download code'>(download source)</a> </h3> <ol class='code' start='139'> <li> <code class='tab_1 comment'> // Here I&#39;m using $.fn.extend to add my functions to the jQuery </code> </li> <li> <code class='tab_1 comment'> // api, this is just a different way to defining a plugin action </code> </li> <li> <code class='tab_1 comment'> // but has the same effect of doing </code> </li> <li> <code class='tab_1 comment'> // </code> </li> <li> <code class='tab_1 comment'> // $.fn.employWidget = function () {} </code> </li> <li> <code class='tab_1 comment'> // </code> </li> <li> <code class='tab_0'> </code> </li> <li> <code class='tab_1'> $.fn.extend({ </code> </li> <li> <code class='tab_2'> employeeWidget: function () { </code> </li> <li> <code class='tab_3 comment'> // add the js class to the element, so we can </code> </li> <li> <code class='tab_3 comment'> // do specific css to javascript users </code> </li> <li> <code class='tab_3'> $(this).addClass(&#39;js&#39;); </code> </li> <li> <code class='tab_2'> </code> </li> <li> <code class='tab_3 comment'> // you can see we are using app.createLink() a reference to </code> </li> <li> <code class='tab_3 comment'> // our utility class outside of its own closure. </code> </li> <li> <code class='tab_3'> app.createLink($(this).find(&#39;.employee&#39;), &quot;options&quot;, &quot;toggle_options&quot;, true).click(function () { </code> </li> <li> <code class='tab_4 comment'> // grab a reference to the toggle link </code> </li> <li> <code class='tab_4'> var link = $(this); </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4 comment'> //toggle the options table up and down </code> </li> <li> <code class='tab_4'> $(this).siblings(&#39;.employee_options&#39;).slideToggle(&#39;slow&#39;, function () { </code> </li> <li> <code class='tab_5 comment'> // once the slideToggle has finished, work out whether to add </code> </li> <li> <code class='tab_5 comment'> // the selected class to the options link .. if the options block </code> </li> <li> <code class='tab_5 comment'> // has the css display property of &#39;block&#39; we know that it is visible </code> </li> <li> <code class='tab_5'> link.toggleClass(&#39;selected&#39;, ($(this).css(&#39;display&#39;) == &quot;block&quot;)); </code> </li> <li> <code class='tab_4'> }); </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4 comment'> // always make the link active when it is clicked </code> </li> <li> <code class='tab_4 comment'> // to provide instant feedback to the user (it will update </code> </li> <li> <code class='tab_4 comment'> // once the slideToggle animation has finished) </code> </li> <li> <code class='tab_4'> link.toggleClass(&#39;selected&#39;, true); </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4 comment'> // finally we hide the employee options, </code> </li> <li> <code class='tab_4 comment'> // so they are hidden when the page loads </code> </li> <li> <code class='tab_3'> }).siblings(&#39;.employee_options&#39;).hide(); </code> </li> <li> <code class='tab_1'> </code> </li> <li> <code class='tab_3 comment'> // apply our enableLabelToggle to each label in the options list, passing in </code> </li> <li> <code class='tab_3 comment'> // the relevant callback to fire once it is clicked </code> </li> <li> <code class='tab_3'> $(this).find(&#39;.employee_options li.manager label&#39;).enableLabelToggle(employeeManagerCallback); </code> </li> <li> <code class='tab_3'> $(this).find(&#39;.employee_options li.assistant label&#39;).enableLabelToggle(employeeAssistantCallback); </code> </li> <li> <code class='tab_3'> $(this).find(&#39;.employee_options li.remove label&#39;).enableLabelToggle(employeeRemoveCallback); </code> </li> <li> <code class='tab_2'> } </code> </li> <li> <code class='tab_1'> }); </code> </li> <li> <code class='tab_0'> </code> </li> <li> <code class=''> })(jQuery); </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_0'> $(document).ready(function () { </code> </li> <li> <code class='tab_1'> $(&#39;#employee_update_settings&#39;).employeeWidget(); </code> </li> <li> <code class=''> }); </code> </li> </ol> </div> <p> If you are struggling try to read the code line by line, breaking it down as they come, you should see they are just simple jQuery statements in isolation. </p> <p> However the following functions you won't have come across yet <code>enableLabelToggle()</code> , <code>employeeManagerCallback()</code> , <code>employeeAssistantCallback()</code> and <code>employeeRemoveCallback()</code> which can be found in the final three lines of the plugin above. </p> <div class='code_sample'> <h3> The employee widget plugin <a href ='/examples/article_1/j/jshizzle.js' title='Download code'>(download source)</a> </h3> <ol class='code' start='177'> <li> <code class='tab_3'> $(this).find(&#39;.employee_options li.manager label&#39;).enableLabelToggle(employeeManagerCallback); </code> </li> <li> <code class='tab_3'> $(this).find(&#39;.employee_options li.assistant label&#39;).enableLabelToggle(employeeAssistantCallback); </code> </li> <li> <code class='tab_3'> $(this).find(&#39;.employee_options li.remove label&#39;).enableLabelToggle(employeeRemoveCallback); </code> </li> </ol> </div> <h4>Taking a lowly label &amp; making it shine.</h4> <p>We want our widget to control the form that is submitted to our application, so whatever fancy ui elements we can think up will ultimately have to be translated onto the form inputs underneath.</p> <p> The first function we need to implement to do this is the <code>enableLabelToggle()</code> a somewhat dubious function name, nevertheless it's principal role is taking a form label and turning it into the toggle links we see in the <a href ='/examples/article_1/example_2.html' title='View finished example'>final example</a>. </p> <p>Here is the code (I can see you are getting into this now):</p> <div class='code_sample'> <h3> Making labels rock <a href ='/examples/article_1/j/jshizzle.js' title='Download code'>(download source)</a> </h3> <ol class='code' start='39'> <li> <code class='tab_1'> $.fn.extend({ </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_2'> enableLabelToggle: function(action_callback) { </code> </li> <li> <code class='tab_3'> createLink($(this), &quot;&quot;, &quot;action&quot;).click(function () { </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4 comment'> // grab related input element .. using our lovely </code> </li> <li> <code class='tab_4 comment'> // little utility method. </code> </li> <li> <code class='tab_4'> var input = getSisterInput($(this)); </code> </li> <li> <code class='tab_7'> </code> </li> <li> <code class='tab_4 comment'> // is the input checked? - (try it in the console) </code> </li> <li> <code class='tab_4'> var selected = !input.attr(&#39;checked&#39;); </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4 comment'> // now we add some behavioural rules ... </code> </li> <li> <code class='tab_4'> var canChange = true; </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4 comment'> // make sure we don&#39;t uncheck any radio buttons that are selected </code> </li> <li> <code class='tab_4'> if (input.attr(&#39;type&#39;) == &quot;radio&quot; &amp;&amp; input.attr(&#39;checked&#39;)) canChange = false; </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4 comment'> // we add more later, lets stay agile and all that .. </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4 comment'> // if all our rules passed, we are good to make the change. </code> </li> <li> <code class='tab_4'> if (canChange) { </code> </li> <li> <code class='tab_5 comment'> // toggle the link&#39;s class name depending on input state </code> </li> <li> <code class='tab_5'> $(this).toggleClass(&#39;selected&#39;, selected); </code> </li> <li> <code class='tab_7'> </code> </li> <li> <code class='tab_5 comment'> // toggle the input box </code> </li> <li> <code class='tab_5'> input.attr(&#39;checked&#39;, selected); </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_5 comment'> // if the input element is a radio button </code> </li> <li> <code class='tab_5 comment'> // we need to tell the other radio elements </code> </li> <li> <code class='tab_5 comment'> // within the group that they have changed </code> </li> <li> <code class='tab_5 comment'> // so they can update their associated links </code> </li> <li> <code class='tab_5'> if (input.attr(&#39;type&#39;) == &quot;radio&quot;) { </code> </li> <li> <code class='tab_6 comment'> // find any inputs that have the same name, </code> </li> <li> <code class='tab_6 comment'> // as they will be part of the same group </code> </li> <li> <code class='tab_6 comment'> // and call change() as defined in the &quot;each&quot; </code> </li> <li> <code class='tab_6 comment'> // function below </code> </li> <li> <code class='tab_6'> $(&#39;input[name=&quot;&#39;+input.attr(&#39;name&#39;)+&#39;&quot;]&#39;).change(); </code> </li> <li> <code class='tab_5'> }; </code> </li> <li> <code class='tab_4'> }; </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4 comment'> // call the function passed into enableLabelToggle </code> </li> <li> <code class='tab_4 comment'> // using apply to make any references to &#39;this&#39; </code> </li> <li> <code class='tab_4 comment'> // inside the callback function point to this link. </code> </li> <li> <code class='tab_4'> action_callback.apply($(this)); </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_4 comment'> // return false, so it doesn&#39;t do anything else. </code> </li> <li> <code class='tab_4'> return false; </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4 comment'> //next we loop through each matching label, and apply the following: </code> </li> <li> <code class='tab_3'> }).each(function () { </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4 comment'> // we also want to catch any change </code> </li> <li> <code class='tab_4 comment'> // events on the input elements this </code> </li> <li> <code class='tab_4 comment'> // link controls, so we can update </code> </li> <li> <code class='tab_4 comment'> // the link state if the input changes </code> </li> <li> <code class='tab_4 comment'> // by another event that this link&#39;s </code> </li> <li> <code class='tab_4 comment'> // click event </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4 comment'> // grab a reference to link for closure </code> </li> <li> <code class='tab_4'> var link = $(this); </code> </li> <li> <code class='tab_7'> </code> </li> <li> <code class='tab_4 comment'> // find inputs to bind change event on, then hide them </code> </li> <li> <code class='tab_4'> $(this).siblings(&#39;input:radio, input:checkbox&#39;).hide().change(function (){ </code> </li> <li> <code class='tab_5 comment'> // toggle the link&#39;s class name depending on input state </code> </li> <li> <code class='tab_5'> link.toggleClass(&#39;selected&#39;, $(this).attr(&#39;checked&#39;)); </code> </li> <li> <code class='tab_4'> }).change(); </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_4 comment'> // I have appended a change() on the end of the change() definition </code> </li> <li> <code class='tab_4 comment'> // to catch any initial states set on the form .. </code> </li> <li> <code class='tab_3'> </code> </li> <li> <code class='tab_3'> }); </code> </li> <li> <code class='tab_2'> </code> </li> <li> <code class='tab_3 comment'> // return $(this) so we can chain the method should we wish. </code> </li> <li> <code class='tab_3'> return $(this); </code> </li> <li> <code class='tab_2'> } </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_1'> }); </code> </li> </ol> </div> <p> A quick summary of what is happening in our <code>enableLabelToggle()</code> function: </p> <ol> <li> <p>Wrap the label in a link and define the onclick function*.</p> </li> <li> <p>Create a reference to the input we want to toggle.</p> </li> <li> <p>Find out if the input is currently selected / checked.</p> </li> <li> <p>Apply rules to figure out if we can toggle the input.</p> </li> <li> <p>If so, we toggle the input, and update the link.</p> </li> <li> <p>If the input is a radio element, we update all radio links.</p> </li> <li> <p>Fire the link callback that is passed into the function</p> </li> <li> <p>Listen for any input changes (catching any initial states) and to update the links as they happen.</p> </li> </ol> <p>* Yes we could bind the function straight onto the label, but I'm sure that isn't as accessible?</p> <h3>Defining the callbacks</h3> <p>The final piece of the puzzle, is what makes the widget actually useful and I've left it out for you to define in your own application. This is where you fire some ajax call off to update the backend, and then probably update the widget with a result. It is where your widget becomes alive.</p> <p>Here are the callbacks as defined in our example:</p> <div class='code_sample'> <h3> Separating out functionality with callbacks <a href ='/examples/article_1/j/jshizzle.js' title='Download code'>(download source)</a> </h3> <ol class='code' start='127'> <li> <code class='tab_1'> var employeeManagerCallback = function () { </code> </li> <li> <code class='tab_2'> console.log(&quot;FIRE AJAX FOR MANAGER!&quot;); </code> </li> <li> <code class='tab_1'> } </code> </li> <li> <code class='tab_0'> </code> </li> <li> <code class='tab_1'> var employeeAssistantCallback = function () { </code> </li> <li> <code class='tab_2'> console.log(&quot;FIRE AJAX FOR ASSISTANT!&quot;); </code> </li> <li> <code class='tab_1'> } </code> </li> <li> <code class='tab_0'> </code> </li> <li> <code class='tab_1'> var employeeRemoveCallback = function () { </code> </li> <li> <code class='tab_2'> $(this).parents().filter(&#39;.employee&#39;).fadeOut(); </code> </li> <li> <code class='tab_1'> } </code> </li> </ol> </div> <p>You should be able to match up what you see in the code to what happens when you click on any of the actions - check your console to see the messages being output (I previously had alerts but I think they detract from the overall experience of the widget example).</p> <h4>Why use callbacks?</h4> <p>The reason why I've separated each function out into a callback, is the <strong>manager</strong>, <strong>assistant</strong> and <strong>remove</strong> actions are undoubtably doing different things.</p> <p> We could very easily define an ajax request (or whatever the action does) inside of <code>enableLabelToggle()</code> but it would start getting unwieldy and lose focus if we had lots of different actions all with individually defined behaviour. We would also have to check what type of action has occurred (i.e. remove) whereas when we bind the <code>employeeRemoveCallback()</code> to all labels that are associated with the remove input elements ( <code>.employee_options li.remove label</code> ) we are are removing the need to do this. Using callbacks promotes cleaner code and provides us with greater flexibility and perhaps most important of all it increases readability. </p> <h3>Adding style to our behavioural additions.</h3> <p>You may remember in our widget plugin, we added a class to our employee list called 'js' which we can use to hook additional CSS declarations onto once the javascript has been attached. You can see these at the bottom of the stylesheet linked to the example page, but here is a quick snapshot of some of the additions to the CSS.</p> <div class='code_sample'> <h3> Uprating our widget <a href ='/examples/article_1/screen.css' title='Download code'>(download source)</a> </h3> <ol class='code' start='108'> <li> <code class='tab_0'> /* style the action buttons */ </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_0'> #employee_update_settings.js .employee ul.employee_options { </code> </li> <li> <code class='tab_1'> height: 50px; </code> </li> <li> <code class='tab_1'> padding: 0; </code> </li> <li> <code class='tab_1'> margin: 0; </code> </li> <li> <code class=''> } </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_0'> #employee_update_settings.js .employee ul.employee_options li { </code> </li> <li> <code class='tab_1'> padding: 0; </code> </li> <li> <code class='tab_1'> display: inline; </code> </li> <li> <code class='tab_1'> position: relative; </code> </li> <li> <code class=''> } </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_0'> #employee_update_settings.js .employee ul.employee_options li a.action { </code> </li> <li> <code class='tab_1'> width: 38px; </code> </li> <li> <code class='tab_1'> height: 0px; </code> </li> <li> <code class='tab_1'> display: block; </code> </li> <li> <code class='tab_1'> background: url(i/actions.png) 0 -39px; </code> </li> <li> <code class='tab_1'> position: absolute; </code> </li> <li> <code class='tab_1'> top: 5px; </code> </li> <li> <code class='tab_1'> left: 0; </code> </li> <li> <code class='tab_1'> padding-top: 30px; </code> </li> <li> <code class='tab_1'> text-align: center; </code> </li> <li> <code class='tab_1'> text-decoration: none; </code> </li> <li> <code class='tab_1'> text-shadow: 0.1em 0.1em 0.2em #999; </code> </li> <li> <code class=''> } </code> </li> <li> <code class=''> </code> </li> <li> <code class='tab_0'> #employee_update_settings.js .employee ul.employee_options li a { </code> </li> <li> <code class='tab_1'> color: #666; </code> </li> <li> <code class=''> } </code> </li> <li> <code class=''> </code> </li> </ol> </div> <h4>Wrapping up</h4> <p>So there you have it, all the elements needed to create a degradable interface elements that not only enhance the user experience but also degrade gracefully for less able devices.</p> <p class='emphasise'> Just to recap you can see the finished example <a href='/examples/article_1/example_2.html'>here</a>. </p> <h3>Hang on a minute.</h3> <p> You may think that we have written a hell of a lot of code to achieve what could be argued as something that does very little? Should you say: </p> <blockquote> Surely Jase, this is why the jQuery UI project exists?! <span class='source'>- A frustrated designer</span> </blockquote> <p>Well yes, you can get away with the crafty one-liners we all love but sometimes they just don't exist, or you end up writing boat loads of bridge code just to get it working the way you need. I'd probably say:</p> <blockquote> You need to make something bespoke, baby. <span class='source'>- A wily Jase</span> </blockquote> <p>In reality once you get to grips with jQuery internals, you will be writing these kind of enhancements a dime a dozen. You will also find that you can write a really complex yet elegant interface elements in 100 lines that would normally take you five or ten times that with vanilla javascript. Best of all, its 100% degradable and unobtrusive so it makes everybody happy.</p> <h3>Thanks for reading</h3> <p>This has been my first article (of 52 this year), and I hope it wasn't too overwhelming and you could get through it fairly easily (extra well done if you got this far without skipping!).</p> <p> Any comments feel free to <a href ='mailto:jase@jaseandtonic.com' title='visit link: send me an email'>send me an email</a>, or message me on <a href ='http://twitter.com/jasoncale' title='Follow me on twitter'>twitter</a> and I'll try to respond. </p> <h3>Want something similar on your project?</h3> <p> <a href ='http://jaseandtonic.com' title='Jase &amp; Tonic Ltd'>I'm for hire</a> and also available as part of the <a href ='http://gofreerange.com' title='Go Go Free Range'>best team in town</a>. </p> Fri, 01 Jan 2010 10:03:18 -0800 http://jasoncale.com/articles/1-degradable-interface-elements The importance of yellow: I'm a one man guy is me. http://jasoncale.com/articles/4-the-importance-of-yellow <h2>Sell yourself, to yourself.</h2> <p>Now first thing is first, this isn't some bullshit diatribe about personal branding and how to get yourself noticed, how to promote your blog or whatever other crap that is written about self promotion. I couldn't care less about that, and I'll assume I don't need to come up with artificial ways to try and seduce you.</p> <p>Those soulless buggers who talk about self promotion whilst spoon-feeding you checklists to your own greatness, are the vacuous bleeders who devoid of any real character can make us vulnerable people swoon like flowering teenagers, because they know what we crave.</p> <h4>Make yourself comfortable taking pain.</h4> <p>It is my belief that any creative endeavour should be traumatic. If I'm drawing from my experience, ability and passion effectively then I should be running to the edge of my control, not knowing what the fuck I'm doing but knowing where I've come from is where I desire to pass through at least once on any project.</p> <p> My tip is to surround yourself with little reminders of who you are, and aspire to be. It can be immensely beneficial to keeping on track, drawing strength from them as you go. By building a brand and identity for yourself to immerse within can be a very effective proponent when arguing with your own limits. Which brings me to the somewhat loose point of this article: Forget everyone else, build yourself for you, then take confidence from it. It will help you justify yourself and face that fear that seems to linger around every project I start working on (and <a href ='http://twitter.com/mikekus/status/8281631609' title='@mikekus on twitter'>others do too</a>). </p> <p>It is worth noting that the trauma when creating must come from you and not your clients; there is a big difference. Although client pain can sometimes indirectly produce results I wouldn't recommend seeking inspiration in that form.</p> <h4>Beware of plain sailing.</h4> <p>When it is easy, the chances are you are just imitating your surroundings, you are subconsciously fitting in. Defining yourself by your peers may get an invite to a cool party, or make your blog en-vogue - but most folks just aren't clever enough to pull that kind of replication off without it being noticeable.</p> <p> Worst still you could be imitating and rehashing what you already know. <blockquote> &ldquo;Hmm those guys loved the buttons from the last job.&rdquo; <span class='source'>&mdash; a lazy sod</span> </blockquote> </p> <p>The trauma of creating something should be right there in your face, willing you to fail, wanting you to take the easy solution. Yes, sometimes the easy solution is the best one, move on, but more often you need to dig in deep and prepare for battle. Giving yourself some identity to hang off (even if you never share it with anyone else) will help you refute those nagging doubts and insecurities when you work.</p> <h4>Yellow be thy guide.</h4> <p> Just before I designed my <a href ='http://jaseandtonic.com' title='Jase & Tonic'>company website</a>, I spent the preceding weeks reading a <a href ='http://www.amazon.co.uk/Copywriting-Successful-Writing-Advertising-Marketing/dp/1856695689/ref=sr_1_1?ie=UTF8&s=books&qid=1264631224&sr=8-1' title='visit link: book about copywriting'>book about copywriting</a> which has a yellow cover. At the time I didn't realise that was where my inspiration was coming from, I didn't even have the book with me over the christmas holidays when I had nothing else to do other than make a site for myself. </p> <p> The point is that book meant something, it was a step I had consciously made to try and begin writing (or because <a href ='http://sam.brown.tc/' title='visit link: Sam Brown'>Sam Brown</a> had been prodding me to start for a couple of months), so it made sense that I had ripped some of the style off for my new identity. It defined something that I wanted to believe about myself. </p> <p>First thing I did once I launched the site that evening, (other than feel vulnerable) was plaster my surroundings with the colours, textures and ideas. My wallpaper on my mac adorned the logo and strap-line setup upon that bright yellow background - a few days later I bought some yellow teeshirts (although at the time I had no idea why). I felt comfortable with what I had created and I was embracing it. Even now I've setup WriteRoom to be black with yellow text so it feels like it is a homogenous part of my brand.</p> <h4>Developing your own conclusion.</h4> <p>What am I getting at with all this? Well I believe that by constructing a brand or identity to surround yourself with, you have a canvas to start and try to understand what you are about, what turns you on and most importantly to let you develop the confidence to be who you are, and push your own ability out into the world instead of just absorbing and reflecting what others do around you.</p> <p>Forget branding to sell yourself to other people, do something that makes you like you a little more, after all it is your head you are living in.</p> <p style='font-size: 4em; width: auto'>And to those who have objected to the 'garish' yellow, well fuck you, this is my yellow.</p> Tue, 26 Jan 2010 15:45:09 -0800 http://jasoncale.com/articles/4-the-importance-of-yellow From the blackness http://jasoncale.com/articles/8-from-the-blackness-online-persona <h2>I found this today.</h2> <p>This morning whilst eating my breakfast I was trying to log into tumblr on my phone to see if there were any updates from my friends (yeah I forgot about the app) and I logged into the wrong account; it was an account I had a while back and no longer use.</p> <p>I came across a post that was marked as private, I read it and it made me laugh .. I used to have a problem, I still have a smaller problems but man I've lightened up a whole bunch.</p> <p>Anyway, I thought I'd publish it here for your amusement; I can see where that guy was coming from but I'm glad the current incarnation of "myself" is more concerned with just breathing in and out.</p> <p>Enjoy! The remaining copy is copied and pasted without any editing <em>I've added some edit quotes at the bottom where my rambling made no sense &mdash; ed</em>.</p> <h2>These day's I really wonder if the internet is good for my mental health.</h2> <p>I spend a too much time worrying about how I am perceived and it's pretty much a negative experience. An additional problem is that my profession requires that I am online, which throws all sorts of risks into the mix. The social web has turned nearly everything into a popularity contest, so while I'm doing my shopping online I can connect with other shoppers, and see whether my shopping habits are better than my peers or make friends with other people who like to buy organic toothbrushes.</p> <p>Ok maybe I can't do that, but its not far off from the kinda crap 'social networking' gets thrown into simply because it can be done.</p> <p>Maybe I shouldn't be so narcissistic, or introspective but that is also a defining part of who I am - the self obsessive flaw makes me continually do things to try and make myself less mediocre. A trait that is often destructive both on and offline, but normally I come across a lot better in real life or at least I can poke at the underlying context of where I'm coming from, even if the people around me don't get on with my behaviour or viewpoints.</p> <p>I can't do this online, and I've tried and tried to the point where I self edit to the point where I'm bland and boring as fuck. This in turn frustrates me, and I'll probably have some weak reaction to the situation, much like this dribble.</p> <p>A lot of the time I'm confused why certain people seem to flourish online, whereas I'd would have thought they would struggle in so called real life. I'm not an overly easy person to get on with anyway, I'm pretty obtuse - so forgive me if I seems like I'm saying 'hey im a good guy, why are all these nonses getting head online and not me' - that's missing my point.</p> <p>My main point is, if we are living in such a social revolution, how come its bloody hard to convey the same kinda social interactions online that exist in real life? I've met some people online, that in real life try and interact with me like we are still online - its easy to snub people online, and its easy to let someone down - you aren't tied into the same kinda spacial and logistic consequences that you are when it comes down to physical contact.</p> <p> <em>ed &mdash; This next sentence doesn't make sense .. I'll add after what I think I meant.</em> </p> <p>Is it true, that unless people - who quite like traditional social contact - are fucked if we don't learn how to convey a decent personality online, or do we just bumble along and see what happens?</p> <p> <em>Is it true that we (people who quite like traditional social contact) are fucked if we don't learn how to convey a convincing personality online, or do we just bumble along and see what happens?</em> </p> <h3>Self preservation is a hard thing anyway, but how do I do it online? And quickly.</h3> Wed, 23 Jun 2010 03:07:41 -0700 http://jasoncale.com/articles/8-from-the-blackness-online-persona The windy leaves did blow: Build Conference 2010 http://jasoncale.com/articles/9-build-conference-2010 <h2>That difficult second album</h2> <p> I have just returned from four days in Belfast, Northern Ireland where I attended the second incarnation of <a href ='http://buildconf.com' title='Build Conference'>Build</a>. A web design conference whose debut I was lucky enough to attend last year. I was impressed enough to go again, and the standard reached this year I'm pleased to say was even higher. </p> <p> The odds of <a href ='http://buildconf.com' title='Build Conference'>Build</a> being a success were pretty good. <a href ='http://twitter.com/goodonpaper' title='visit link: Andy McMillan'>Andy McMillan</a> the titanic heart & mind behind <a href ='http://buildconf.com' title='Build Conference'>Build</a> is tireless in his pursuit of putting on a good show. </p> <p>Even with his modesty deflecting praise and graciously praising his collaborators; it is clear that his vision and determination made all the component parts sing in vibrant orchestration.</p> <p> Whilst most conferences are sold entirely on the main event <a href ='http://buildconf.com' title='Build Conference'>Build</a> widens its lens and offers five days of fringe events. Sure the natural capstones are present with a day of practical workshops followed by a day of talks, but these are surrounded by carefully considered leisure offerings which serve to house and invigorate the discussion which fills the bars and dinner tables afterwards. </p> <h3>Shall we go to the crow bar?</h3> <p>Most seasoned conference attendees have figured out most of the good stuff happens off-piste. Andy knows this well and has built it into part of the week, even providing a map of local bars and evening activities that funnel the attendees into the best places to talk and unwind.</p> <p>Most of the London based conferences I've been to tend to hire an expensive faux-trendy bar featuring awful music far too loud to talk over and a price list which evaporates the media-temple-sponsored-bar-tab almost instantly. Frustrated attendees scatter to more suitable venues which ends up a fragmented mess; most veterans head off in their own established groups which ruins any chance of cross pollenating the collective consciousness.</p> <p>I digress but the point I'm fingering is that Andy is clearly a conference attendee who places his own experience and wishes at heart when addressing the needs of his own audience.</p> <h3>Welcome to Belfast</h3> <p> I arrived into Belfast on Tuesday morning and was met with mild autumnal sunshine tempered only by the wind which seemed to be the underlying elemental theme throughout the week. Like most people I had booked a room at the chic hotel <a href ='http://www.malmaison-belfast.com/' title='Malmaision hotel Belfast'>Malmaison</a> as Andy had set up special rates for attendees &mdash; nice. Packed with revellers, speakers and Andy himself <a href ='http://buildconf.com' title='Build Conference'>Build</a> was proudly on display throughout the hotel, even boasting a few additions to the cocktail menu which the jovial delegates in the bar enjoyed until the early hours. </p> <h4>Settle down son, there is work to be done</h4> <p> Once I'd made my way to the hotel from the airport, I ordered a black coffee and with complimentary wifi pass in hand unsheathed my laptop to settle into some work. <a href ='http://gofreerange.com' title='Building outstanding software for the web'>My company</a> had been working on secret project for <a href ='http://buildconf.com' title='Build Conference'>Build</a> over the last few weeks and I needed to finish off some last minute adjustments before the conference the next day. I was trying to pair with <a href ='http://chrisroos.co.uk' title='visit link: Chris'>Chris</a> who was in our office in London but I kept getting distracted by the many faces appearing in the bar around me. </p> <p>Faces of friends I've made on the web or even previous conferences appearing from behind the oversized velvet high-back chairs which govern the landscape of the Malmaison bar was a most delightful respite from the nerves which sat in my stomach due to the remaining work that needed to be done.</p> <p> Lunchtime and a dead battery allowed me to catch up over food with <a href ='http://sam.brown.tc' title='visit link: Sam'>Sam</a>, <a href ='http://cole007.net/' title='visit link: Cole'>Cole</a> and <a href ='http://www.robbiemanson.com/' title='visit link: Robbie'>Robbie</a>. When I returned Chris had worked his magic leaving me with a few meagre lines of CSS to write which would hook it all together. Thanks Chris. </p> <p>Decamping to the Merchant hotel to see Andy, work and catch a glimpse of the workshop attendees. Andy showed me a piece of paper with lists on both sides: one side with things he was worried about, the other was things he wasn't. Thankfully our project was on the side that wasn't worrying him and as the day wore on I started to agree.</p> <h4>Jessica, Jessica <strike>Simpson</strike> Hische, you've got it all <strike>wrong</strike> right.</h4> <p> There wasn't much time for anxiety though as soon it was time to head over to the University of Ulster to hear <a href ='http://jessicahische.com' title='Bloody good stuff'>Jessica Hische</a> talk. I was already aware of Jessica's work as she is all over the web but it was in <a href ='http://8faces.com/' title='8 Faces is a new magazine for devotees of typography'>8faces</a> where I'd first learned about the girl behind the dropcaps. There was a palpable energy in the room, and once her talk was underway it didn't abate. </p> <p>Jessica is not only insanely talented, she pairs a strong work ethic with a humour and frankness that I really admire. We were taken on a whirlwind tour of her work and career experience with interesting narrative with sumptuous visual accompaniment. It is probably fair to say that she gained &amp; retained many admirers, and that we all left the room quite rightly smitten.</p> <p> In high spirits we floated across to <a href ='http://www.21social.co.uk/' title='A cool bar / eatery in Belfast'>21 Social</a> for the <a href ='http://www.webstandardistas.com' title='visit link: Standardistas'>Standardistas</a> rip rollicking take on a pub quiz. Geek trivia and alcohol whipped the room into a frenzy, and with a table full of goodies to be had there was good reason. I joined <a href ='http://gregorywood.co.uk' title='visit link: Gregory'>Gregory</a>, <a href ='http://colly.com' title='visit link: Colly'>Colly</a> &amp; <a href ='http://sleepykyoto.com/' title='met James for first time at Build - Good lad, hard worker - could tell from the way he did all the work in the quiz whilst we fucked about'>James</a> and we scored a respectable 74/100 most of which can be attributed to James' hard work. </p> <p> The evening saw everyone suitably plied with booze (<a href ='http://soberjase.heroku.com' title='visit link: apart from me'>apart from me</a>) and in usual Standardista style we laughed and cheered our way past closing time before stumbling back towards the hotel bar for a nightcap. <p>Needing to be up early to kick off our project at the venue, I managed to escape the bar at 1:30 for a little ironing and last minute CSS tweaks before bed.</p> <p>I think the time has come to explain what I'd been working on ...</p> </p> <img alt='Campaign monitor' class='bleed' src='http://farm5.static.flickr.com/4104/5176210585_536ac39a26_o.png' /> <h3>Caffeine Monitor</h3> <p> Andy asked us at <a href ='http://gofreerange.com' title='Bad ass software'>Go Free Range</a> to create an app to track the caffeine intake of conference attendees and display it back to them as a live info-graphic. Sponsored by the kick-ass folks at <a href ='http://campaignmonitor.com' title='visit link: Campaign Monitor'>Campaign Monitor</a> we teamed up with the well known info-graphic sensei <a href ='http://feltron.com' title='visit link: Nicholas Felton'>Nicholas Felton</a> to bring the idea to life. </p> <p>I'm planning to cover the details on our company blog (and open source the code) but basically we created an offline capable iphone web app to record the drinks, and built a simple rails app to display the info-graphic pictured above in HTML/CSS.</p> <p>Andy arranged a team of helpers for the day, I loaded up the app on their iPhones and set them free. The data was collected then displayed on plasma screens around the venue and on the projector in the main conference hall. It all worked seamlessly!</p> <p>From what I observed the attendees enjoyed it and there was a positive reception on the web. Personally I'm very happy with the way it turned out; once I'd set it all up I just sat back and watched the visualisation come to life.</p> <p>Upon reflection the extra hours we put into making the app rock solid was worth it. From the beginning our top priority was for it to "just work" and I'm pretty happy that on the day it did just that.</p> <p> You can see the results frozen in time at <a href ='http://cm.buildconf.com' title='visit link: http://cm.buildconf.com'>http://cm.buildconf.com</a> </p> <h3>What about the talks?</h3> <p> The conference day was on the whole very good. <a href ='http://buildconf.com' title='Build Conference'>Build</a> asks its speakers to convey a story or concept instead of direct practical advice (which should be left for the workshops) because most of us doing our jobs keep up with the practical stuff. The idea is to transcend technique and to inspire; an approach I totally agree with. Unfortunately not all the speakers managed to pull this off, but on the whole the rhetoric was solid. </p> <blockquote>A great day which left me itching to get back to work.</blockquote> <p> The highlight for me was <a href ='http://bobulate.com' title='visit link: Liz Danzico'>Liz Danzico</a> whose <a href ='http://vimeo.com/17084428' title='watch the video on vimeo'>talk</a> was well articulated and thought provoking. I was in awe of her speaking style and could have listened all day. She spoke of the power of the pause, its importance and appearance in not only our work as designers but our life outside of work. As a practitioner of <a href ='http://en.wikipedia.org/wiki/Zazen' title='visit link: Zazen'>Zazen</a> I know the power of pause in my day, the resulting clarity and balance which was something I had wanted to share, but I never quite managed to assemble my thoughts and convince myself that I should engage Liz in conversation &mdash; shame. </p> <p>The irony of wanting to talk to Liz about Zen but not being able to because of my ego wasn't lost on me. Feeling weary and tired I decided against dinner with others in favour of my hotel room to do some yoga, sit zazen and grab some room service.</p> <p> Recentered I headed down to lobby to meet Sam &amp; <a href ='http://twitter.com/becky_brown' title='visit link: Becky'>Becky</a> and we wandered over to <a href ='http://www.mchughsbar.com/' title='visit link: McHugh's'>McHugh's</a> the venue of the official after party. Now like I mentioned before, Andy is a sensible chap and this after party was in a pub which served good food, had a free bar for nearly all the night and had music which didn't invade your senses. <p>Everyone waltzed merrily around the room in sparks of conversation; wonderfully punctuated by laughter, cigarettes breaks and the almost constant shutter snap of DSLR's worn like geek medallions throughout the room. The festivities spilled out into the night and ended up in the Malmaison bar. I managed to see through a few more hours but without the booze to keep me propelled I faded into a dream state and said and hugged my goodbyes.</p> </p> <h3>Thursday slept in Wednesday's clothes</h3> <p>Missing out on much of Thursday &mdash; I slept until half past two. My insomnia riddled body was most thankful as I staggered around my room trying to make sense of the time. A few strong coffees chucked down my gullet and I was ready to head out for the evening's activities.</p> <p> We braved torrential rain and zigzagged back over to the university to hear <a href ='http://twitter.com/brockrumer' title='visit link: Brock Rumer'>Brock Rumer</a> talk all about <a href ='http://threadless.com' title='visit link: Threadless'>Threadless</a>. I was a bit unsure about whether I wanted to hear the talk but I was soon won over and it was great to see Brock talk enthusiastically about a great company. </p> <p> This <a href ='http://vimeo.com/15672936' title='visit link: video'>video</a> Brock showed at the end made me smile. </p> <p> After the talk we headed to 21 Social for food, before wandering back to the hotel to drink and talk some more. I struck up a conversation with (speaker) <a href ='http://nicewebtype.com/' title='visit link: Tim Brown'>Tim Brown</a> and we ended up having a great chinwag about Typekit, Go Free Range and importance of source control in the design workflow. It was definitely the most lucid conversation I had in Belfast. </p> <p>Andy sprung some Champagne on us (I had fake beer), and we toasted all the freaking awesome stuff that has happened in the last year.</p> <h3>Just before I headed home</h3> <p>I caught up with a few faces for lunch on Friday before hugs and goodbyes. I left to wander across a cold windy Belfast to catch the bus to the airport.</p> <p>Sitting on the bus I wrote to myself:</p> <blockquote>Heading back to London with a soft sadness moored in my chest. All aboard.</blockquote> <p> But back in my flat I'm feeling good about our little industry: </p> <p> <a href ='http://buildconf.com' title='Build Conference'>Build</a> embodied hard work and craftsmanship in its execution and sent gentle reminders that this is what we should aspire to as web professionals. If we put our minds, talent and hearts into what we do; we too can build something truly memorable and worthwhile. </p> <p>I'd love to speak at such a conference <br/ > upon its dark stage I'd spill out my heart<br /> like a cup into the sea.</p> <h3>See you in Belfast next year.</h3> Sun, 14 Nov 2010 18:01:06 -0800 http://jasoncale.com/articles/9-build-conference-2010 Is a Designer. http://jasoncale.com/articles/6-giving-up-the-code-job <h2>Deciding to give up programming (professionally).</h2> <p>For the last 6 years I've been working on the web getting paid to build websites, applications and services. For better or for worse I've been exposed to a multitude of disciplines and practices to get things done. I've written code because there was no-one around who could do it well, I've designed interfaces because I knew how they should work and how to best integrate them with the underlying applications.</p> <p>I've struggled on for years telling myself I could do everything, that I can design and I can code <em> not html / css I mean real programming</em>. I've been successful, I've worked on big projects and small startups, I've made good money and I've enjoyed seeing myself achieve things that people had no confidence in me completing; because I was the programmer who said he could design, and vice versa.</p> <p>I know it isn't black and white, and I know programming can at times be an order of magnitude more creative than even the hallowed designer could attain. But I'm tired of the grey garden in which I setup my store.</p> <p>Just before I left the agency where I'd been able to float between disciplines to start out on my own, I decided I was tired of doing it all and I would focus on development. The one consistent love I had was Ruby and I figured programming would be a more earnest path to follow.</p> <p>At first I was happy, but in the last 18 months of self employment I've become more and more confident of who I am, and that person (even though I've tried my hardest to resist) just needs to be a visual designer. I can't explain the deep seated urge, and it may turn out to be the greatest failure of my life but I need to try and see what is out there for me.</p> <p> So, apart from the outstanding commitments I have for development projects I will no longer be taking on programming jobs, I will be designing interfaces and I will let my talented collaborators at <a href ='http://gofreerange.com' title='visit link: Go Free Range'>Go Free Range</a> concentrate on the development*, after all it is their unrelenting talent that has given me the courage to step out of the midway and into the traffic; my self-esteem. </p> <blockquote> Is A Designer. (Write this down). <span class='source'>Jase &mdash; Wednesday 3rd March, 2010. 16:17pm.</span> </blockquote> <p>*part of this challenge is proving that design can be done in a way that is truly agile.</p> Wed, 03 Mar 2010 08:00:05 -0800 http://jasoncale.com/articles/6-giving-up-the-code-job A day out in Dalston:<br/> Fun at the Print Club http://jasoncale.com/articles/3-print-club-dalston <h2>Print Club, Dalston.</h2> <p> <a href ='http://http://www.printclublondon.com' title='visit link: Print Club'>Print Club</a> is a workspace in <a href ='http://maps.google.com/maps?client=safari&oe=UTF-8&ie=UTF8&q=print+club&fb=1&hq=print+club&hnear=London&cid=0,0,14823588784684106201&ei=139cS7TPCp-60gTG8KmIBQ&ved=0CAoQnwIwAA&z=16&iwloc=A' title='View in google maps'>Dalston, north east London</a> where for a rolling monthly membership you can access everything you need to do water based screen printing (using water based inks mean screens are far easier to clean and it is also better for the environment). As part of an introduction to the facilities and everything you need to know to get up and running with the printing process they put on a weekend workshop for beginners - I've wanted to do screen printing for years so yesterday I was booked into the workshop and got my first taste of what is on offer. </p> <p>Dalston is the other side of London to where I live, but it was easy enough to find the club, a short bus ride from Old Street and I was there. Tucked down a side road the warehouse/studio environment is authentic and no nonsense. It isn't a tourist trap for hipster runoff, its a practical space for working artists to get access to the large and expensive equipment needed to do screen printing.</p> <img alt='print club sign' src='http://farm5.static.flickr.com/4065/4300336379_54f622f70b.jpg' /> <p>I arrived and was greeted with tea and biscuits and a selection of design books to look over whilst waiting for the other participants to arrive in from the cold. For the introduction workshop you can do a single colour print which we were asked to bring a 'positive' of to reproduce. These were scanned into one of the macs and printed onto tracing paper for use when developing our screens.</p> <p>There were about a dozen of us for the workshop which is a nice size to have a chat and feel part of a group. The workshop was £35 for 11am - 4pm and it's all inclusive of materials and tea.</p> <p> First we were given a tour of the space, looking at some of the work that club members have hung up around the main room to see what is possible. Print Club owner <a href ='http://www.printclublondon.com/info.php' title='visit link: Fred Higginson'>Fred Higginson</a> led the way before and explained the steps we would be taking throughout the day. </p> <img alt='Image of the workspace' src='http://farm3.static.flickr.com/2725/4300336569_52da23561a.jpg' /> <h4>Preparation.</h4> <p>The way the screens are prepared is to paint a screen with light sensitive emulsion which is then exposed in a light-box which bakes the areas which aren't covered by your design leaving the actual emulsion covering your design to wash off, leaving exposed mesh for your ink to pass through when printing onto paper or fabric.</p> <h4>Coating your screen.</h4> <p>Painting the emulsion onto the screens is done via a trough which you drag up your screen at an angle leaving a thin film of emulsion left on the screen (this takes place within a dark room style area which is lit with red lamps). The whole day is hands on and you are thrown in to do everything yourself under the watchful eye of Fred who keeps the daunting task lighthearted. Any mistakes present themselves as an excellent way to teach us how to remedy our beginner mishaps for future use.</p> <h4>Exposing the design.</h4> <p>Once the emulsion on the screen has dried, you can expose the positive upon it using the light-box which is a huge vacuum operated beast. The actual exposure takes 15 seconds, once this is done you simply wash off the emulsion that hasn't been exposed leaving our design ready to print. At this point we left the water to dry off our screens and headed out for lunch.</p> <h4>Print setup.</h4> <p>The final part of the day was getting to grips with the print beds, which vary slightly but the principal function is a clamp in which to hold your screen in place allowing you to lower and raise it to just above the paper or fabric you are printing onto. When using paper the beds have lots of tiny holes in them much like an air-hockey table, except they suck air instead of blow it out which holds your paper steady.</p> <h4>Setting your guides.</h4> <p>To ensure you can print multiple copies with accuracy, or when doing multiple passes for multi-colour prints you overlay your original design template (which has been fixed to a piece of the final paper size you are printing onto) with some acetate and print on top of the acetate. You can line up the two designs and mark where the edge of the paper is with card to use as a guide when loading the bed with paper after each successive print.</p> <h4>Creating your image.</h4> <p>Once you have all your alignment ready you load the screen with ink and simply pull the ink across the screen to 'flood' it with ink, this part is done with the screen raised off the bed so you don't actually print onto your paper. Then you lower the screen into position and drag the squeegee back across the screen in a fluid single sweeping motion, before finally lifting the screen to reveal the print.</p> <h4>Print factory.</h4> <p>You simply re-flood the screen by dragging the squeegee back in the other direction before loading another sheet of paper onto the print bed, being careful to line up the edges to your registration marks and print the next one. Repeat as necessary.</p> <h4>In summary.</h4> <p>For the workshop we each did 6 prints of our chosen design, and we were encouraged to experiment with colour. Some of my fellow participants managed some really cool effects with their prints, whilst I somehow managed to do a 2 colour pass which was technically against the rules of day.</p> <img alt='Jase &amp; Tonic Logo' src='http://farm5.static.flickr.com/4008/4300336237_201261852c.jpg' /> <p>Either way it was a great day out, and I will definitely signup for a months membership later in the year once I have enough designs to do a big job lot of prints.</p> <p>If you are interested in screen printing, or just looking for a fun day doing something different then I definitely recommend the Print Club. Perhaps even a good present for the creative ones in your life?</p> <h3>Get down there.</h3> <p> For more information check out the website at <a href ='http://www.printclublondon.com/info.php' title='visit link: http://printclublondon.com/'>http://printclublondon.com/</a> and book yourself in for a fun saturday of hands on fun. </p> Sun, 24 Jan 2010 08:38:59 -0800 http://jasoncale.com/articles/3-print-club-dalston Building Go Free Range:<br/> Looking inward. http://jasoncale.com/articles/7-building-a-company-starting-with-our-personal-goals <h2>Cultivating a collective mind.</h2> <p> I'm part of a group of people, together we are building a company called <a href ='http://gofreerange.com' title='Software revolutionaries'>Go Free Range</a>. </p> <h4>Introspection, for the good of the company.</h4> <p>One of the nice things about Go Free Range is the feeling being part of a group, but that requires learning about and trusting each other. We are currently sharpening our focus on what is important to us as a company, and part of this exercise was to write down our personal viewpoint and goals.</p> <p>I'd like to share what I wrote down.</p> <ol> <li> <p>I want to simplify my decisions.</p> </li> <li> <p>I want to work on one thing [Go Free Range], because I have found that I'm not very good doing multiple things.</p> </li> <li> <p>I want to establish a brand, a cohesive identify I can believe in, tell people about, and give myself to. Other than a group of freelancers, the loose association doesn't make me happy, nor does my singular existence as a freelancer. I have trouble with the term already, I think because my normal inclination is to be drawn into chaos, I prefer to discipline myself.</p> </li> <li> <p>I want to refresh myself regularly, I feel I've stagnated since I left my agency, I used to think I was excellent, now I think I'm coasting as mildly good.</p> </li> <li> <p>I want to belong to something that with my involvement will be greater, yet perhaps more importantly I'm better off because of my involvement within it.</p> </li> <li> <p>I want to work full time, and because of that I will afford myself a set period of sabbatical.</p> </li> <li> <p>I want to share space with others and interact with them on a daily basis, I find this allows me to focus and get inspired.</p> </li> <li> <p>I want to build products, that are great to use, and inspire me to work on, and use daily.</p> </li> <li> <p>I want to share what I learn with others, and document what I learn, perhaps even publish something.</p> </li> <li> <p>I want to become a better designer, and focus on front end development. Weirdly enough I do like javascript.</p> </li> <li> <p>I want to work with engineers, and I want to establish working practices that will explore the idea of better integrating design into the software process.</p> </li> <li> <p>I've realised that my original idea of allowing ideas to evolve, and prefer an organic approach is actually aversion and delusion of what I perceived to be freedom.</p> </li> <li> <p>I now know that discipline and defined action, which followed through daily is the best way I have found to cultivate freedom and happiness.</p> </li> <li> <p>My wish to travel and live outside of london (I have considered NY, SF, or Japan etc) is really just aversion, and is an attempt to create a focus by removing all other distractions.</p> </li> <li> <p>I want to practice yoga, and meditation everyday, but I feel I can fit this around a structured work day.</p> </li> <li> <p>I want to promote education and share knowledge with younger people, as I believe this will help the web / industry that I work in.</p> </li> <li> <p>I want to be good, mindful of others and I want to learn.</p> </li> <li> <p>I want to learn to live by less money.</p> </li> </ol> Thu, 06 May 2010 14:14:56 -0700 http://jasoncale.com/articles/7-building-a-company-starting-with-our-personal-goals