<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[dhar's blog]]></title>
  <link href="http://www.dhar.fr/atom.xml" rel="self"/>
  <link href="http://www.dhar.fr/"/>
  <updated>2013-05-12T23:50:36+02:00</updated>
  <id>http://www.dhar.fr/</id>
  <author>
    <name><![CDATA[Olivier Audard]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Reading List #1]]></title>
    <link href="http://www.dhar.fr/blog/2013/01/27/reading-list-number-1/"/>
    <updated>2013-01-27T18:36:00+01:00</updated>
    <id>http://www.dhar.fr/blog/2013/01/27/reading-list-number-1</id>
    <content type="html"><![CDATA[<h2>Web Development</h2>

<ul>
<li><a href="http://parsleyjs.org/">Javascript forms validation.Powerful, UX aware &amp; Dead simple.</a></li>
<li><a href="https://developers.google.com/speed/">Make the Web Faster — Google Developers</a></li>
<li><a href="http://stackoverflow.com/questions/12556593/determining-a-page-is-outdated-on-github-pages">stackoverflow &ndash; Determining a page is outdated on github pages</a></li>
<li><a href="http://www.softwareishard.com/blog/firebug/firebug-tip-include-command/">Firebug Tip : include() command</a></li>
<li><a href="http://csswizardry.com/2013/01/front-end-performance-for-web-designers-and-front-end-developers/">Front-end performance for web designers and front-end developers</a></li>
<li><a href="http://parsleyjs.org/index.html">Javascript forms validation.Powerful, UX aware &amp; Dead simple.</a></li>
<li><a href="http://net.tutsplus.com/tutorials/javascript-ajax/important-considerations-when-building-single-page-web-apps/">Important Considerations When Building Single Page Web Apps</a></li>
<li><a href="http://javascriptplayground.com/blog/2013/01/talking-requirejs-at-takeoff-conf">Talking RequireJS at TakeOff Conf</a></li>
<li><a href="http://www.js-attitude.fr/2013/01/21/dix-bonnes-pratiques-javascript/?utm_source=jslive&amp;utm_medium=referers&amp;utm_campaign=js-10-bp">[FR] 10 Bonnes Pratiques JavaScript</a></li>
<li><a href="https://dl.dropbox.com/u/3531958/es6-favorite-parts/index.html#/">ES6 : My Favorite Parts</a></li>
<li><a href="http://blog.appfog.com/angularjs-the-beauty-of-concision/">AngularJS: the beauty of concision</a></li>
<li><a href="https://hacks.mozilla.org/2012/02/storing-images-and-files-in-IndexedDB/">Storing images and files in IndexedDB</a></li>
<li><a href="https://nicolas.perriault.net/code/2013/why_javascript/">Why Javascript?</a></li>
</ul>


<h2>Misc</h2>

<ul>
<li><a href="http://alias.sh">alias.sh Featured Aliases</a></li>
<li><a href="https://hacks.mozilla.org/2013/01/announcing-the-firefox-os-developer-preview-phone/">Announcing the Firefox OS Developer Preview Phone!</a></li>
<li><a href="http://mobile.smashingmagazine.com/2012/09/24/establishing-an-open-device-lab/">Establishing An Open Device Lab</a></li>
<li><a href="http://www.nczonline.net/blog/2013/01/10/advice-for-new-and-aspiring-technical-speakers/">Advice for new and aspiring technical speakers</a></li>
<li><a href="http://www.ekito.fr/people/?p=51&amp;utm_source=buffer&amp;buffer_share=c427a">[FR] Développeurs seniors. Pourquoi ? Comment ?</a></li>
<li><a href="http://blog.davidtate.org/2010/08/key-points-to-look-for-in-your-next-job-if-you-are-a-developer/">Key points to look for in your next job if you are a developer</a></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Starting a "Reading List" posts series]]></title>
    <link href="http://www.dhar.fr/blog/2013/01/27/starting-a-reading-list-posts-series/"/>
    <updated>2013-01-27T18:29:00+01:00</updated>
    <id>http://www.dhar.fr/blog/2013/01/27/starting-a-reading-list-posts-series</id>
    <content type="html"><![CDATA[<p>I read several articles on the Web every day.
When discovering an article, if I find it interesting, or if I don&rsquo;t have time to read it at the time, I put it aside on <a href="http://getpocket.com" title="Pocket">Pocket</a> in order to easily find it later.</p>

<p>The downsides are :</p>

<ul>
<li>I put aside too many items</li>
<li>I often forgot to check out my reading list on Pocket</li>
<li>Pocket doesn&rsquo;t provide a easy way share a bunch of links</li>
<li>I don&rsquo;t want to save those on Pocket without a backup somewhere else</li>
</ul>


<p>For some time now, I looking for a way to force myself to check this list on a regular basis.
Moreover, even if <a href="https://ifttt.com" title="IF This Then That">IFTTT</a> allows me to perform automatic backup of the bookmarks, no one but me can take advantage of this list.</p>

<p>Starting today, I am launching a new series of articles entitled &ldquo;Reading List&rdquo;.
As its name obviously suggests, each article will bring together a few links to sites, articles, resources that have caught my attention on the web during the past few days.</p>

<p>I plan to publish these posts on a weekly basis but it could be less depending on the volume I&rsquo;ll collect every week.
I hope some of you will find this useful.
Do not hesitate to tell me your thoughts about this in the comments below.</p>

<p>As the process is mostly automated using IFTTT, Dropbox and a few scripts, I&rsquo;ll also think about explaining it in a upcoming article.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[De l'art de converser sur Twitter (entre geeks)]]></title>
    <link href="http://www.dhar.fr/blog/2013/01/24/fr-de-lart-de-converser-sur-twitter/"/>
    <updated>2013-01-24T23:28:00+01:00</updated>
    <id>http://www.dhar.fr/blog/2013/01/24/fr-de-lart-de-converser-sur-twitter</id>
    <content type="html"><![CDATA[<p>Ce soir, pour la première fois depuis la création de mon compte il y a environ 3 400 tweets, je me suis fait agresser sur Twitter.</p>

<p>Bon, d&#8217;accord, j&#8217;exagère un peu. C&#8217;est bien moins grave que ça en a l&#8217;air mais cette prise à partie m&#8217;a tellement surpris que j&#8217;en écris un article à chaud.</p>

<p>Oh, je m&#8217;en remettrais, hein! Ne vous en faites pas ;)</p>

<!-- more -->


<h2>Un peu de contexte</h2>

<p>Voici donc le tweet initial, celui qui a attiré mon attention et m&#8217;a fait réagir :</p>

<blockquote><p>@____ @________ de ce côté tu seras pas déçu, y a *rien* de fait pour le blogging ;) quelques hooks plus tard je vous dirai des news ^^</p></blockquote>


<p>Et voilà ma réponse :</p>

<blockquote><p>@_______ @____ @________ Pas sur d&#8217;avoir tout le contexte, mais http://octopress.org/  ? non?</p><footer><strong>@_dhar</strong></footer></blockquote>


<p>Ça semble anodin comme ça&hellip;</p>

<p>En intervenant dans cette conversation, mon intention était avant tout d&#8217;apporter mon aide éventuelle et d&#8217;en apprendre plus sur des outils que je peux être amené à utiliser.
Mon erreur est sans doute d&#8217;avoir donné mon avis sans connaître le contexte complet de la conversation, ni même les participants.
Mais après tout, le propre d&#8217;une conversation sur un media public, c&#8217;est bien qu&#8217;elle est ouverte à tout le monde, non?
Pour avoir suivie celle-ci jusqu&#8217;au bout, il est évident maintenant que mon intervention était hors sujet et que je manquais d&#8217;éléments pour fournir un point de vue pertinent; pour autant, ça ne justifie pas le ton agressif de certaines des réponses que j&#8217;ai reçu.</p>

<p>L&#8217;objectif de ce billet n&#8217;est pas de commenter l&#8217;intégralité de la conversation, ni même de justifier mes arguments au cours de celle-ci ou encore d&#8217;accuser qui que ce soit, mais plutôt de présenter mon ressenti à la lecture de certaines des réponses que l&#8217;on m&#8217;a adressé.</p>

<h2>Principes de base</h2>

<p>Lorsque je m&#8217;adresse à quelqu&#8217;un, que ce soit dans la vie réelle, sur Internet, en privé ou en public, je fais de mon mieux pour rester respectueux et poli, et j&#8217;attends de mes interlocuteurs qu&#8217;ils en fassent de même.
C&#8217;est la base de relations sociales <em>saines</em> et <em>constructives</em>.
À partir de là, on peut discuter normalement.
À partir de là, chacun peut avoir une opinion différente, exposer son point de vue, se tromper, convaincre ou rester sur ses positions.</p>

<p>Je crois avoir respecté ces principes de base ici aussi, et si malgré tout, certains de mes propos ont étés mal compris je m&#8217;en excuse. Certaines des réponses que j&#8217;ai reçu, en revanche, m&#8217;ont paru aller bien au delà de ces principes.
Ça reste un ressenti personnel, j&#8217;aurai peut-être réagi différemment à un autre moment et je aussi pense que le format en 140 caractères imposé par Twitter contribue à amplifier cette impression, mais j&#8217;ai sérieusement vécu ce moment comme une agression.
Je ne suis même pas certain que tous les autres participants aient pris conscience de la tournure déplacée de certains propos.</p>

<p>En écrivant ce billet, mon intention n&#8217;est pas de viser quelqu&#8217;un en particulier.
J&#8217;avais simplement besoin de poser ça par écrit.
D&#8217;abord pour me rappeler ces quelques minutes, et aussi en espérant que les rares lecteurs qui me liront s&#8217;en souviendrons lors de leurs discussions futures, en ligne ou non.</p>

<h2>Pour finir</h2>

<p>&hellip;si je peux me permettre un conseil qui vaut ce qu&#8217;il vaut:</p>

<p>Démarrer une conversation sur un media public implique que tout le monde peut y participer.
Dans ce contexte, même si chacun est en droit d&#8217;estimer qu&#8217;un point de vue manque de pertinence, je ne vois pas ce qui justifie le fait d&#8217;exprimer son désaccord de façon agressive ou irrespectueuse.
Si vous ne souhaitez voir personne d&#8217;autre intervenir, mentionnez le clairement ou mieux, utilisez un autre moyen de communication, privé de préférence.</p>

<p>Et puis, quand on parle de technos Web là, ça devrait rester fun, non?</p>

<hr />

<p>PS : <em>Pour ceux qui ont participé à la conversation dont il est question ici, s&#8217;ils vous arrivait de lire ce texte, sachez que je suis tout à fait disposé à discuter de l&#8217;usage et de la pertinence ou non d&#8217;octopress comme engine de blog, tant que ça n&#8217;a pas lieu en 140 caractères et que le ton reste amical.</em></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Adding Grunt to your web-application project]]></title>
    <link href="http://www.dhar.fr/blog/2012/10/28/adding-grunt-to-your-web-application-project/"/>
    <updated>2012-10-28T00:24:00+02:00</updated>
    <id>http://www.dhar.fr/blog/2012/10/28/adding-grunt-to-your-web-application-project</id>
    <content type="html"><![CDATA[<p>A few weeks ago, a gave a quick talk about <a href="http://www.gruntjs.com" title="Grunt homepage">Grunt</a> at <a href="http://www.twitter.com/jssophia" title="JS Sophia-Antipolis">@JSSophia</a>, our local Javascript User Group.
During this talk, my purpose was to quickly present the tool and show some example use cases.
I must confess I wasn&rsquo;t as prepared as I would have been, so my talk may have been confused or unclear from time to time.
If you attended the event, I hope this post will give you more details.
If not, it doesn&rsquo;t matter, I&rsquo;m still happy to share my thoughts about this amazing tool.</p>

<p>You&rsquo;ll find the slides bellow.
The first part mostly present <em>Grunt</em> and why I think it&rsquo;s a game-changer for front-end developers. As I already wrote about this in my <a href="http://www.dhar.fr/blog/2012/08/26/grunt-brings-automation-to-the-front-end-side/" title="Grunt Brings Automation to the Front-end Side">previous post about Grunt</a>, I invite you to read it if it sounds interesting to you.
In the second part, I focused on showing a few examples use cases and concrete examples.
That&rsquo;s what I&rsquo;m going to detail in this post.</p>

<div class="dhar-style-embedder">
  <style>
    .clearfix { clear:both; }
    div.keep-aspect-ratio { max-width:600px;margin:0 auto; }
    div.keep-aspect-ratio > div { border:0;padding:0;margin:0;position:relative; }
    div.keep-aspect-ratio > div > img { border:0;padding:0;margin:0;z-index:-1000;position:relative;top:0;bottom:0;left:0;width:100%;display:block; }
    div.keep-aspect-ratio > div > div { border:0;padding:0;margin:0;position:absolute;top:0;bottom:0;left:0;width:100%;overflow:auto;}
  </style>
  <div class="keep-aspect-ratio">
  <div><img src="http://www.dhar.fr/assets/dhar/aspect-ratio-4-3.png" /><div>
  <iframe src="http://www.dhar.fr/assets/slides/embedder.html#grunt/template.html" frameborder="0" width="100%" height="95%"></iframe>
  </div></div><div class="clearfix"></div>
  </div>
</div>




<!-- more -->


<h2>Automating your web application</h2>

<p>Bringing some automation to your web-application is probably the first thing you&rsquo;ll try with Grunt.
After all, that&rsquo;s its first purpose, why it was designed for.</p>

<p>Because nothing worth an example, I reused an old project to illustrate this case.
It&rsquo;s a simple Gallery application build over Backbone.JS, jQuery, QUnit and Twitter Bootstrap.
The full project is available <a href="https://github.com/dharFr/gallery" title="Gallery App: 'master' branch">on Github</a>.
The code I used as an example lives in the <em>master</em> branch.
The original code, as it was before adding Grunt, lives in the <a href="https://github.com/dharFr/gallery/tree/before-grunt" title="Gallery App: 'before-grunt' branch">before-grunt</a> branch.</p>

<h3>Adding Grunt to an existing project</h3>

<p>Assuming Grunt is already <a href="https://github.com/gruntjs/grunt#installing-grunt" title="Installing Grunt">installed</a> on your system, adding Grunt to your project is as simple as typing the following in your terminal:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>&gt; <span class="nb">cd</span> /path/to/your/project/
</span><span class='line'>&gt; grunt init:gruntfile
</span></code></pre></td></tr></table></div></figure>


<p>After answering a few question, this will produce a single <code>grunt.js</code> file in your project&rsquo;s folder.
The basic structure of a gruntfile is looks like this:</p>

<figure class='code'><figcaption><span>grunt file basic structure</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="cm">/*global module:false*/</span>
</span><span class='line'><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">grunt</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// Project configuration.</span>
</span><span class='line'>  <span class="nx">grunt</span><span class="p">.</span><span class="nx">initConfig</span><span class="p">({</span>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'>    <span class="nx">taskName</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>      <span class="c1">// task properties</span>
</span><span class='line'>    <span class="p">},</span>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'>  <span class="p">});</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>


<p>We are working with a web-application, so most of the tasks we need are already included in grunt.
What do we basically need ?</p>

<ul>
<li><em>lint</em> javascript files</li>
<li>run <em>qunit</em> unit tests</li>
<li><em>concat</em> and <em>minify</em> javascript files</li>
</ul>


<p>In addition, it would be interesting to:</p>

<ul>
<li>run <em>qunit</em> tests again on the minified <code>js</code> files to check if anything is broken in the process</li>
<li><em>copy</em> assets (<code>css</code>, pictures, etc.) to a build folder in order to have a standalone built version of the application</li>
<li>create an alternative version of the <code>html</code> files containing minified <code>js</code> files rather than development files</li>
</ul>


<h3>Setting up your tasks</h3>

<p>Lint, QUnit, concatenation and minification tasks are already built in Grunt. It won&rsquo;t be too difficult to define these for our project.
If you need another task, start by searching if an existing <code>grunt-plugin</code> have already been created by the community.
You can search for an existing plugin on <a href="http://www.gruntjs.com" title="Grunt homepage">grunt homepage</a> or directly with npm:</p>

<figure class='code'><figcaption><span>Searching for grunt plugins on NPM</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="c"># Search for a grunt plugin to do some magic:</span>
</span><span class='line'>&gt; npm search gruntplugin <span class="s1">&#39;do magic&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Otherwise, you can define your own task using the <a href="https://github.com/gruntjs/grunt/blob/master/docs/api.md" title="Grunt API">Grunt API</a>, but unless you need something very specific, I doubt you had to go there.
Seriously, there are already 190 existing plugins at the time I write these lines.</p>

<p>Once you&rsquo;ve found and installed the plugin you need, you still have to made it available in your <code>gruntfile</code> by using the <code>loadNpmTasks</code> api.
In our case, we&rsquo;ll need two external tasks:</p>

<figure class='code'><figcaption><span>Loading external tasks</span><a href='https://github.com/dharFr/gallery/blob/master/grunt.js#L125-126'>source</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'>  <span class="c1">// ...</span>
</span><span class='line'>  <span class="nx">grunt</span><span class="p">.</span><span class="nx">loadNpmTasks</span><span class="p">(</span><span class="s1">&#39;grunt-contrib-copy&#39;</span><span class="p">);</span>
</span><span class='line'>  <span class="nx">grunt</span><span class="p">.</span><span class="nx">loadNpmTasks</span><span class="p">(</span><span class="s1">&#39;grunt-targethtml&#39;</span><span class="p">);</span>
</span><span class='line'>  <span class="c1">// ...</span>
</span></code></pre></td></tr></table></div></figure>


<p>From there, we just need to configure our tasks.
I&rsquo;m not going to detail every single line in the resulting <code>gruntfile</code> bellow.
Basically, it allows us to build (lint, concat and minify) javascript files, copy any other files to a <code>dist</code> folder, and run the tests on both <code>dev</code> and <code>dist</code> files.
The syntax is quite self-explaining and you can always refer to the <a href="https://github.com/gruntjs/grunt/blob/master/docs/toc.md" title="Grunt Documentation">official documentation</a> is needed.</p>

<figure class='code'><figcaption><span>Extract from Gallery Gruntfile</span><a href='https://github.com/dharFr/gallery/blob/master/grunt.js'>source</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
<span class='line-number'>120</span>
<span class='line-number'>121</span>
<span class='line-number'>122</span>
<span class='line-number'>123</span>
<span class='line-number'>124</span>
<span class='line-number'>125</span>
<span class='line-number'>126</span>
<span class='line-number'>127</span>
<span class='line-number'>128</span>
<span class='line-number'>129</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="cm">/*global module:false*/</span>
</span><span class='line'><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">grunt</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// Project configuration.</span>
</span><span class='line'>  <span class="nx">grunt</span><span class="p">.</span><span class="nx">initConfig</span><span class="p">({</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// read some data from package.json file</span>
</span><span class='line'>    <span class="nx">pkg</span><span class="o">:</span> <span class="s1">&#39;&lt;json:package.json&gt;&#39;</span><span class="p">,</span>
</span><span class='line'>    <span class="c1">// Defines project&#39;s meta data</span>
</span><span class='line'>    <span class="c1">// the banner is used by minification task and </span>
</span><span class='line'>    <span class="c1">// will be at the beginning of each processed file</span>
</span><span class='line'>    <span class="nx">meta</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">banner</span><span class="o">:</span> <span class="s1">&#39;/*! &lt;%= pkg.title || pkg.name %&gt; - v&lt;%= pkg.version %&gt; - &#39;</span> <span class="o">+</span>
</span><span class='line'>        <span class="s1">&#39;&lt;%= grunt.template.today(&quot;yyyy-mm-dd&quot;) %&gt;\n&#39;</span> <span class="o">+</span>
</span><span class='line'>        <span class="s1">&#39;&lt;%= pkg.homepage ? &quot;* &quot; + pkg.homepage + &quot;\n&quot; : &quot;&quot; %&gt;&#39;</span> <span class="o">+</span>
</span><span class='line'>        <span class="s1">&#39;* Copyright (c) &lt;%= grunt.template.today(&quot;yyyy&quot;) %&gt; &lt;%= pkg.author.name %&gt;;&#39;</span> <span class="o">+</span>
</span><span class='line'>        <span class="s1">&#39; Licensed &lt;%= _.pluck(pkg.licenses, &quot;type&quot;).join(&quot;, &quot;) %&gt; */&#39;</span>
</span><span class='line'>    <span class="p">},</span>
</span><span class='line'>    <span class="c1">// Defines a custom config property.</span>
</span><span class='line'>    <span class="c1">// This property &#39;&lt;%= build.dest %&gt;&#39;</span>
</span><span class='line'>    <span class="nx">build</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">dest</span><span class="o">:</span> <span class="s1">&#39;dist&#39;</span>
</span><span class='line'>    <span class="p">},</span>
</span><span class='line'>    <span class="c1">// lint task</span>
</span><span class='line'>    <span class="c1">// Defines witch files to lint</span>
</span><span class='line'>    <span class="nx">lint</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">files</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;grunt.js&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/**/*.js&#39;</span><span class="p">,</span> <span class="s1">&#39;tests/js/**/*.js&#39;</span><span class="p">]</span>
</span><span class='line'>    <span class="p">},</span>
</span><span class='line'>    <span class="c1">// qunit multi-task</span>
</span><span class='line'>    <span class="c1">// Defines 2 different targets</span>
</span><span class='line'>    <span class="c1">// (dev, dist) for running qunit.</span>
</span><span class='line'>    <span class="c1">// Each target defines a list of test files</span>
</span><span class='line'>    <span class="nx">qunit</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">dev</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;tests/index.html&#39;</span><span class="p">],</span>
</span><span class='line'>      <span class="nx">dist</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;&lt;%= build.dest %&gt;/tests/index.html&#39;</span><span class="p">]</span>
</span><span class='line'>    <span class="p">},</span>
</span><span class='line'>    <span class="c1">// concat multi-task</span>
</span><span class='line'>    <span class="c1">// Defines 3 different targets </span>
</span><span class='line'>    <span class="c1">// (libs, tests, dist) for concatenation.</span>
</span><span class='line'>    <span class="c1">// Each target defines a list of files to concatenate</span>
</span><span class='line'>    <span class="c1">// and a destination file to write the output</span>
</span><span class='line'>    <span class="nx">concat</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">libs</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>        <span class="nx">src</span><span class="o">:</span> <span class="p">[</span> <span class="s2">&quot;js/libs/json2.js&quot;</span><span class="p">,</span> <span class="s2">&quot;js/libs/jquery-1.8.2.min.js&quot;</span><span class="p">,</span> <span class="s2">&quot;js/libs/mustache-0.7.js&quot;</span><span class="p">,</span> <span class="s2">&quot;js/libs/underscore-1.4.1.min.js&quot;</span><span class="p">,</span> <span class="s2">&quot;js/libs/backbone-0.9.2.min.js&quot;</span> <span class="p">],</span>
</span><span class='line'>        <span class="nx">dest</span><span class="o">:</span> <span class="s1">&#39;&lt;%= build.dest %&gt;/js/libs/&lt;%= pkg.name %&gt;-libs.&lt;%= pkg.version %&gt;.js&#39;</span>
</span><span class='line'>      <span class="p">},</span>
</span><span class='line'>      <span class="nx">tests</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>        <span class="nx">src</span><span class="o">:</span> <span class="p">[</span>
</span><span class='line'>          <span class="s1">&#39;&lt;banner:meta.banner&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/config.js&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/models/gallery.js&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/views/header.js&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/views/main-image.js&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/views/thumbnails.js&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/views/gallery.js&#39;</span> <span class="p">],</span>
</span><span class='line'>        <span class="nx">dest</span><span class="o">:</span> <span class="s1">&#39;&lt;%= build.dest %&gt;/tests/js/&lt;%= pkg.name %&gt;-tests.&lt;%= pkg.version %&gt;.js&#39;</span>
</span><span class='line'>      <span class="p">},</span>
</span><span class='line'>      <span class="nx">dist</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>        <span class="nx">src</span><span class="o">:</span> <span class="p">[</span>
</span><span class='line'>          <span class="s1">&#39;&lt;banner:meta.banner&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/config.js&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/models/gallery.js&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/views/header.js&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/views/main-image.js&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/views/thumbnails.js&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/views/gallery.js&#39;</span><span class="p">,</span> <span class="s1">&#39;js/gallery/app.js&#39;</span> <span class="p">],</span>
</span><span class='line'>        <span class="nx">dest</span><span class="o">:</span> <span class="s1">&#39;&lt;%= build.dest %&gt;/js/&lt;%= pkg.name %&gt;-app.&lt;%= pkg.version %&gt;.js&#39;</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>    <span class="p">},</span>
</span><span class='line'>    <span class="c1">// min multi-task</span>
</span><span class='line'>    <span class="c1">// Defines 3 different targets </span>
</span><span class='line'>    <span class="c1">// (libs, tests, dist) for minification.</span>
</span><span class='line'>    <span class="c1">// Each target defines a list of files to minify</span>
</span><span class='line'>    <span class="c1">// and a destination file to write the output</span>
</span><span class='line'>    <span class="nx">min</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">libs</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>        <span class="nx">src</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;&lt;config:concat.libs.dest&gt;&#39;</span><span class="p">],</span>
</span><span class='line'>        <span class="nx">dest</span><span class="o">:</span> <span class="s1">&#39;&lt;%= build.dest %&gt;/js/libs/&lt;%= pkg.name %&gt;-libs.&lt;%= pkg.version %&gt;.min.js&#39;</span>
</span><span class='line'>      <span class="p">},</span>
</span><span class='line'>      <span class="nx">tests</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>        <span class="nx">src</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;&lt;banner:meta.banner&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;config:concat.tests.dest&gt;&#39;</span><span class="p">],</span>
</span><span class='line'>        <span class="nx">dest</span><span class="o">:</span> <span class="s1">&#39;&lt;%= build.dest %&gt;/tests/js/&lt;%= pkg.name %&gt;-tests.&lt;%= pkg.version %&gt;.min.js&#39;</span>
</span><span class='line'>      <span class="p">},</span>
</span><span class='line'>      <span class="nx">dist</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>        <span class="nx">src</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;&lt;banner:meta.banner&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;config:concat.dist.dest&gt;&#39;</span><span class="p">],</span>
</span><span class='line'>        <span class="nx">dest</span><span class="o">:</span> <span class="s1">&#39;&lt;%= build.dest %&gt;/js/&lt;%= pkg.name %&gt;-app.&lt;%= pkg.version %&gt;.min.js&#39;</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>    <span class="p">},</span>
</span><span class='line'>    <span class="c1">// targethtml multi-task</span>
</span><span class='line'>    <span class="c1">// Defines 2 different targets (release, tests) </span>
</span><span class='line'>    <span class="c1">// Each target defines a source file to process</span>
</span><span class='line'>    <span class="c1">// and a destination file to write the output</span>
</span><span class='line'>    <span class="nx">targethtml</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">release</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>        <span class="nx">src</span><span class="o">:</span> <span class="s1">&#39;index.html&#39;</span><span class="p">,</span>
</span><span class='line'>        <span class="nx">dest</span><span class="o">:</span> <span class="s1">&#39;&lt;%= build.dest %&gt;/index.html&#39;</span>
</span><span class='line'>      <span class="p">},</span>
</span><span class='line'>      <span class="nx">tests</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>        <span class="nx">src</span><span class="o">:</span> <span class="s1">&#39;tests/index.html&#39;</span><span class="p">,</span>
</span><span class='line'>        <span class="nx">dest</span><span class="o">:</span> <span class="s1">&#39;&lt;%= build.dest %&gt;/tests/index.html&#39;</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>    <span class="p">},</span>
</span><span class='line'>    <span class="c1">// copy multi-task</span>
</span><span class='line'>    <span class="c1">// Defines 1 single target (dist) </span>
</span><span class='line'>    <span class="c1">// copy files from development path </span>
</span><span class='line'>    <span class="c1">// to &#39;build.dest&#39; folder</span>
</span><span class='line'>    <span class="nx">copy</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">dist</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>        <span class="nx">files</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>          <span class="s2">&quot;&lt;%= build.dest %&gt;/css/&quot;</span><span class="o">:</span> <span class="s2">&quot;css/**&quot;</span><span class="p">,</span>
</span><span class='line'>          <span class="s2">&quot;&lt;%= build.dest %&gt;/img/gallery/&quot;</span><span class="o">:</span> <span class="s2">&quot;img/gallery/**&quot;</span><span class="p">,</span>
</span><span class='line'>          <span class="s2">&quot;&lt;%= build.dest %&gt;/js/libs/bootstrap/&quot;</span><span class="o">:</span> <span class="s2">&quot;js/libs/bootstrap/**&quot;</span><span class="p">,</span>
</span><span class='line'>          <span class="s2">&quot;&lt;%= build.dest %&gt;/tests/&quot;</span><span class="o">:</span> <span class="p">[</span><span class="s2">&quot;tests/js/**&quot;</span><span class="p">,</span> <span class="s2">&quot;tests/libs/**&quot;</span><span class="p">],</span>
</span><span class='line'>          <span class="s2">&quot;&lt;%= build.dest %&gt;/gallery_data.json&quot;</span><span class="o">:</span> <span class="s2">&quot;gallery_data.json&quot;</span>
</span><span class='line'>        <span class="p">}</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>    <span class="p">},</span>
</span><span class='line'>    <span class="c1">// clean task</span>
</span><span class='line'>    <span class="c1">// remove every file from the defined folders</span>
</span><span class='line'>    <span class="nx">clean</span><span class="o">:</span> <span class="p">[</span><span class="s2">&quot;&lt;%= build.dest %&gt;&quot;</span><span class="p">],</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// watch task</span>
</span><span class='line'>    <span class="c1">// runs the defined tasks every time a watched file is updated</span>
</span><span class='line'>    <span class="nx">watch</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">files</span><span class="o">:</span> <span class="s1">&#39;&lt;config:lint.files&gt;&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="nx">tasks</span><span class="o">:</span> <span class="s1">&#39;lint qunit:dev&#39;</span>
</span><span class='line'>    <span class="p">},</span>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'>  <span class="p">});</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// Load external tasks (grunt plugins)</span>
</span><span class='line'>  <span class="nx">grunt</span><span class="p">.</span><span class="nx">loadNpmTasks</span><span class="p">(</span><span class="s1">&#39;grunt-contrib-clean&#39;</span><span class="p">);</span>
</span><span class='line'>  <span class="nx">grunt</span><span class="p">.</span><span class="nx">loadNpmTasks</span><span class="p">(</span><span class="s1">&#39;grunt-contrib-copy&#39;</span><span class="p">);</span>
</span><span class='line'>  <span class="nx">grunt</span><span class="p">.</span><span class="nx">loadNpmTasks</span><span class="p">(</span><span class="s1">&#39;grunt-targethtml&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// Register custom tasks (alias tasks)</span>
</span><span class='line'>  <span class="nx">grunt</span><span class="p">.</span><span class="nx">registerTask</span><span class="p">(</span><span class="s1">&#39;build&#39;</span><span class="p">,</span> <span class="s1">&#39;concat min targethtml copy&#39;</span><span class="p">);</span>
</span><span class='line'>  <span class="nx">grunt</span><span class="p">.</span><span class="nx">registerTask</span><span class="p">(</span><span class="s1">&#39;clean-build&#39;</span><span class="p">,</span> <span class="s1">&#39;clean concat min targethtml copy&#39;</span><span class="p">);</span>
</span><span class='line'>  <span class="c1">// Default task.</span>
</span><span class='line'>  <span class="nx">grunt</span><span class="p">.</span><span class="nx">registerTask</span><span class="p">(</span><span class="s1">&#39;default&#39;</span><span class="p">,</span> <span class="s1">&#39;lint qunit:dev build qunit:dist&#39;</span><span class="p">);</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>


<p>Each task can be run independently by typing <code>grunt taskName</code> in a terminal.
Additionally, you can run a specific target on every multi-task by typing <code>grunt multiTaskName:targetName</code>.
The <code>registerTask</code> API allows us to define aliases to run a few tasks with a single command.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="c"># run lint task</span>
</span><span class='line'>&gt; grunt lint
</span><span class='line'>
</span><span class='line'><span class="c"># run concat and minify tasks</span>
</span><span class='line'>&gt; grunt concat min
</span><span class='line'>
</span><span class='line'><span class="c"># run only dev target of qunit task</span>
</span><span class='line'>&gt; grunt qunit:dev
</span><span class='line'>
</span><span class='line'><span class="c"># run &quot;build&quot; alias (ie: &#39;grunt concat min targethtml copy&#39;)</span>
</span><span class='line'>&gt; grunt build
</span><span class='line'>
</span><span class='line'><span class="c"># run default task (ie: &#39;grunt lint qunit:dev build qunit:dist&#39;)</span>
</span><span class='line'>&gt; grunt
</span></code></pre></td></tr></table></div></figure>


<h2>So what&rsquo;s next?</h2>

<p>I hope you already see the kind of benefits you can get by adding Grunt to your web-application projects.</p>

<p>I also encourage you to take a look at the plugin system, which will allow you to create your own tasks.
The well made <code>gruntplugin</code> init task (<code>grunt init:gruntplugin</code>) will bootstrap everything you need to start your own task and publish it in minutes.
If you find yourself stucked at some point, the <a href="https://github.com/gruntjs/grunt/blob/master/docs/api.md" title="Grunt API">Grunt API documentation</a> is a very good reference.
You can also check the source code of one of the official plugins on github.</p>

<p>As I wrote at the beginning of this post, using Grunt to automate some tasks in your web-application projects is probably the first thing you&rsquo;re going to try.
But I&rsquo;m convinced you can use it in many other ways.
If you need some more examples, I invite you to look at my own experiments with Grunt:</p>

<ul>
<li><a href="https://github.com/dharFr/static-templater" title="Static Templater">static-templater</a>: A grunt-based command line tool to render HMTL and PDF from JSON and HTML templates</li>
<li><a href="https://github.com/dharFr/grunt-wkhtmltopdf" title="grunt-wkhtmltopdf">grunt-wkhtmltopdf</a>: A simple Grunt multitask that uses wkhtmltopdf to convert HTML files to PDF.</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Grunt brings automation to the front-end side]]></title>
    <link href="http://www.dhar.fr/blog/2012/08/26/grunt-brings-automation-to-the-front-end-side/"/>
    <updated>2012-08-26T16:26:00+02:00</updated>
    <id>http://www.dhar.fr/blog/2012/08/26/grunt-brings-automation-to-the-front-end-side</id>
    <content type="html"><![CDATA[<p>Over the past few weeks, I realized that I added <a href="http://www.gruntjs.com" title="Grunt">grunt</a> in every little side project I worked on.
Thinking about it, I&rsquo;m not sure if I can even imagine to start a project without this tool.</p>

<p>You probably already heard about <strong>grunt</strong>, don&rsquo;t you? In case you don&rsquo;t (seriously?), it&rsquo;s been created by <a href="http://benalman.com/">Ben Alman (aka. cowboy)</a>.
I guess the best description is the one from the official home page:</p>

<blockquote><p>Grunt is a task-based command line build tool for JavaScript projects.</p></blockquote>

<p>OK, looks nice.
But what&rsquo;s new?
I already have tools to <em>lint</em> or <em>minify</em> my Javascript.
I already use <em>qunit</em> to unit test my code.
And so on&hellip; Why should I use <em>grunt</em> instead of all these tools?</p>

<p>Here is why:</p>

<ol>
<li>Because you probably don&rsquo;t really use all these tools.
I mean, for sure you know about them, and you already give them a try; but most people I worked with (including me) just don&rsquo;t use them on real projects, in their day to day work, because bringing the pieces together is not that easy.</li>
<li><em>Grunt</em> also uses the exact same tools you already know, or in the worst case, it can learn to use them.
It doesn&rsquo;t reinvent anything but allows you to organize your workflow in an uniform, yet flexible, way.</li>
</ol>


<h2>Do we need such a tool?</h2>

<p>As a front-end developer, automation wasn&rsquo;t really part of my workflow.
My first job was in some king of web agency were every desktop machine ran on Windows XP, and our main development tools were Dreamweaver MX (I guess I&rsquo;m getting old&hellip;) and Filezilla. <!-- more -->
At the time we would never have considered automation, unit testing or continuous integration.</p>

<p>Then I left that company and found a real engineer job.
But still, like many other developers, I relied on some kind of heavy IDE where every <em>low level</em> interaction with the OS tend to be hidden.
And I never really felt a need to dig into this.
Until recently, I was convinced <em>automation</em> was only a concern for back-end or system engineers.</p>

<h2>Everything you need is a terminal!</h2>

<p>On the other hand, a lot of <em>front-end</em> tools came up recently, especially since <em>Node.js</em> brought Javascript to the Terminal but not only.
<strong>Uglify-js</strong>, <strong>JSLint</strong>, <strong>Qunit</strong>, <strong>Jasmine</strong>, <strong>CoffeeScript</strong>, <strong>SASS</strong>, <strong>LESS</strong> are only the most famous but there are many others.
These tools are changing our approach to front-end technologies, they make us more productive, adding value to our jobs.</p>

<p>But those tools remains <em>command line tools</em>.
Even if each one of them is pretty simple to setup and use, combining all of these to make something adapted to a particular project can quickly become a nightmare for someone who&rsquo;s not familiar with his Terminal.
From my experience, a lot of front-end developers, especially younger ones, are not familiar with Bash scripting (<em>and sometimes are afraid of it</em>). For sure, that&rsquo;s probably a bad approach, but that&rsquo;s how I felt not that long ago and I&rsquo;m pretty sure I&rsquo;m not the only one in that case.</p>

<p>Grails developers write their scripts in Groovy.
Rails developers have Rake files.
<strong>We know how to write Javascript!</strong> That&rsquo;s where we are comfortable and productive.
We don&rsquo;t want to get a headache by writing some messy <em>bash</em> script <sup>[<a href="#note1">1</a>]</sup>.</p>

<h2>Here comes grunt</h2>

<p>That&rsquo;s what <em>grunt</em> does. It allows you to define a bunch of tasks, in a <strong>consistent way</strong>, by writing Javascript.
<em>Consistent</em> is an important word here because you could probably achieve the same goal directly with <em>Node.js</em> but <em>grunt</em> gives you a simple way to write and organize your tasks.
The most common ones (<em>lint</em>, <em>concat</em>, <em>minify</em>, <em>test</em>, etc.) are already included <a href="https://github.com/cowboy/grunt#built-in-tasks" title="grunt built-in Tasks">in the package</a> so you don&rsquo;t have to think about how to deal with them.</p>

<p>It also came with a really simple <a href="https://github.com/cowboy/grunt/blob/master/docs/getting_started.md#loading-grunt-plugins-or-tasks-folders" title="Loading grunt plugins or tasks folders">plugin system</a> based on <a href="https://npmjs.org" title="Node Packaged Modules">npm</a>.
If you find yourself needing to do something not included as a build-in task, try to search <em>npm</em> to see if somebody else has not already released a plugin that fits your needs.
Otherwise, you can still write your own plugin and publish it to <em>npm</em>.
The <a href="https://github.com/cowboy/grunt/blob/master/docs/api.md" title="The grunt API">grunt API</a> allows you to do pretty much everything you could need.
And thanks to the built-in project scaffolding, it only takes a few minutes to change your spaghetti code into a well written plugin. Once here, publishing to npm is just a command line away so do not hesitate.</p>

<h2>What&rsquo;s next?</h2>

<p>I hope you will give a try to <em>grunt</em>. Even more because something called <a href="http://yeoman.io/">Yeoman</a> is getting close to the public release. I asked for a beta invite on twitter but for now, I didn&rsquo;t have a chance to try it yet.
It seems that it can do many more and as it&rsquo;s based on <em>grunt</em>, among many others, it&rsquo;s probably a good idea to get familiar with that one as soon as possible.</p>

<p><a id="note1"></a>
<small>[1]: I actually did a lot of bash scripting recently and, believe it or not, I liked it. I wouldn&rsquo;t have said that a few years ago. It&rsquo;s a powerful programming tool and every developer should be comfortable with it. You&rsquo;re not? Learn some basics. ;)</small></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Compte-rendu du Riviera Coding Week-end]]></title>
    <link href="http://www.dhar.fr/blog/2012/08/13/fr-compte-rendu-du-riviera-coding-week-end/"/>
    <updated>2012-08-13T15:07:00+02:00</updated>
    <id>http://www.dhar.fr/blog/2012/08/13/fr-compte-rendu-du-riviera-coding-week-end</id>
    <content type="html"><![CDATA[<p><em>This post is about the Riviera Coding Week-end, a geek event that took place in Nice (France) from 10 to 12 August 2012.
As this post is closely related to a French event, I think for once, it&rsquo;s more appropriate to write in French, even if I usually blog in English.
If you&rsquo;re anyway interested, I&rsquo;m sure <a href="http://translate.google.com/translate?hl=en&amp;sl=fr&amp;tl=en&amp;u=http%3A%2F%2Fwww.dhar.fr%2Fblog%2F2012%2F08%2F13%2Ffr-compte-rendu-du-riviera-coding-week-end%2F">Google translate</a> or any other translation tool can fit your needs&hellip;</em></p>

<p><a href="http://photos.dhar.fr/p/ke/album-2"><img class="right" src="http://dhar.openphoto.me.s3.amazonaws.com/custom/201208/5d466e-EB855D13-DD73-423D-ACF1-51A94E35A82A_960x180.jpg"></a>
Du 10 au 12 Août dernier, j&#8217;ai participé au premier <em>Riviera Coding Week-end</em>, organisé par les membres du <a href="http://www.meetup.com/Riviera-Groovy-Grails-User-Group/">RivieraGUG</a> avec la participation du <a href="http://groups.google.com/group/jssophia">JSSophia</a> dont je fais partie.
À ma connaissance, c&#8217;est le premier événement du genre qui ait lieu sur la côte d&#8217;azur.
C&#8217;est en tout cas le premier auquel j&#8217;ai eu l&#8217;occasion de participer.
Après ces 48 heures passées à construire, échanger, mais surtout coder, un petit bilan me semble bien utile.</p>

<!-- more -->


<h2>Un Coding Week-End, quelle idée&hellip;</h2>

<p>D&#8217;abord initié par le <em><a href="http://www.meetup.com/Riviera-Groovy-Grails-User-Group/">Groovy &amp; Grails User Group</a></em> , l&#8217;événement avait pour objectif de construire un site dédié pour le groupe.
Par la suite, alors que certains membres du <em><a href="http://groups.google.com/group/jssophia">Javascript User Group</a></em> ont aussi souhaité participer au week-end, la thématique de l&#8217;événement a un peu changée, pour s&#8217;axer d&#8217;avantage sur la collaboration entre les communautés locales.</p>

<p><a href="http://photos.dhar.fr/p/kd/album-2"><img class="left" src="http://dhar.openphoto.me.s3.amazonaws.com/custom/201208/3eebc3-26D8653A-2BBB-4830-9F00-A240FF4514C6_960x180.jpg"></a>
Nous y voilà, c&#8217;est Vendredi soir, il est un peu plus de 19h30 lorsque j&#8217;arrive aux <a href="http://www.satellites-teletravail.com/">Satellites</a> (qui nous ont hébergés gracieusement tout le week-end).
La plupart des participants sont déjà arrivés.
Il y a quelques visages bien connus, des collègues de travail, avec qui je passe déjà mes journées en semaines; certains sont simplement familiers, croisés lors des précédentes réunions du JSSophia ou lors de conférences qui ont eu lieu à Sophia-Antipolis quelques mois plus tôt; puis d&#8217;autres, enfin, que je rencontre pour la première fois.</p>

<p>D&#8217;entrée de jeu, l&#8217;ambiance est décontractée, l&#8217;accueil chaleureux et tout le monde est souriant.
Sans trop savoir ce que va donner cette expérience, on sait déjà qu&#8217;on est tous là pour la même chose: partager notre passion du web et construire quelque chose, tous ensemble, <em>just for fun</em>.</p>

<h2>Entrée en matière</h2>

<pre><code>| Loading Grails 2.1.0
</code></pre>

<p>Le programme du Week-end est assez simple et couvre principalement la soirée du vendredi, après tout, on est pas là pour subir un planning rigoureux.</p>

<p>Le début de soirée est assez calme.
On fait connaissance, on se raconte nos vacances (pour ceux qui en ont pris&hellip;), on prends l&#8217;apéro en terrasse, on envoie quelques tweets en espérant ramener de nouveaux participants de dernière minute.
Certains configurent le Raspberry Pi qui hébergera un <a href="http://fr.wikipedia.org/wiki/EtherPad">EtherPad</a> pour la durée du week-end.</p>

<h2>Grails Crash Course</h2>

<pre><code>| Configuring classpath
</code></pre>

<p><a href="http://photos.dhar.fr/p/k2/album-2"><img class="right" src="http://dhar.openphoto.me.s3.amazonaws.com/custom/201208/2a719f-04CDD1E8-97CF-4210-9593-14718F7D2CBC_960x180.jpg"></a>
Après avoir dévoré quelques pizzas, on attaque les choses sérieuses avec un <em>Crash Course Grails</em> d&#8217;une petite demi-heure présenté par <a href="https://twitter.com/bgoetzmann">Bertrand Goetzmann</a>, bien utile pour ceux qui n&#8217;auraient jamais eu l&#8217;occasion d&#8217;utiliser le Framework.
Là encore, l&#8217;ambiance est bien loin d&#8217;un cours magistral.
La plupart des participants connaissent bien les rouages de Grails et le cours de Bertrand devient un bon prétexte pour partager les expériences de chacun et échanger les points de vue.</p>

<h2>Brainstorming</h2>

<pre><code>| Environment set to development
</code></pre>

<p>Presque deux heures plus tard (la demi-heure la plus longue qu&#8217;on ai connu), nous démarrons un Brainstorming animé avec un objectif simple : qu&#8217;allons nous construire pendant le week-end?</p>

<p>Rapidement, quelques sujets intéressants font surface, souvent liés à l&#8217;activité des User Groups autour de Sophia-Antipolis :</p>

<p><a href="http://photos.dhar.fr/p/k8/album-2"><img class="left" src="http://dhar.openphoto.me.s3.amazonaws.com/custom/201208/35f68b-C28C7051-09CB-46B5-9D8C-BB48B373EF4D_960x180.jpg"></a></p>

<ul>
<li>Manque d&#8217;activité des communautés : Il y a bien quelques user groups plus ou moins actifs mais la plupart restent globalement peu connus.</li>
<li>Manque de relations et de collaboration entre ces groupes.</li>
<li>Problématiques récurrentes d&#8217;un groupe à l&#8217;autre: trouver une salle, un sponsor, se faire connaître localement, informer et impliquer les membres</li>
</ul>


<p>Vient ensuite l&#8217;idée de créer un site dédié aux User Groups de la région, ayant pour objectif de faciliter la découverte des communautés locales et leur collaboration.
Le projet est ambitieux, mais l&#8217;important est surtout de lancer une initiative.
Pour pouvoir obtenir un résultat concret en un week-end, nous décidons de nous concentrer sur les éléments de base du site et de garder de côté les idées qui demandent davantage de travail.</p>

<h4>Première itération: Briques de base</h4>

<ul>
<li>Enregistrement des utilisateurs</li>
<li>Création d&#8217;un groupe par un utilisateur</li>
<li>Abonnement à un groupe existant par un utilisateur</li>
<li>Publication d&#8217;éventements organisés par le groupe</li>
<li>Publication d&#8217;articles (blog) par un groupe</li>
<li>Présentation des sponsors d&#8217;un groupe</li>
<li>Association de tags aux groupes, utilisateurs</li>
</ul>


<h4>Développements ultérieurs:</h4>

<ul>
<li>Favoriser la mise en relations des groupes géographiquement proches</li>
<li>Favoriser la découverte des groupes par les utilisateurs</li>
<li>Favoriser la mise en commun des ressources (salles, sponsors, relations) des groupes</li>
</ul>


<p> C&#8217;est un résumé un peu rapide, mais tous les détails sont en ligne grâce au <a href="https://github.com/rivieragug/website/blob/master/RASPBERRY_MINUTE.md">Raspberry Minute</a></p>

<h2>On est là pour coder, non?</h2>

<pre><code>| Packaging Grails application
</code></pre>

<p><a href="http://photos.dhar.fr/p/kc/album-2"><img class="right" src="http://dhar.openphoto.me.s3.amazonaws.com/custom/201208/495cd2-54FB5929-52D6-4A99-8A37-D7DC18031AC9_960x180.jpg"></a>
Après avoir déterminé notre objectif pour le week-end, nous n&#8217;avions plus qu&#8217;à nous mettre au travail.
Raconter les deux jours suivants en détail serait sans doute trop long et assez peu constructif.</p>

<p>L&#8217;important à retenir est sans doute que les contributions ont été nombreuses : écrire du code, décortiquer OAuth, dessiner des croquis d&#8217;IHM, mettre en place l&#8217;intégration continue (<em>continious outage?</em>), travailler le design de site, aider les débutants ou simplement mettre l&#8217;ambiance et remotiver les troupes; chacun a contribué au projet selon ses compétences et sa forme du moment.</p>

<p>Le résultat est là! Le projet est bien démarré, le code est <a href="https://github.com/rivieragug/website">disponible sur Github</a> et une première version est <a href="http://ughub.cloudfoundry.com/">déjà en ligne</a></p>

<h2>Bilan</h2>

<pre><code>| Running Grails application
</code></pre>

<p>Concernant la soirée de vendredi, je crois qu&#8217;il aurait été judicieux d&#8217;attaquer le brainstorming avant le Crash Course Grails.
Cela aurait permis d&#8217;entrer directement dans le vif du sujet et d&#8217;utiliser le cours pour construire les premiers éléments du projet. On aurait gagné un peu de temps, et tout le monde aurait été plus impliqué dans le cours.</p>

<p>Ensuite, comme je l&#8217;ai dis plus haut, le projet était sans doute trop ambitieux par rapport au temps à notre disposition. Il faut reconnaître que la version obtenue à l&#8217;issue du week-end est plus proche du prototype que d&#8217;une application de qualité professionnelle.</p>

<p>Malgré tout, en ce qui me concerne, cette expérience a été clairement positive.
Une ambiance bien sympa, des locaux au top, et une belle brochette de passionnés qui se sont tous  impliqués dans le projet comme si l&#8217;enjeu avait été important.</p>

<p>Et tant pis si le résultat n&#8217;a pas la qualité que nous aurions pu attendre.
Après tout, l&#8217;initiative est lancée et le code est là, ouvert à tous, disponible sur Github.
Il ne tiens qu&#8217;à nous de continuer à faire avancer ce projet, en y contribuant nous-même ou en motivant d&#8217;autres personnes à participer. Quelques <em>pull requests</em> de plus et on l&#8217;aura le site communautaire qu&#8217;on a imaginé tous ensemble vendredi dernier.</p>

<p>Y&#8217;a plus qu&#8217;à comme on dit&hellip; ;)</p>

<h2>Remerciements</h2>

<pre><code>| Server running. Browse to http://ughub.cloudfoundry.com/
</code></pre>

<p>Quelques remerciements pour finir.
D&#8217;abord parce que j&#8217;ai passé un excellent week-end, mais aussi parce que ce type d&#8217;initiative participe à créer cette dynamique locale qui nous tiens tous à cœur.</p>

<p>Merci, donc, aux membres du RiveraGUG pour avoir lancé l&#8217;initiative et géré l&#8217;organisation.
Merci aux <a href="http://www.satellites-teletravail.com/">Satellites</a>, et plus particulièrement à Nicolas, qui a accueilli notre petit groupe sans rien demander en retour. Vos locaux sont géniaux, si un jour je me met à mon compte, je sais déjà où établir mon QG ;)
Merci aussi à nos deux sponsors, <a href="http://www.avisto.com">Avisto</a> et <a href="http://www.sopragroup.com/">Sopra Group</a> pour avoir nous avoir permis de travailler le ventre plein.</p>

<p>Et merci enfin à tous ceux qui étaient présent et qui se sont impliqués au cours du week-end.</p>

<h2>Quelques liens en vrac</h2>

<ul>
<li>L&#8217;application sur cloud-foundry : <a href="http://ughub.cloudfoundry.com/">UG-hub</a></li>
<li>Le <a href="https://github.com/rivieragug/website">Code Source</a> sur Github</li>
<li><a href="http://photos.dhar.fr/photos/album-2/list">Quelques Photos</a></li>
<li>Les participants sont aussi <a href="https://twitter.com/_dhar/rivieracwe-2012">sur Twitter</a></li>
<li><em>Update</em>: Les <a href="http://www.odelia-technologies.com/Grails/Grails.impress.html">slides</a> de Bertrand sont maintenant disponibles</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Some fun with git hooks and Grunt.js]]></title>
    <link href="http://www.dhar.fr/blog/2012/07/23/some-fun-with-git-hooks-and-grunt-dot-js/"/>
    <updated>2012-07-23T22:55:00+02:00</updated>
    <id>http://www.dhar.fr/blog/2012/07/23/some-fun-with-git-hooks-and-grunt-dot-js</id>
    <content type="html"><![CDATA[<p>Before going further, I&rsquo;ll start by saying that I&rsquo;m a Git and Github noob, so if you have a better solution to achieve the same goal, give me a shout, I&rsquo;ll be happy to hear it..!</p>

<p>A few weeks ago, I implemented a small bookmarklet to apply <a href="https://code.google.com/p/google-code-prettify/">google-code-prettify</a> anywhere on the Web.
I put the source code <a href="https://github.com/dharFr/prettyprint-bookmarklet">on Github</a> and used the (<em>awesome</em>) <a href="https://help.github.com/articles/creating-pages-with-the-automatic-generator">Automatic Page Generator</a> to quickly create a landing page to host my bookmarklet.</p>

<p>The generated page lives on the same repository, on a branch called <code>gh-pages</code>.
At this point, my concern was the following: How could I include the bookmarklet link on <code>gh-pages</code> branch from the source code living on the <code>master</code>?</p>

<!-- more -->


<h2>Basic (handmade™) workflow</h2>

<p>In a first try, I could just copy/paste the minified source into an <code>&lt;a href="..."&gt;</code> link in my <code>index.html</code>.
But what happens if I update the source?
I&rsquo;ll probably have to deal with that kind of work flow:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='sh'><span class='line'>grunt <span class="c"># lint, concat and minifies source</span>
</span><span class='line'>git add .
</span><span class='line'>git commit -m <span class="s2">&quot;Probably improved something in there&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="c"># copy content from dist/prettyprinter.min.js</span>
</span><span class='line'>
</span><span class='line'>git checkout gh-pages <span class="c"># checkout gh-pages branch</span>
</span><span class='line'>
</span><span class='line'><span class="c"># paste code somewhere into index.html (without)</span>
</span><span class='line'>
</span><span class='line'>git add .
</span><span class='line'>git commit -m <span class="s2">&quot;Updated landing page with latest bookmarklet version&quot;</span>
</span><span class='line'>
</span><span class='line'>git checkout master <span class="c"># back to master branch</span>
</span></code></pre></td></tr></table></div></figure>


<p>Rather boring, right? Totally agree! And that&rsquo;s why I decided to dig a little further to see how I could automate this.</p>

<h2>Automate the whole thing!</h2>

<h3>Avoiding copy / paste</h3>

<p>Copy/paste a file from a branch to another <em>may</em> be acceptable if you do it only once. From there, it&rsquo;s probably better to use the following:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='sh'><span class='line'>git checkout gh-pages <span class="c"># checkout gh-pages branch</span>
</span><span class='line'>
</span><span class='line'><span class="c"># add/update &#39;dist&#39; directory from master branch</span>
</span><span class='line'>git checkout master -- dist
</span></code></pre></td></tr></table></div></figure>


<h3>Updating HTML content</h3>

<p>As mentioned earlier, I already used <a href="http://gruntjs.com/">grunt.js</a> to lint, concat and minify my source on the <code>master</code> branch.
So I searched for a way to use grunt to update the HTML link. I quickly found <a href="https://github.com/outaTiME/grunt-replace">grunt-replace</a>, perfect fit for the job.
I ended up with an HTML source file, with a placeholder for the bookmarklet:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">&#39;@@bookmarklet&#39;</span><span class="nt">&gt;</span>Prettify<span class="nt">&lt;/a&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>And a simple grunt <code>replace</code> task, reading the minified source and generating an up-to-date <code>index.html</code></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'>  <span class="nx">grunt</span><span class="p">.</span><span class="nx">initConfig</span><span class="p">({</span>
</span><span class='line'>    <span class="nx">replace</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">dist</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>        <span class="nx">src</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;src/index.html&#39;</span><span class="p">],</span>
</span><span class='line'>        <span class="nx">dest</span><span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span>
</span><span class='line'>        <span class="nx">variables</span><span class="o">:</span> <span class="p">{</span>
</span><span class='line'>          <span class="nx">bookmarklet</span><span class="o">:</span> <span class="s1">&#39;&lt;%= grunt.file.read(\&#39;dist/prettyprinter.min.js\&#39;) %&gt;&#39;</span>
</span><span class='line'>        <span class="p">}</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Introducing Git Hooks</h3>

<p>Basically, <a href="http://git-scm.com/book/en/Customizing-Git-Git-Hooks">Git Hooks</a> allow you to automatically run custom scripts at any step in your workflow.
Hooks must be defined in the <code>.git/hooks/</code> folder.
Placeholder files are already created, giving a pretty good idea about what&rsquo;s possible or not.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>ls .git/hooks/
</span><span class='line'>applypatch-msg.sample
</span><span class='line'>commit-msg.sample
</span><span class='line'>post-commit.sample
</span><span class='line'>post-receive.sample
</span><span class='line'>post-update.sample
</span><span class='line'>pre-applypatch.sample
</span><span class='line'>pre-commit.sample
</span><span class='line'>pre-rebase.sample
</span><span class='line'>prepare-commit-msg.sample
</span><span class='line'>update.sample
</span></code></pre></td></tr></table></div></figure>


<p>You only need to remove the <code>.sample</code> extension to define a hook, then edit the script to create your own awesome automation.</p>

<h3>Bringing the pieces together</h3>

<p>In my case, I created a <code>post-commit</code> script. Right after every new commit on the <code>master</code> branch, this piece of code runs and does all the crappy work.</p>

<figure class='code'><figcaption><span>post-commit</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="c">#!/bin/sh</span>
</span><span class='line'><span class="nb">echo</span> <span class="s2">&quot;\n| [prettify bookmarklet post-commit hook]&quot;</span>
</span><span class='line'>git checkout gh-pages
</span><span class='line'>
</span><span class='line'><span class="c"># Update bookmarklet script from master branch</span>
</span><span class='line'>git checkout master -- dist lib
</span><span class='line'>
</span><span class='line'><span class="c"># update index.html &amp; commit changes</span>
</span><span class='line'>grunt replace
</span><span class='line'>git add .
</span><span class='line'>git commit -m <span class="s2">&quot;Regenerated index.html from master branch&quot;</span>
</span><span class='line'>
</span><span class='line'>git checkout master
</span><span class='line'><span class="nb">echo</span> <span class="s2">&quot;| All Done -- Use &#39;git push --all&#39; instead of &#39;git push origin master&#39; to push changes&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p>As both <code>master</code> and <code>gh-pages</code> branches are modified, they both need to be pushed on the remote repository.
I use <code>git push --all</code>, which is fine if you don&rsquo;t have any other updated branch. Otherwise, you&rsquo;ll need a specific push for each branch.</p>

<h2>Going further</h2>

<p>I&rsquo;d like to find a way to stop the script if the commit doesn&rsquo;t occur on the <code>master</code> branch, but I&rsquo;m not sure how to do it&hellip;</p>

<p>I&rsquo;ll probably also add a <code>pre-commit</code> hook to lint/concat/minify the source.
Grunt.js already simplified this to a one liner, but I often forget to call it before committing changes.</p>

<p>(Grunt + Git Hooks) appears to be a nice couple with a huge time-saving potential. I&rsquo;d like to have an opportunity to try it on a larger project and see how it goes.</p>

<hr />

<h2>References</h2>

<ul>
<li><a href="http://lea.verou.me/2011/10/easily-keep-gh-pages-in-sync-with-master/">Easily keep gh-pages in sync with master</a> by Lea Verou</li>
<li><a href="http://oli.jp/2011/github-pages-workflow/">Github Pages Workflow</a> by by Oli Studholme</li>
<li><a href="http://get.inject.io/n/XxsZ6RE7">Git post-commit hook to keep master and gh-pages branch in sync</a></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[File Upload Form - Part 2: Loosely Coupled Modules]]></title>
    <link href="http://www.dhar.fr/blog/2012/04/07/file-upload-form-part-2-loosely-coupled-modules/"/>
    <updated>2012-04-07T17:48:00+02:00</updated>
    <id>http://www.dhar.fr/blog/2012/04/07/file-upload-form-part-2-loosely-coupled-modules</id>
    <content type="html"><![CDATA[<p>In this post, I&rsquo;ll continue to work on the code started in the first article on <a href="http://www.dhar.fr/blog/2012/03/24/file-upload-form-part-1-feature-detection/">Feature Detection and File Upload Forms</a>, so you&rsquo;d better read it before going further.</p>

<p>Last time, we created a Javascript component used to upload a file asynchronously on the server.
It uses <code>FormData</code> and <code>FileList</code> APIs in modern browsers but also degrades gracefully with browsers that don&rsquo;t support those APIs.</p>

<p>This time, I&rsquo;ll explain how to handle the thumbnail associated to the file input field.
It&rsquo;s a good example to introduce <em>loosely coupled modules</em>, and to show some other uses of the <em>feature detection</em> technique.</p>

<p>As mentioned in the previous post, you can find the source code on Github: <a href="https://github.com/dharFr/uploader-thumbnail/">uploader-thumbnail</a>.</p>

<h3>Loosely Coupled Modules</h3>

<p>If you never hear about loosely coupled module, I highly recommended you to read/watch the following:</p>

<ul>
<li>Nicholas Zakas&#8217; talk on <a href="http://www.youtube.com/watch?v=vXjVFPosQHw">Scalable JavaScript Application Architecture</a> [YouTube]</li>
<li>Addy Osmani&rsquo;s <a href="http://addyosmani.com/largescalejavascript/">Patterns For Large-Scale JavaScript Application Architecture</a></li>
</ul>


<!-- more -->


<p>Those links will give you a pretty good picture but to summarize briefly, the main  concepts to keep in mind when you want to rely on a <em>loosely coupled modules</em> architecture is that you need to:</p>

<ul>
<li>Split your code into separate modules, obviously.</li>
<li>Don&rsquo;t allow a module to know about each-other.</li>
</ul>


<p>How could you do that? Let&rsquo;s try to illustrate the idea with our file upload form.</p>

<h3>Creating modules</h3>

<p>We will create three simple modules to complete our file upload form, each one related to a very simple functionality:</p>

<ul>
<li>1st Module <code>uploader</code>: uploads a file</li>
<li>2nd Module <code>remover</code>: ask for deleting a previously uploaded file</li>
<li>3rd Module <code>thumbnail</code>: display a thumbnail</li>
</ul>


<p>In <a href="http://www.dhar.fr/blog/2012/03/24/file-upload-form-part-1-feature-detection/">the first part</a> we have already build the first one. As the two other ones are quite easy to implement, I won&rsquo;t detail every piece of code in this post. Feel free to look at the <a href="https://github.com/dharFr/uploader-thumbnail/">complete source</a> if necessary. For now let&rsquo;s see those two as black boxes that fits with our requirements.</p>

<h3>Communication between modules: introducing the observer</h3>

<h4>The Observer Pattern</h4>

<p>As mentioned before, our modules can&rsquo;t reference each-other. In other words, in the <code>uploader</code>&rsquo;s code, calling a method from the <code>thumbnail</code> object or referring to it in any other way is forbidden.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="c1">// uploader&#39;s inside code</span>
</span><span class='line'><span class="nx">thumbnail</span><span class="p">.</span><span class="nx">display</span><span class="p">(</span><span class="nx">picture</span><span class="p">)</span> <span class="c1">// &lt;-- WRONG!</span>
</span></code></pre></td></tr></table></div></figure>


<p>That&rsquo;s why we need to introduce the observer component. Its role is to allow communication between modules. In other words, instead of talking directly to each-others, modules in your application will talk and listen to the observer.</p>

<p>There many different implementations of the observer pattern but it&rsquo;s basically a component with 3 methods:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">observer</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">publish</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span> <span class="nx">topic</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>  <span class="nx">subscribe</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span> <span class="nx">topic</span><span class="p">,</span> <span class="nx">func</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>  <span class="nx">unsubscribe</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span> <span class="nx">topic</span><span class="p">,</span> <span class="nx">func</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<ul>
<li><code>observer.publish('some-topic', message)</code>: send a message on the topic &lsquo;some-topic&rsquo;</li>
<li><code>observer.subscribe('some-topic', callbackFunc)</code>: starts listening messages on the topic &lsquo;some-topic&rsquo;. <code>callbackFunc</code> will be called every times a message is published on the topic, the <code>message</code> will be passed as a parameter.</li>
<li><code>observer.publish('some-topic', callbackFunc)</code>: stops listening messages on the topics &lsquo;some-topic&rsquo;.</li>
</ul>


<h4>Using the observer</h4>

<p>Back the the upload form, the implementation doesn&rsquo;t change that much. You only need to pass the observer as parameter, and publish some events to notify the application</p>

<figure class='code'><figcaption><span>adding the observer</span><a href='https://github.com/dharFr/uploader-thumbnail/blob/step-by-step-demo/public/js/step3/upload.js#L13'>Source</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="k">this</span><span class="p">.</span><span class="nx">obs</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">observer</span> <span class="o">||</span> <span class="p">{</span><span class="nx">publish</span><span class="o">:</span><span class="kd">function</span><span class="p">(){},</span> <span class="nx">subscribe</span><span class="o">:</span><span class="kd">function</span><span class="p">(){}};</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span>notifying the observer</span><a href='https://github.com/dharFr/uploader-thumbnail/blob/step-by-step-demo/public/js/step3/upload.js#L132-144'>Source</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">beforeUpload</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">file</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">this</span><span class="p">.</span><span class="nx">obs</span><span class="p">.</span><span class="nx">publish</span><span class="p">(</span><span class="s1">&#39;submit.uploader&#39;</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">fileId</span><span class="p">,</span> <span class="nx">file</span><span class="p">);</span>
</span><span class='line'><span class="p">},</span>
</span><span class='line'>
</span><span class='line'><span class="nx">onUploadDone</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// ...</span>
</span><span class='line'>  <span class="k">this</span><span class="p">.</span><span class="nx">obs</span><span class="p">.</span><span class="nx">publish</span><span class="p">(</span><span class="s1">&#39;uploaded.uploader&#39;</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">fileId</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">data</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>On the other side, the thumbnail module need to listen to these events and to react to these in an appropriate way. In our case, when receiving a <code>submit</code> event, the thumbnail module should hide an existing image and display a load indicator. When receiving a <code>uploaded</code> event, it have to show the newly uploaded picture.</p>

<figure class='code'><figcaption><span>listening to the observer</span><a href='https://github.com/dharFr/uploader-thumbnail/blob/step-by-step-demo/public/js/step3/thumbnail.js#L19-31'>Source</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">Thumbnail</span><span class="p">.</span><span class="nx">prototype</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">init</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// Observe uploader events</span>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">obs</span><span class="p">.</span><span class="nx">subscribe</span><span class="p">(</span><span class="s1">&#39;submit.uploader&#39;</span><span class="p">,</span> <span class="nx">$</span><span class="p">.</span><span class="nx">proxy</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">onUploadStart</span><span class="p">,</span> <span class="k">this</span><span class="p">));</span>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">obs</span><span class="p">.</span><span class="nx">subscribe</span><span class="p">(</span><span class="s1">&#39;uploaded.uploader&#39;</span><span class="p">,</span> <span class="nx">$</span><span class="p">.</span><span class="nx">proxy</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">onUploadDone</span><span class="p">,</span> <span class="k">this</span><span class="p">));</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>  <span class="c1">// ...</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>As you can see in the above code, both <code>uploader</code> and <code>thumbnail</code> module are not aware from each others, they only talk and listen to the observer.</p>

<h3>Conclusion</h3>

<ul>
<li>You mat decide to completely change some module implementation, as long as it sends the same messages to the observer, everything is fine.</li>
<li>Every other module in your application can listen to observer. The thumbnail may not be the only piece of application interested in <code>uploader</code> events. That&rsquo;s fine, the new module just need to subscribe the appropriate event.</li>
<li>Last but not least, if some module appears to be broken, or if it doesn&rsquo;t starts as expected, other modules won&rsquo;t be much affected and your application is still working (even if some features are down).</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Queued ajax requests with jQuery and Coffescript]]></title>
    <link href="http://www.dhar.fr/blog/2012/03/31/queued-ajax-requests-with-jquery-and-coffescript/"/>
    <updated>2012-03-31T21:46:00+02:00</updated>
    <id>http://www.dhar.fr/blog/2012/03/31/queued-ajax-requests-with-jquery-and-coffescript</id>
    <content type="html"><![CDATA[<p>I recently had to queue a few ajax requests. I wrote a little piece of Coffeescript+jQuery to provide a reusable way of doing it.
Using jQuery&rsquo;s <a href="http://api.jquery.com/category/deferred-object/">Deferred</a> objects and CoffeeScript makes the task really easy.</p>

<!--more-->


<p>You probably already know that all jQuery&rsquo;s ajax methods implement <a href="http://api.jquery.com/Types/#Promise">Promise</a> interface. That&rsquo;s why we can use the <code>pipe()</code> method to queue the queries, as well as <code>done()</code> and <code>fail()</code> methods to track the queries&#8217; progress.</p>

<p>Another interesting point is how CoffeeScript make the code clearer and easy to read. I particularly enjoyed using <a href="http://jashkenas.github.com/coffee-script/#splats">splats</a> (<code>...</code>) to write the <code>$.when(deferredObjs...)</code> part on line 34. Speaking about code readability, it&rsquo;s such an improvement compared to the <code>$.when.apply($, deferredObjs)</code> Javascript counterpart.</p>

<p>You can find a <a href="http://jsfiddle.net/wA6K8/1/">working sample</a> on jsFiddle.</p>

<div><script src='https://gist.github.com/2244946.js?file=jquery.queue.coffee'></script>
<noscript><pre><code>###*
 * jQuery queue plugin v0.1
 * ==========================
 *
 * Used to queue $.Deferred's Promise objects
 * author @_dhar
###

(($) -&gt;

  class $.Queueable

    constructor: (@builder, @args, @validator = -&gt; yes) -&gt;

    promise: -&gt; @builder(@args...).promise()
    expose:  -&gt; @args
    isValid: -&gt; @validator(@args...)

  $.queuedWhen = (queueables) -&gt;
    
    d = $.Deferred();

    prev = null
    deferredObjs = ((
      do (q) -&gt;
        if not q instanceof $.Queueable 
          d.reject &quot;#{q} is not a $.Queueable object&quot;, q
        else
          prev = if prev then prev.pipe -&gt; q.promise() else q.promise()
          prev.done -&gt; d.notify q.expose()
          prev.fail -&gt; d.reject q.expose()
    ) for q in queueables when q.isValid() )

    $.when(deferredObjs...).then -&gt; d.resolve()

    return d.promise()
)(jQuery)</code></pre></noscript></div>


<h3>References</h3>

<ul>
<li>jQuery&rsquo;s <a href="http://api.jquery.com/category/deferred-object/">Deferred</a> objects</li>
<li><a href="https://gist.github.com/2244946">Source code</a> on gist</li>
<li><a href="http://jsfiddle.net/wA6K8/">Working sample</a> on jsFiddle</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[File Upload Form - Part 1: Feature Detection]]></title>
    <link href="http://www.dhar.fr/blog/2012/03/24/file-upload-form-part-1-feature-detection/"/>
    <updated>2012-03-24T16:55:00+01:00</updated>
    <id>http://www.dhar.fr/blog/2012/03/24/file-upload-form-part-1-feature-detection</id>
    <content type="html"><![CDATA[<p>Last Thursday, I gave a talk at <a href="http://www.twitter.com/jssophia">@JSSophia</a>, the local Javascript User Group I co-founded with <a href="http://www.twitter.com/FredGuillaume">@FredGuillaume</a>.
The group is just starting (2nd meeting), so there were only a few people, but as some of them looked quite interested by my talk, and some other couldn&rsquo;t come due to personal or professional duties, I thought I could write a couple of blog posts about the same topic.</p>

<p>I choose <em>File Upload Form</em> example because it&rsquo;s standalone, frequently used and it can be improved by many ways with HTML5 APIs.
It&rsquo;s a good example to introduce some very important Javascript concepts:</p>

<ol>
<li>Using <strong>feature detection</strong> for <strong>progressive enhancement</strong></li>
<li>Using <strong>loosely coupled modules</strong> to architecture web applications.</li>
</ol>


<p>This post focus on the first part of the talk.
It presents the <em>feature detection</em> technique.
I&rsquo;ll cover the second part, <em>loosely coupled modules</em>, in another article.</p>

<p>If you&rsquo;re in a hurry, or simply don&rsquo;t want to read the whole post, you&rsquo;ll find the slides embedded below and everything else on Github:</p>

<ul>
<li>The final <a href="https://github.com/dharFr/uploader-thumbnail/">uploader-thumbnail</a> source code.</li>
<li>The <a href="https://github.com/dharFr/uploader-thumbnail/tree/step-by-step-demo">step by step demo</a> I used during the talk.</li>
<li>The <a href="https://github.com/dharFr/uploader-thumbnail/tree/slides">slides</a>.</li>
</ul>


<p>The talk was in French so the slides are also written in French, even if it uses a lot of English keywords.</p>

<div class="dhar-style-embedder">
    <style>
        .clearfix { clear:both; }
        div.keep-aspect-ratio { max-width:600px;margin:0 auto; }
        div.keep-aspect-ratio > div { border:0;padding:0;margin:0;position:relative; }
        div.keep-aspect-ratio > div > img { border:0;padding:0;margin:0;z-index:-1000;position:relative;top:0;bottom:0;left:0;width:100%;display:block; }
        div.keep-aspect-ratio > div > div { border:0;padding:0;margin:0;position:absolute;top:0;bottom:0;left:0;width:100%;overflow:auto;}
    </style>
    <div class="keep-aspect-ratio">
    <div><img src="http://www.dhar.fr/assets/dhar/aspect-ratio-4-3.png" /><div>
    <iframe src="http://www.dhar.fr/assets/slides/embedder.html#uploader-thumbnail/slides.html" frameborder="0" width="100%" height="95%"></iframe>
    </div></div><div class="clearfix"></div>
    </div>
</div>




<!-- more -->


<h3>Initial Markup</h3>

<p>The main idea in progressive enhancement is to provide an application that work in any context.
A good approach is to start development with features that will work (quite) everywhere, and <em>progressively</em> add more specific features to improve your application&rsquo;s user experience in modern browsers.</p>

<p>Talking about <em>file upload form</em>, our starting point is a simple HTML markup.</p>

<figure class='code'><figcaption><span>Initial Markup</span><a href='https://github.com/dharFr/uploader-thumbnail/blob/step-by-step-demo/views/upload.ejs'>Source</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;form</span> <span class="na">id=</span><span class="s">&quot;upload-form&quot;</span> <span class="na">action=</span><span class="s">&quot;&quot;</span> <span class="na">method=</span><span class="s">&quot;post&quot;</span> <span class="na">enctype=</span><span class="s">&quot;multipart/form-data&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  
</span><span class='line'>  <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">&quot;upload&quot;</span><span class="nt">&gt;</span>Go Upload Something<span class="nt">&lt;/label&gt;&lt;br&gt;</span>
</span><span class='line'>
</span><span class='line'>  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">&quot;hidden&quot;</span> <span class="na">name=</span><span class="s">&quot;fileId&quot;</span> <span class="na">value=</span><span class="s">&quot;12345&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">&quot;file&quot;</span> <span class="na">name=</span><span class="s">&quot;upload&quot;</span> <span class="na">id=</span><span class="s">&quot;upload&quot;</span> <span class="na">accept=</span><span class="s">&quot;image/*&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">&quot;submit&quot;</span> <span class="na">value=</span><span class="s">&quot;Upload&quot;</span><span class="nt">&gt;</span>
</span><span class='line'><span class="nt">&lt;/form&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>It&rsquo;s simple, works in every browser and, assuming the server behind do his job, it works without a single line of Javascript.
On the other hand, it requires a full page reload so the first thing to do to bring some <em>hype</em> in this is to allow uploading the file with an asynchronous request.</p>

<h3>Feature detection</h3>

<p>Uploading a file trough an asynchronous request isn&rsquo;t that easy.
The <a href="https://developer.mozilla.org/en/DOM/XMLHttpRequest/FormData">FormData</a> API perfectly fits our needs but it&rsquo;s not well supported across all browsers (IE, I&rsquo;m looking at you&hellip; See <a href="https://developer.mozilla.org/en/DOM/XMLHttpRequest/FormData#Browser%20compatibility">Browser_compatibility</a> section).</p>

<p>Remember that our main concern is to provide the best user experience on each browser.
So how do we upload a file <em>asynchronously</em> in a browser that don&rsquo;t support <code>FormData</code> API?
Answer is by using an <code>iframe</code>.</p>

<h4>iframe file upload</h4>

<p>Please note that I started by creating a jQuery plugin to make the code more easily reusable.
I also hid the submit button and the bound event &lsquo;onchange&rsquo; on the input field to submit the form.
The following code snippets come from <a href="https://github.com/dharFr/uploader-thumbnail/blob/step-by-step-demo/public/js/step1/upload.js">step1/upload.js</a> file.</p>

<p>First, we have to listen to the <code>submit</code> event to prepare the form:</p>

<figure class='code'><figcaption><span>form submit event listener</span><a href='https://github.com/dharFr/uploader-thumbnail/blob/step-by-step-demo/public/js/step1/upload.js#L26-31'>Source</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="k">this</span><span class="p">.</span><span class="nx">$form</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;submit.uploader&#39;</span><span class="p">,</span> <span class="nx">$</span><span class="p">.</span><span class="nx">proxy</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// old-school iframe method</span>
</span><span class='line'>  <span class="k">this</span><span class="p">.</span><span class="nx">prepareIframeUpload</span><span class="p">();</span>
</span><span class='line'>  <span class="k">return</span> <span class="kc">true</span><span class="p">;</span> <span class="c1">// submit the form</span>
</span><span class='line'><span class="p">},</span> <span class="k">this</span><span class="p">));</span>
</span></code></pre></td></tr></table></div></figure>


<p>Next, let&rsquo;s append an hidden <code>iframe</code> to the form and define the <code>target</code> attribute to match the <code>iframe</code> id.
Once done, the form can be submitted as usual, the server&rsquo;s answer will be loaded into the <code>iframe</code>.</p>

<p>However, due to security concerns, we won&rsquo;t be able to read the <code>iframe</code> content once loaded, so we also need to create a callback function and to send the function name to the server as a URL parameter.
This way, the server script will be aware that we are using an <code>iframe</code> and will be able to generate the appropriate response.</p>

<figure class='code'><figcaption><span>iframe upload</span><a href='https://github.com/dharFr/uploader-thumbnail/blob/step-by-step-demo/public/js/step1/upload.js#L47-80'>Source</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">prepareIframeUpload</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>  <span class="kd">var</span> <span class="nx">id</span><span class="p">,</span> <span class="nx">cb</span><span class="p">,</span> <span class="nx">iframe</span><span class="p">,</span> <span class="nx">url</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// Generating a random id to identify</span>
</span><span class='line'>  <span class="c1">// both the iframe and the callback function</span>
</span><span class='line'>  <span class="k">this</span><span class="p">.</span><span class="nx">id</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">);</span>
</span><span class='line'>  <span class="nx">id</span> <span class="o">=</span> <span class="s2">&quot;uploader-frame-&quot;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
</span><span class='line'>  <span class="nx">cb</span> <span class="o">=</span> <span class="s2">&quot;uploader-cb-&quot;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// creating iframe and callback</span>
</span><span class='line'>  <span class="nx">iframe</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">&#39;&lt;iframe id=&quot;&#39;</span><span class="o">+</span><span class="nx">id</span><span class="o">+</span><span class="s1">&#39;&quot; name=&quot;&#39;</span><span class="o">+</span><span class="nx">id</span><span class="o">+</span><span class="s1">&#39;&quot; style=&quot;display:none;&quot;&gt;&#39;</span><span class="p">);</span>
</span><span class='line'>  <span class="nx">url</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">$form</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;action&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">this</span><span class="p">.</span><span class="nx">$form</span>
</span><span class='line'>      <span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;target&#39;</span><span class="p">,</span> <span class="nx">id</span><span class="p">)</span>
</span><span class='line'>      <span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="nx">iframe</span><span class="p">)</span>
</span><span class='line'>      <span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;action&#39;</span><span class="p">,</span> <span class="nx">url</span> <span class="o">+</span> <span class="s1">&#39;?iframe=&#39;</span> <span class="o">+</span> <span class="nx">cb</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// defining callback</span>
</span><span class='line'>  <span class="nb">window</span><span class="p">[</span><span class="nx">cb</span><span class="p">]</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">proxy</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;received callback:&#39;</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>      <span class="c1">// removing iframe</span>
</span><span class='line'>      <span class="nx">iframe</span><span class="p">.</span><span class="nx">remove</span><span class="p">();</span>
</span><span class='line'>      <span class="k">this</span><span class="p">.</span><span class="nx">$form</span><span class="p">.</span><span class="nx">removeAttr</span><span class="p">(</span><span class="s1">&#39;target&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>      <span class="c1">// removing callback</span>
</span><span class='line'>      <span class="k">this</span><span class="p">.</span><span class="nx">$form</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;action&#39;</span><span class="p">,</span> <span class="nx">url</span><span class="p">);</span>
</span><span class='line'>      <span class="nb">window</span><span class="p">[</span><span class="nx">cb</span><span class="p">]</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>      <span class="k">this</span><span class="p">.</span><span class="nx">onUploadDone</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
</span><span class='line'>  <span class="p">},</span> <span class="k">this</span><span class="p">);</span>
</span><span class='line'><span class="p">},</span>
</span></code></pre></td></tr></table></div></figure>


<p>Knowing that the server response will be loaded as <code>iframe</code> content, the server script has to generate this small piece of HTML.
It includes a <code>script</code> tag, witch calls the <code>callback</code> function on the parent window. The json <code>result</code> is send as a parameter of that function.</p>

<figure class='code'><figcaption><span>server response</span><a href='https://github.com/dharFr/uploader-thumbnail/blob/step-by-step-demo/views/upload-iframe.ejs'>Source</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;script </span><span class="na">type=</span><span class="s">&quot;text/javascript&quot;</span><span class="nt">&gt;</span>
</span><span class='line'><span class="nb">window</span><span class="p">.</span><span class="nx">top</span><span class="p">.</span><span class="nb">window</span><span class="p">[</span><span class="s1">&#39;&lt;%- callback %&gt;&#39;</span><span class="p">](</span><span class="o">&lt;%-</span> <span class="nx">result</span> <span class="o">%&gt;</span><span class="p">);</span>
</span><span class='line'><span class="nt">&lt;/script&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Here we are.
Our script can send files asynchronously, without reloading the whole page, and it even works with old browsers.
Of course, we could decide to stop there, but we won&rsquo;t because of the following:</p>

<ul>
<li>No Error handling: if something goes wrong while sending the file, or if the server don&rsquo;t render the good response, the callback function will never be called, and we can&rsquo;t handle the error.
You probably want to add a timeout to the script above to avoid waiting for an answer that would never come.</li>
<li>It&rsquo;s not AJAX.
You probably already notice this point.
We are faking it.
The form is still sent as HTML form, we only changed his target.
The file is uploaded asynchronously, but without any XmlHttpRequest involved.</li>
<li>It&rsquo;s dirty.
I&rsquo;m OK as it stays a fall-back solution, but keeping it as the main implementation? Yuck!</li>
</ul>


<h4>FormData file upload</h4>

<p>Time to do things the right way? OK. Let&rsquo;s start by editing the submit event listener as following:</p>

<figure class='code'><figcaption><span>updated submit event listener</span><a href='https://github.com/dharFr/uploader-thumbnail/blob/step-by-step-demo/public/js/step2/upload.js#L26-46'>Source</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="k">this</span><span class="p">.</span><span class="nx">$form</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;submit.uploader&#39;</span><span class="p">,</span> <span class="nx">$</span><span class="p">.</span><span class="nx">proxy</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
</span><span class='line'>
</span><span class='line'>  <span class="kd">var</span> <span class="nx">file</span> <span class="o">=</span> <span class="kc">false</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">$upload</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">files</span><span class="p">)</span> <span class="nx">file</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">$upload</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">files</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">this</span><span class="p">.</span><span class="nx">beforeUpload</span><span class="p">(</span><span class="nx">file</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">FormData</span> <span class="o">&amp;&amp;</span> <span class="nx">file</span> <span class="p">)</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;FormData supported and file is:&#39;</span><span class="p">,</span> <span class="nx">file</span><span class="p">);</span>
</span><span class='line'>      <span class="k">this</span><span class="p">.</span><span class="nx">upload</span><span class="p">(</span><span class="nx">file</span><span class="p">);</span>
</span><span class='line'>      <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>  <span class="c1">// fallback to old-school iframe method</span>
</span><span class='line'>  <span class="k">else</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;FormData is not supported or file is undefined:&#39;</span><span class="p">,</span> <span class="nx">file</span><span class="p">);</span>
</span><span class='line'>      <span class="k">this</span><span class="p">.</span><span class="nx">prepareIframeUpload</span><span class="p">();</span>
</span><span class='line'>      <span class="k">return</span> <span class="kc">true</span><span class="p">;</span> <span class="c1">// submit the form</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="p">},</span> <span class="k">this</span><span class="p">));</span>
</span></code></pre></td></tr></table></div></figure>


<p>The <code>this.$upload</code> variable represents a jQuery object containing the <code>input[type=file]</code> DOM node (see the complete <a href="https://github.com/dharFr/uploader-thumbnail/blob/step-by-step-demo/public/js/step2/upload.js">step2/upload.js</a> file for more details).
Here we have to check if the browser supports both <code>File</code> and <code>FormData</code> APIs.
If these two conditions are satisfied, we can go with the <em>&ldquo;HTML5&rdquo;</em> file upload.
Otherwise, we just fall-back to the <code>iframe</code> hack&hellip; Simple isn&rsquo;t it?</p>

<p>This is <strong>Feature Dectection</strong> and it&rsquo;s one of the <strong>key concepts of modern web development</strong>.
It&rsquo;s the only way we have to use the latest HTML5 features without breaking old browser&rsquo;s support.</p>

<p>Now, we&rsquo;re sure that we can use <code>FormData</code> upload, we just need to implement the method as shown in the following code extract.
As you can read, it&rsquo;s way simpler and less hacky compared to the <code>iframe</code> method.
Server response and errors are handled the same way than with any other ajax request.</p>

<figure class='code'><figcaption><span>FormData upload</span><a href='https://github.com/dharFr/uploader-thumbnail/blob/step-by-step-demo/public/js/step2/upload.js#L61-80'>Source</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">upload</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">file</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>  <span class="kd">var</span> <span class="nx">formdata</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">FormData</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">$form</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="nx">formdata</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="kd">var</span> <span class="nx">jqXhr</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">({</span>
</span><span class='line'>          <span class="nx">url</span><span class="o">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">$form</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;action&#39;</span><span class="p">),</span>
</span><span class='line'>          <span class="nx">type</span><span class="o">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">$form</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;method&#39;</span><span class="p">),</span>
</span><span class='line'>          <span class="nx">data</span><span class="o">:</span> <span class="nx">formdata</span><span class="p">,</span>
</span><span class='line'>          <span class="c1">// tells jQuery not to prepare data before sending the request</span>
</span><span class='line'>          <span class="nx">processData</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
</span><span class='line'>          <span class="nx">contentType</span><span class="o">:</span> <span class="kc">false</span>
</span><span class='line'>      <span class="p">});</span>
</span><span class='line'>
</span><span class='line'>      <span class="nx">jqXhr</span>
</span><span class='line'>          <span class="p">.</span><span class="nx">done</span><span class="p">(</span><span class="nx">$</span><span class="p">.</span><span class="nx">proxy</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">onUploadDone</span><span class="p">,</span> <span class="k">this</span><span class="p">))</span>
</span><span class='line'>          <span class="p">.</span><span class="nx">fail</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
</span><span class='line'>              <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;upload error:&quot;</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">);</span>
</span><span class='line'>          <span class="p">});</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">},</span>
</span></code></pre></td></tr></table></div></figure>


<p>We&rsquo;re done for part 1.
Our upload form is fully functional for both modern and old browsers, and even with Javascript disabled.
In the 2nd part, I explain how to handle the thumbnail associated to the file input field.
It&rsquo;s a very good example to introduce <em>loosely coupled modules</em>, and to show some other uses of the <em>feature detection</em> technique.
<a href="http://www.dhar.fr/blog/2012/04/07/file-upload-form-part-2-loosely-coupled-modules/">File Upload Form &ndash; Part 2: Loosely Coupled Modules</a></p>

<h3>References:</h3>

<ul>
<li><a href="https://developer.mozilla.org/en/Browser_detection_using_the_user_agent">Browser detection using the user agent</a> on MDC</li>
<li><a href="https://developer.mozilla.org/en/DOM/XMLHttpRequest/FormData">FormData</a> API</li>
<li><a href="https://developer.mozilla.org/en/DOM/FileList">FileList</a> API</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[jQuery plugin for ping-URL process]]></title>
    <link href="http://www.dhar.fr/blog/2011/07/26/jquery-plugin-for-ping-url-process/"/>
    <updated>2011-07-26T00:00:00+02:00</updated>
    <id>http://www.dhar.fr/blog/2011/07/26/jquery-plugin-for-ping-url-process</id>
    <content type="html"><![CDATA[<p>If your page runs into an iframe hosted by another domain, you may want to keep the session open. The following jQuery plugin automates the &ldquo;ping URL&rdquo; process and provides some options.</p>

<!--more-->


<p>The pinger will ask the given URL every &lsquo;interval&rsquo; minutes if it detects
some activity by listening to the events listed in &lsquo;listen&rsquo; parameter.</p>

<p>Have a look to the &lsquo;defaults&rsquo; variable below for further details about available parameters and default values.</p>

<div><script src='https://gist.github.com/1107059.js'></script>
<noscript><pre><code>/**
 * $.pinger
 * 
 * If your page runs into an iframe hosted by another domain, you may want to keep the session open.
 * This plugin automates the &quot;ping URL&quot; process and provides some options.
 * 
 * The pinger will ask the given URL every 'interval' minutes if it detects
 * some activity by listening to the events listed in 'listen' parameter.
 * 
 * Have a look to the 'defaults' variable below for further details about available parameters and default values.
 * 
 * Example:
 * Ping Google Logo every 5 minutes and launch the first ping right now:
 *  $.pinger({
 *      interval: 5
 *      url: &quot;http://www.google.co.uk/images/logos/ps_logo2.png&quot;,
 *      pingNow: true
 *  });
 * 
 * Initialize pinger without listening to events. Update activity on demand.
 *  $.pinger({
 *      url: &quot;http://www.google.co.uk/images/logos/ps_logo2.png&quot;,
 *      listen: null
 *  });
 *  ...
 *  $.pinger.now('manual ping');
 */
(function($){

    var defaults = {
        interval: 10,                   // pings the given URL every 'interval' MINUTES. Set to 0 for manual ping only
        url: null,                      // the URL to ping
        listen: [&quot;click&quot;, &quot;keydown&quot;],   // events to listen for updating activity
        pingNow: false,                 // If true, sends a ping request just after init
        beforeSend: null,               // Callback function, called before ping (should return true. false will cancels ping query)
        callback: false                 // Callback function, called after ping query callback received
    };
    
    var options = {};
    var lastUpdate, checkInterval, iTime, pingImg, _pingerLogs = true;
    
    /* Public methods */
    var methods = {
        init: function( settings ) {
            options = $.extend(true, defaults, settings);

            if (!options.url) {
                $.error( 'jQuery.pinger: url parameter is mandatory');
                return;
            }
            
            log(&quot;$.pinger.init:&quot;, options);
            if ( options.interval &gt; 0 ) {
                
                lastUpdate = 0;
                iTime = (options.interval * 60 * 1000);
                
                checkInterval = setInterval( function(){

                    log(&quot;$.pinger: Should I ping? (&quot;, ((new Date()).getTime() - lastUpdate), &quot;&gt;&quot;, iTime, &quot;?)&quot;);
                    if ( ( (new Date()).getTime() - lastUpdate) &gt; iTime ) {
                        stop('timeout');
                    }
                    else {
                        ping('interval');
                    }
                }, iTime);
                
                if (options.listen &amp;&amp; $.isArray(options.listen) &amp;&amp; options.listen.length &gt; 0) {

                    $(document).bind(options.listen.join('.pinger '), function(event) {
                        update(event.type);
                    }); 
                }
                
                if (options.pingNow) {
                    ping('init');
                }
            }
        },
        /*
         * $.pinger.now(param)
         * Manual activity update
         * param : some message to log
         */
        now: function (param) {
            ( options.interval &amp;&amp; options.interval &gt; 0 ) ? update(param) : ping(param);
        },
        /*
         * $.pinger.destroy();
         * destroy pinger
         */
        destroy: function() {

            stop('destroy');
        }
    };

    /* Private Methods */
    function update(param) {
        log(&quot;$.pinger: activity update -&quot;,param);
        lastUpdate = (new Date()).getTime();
    }
    
    function ping(param) {
        log(&quot;$.pinger: Ping to&quot;, options.url, &quot;(&quot;, param, &quot;)&quot;);
        if (!options.beforeSend || options.beforeSend.apply(this, arguments)) {
            
            if (!pingImg) {
                // In FF or Chrome, we could use a GET xhr but IE blocks due to cross-domain policy
                // Image object looks fine for that ping job
                pingImg = new Image();
                pingImg.onload = function() {
                    //Success callback
                    log(&quot;$.pinger: Ping callback&quot;, arguments);
                    if (options.callback) {
                        options.callback.apply(this, arguments);
                    }
                }
            }
            pingImg.src = options.url + &quot;?&quot; + (new Date().getTime());
        }
    }
    
    function stop(param) {
        log(&quot;$.pinger: Stopped -&quot;,param);
        if (options.listen &amp;&amp; $.isArray(options.listen) &amp;&amp; options.listen.length &gt; 0) {
            $(document).unbind(options.listen.join('.pinger '));
        }
        clearInterval(checkInterval);
    }
    
    function log() {
        if (_pingerLogs &amp;&amp; console &amp;&amp; console.log) {
            if (console.log.apply) {
                console.log.apply(console, arguments);
            }
            else {
                // console.log doesn't seem to be a &quot;real&quot; function in IE so apply can't be used 
                console.log((Array.prototype.slice.call(arguments)).join(&quot; &quot;));
            }
        }
    }

    /* Plugin entry point */
    $.pinger = function( method ) {
        // Method calling logic
        if ( methods[method] ) {
            return methods[ method ].apply( this, Array.prototype.slice.call(arguments, 1));
        } else if ( typeof method === 'object' || !method ) {
            return methods.init.apply(this, arguments );
        } else {
            $.error( 'Method ' + method + ' does not exist on jQuery.pinger');
            return this;
        }
    };
})(jQuery);</code></pre></noscript></div>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[jQuery plugin pattern written in Coffeescript]]></title>
    <link href="http://www.dhar.fr/blog/2011/07/24/jquery-plugin-pattern-written-in-coffeescript/"/>
    <updated>2011-07-24T00:00:00+02:00</updated>
    <id>http://www.dhar.fr/blog/2011/07/24/jquery-plugin-pattern-written-in-coffeescript</id>
    <content type="html"><![CDATA[<p>Once your <a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a> environment is up and running, you may want to write some awesome new jQuery plugin with CoffeeScript.</p>

<p>The code bellow is a starting point, it&rsquo;s clearly inspired from the <a href="http://docs.jquery.com/Plugins/Authoring">jQuery Doc</a>. Just search/replace <code>pluginName</code> with your plugin name and go ahead with your own code.</p>

<div><script src='https://gist.github.com/1101485.js'></script>
<noscript><pre><code>###*
 * jQuery pluginName plugin v0.1
 * ==========================
 * see http://docs.jquery.com/Plugins/Authoring
 *
 * plugin description goes here
 * author your.name@email.com
###

(($) -&gt;
    # Private functions 
    privateFunc = () -&gt;
        console.log &quot;private&quot;
    
    # Public Functions
    methods = 
        init: () -&gt;
            console.log 'init'
            @each -&gt;
                $this = $(@)
                data = $this.data 'pluginName'
                if not data
                    ### Do more stuff here ###
                    $(@).data 'pluginName' 
                        target: $this
                return
        
        destroy: () -&gt;
            @each -&gt;
                $this = $(@)
                data = $this.data 'pluginName'
                
                data.pluginName.remove()
                $this.removeData 'pluginName'
                return

    $.fn.pluginName = (method) -&gt;
        
        # Method calling logic
        if methods[method]
            methods[method].apply this, Array.prototype.slice.call arguments, 1 
        else if typeof method is 'object' or !method 
            methods.init.apply this, arguments
        else
            $.error &quot;jQuery.pluginName: Method #{ method } does not exist on jQuery.pluginName&quot;
    return
)(jQuery)
</code></pre></noscript></div>


<p>Links Summary:</p>

<ul>
<li><a href="https://gist.github.com/1101485#file_jquery.plugin_name.coffee">jquery.plugin_name.coffee</a> source code</li>
<li><a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a></li>
<li><a href="http://docs.jquery.com/Plugins/Authoring">jQuery Doc</a></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Plugin jQuery - Aide contextuelle Javascript]]></title>
    <link href="http://www.dhar.fr/blog/2010/09/05/plugin-jquery-aide-contextuelle-javascript/"/>
    <updated>2010-09-05T00:00:00+02:00</updated>
    <id>http://www.dhar.fr/blog/2010/09/05/plugin-jquery-aide-contextuelle-javascript</id>
    <content type="html"><![CDATA[<p>Voilà déjà pas mal de temps que je n&#8217;ai rien publié ici&hellip; Ce qui ne veux pas dire que j&#8217;ai rien dans les cartons. C&#8217;est plutôt le temps qui manque un peu quand il s&#8217;agit de présenter tout ça de façon correcte.</p>

<p>Pour changer un peu des précédent articles dédiés au développement iPhone, je vais aujourd&#8217;hui présenter un petit outil Javascript, utilisant le Framework jQuery. Rien de révolutionnaire, c&#8217;est simplement un plugin jQuery permettant de dérouler un bandeau HTML au dessous d&#8217;un autre. J&#8217;ai appelé ce plugin &lsquo;helpBox&rsquo; car ce widget est particulièrement adapté pour afficher une aide contextuelle.</p>

<p>Voici le <strong> <a href="https://gist.github.com/1101480">code source</a></strong>.</p>

<!--more-->


<p>Rien de bien compliqué ici si l&#8217;on connais déjà la structure d&#8217;un plugin jQuery.
On commence par définir quelques paramètres&hellip;</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="kd">var</span> <span class="nx">defaults</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>    <span class="nx">helpContent</span><span class="o">:</span><span class="s1">&#39;&lt;p&gt;help content&lt;/p&gt;&#39;</span><span class="p">,</span>  <span class="c1">// jQuery Selector or plain text HTML.</span>
</span><span class='line'>    <span class="nx">contentCls</span><span class="o">:</span><span class="s1">&#39;help-content&#39;</span><span class="p">,</span>          <span class="c1">// CSS Class applied to the help box.</span>
</span><span class='line'>    <span class="nx">buttonCls</span><span class="o">:</span><span class="s1">&#39;help-button&#39;</span><span class="p">,</span>            <span class="c1">// CSS Class applied to the help button.</span>
</span><span class='line'>    <span class="nx">buttonText</span><span class="o">:</span><span class="s1">&#39;Help&#39;</span>                   <span class="c1">// Help Button text</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Ensuite, le plugin &lsquo;helpBox&rsquo; se contente de recherche le code HTML du contenu de l&#8217;aide pour l&#8217;ajouter au document avec le bouton associé.</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">each</span><span class="p">(</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">var</span> <span class="nx">o</span> <span class="o">=</span> <span class="nx">options</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// Gets help content</span>
</span><span class='line'>    <span class="kd">var</span> <span class="nx">content</span> <span class="o">=</span> <span class="p">(</span> <span class="nx">$</span><span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">helpContent</span><span class="p">).</span><span class="nx">size</span><span class="p">()</span> <span class="o">&amp;</span><span class="nx">gt</span><span class="p">;</span> <span class="mi">0</span> <span class="p">)</span> <span class="o">?</span> <span class="nx">$</span><span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">helpContent</span><span class="p">).</span><span class="nx">html</span><span class="p">()</span> <span class="o">:</span> <span class="nx">o</span><span class="p">.</span><span class="nx">helpContent</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// Appends help box and help button</span>
</span><span class='line'>    <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">append</span><span class="p">(</span><span class="s2">&quot;&amp;lt;div class=&#39;&quot;</span><span class="o">+</span><span class="nx">o</span><span class="p">.</span><span class="nx">contentCls</span><span class="o">+</span><span class="s2">&quot;&#39;&gt;&quot;</span> <span class="o">+</span> <span class="nx">content</span> <span class="o">+</span> <span class="s2">&quot;&amp;lt;/div&gt;&quot;</span><span class="p">)</span>
</span><span class='line'>        <span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s2">&quot;&amp;lt;div class=&#39;&quot;</span><span class="o">+</span><span class="nx">o</span><span class="p">.</span><span class="nx">buttonCls</span><span class="o">+</span><span class="s2">&quot;&#39;&gt;&amp;lt;a href=&#39;#&#39;&gt;&quot;</span><span class="o">+</span><span class="nx">o</span><span class="p">.</span><span class="nx">buttonText</span><span class="o">+</span><span class="s2">&quot;&amp;lt;/a&gt;&amp;lt;/div&gt;&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="o">+</span><span class="nx">o</span><span class="p">.</span><span class="nx">contentCls</span><span class="p">).</span><span class="nx">hide</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// [...]</span>
</span><span class='line'><span class="p">})</span>
</span></code></pre></td></tr></table></div></figure>


<p>Ensuite, il ajoute deux gestionnaires d’événement au bouton: un &lsquo;mouseover&rsquo; pour ouvrir le dialogue d&#8217;aide et un &lsquo;click&rsquo; pour fermer ce dernier.</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="c1">// Open the box on button mouseover, close it on click</span>
</span><span class='line'><span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="o">+</span><span class="nx">o</span><span class="p">.</span><span class="nx">buttonCls</span><span class="o">+</span><span class="s1">&#39; a&#39;</span><span class="p">).</span><span class="nx">mouseover</span><span class="p">(</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">parent</span><span class="p">().</span><span class="nx">prev</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="o">+</span><span class="nx">o</span><span class="p">.</span><span class="nx">contentCls</span><span class="o">+</span><span class="s1">&#39;:hidden&#39;</span><span class="p">).</span><span class="nx">slideDown</span><span class="p">();</span>
</span><span class='line'><span class="p">}).</span><span class="nx">click</span><span class="p">(</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">parent</span><span class="p">().</span><span class="nx">prev</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="o">+</span><span class="nx">o</span><span class="p">.</span><span class="nx">contentCls</span><span class="o">+</span><span class="s1">&#39;:visible&#39;</span><span class="p">).</span><span class="nx">slideUp</span><span class="p">();</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>


<p>Voilà tout. Facile non?</p>

<ul>
<li>Le code complet est ici: <strong> <a href="https://gist.github.com/1101480">jquery.helpbox.js</a> </strong></li></li>
</ul>


<p>Quelques ressources utiles pour finir:</p>

<ul>
<li><a href="http://docs.jquery.com/Plugins/Authoring">jQuery Plugin Authoring</a></li>
<li><a href="http://www.learningjquery.com/2007/10/a-plugin-development-pattern">Les bases du développement de plugin jQuery</a> sur learningjquery.com</li>
</ul>


<p>Enjoy!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[QR Codes: intégration dans votre application iPhone en 10 minutes chrono!]]></title>
    <link href="http://www.dhar.fr/blog/2010/04/20/qr-codes-integration-dans-votre-application-iphone-en-10-minutes-chrono/"/>
    <updated>2010-04-20T00:00:00+02:00</updated>
    <id>http://www.dhar.fr/blog/2010/04/20/qr-codes-integration-dans-votre-application-iphone-en-10-minutes-chrono</id>
    <content type="html"><![CDATA[<p><img class="right" src="http://www.dhar.fr/assets/dhar/qrcode.png" width="150" height="150" title="Decode me if you can" alt="Sample QR Code"></p>

<h3>Pour les plus pressés, ça se passe ici:</h3>

<p><a href="http://sourceforge.net/apps/mediawiki/zbar/index.php?title=HOWTO:_Add_a_barcode_reader_to_an_iPhone_app">ZBar: How to add a barcode reader to an iPhone app</a></p>

<h3>Pour les autres, voilà un peu plus de détails:</h3>

<p>Les <a href="http://en.wikipedia.org/wiki/QR_Code">QR Codes</a> sont de plus en plus répandus dans les applications mobiles. Au détour d&#8217;un projet iPhone, vous pourriez être amenés, tout comme moi, à devoir décoder ces carrés &ldquo;magiques&rdquo;.<!--more--></p>

<p>Si tel est votre cas, sachez que la tâche sera des plus simples grâce à l&#8217;excellent projet <a href="http://zbar.sourceforge.net/">ZBar bar code reader</a>. L&#8217;intégration du wrapper Objective-C de cette librairie m&#8217;a pris en tout en pour tout 10 minutes. De plus, le scan des codes est effectué à la volée (comprenez sans que l&#8217;utilisateur ait besoin de presser le bouton de l&#8217;appareil photo, dès que le code est dans le cadre). La documentation limpide fournie sur le wiki du projet transformera votre application en un lecteur de codes à rendre jaloux le caissier de l&#8217;hyper en bas de chez vous.</p>

<p>La doc est là:<a href="http://sourceforge.net/apps/mediawiki/zbar/index.php?title=HOWTO:_Add_a_barcode_reader_to_an_iPhone_app">ZBar: How to add a barcode reader to an iPhone app</a>. Dépêchez-vous, plus que 9&#8217;30&hellip;</p>

<h4>Décoder des codes QR:</h4>

<ul>
<li><a href="http://itunes.apple.com/us/app/zbar-barcode-reader/id344957305?mt=8">L&#8217;application ZBar sur l&#8217;AppStore</a></li>
<li><a href="http://code.google.com/p/zxing/">ZXing</a> (prononcer &ldquo;Zebra_Crossing&rdquo;)</li>
</ul>


<h4>Générer des QR Codes en ligne:</h4>

<ul>
<li><a href="http://qrcode.kaywa.com">Générateur de QR Code</a></li>
<li><a href="http://zxing.appspot.com/generator/">QR Code Generator</a></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[UIScrollView: Extention du protocole associé au delegate]]></title>
    <link href="http://www.dhar.fr/blog/2010/04/15/uiscrollview-extention-du-protocole-associe-au-delegate/"/>
    <updated>2010-04-15T00:00:00+02:00</updated>
    <id>http://www.dhar.fr/blog/2010/04/15/uiscrollview-extention-du-protocole-associe-au-delegate</id>
    <content type="html"><![CDATA[<p><img class="right" src="http://www.dhar.fr/assets/dhar/ImageViewer1-161x300.png" width="161" height="300" title="UIScrollView dans un ImageViewer" alt="ImageViewer"></p>

<p>Après le grand ménage sur le blog, plein d&#8217;enthousiasme, j&#8217;ai entrepris de rédiger un tutoriel  détaillé  à propos du développement d&#8217;un ImageViewer pour iPhone, avec une interface la plus proche possible de l&#8217;application <code>Photos</code>. Au cours de l&#8217;écriture de ce billet, j&#8217;ai constaté 2 choses:</p>

<ul>
<li>Tout d&#8217;abord, ça fait un billet sacrément long, à l&#8217;écriture comme à la lecture.</li>
<li>Ensuite et surtout, j&#8217;ai constaté que l&#8217;intérêt était assez limité car l&#8217;exercice s&#8217;est révélé relativement simple.</li>
</ul>


<p>En revanche, lors du développement de mon ImageViewer, il y a un aspect qui a attiré mon attention: l&#8217;extension d&#8217;un protocole. Ce point précis peut présenter une certaine difficulté pour peu qu&#8217;on n&#8217;y ai jamais été confronté et il m&#8217;a été assez difficile de trouver des exemples clair sur le web.
J&#8217;ai donc décidé de rédiger un billet plus court, qui détaille la façon de dériver la classe <code>UIScrollView</code> tout en étendant le protocole <code>UIScrollViewDelegate</code> associé.</p>

<!--more-->


<p>Si vous souhaitez, comme moi, reproduire l&#8217;interface de l&#8217;application <code>Photos</code> de votre iPhone, vous allez sans doute créer un <code>UIScrollView</code> afin de permettre à l&#8217;utilisateur de naviguer d&#8217;une image à l&#8217;autre. Pour ce faire, le projet &ldquo;<a href="http://developer.apple.com/iphone/library/samplecode/Scrolling/Listings/MyViewController_m.html#//apple_ref/doc/uid/DTS40008023-MyViewController_m-DontLinkElementID_6">Scrolling</a>&rdquo; fourni en exemple dans la documentation d’Apple constitue un bon point de départ. La logique du scroll est contenue dans  les méthodes <code>viewDidLoad</code> et <code>layoutScrollImages</code> du fichier <code>MyViewController.m</code> mais il vous faudra l’adapter un peu à votre cas d’utilisation.</p>

<p>En revanche, j&#8217;ai constaté que les événements de <code>Touch</code> n&#8217;étaient pas transmis par la <code>UIScrollView</code>. Gênant lorsque l&#8217;on veut ajouter des interactions en plus du scroll.</p>

<p>Pour capturer ces événements, qui ne sont pas transmis par la <code>UIScrollView</code>, la logique voudrait que l&#8217;on créé une classe qui étends la scrollView.</p>

<p>En surchargeant la méthode qui transmet les événements, on obtient ce qui suit:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="c1">// TapScrollView.h</span>
</span><span class='line'><span class="k">@interface</span> <span class="nc">TapScrollView</span> : <span class="nc">UIScrollView</span> <span class="p">{</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="k">@end</span>
</span><span class='line'>
</span><span class='line'><span class="cp">// TapScrollView.m</span>
</span><span class='line'><span class="cp">#import &quot;TapScrollView.h&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="err">@</span><span class="n">implementation</span> <span class="n">TapScrollView</span>
</span><span class='line'><span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nl">touchesBegan:</span><span class="p">(</span><span class="n">NSSet</span> <span class="o">*</span><span class="p">)</span><span class="n">touches</span> <span class="nl">withEvent:</span><span class="p">(</span><span class="n">UIEvent</span> <span class="o">*</span><span class="p">)</span><span class="n">event</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>  <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">delegate</span> <span class="n">tap</span><span class="p">];</span>
</span><span class='line'>  <span class="p">[</span><span class="n">super</span> <span class="nl">touchesBegan:</span><span class="n">touches</span> <span class="nl">withEvent:</span><span class="n">event</span><span class="p">];</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="k">@end</span>
</span></code></pre></td></tr></table></div></figure>


<p>À ce stade, il faut ajouter la méthode <code>tap</code> au protocole qui défini le <code>delegate</code> de notre <code>TapScrollView</code>. On procède en ajoutant la définition d&#8217;un nouveau protocole dans le fichier <code>TapScrollView.h</code>.</p>

<p>Ce protocole va étendre <code>UIScrollViewDelegate</code> afin que l&#8217;on puisse encore recevoir les événements de touch, comme suit:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="c1">// TapScrollView.h</span>
</span><span class='line'><span class="k">@protocol</span> <span class="nc">TapScrollViewDelegate</span> <span class="o">&lt;</span><span class="n">UIScrollViewDelegate</span><span class="o">&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="n">tap</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="k">@end</span>
</span><span class='line'>
</span><span class='line'><span class="k">@interface</span> <span class="nc">TapScrollView</span> : <span class="nc">UIScrollView</span> <span class="p">{</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="k">@end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Si on en reste là, la propriété <code>delegate</code> reste celle défini par <code>UIScrollView</code> car nous ne l&#8217;avons pas surchargée. On peut donc supposer que celle-ci répond au protocole <code>UIScrollViewDelegate</code>, et non pas <code>TapScrollViewDelegate</code> comme on l&#8217;aurai souhaité. Dans ce cas, il suffit de surcharger la propriété <code>delegate</code> dans <code>TapScrollView</code>.
Voilà le code obtenu:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="c1">// TapScrollView.h</span>
</span><span class='line'><span class="k">@protocol</span> <span class="nc">TapScrollViewDelegate</span> <span class="o">&lt;</span><span class="n">UIScrollViewDelegate</span><span class="o">&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="o">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="n">tap</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="k">@end</span>
</span><span class='line'>
</span><span class='line'><span class="k">@interface</span> <span class="nc">TapScrollView</span> : <span class="nc">UIScrollView</span> <span class="p">{</span>
</span><span class='line'>  <span class="kt">id</span><span class="o">&lt;</span><span class="n">TapScrollViewDelegate</span><span class="o">&gt;</span> <span class="n">delegate</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="k">@property</span> <span class="p">(</span><span class="n">nonatomic</span><span class="p">,</span> <span class="n">assign</span><span class="p">)</span> <span class="kt">id</span><span class="o">&lt;</span><span class="n">TapScrollViewDelegate</span><span class="o">&gt;</span> <span class="n">delegate</span><span class="p">;</span>
</span><span class='line'><span class="k">@end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Ok, on approche du but. <code>TapScrollView</code> réponds bien au protocole et la méthode <code>tap</code> sera correctement appelée elle-aussi. En revanche, les méthodes du protocole <code>UIScrollViewDelegate</code> ne sont plus appelés&hellip;
On tourne en rond.
J&#8217;ai mis pas mal de temps à trouver la solution. L&#8217;astuce consiste à surcharger aussi les accès à la propriété <code>delegate</code>, de façon à transmettre les appels dans les deux sens (<code>UIScrollView</code> vers <code>TapScrollView</code> et vice-versa).
Voilà le code final:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="cp">// TapScrollView.m</span>
</span><span class='line'><span class="cp">#import &quot;TapScrollView.h&quot;</span>
</span><span class='line'>
</span><span class='line'><span class="k">@implementation</span> <span class="nc">TapScrollView</span>
</span><span class='line'>
</span><span class='line'><span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">touchesBegan:</span><span class="p">(</span><span class="n">NSSet</span> <span class="o">*</span><span class="p">)</span><span class="nv">touches</span> <span class="nf">withEvent:</span><span class="p">(</span><span class="n">UIEvent</span> <span class="o">*</span><span class="p">)</span><span class="nv">event</span> <span class="p">{</span>
</span><span class='line'>  <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">delegate</span> <span class="n">tap</span><span class="p">];</span>
</span><span class='line'>  <span class="p">[</span><span class="n">super</span> <span class="nl">touchesBegan:</span><span class="n">touches</span> <span class="nl">withEvent:</span><span class="n">event</span><span class="p">];</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="k">-</span> <span class="p">(</span><span class="kt">id</span><span class="o">&lt;</span><span class="n">TapScrollViewDelegate</span><span class="o">&gt;</span><span class="p">)</span> <span class="nf">delegate</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">return</span> <span class="p">(</span><span class="kt">id</span><span class="o">&lt;</span><span class="n">TapScrollViewDelegate</span><span class="o">&gt;</span><span class="p">)</span><span class="n">super</span><span class="p">.</span><span class="n">delegate</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="nf">setDelegate</span> <span class="o">:</span><span class="p">(</span><span class="kt">id</span><span class="o">&lt;</span><span class="n">TapScrollViewDelegate</span><span class="o">&gt;</span><span class="p">)</span> <span class="n">aDelegate</span> <span class="p">{</span>
</span><span class='line'>  <span class="n">super</span><span class="p">.</span><span class="n">delegate</span> <span class="o">=</span> <span class="n">aDelegate</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="k">@end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Vous voilà donc avec une <code>ScrollView</code> qui, en plus de capturer les événements relatifs au scroll, va transmettre les actions de votre choix. Ici, un simple <code>tap</code>, mais le principe reste valable pour des actions plus complexes.</p>

<p>Quelques liens utilies pour finir:</p>

<ul>
<li><a href="http://developer.apple.com/iphone/library/samplecode/Scrolling/Listings/MyViewController_m.html#//apple_ref/doc/uid/DTS40008023-MyViewController_m-DontLinkElementID_6">Scrolling</a> : un sample project de la documentation Apple</li>
<li><a href="http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIScrollViewDelegate_Protocol/Reference/UIScrollViewDelegate.html">UIScrollViewDelegate Protocol Reference</a>: tout ce que fait le protocole associé aux UIScrollView (et ce qu&#8217;il ne fait pas)</li>
<li><a href="http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProtocols.html#//apple_ref/doc/uid/TP30001163-CH15">Protocols</a>: la documentation iPhone sur les protocoles</li>
</ul>

]]></content>
  </entry>
  
</feed>
