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

  <title><![CDATA[Toura Mulberry]]></title>
  <link href="http://mulberry.toura.com/atom.xml" rel="self"/>
  <link href="http://mulberry.toura.com/"/>
  <updated>2012-02-23T17:22:04-05:00</updated>
  <id>http://mulberry.toura.com/</id>
  <author>
    <name><![CDATA[Toura Dev]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Mulberry at RioJS]]></title>
    <link href="http://mulberry.toura.com/blog/2012/02/21/mulberry-at-riojs/"/>
    <updated>2012-02-21T15:10:00-05:00</updated>
    <id>http://mulberry.toura.com/blog/2012/02/21/mulberry-at-riojs</id>
    <content type="html"><![CDATA[<p>We were all surprised to find that one of our Mulberry friends from Brazil,
<a href="https://twitter.com/#!/nprincigalli">Nuba Princigalli</a>, had presented at
<a href="http://www.riojs.org/">RioJS</a> about Mulberry and Dojo (Mulberry uses Dojo as a foundation)!</p>

<p>His talk was recorded and uploaded to YouTube here: <a href="http://www.youtube.com/watch?v=jC_3G-m_hx8">http://www.youtube.com/watch?v=jC_3G-m_hx8</a></p>

<p>Nuba is working on getting his slides translated into English and once he does,
we&#8217;ll link to them from here. Mulberry&#8217;s march across the world continues!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[0.3 Brings New Tools for Interactive Apps]]></title>
    <link href="http://mulberry.toura.com/blog/2012/01/17/todos-app-with-mulberry/"/>
    <updated>2012-01-17T17:00:00-05:00</updated>
    <id>http://mulberry.toura.com/blog/2012/01/17/todos-app-with-mulberry</id>
    <content type="html"><![CDATA[<p>Dan Imal gave a good <a href="http://mulberry.toura.com/blog/2012/01/11/mulberry-0.3/">overview of the 0.3 release of Mulberry</a> the other
day, but I wanted to follow up by taking a deeper dive into some of the new
features that landed that make it easier to use Mulberry to build all kinds of
apps.  I&#8217;ll be talking about all of this at <a href="http://mulberry.toura.com/upcoming_events/">some upcoming events</a>, but if you can&#8217;t make it
to any of them, hopefully this post will give you good insight into how these
improvements can help you build apps faster using Mulberry.</p>

<p>Probably the easiest way to understand these features is to look at a simple
Todos app. Our app will have a home page that lets you add todo items and view
unfinished ones, and a page that shows completed items; those items, and their
state, will persist on the device until the user deletes them. You can follow
along with the completed app <a href="https://github.com/Toura/mulberry-demos/tree/master/todos">on
GitHub</a>.</p>

<p><img src="http://www.rebeccamurphey.com/i/4f15e41f7437a.jpg" alt="A Mulberry Todos App" /></p>

<p>Once we&#8217;ve scaffolded our app by running <code>mulberry scaffold todos</code>, we know
that we&#8217;ll need a few things:</p>

<ul>
<li>A page definition for the Todos page</li>
<li>A page definition for the Completed page</li>
<li>A store for the todo items</li>
<li>Components for entering todos, listing todos, and working with todos en masse</li>
</ul>


<p>We can add all of those things via the command line:</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>
</pre></td><td class='code'><pre><code class=''><span class='line'>mulberry create page_def todos completed
</span><span class='line'>mulberry create store todos
</span><span class='line'>mulberry create component TodoForm TodoList TodoTools</span></code></pre></td></tr></table></div></figure>


<p>We&#8217;ll also want to specify routes for our two pages.  As of 0.3, we get a new
API method, <code>mulberry.page</code>, that lets us define a data-driven route and skip
the need to create a markdown file for the pgae. Here&#8217;s what our <code>routes.js</code>
file will look like:</p>

<figure class='code'><figcaption><span>javascript/routes.js </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">dojo</span><span class="p">.</span><span class="nx">provide</span><span class="p">(</span><span class="s1">&#39;client.routes&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">mulberry</span><span class="p">.</span><span class="nx">page</span><span class="p">(</span><span class="s1">&#39;/todos&#39;</span><span class="p">,</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">name</span> <span class="o">:</span> <span class="s1">&#39;Todos&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="nx">pageDef</span> <span class="o">:</span> <span class="s1">&#39;todos&#39;</span>
</span><span class='line'><span class="p">},</span> <span class="kc">true</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">mulberry</span><span class="p">.</span><span class="nx">page</span><span class="p">(</span><span class="s1">&#39;/completed&#39;</span><span class="p">,</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">name</span> <span class="o">:</span> <span class="s1">&#39;Completed&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="nx">pageDef</span> <span class="o">:</span> <span class="s1">&#39;completed&#39;</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>


<p>Each of these calls to <code>mulberry.page</code> passes an object that has details about
how to display the page associated with the route, and in each case that object
has a <code>pageDef</code> property. Page definitions spell out how different components
will be laid out for a given page, and what capabilities that page will have.
Here&#8217;s the page definition for the todos page, located at <code>page_defs/todos.yml</code>:</p>

<figure class='code'><figcaption><span>page_defs/todos.yml </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>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class='yaml'><span class='line'><span class="l-Scalar-Plain">todos</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="l-Scalar-Plain">capabilities</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">PageTodos</span>
</span><span class='line'>  <span class="l-Scalar-Plain">screens</span><span class="p-Indicator">:</span>
</span><span class='line'>    <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">index</span>
</span><span class='line'>      <span class="l-Scalar-Plain">regions</span><span class="p-Indicator">:</span>
</span><span class='line'>        <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">className</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">todo-form-container</span>
</span><span class='line'>          <span class="l-Scalar-Plain">components</span><span class="p-Indicator">:</span>
</span><span class='line'>          <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">custom.TodoForm</span>
</span><span class='line'>        <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">scrollable</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">true</span>
</span><span class='line'>          <span class="l-Scalar-Plain">className</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">todo-list-container</span>
</span><span class='line'>          <span class="l-Scalar-Plain">components</span><span class="p-Indicator">:</span>
</span><span class='line'>          <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">custom.TodoList</span>
</span><span class='line'>        <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">className</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">todo-tools-container</span>
</span><span class='line'>          <span class="l-Scalar-Plain">components</span><span class="p-Indicator">:</span>
</span><span class='line'>          <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">custom.TodoTools</span>
</span></code></pre></td></tr></table></div></figure>


<p>The 0.3 release also introduced the concept of &#8220;stores,&#8221; which help us persist
and query data. The default behavior of a store is to persist the data on
device using local storage, though you can override or extend that behavior if
you&#8217;d like. Here&#8217;s our todos store, located at <code>javascript/stores/todos.js</code>:</p>

<figure class='code'><figcaption><span>javascript/stores/todos.js </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>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">dojo</span><span class="p">.</span><span class="nx">provide</span><span class="p">(</span><span class="s1">&#39;client.stores.todos&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">mulberry</span><span class="p">.</span><span class="nx">store</span><span class="p">(</span><span class="s1">&#39;todos&#39;</span><span class="p">,</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">model</span> <span class="o">:</span> <span class="s1">&#39;Todo&#39;</span><span class="p">,</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">finish</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">id</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">invoke</span><span class="p">(</span><span class="nx">id</span><span class="p">,</span> <span class="s1">&#39;finish&#39;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">unfinish</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">id</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">invoke</span><span class="p">(</span><span class="nx">id</span><span class="p">,</span> <span class="s1">&#39;unfinish&#39;</span><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>This creates a store at <code>client.stores.todos</code>; that store will automatically
get methods like <code>add</code>, <code>query</code>, <code>remove</code>, and <code>put</code>, plus the additional
<code>finish</code> and <code>unfinish</code> methods that we&#8217;ve specified in the prototype we
passed. Those last two methods are used to pass messages to individual models.</p>

<p>We also specify a model property, which tells the store to expect that we&#8217;ve
defined a <code>Todo</code> model. We do so in <code>javascript/models/Todo.js</code>, and it looks
like this:</p>

<figure class='code'><figcaption><span>javascript/models/Todo.js </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>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">dojo</span><span class="p">.</span><span class="nx">provide</span><span class="p">(</span><span class="s1">&#39;client.models.Todo&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">mulberry</span><span class="p">.</span><span class="nx">model</span><span class="p">(</span><span class="s1">&#39;Todo&#39;</span><span class="p">,</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">complete</span> <span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">finish</span> <span class="o">:</span> <span class="kd">function</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">set</span><span class="p">(</span><span class="s1">&#39;complete&#39;</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">unfinish</span> <span class="o">:</span> <span class="kd">function</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">set</span><span class="p">(</span><span class="s1">&#39;complete&#39;</span><span class="p">,</span> <span class="kc">false</span><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>Now, we&#8217;re ready to wire up our app&#8217;s todos page. When we generated the page
definition file for the todos page, Mulberry automatically assigned it a
capability called <code>PageTodos</code>; this capability will be responsible for getting
the page set up, and then brokering communication between the components as the
user works with their todo items.</p>

<p>Here&#8217;s what that capability, located at <code>javascript/capabilities/PageTodos.js</code>,
looks like, with some inline comments to make it easier to follow:</p>

<figure class='code'><figcaption><span>javascript/capabilities/PageTodos.js </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>
<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>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">dojo</span><span class="p">.</span><span class="nx">provide</span><span class="p">(</span><span class="s1">&#39;client.capabilities.PageTodos&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">mulberry</span><span class="p">.</span><span class="nx">capability</span><span class="p">(</span><span class="s1">&#39;PageTodos&#39;</span><span class="p">,</span> <span class="p">{</span>
</span><span class='line'>  <span class="cm">/*</span>
</span><span class='line'><span class="cm">   * The capability expects the following components to be present in order for</span>
</span><span class='line'><span class="cm">   * the capability to work.</span>
</span><span class='line'><span class="cm">   */</span>
</span><span class='line'>  <span class="nx">requirements</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'>    <span class="nx">todoList</span> <span class="o">:</span> <span class="s1">&#39;custom.TodoList&#39;</span><span class="p">,</span>
</span><span class='line'>    <span class="nx">todoForm</span> <span class="o">:</span> <span class="s1">&#39;custom.TodoForm&#39;</span><span class="p">,</span>
</span><span class='line'>    <span class="nx">todoTools</span> <span class="o">:</span> <span class="s1">&#39;custom.TodoTools&#39;</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="cm">/*</span>
</span><span class='line'><span class="cm">   * These &quot;listeners&quot; will be set up as part of setting up the page. So, for</span>
</span><span class='line'><span class="cm">   * example, when the TodoForm component instance announces that a user has</span>
</span><span class='line'><span class="cm">   * added a todo (by calling its `onAdd` method), then the capability&#39;s `_add`</span>
</span><span class='line'><span class="cm">   * method will be run.</span>
</span><span class='line'><span class="cm">   */</span>
</span><span class='line'>  <span class="nx">connects</span> <span class="o">:</span> <span class="p">[</span>
</span><span class='line'>    <span class="p">[</span> <span class="s1">&#39;todoForm&#39;</span><span class="p">,</span> <span class="s1">&#39;onAdd&#39;</span><span class="p">,</span> <span class="s1">&#39;_add&#39;</span> <span class="p">],</span>
</span><span class='line'>    <span class="p">[</span> <span class="s1">&#39;todoList&#39;</span><span class="p">,</span> <span class="s1">&#39;onComplete&#39;</span><span class="p">,</span> <span class="s1">&#39;_complete&#39;</span> <span class="p">],</span>
</span><span class='line'>    <span class="p">[</span> <span class="s1">&#39;todoList&#39;</span><span class="p">,</span> <span class="s1">&#39;onDelete&#39;</span><span class="p">,</span> <span class="s1">&#39;_delete&#39;</span> <span class="p">],</span>
</span><span class='line'>    <span class="p">[</span> <span class="s1">&#39;todoTools&#39;</span><span class="p">,</span> <span class="s1">&#39;onCompleteAll&#39;</span><span class="p">,</span> <span class="s1">&#39;_completeAll&#39;</span> <span class="p">]</span>
</span><span class='line'>  <span class="p">],</span>
</span><span class='line'>
</span><span class='line'>  <span class="cm">/*</span>
</span><span class='line'><span class="cm">   * When the page is set up, we&#39;ll grab a reference to the todos store, and</span>
</span><span class='line'><span class="cm">   * then update the list of todos.</span>
</span><span class='line'><span class="cm">   */</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="k">this</span><span class="p">.</span><span class="nx">todos</span> <span class="o">=</span> <span class="nx">client</span><span class="p">.</span><span class="nx">stores</span><span class="p">.</span><span class="nx">todos</span><span class="p">;</span>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">_updateList</span><span class="p">();</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_delete</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">id</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">todos</span><span class="p">.</span><span class="nx">remove</span><span class="p">(</span><span class="nx">id</span><span class="p">);</span>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">_updateList</span><span class="p">();</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_add</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">item</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">todos</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">item</span><span class="p">);</span>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">_updateList</span><span class="p">();</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_complete</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">id</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">todos</span><span class="p">.</span><span class="nx">finish</span><span class="p">(</span><span class="nx">id</span><span class="p">);</span>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">_updateList</span><span class="p">();</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_updateList</span> <span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>    <span class="kd">var</span> <span class="nx">items</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">todos</span><span class="p">.</span><span class="nx">query</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="k">return</span> <span class="o">!</span><span class="nx">item</span><span class="p">.</span><span class="nx">complete</span><span class="p">;</span>
</span><span class='line'>    <span class="p">});</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">todoList</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;todos&#39;</span><span class="p">,</span> <span class="nx">items</span><span class="p">);</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_completeAll</span> <span class="o">:</span> <span class="kd">function</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">todos</span><span class="p">.</span><span class="nx">query</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="k">return</span> <span class="o">!</span><span class="nx">item</span><span class="p">.</span><span class="nx">complete</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}).</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">dojo</span><span class="p">.</span><span class="nx">hitch</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">t</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">t</span><span class="p">.</span><span class="nx">finish</span><span class="p">();</span>
</span><span class='line'>      <span class="k">this</span><span class="p">.</span><span class="nx">todos</span><span class="p">.</span><span class="nx">put</span><span class="p">(</span><span class="nx">t</span><span class="p">);</span>
</span><span class='line'>    <span class="p">}));</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">_updateList</span><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>All that&#8217;s left to do now is to actually make the components do what they need
to do. Components are intentionally &#8220;dumb&#8221; &#8211; their job is to receive data from
an outside source, render that data using a template, and announce user
interaction by calling (often empty) methods. Here, for example, is the
TodoForm component, located at <code>javascript/components/TodoForm.js</code>:</p>

<figure class='code'><figcaption><span>javascript/components/TodoForm.js </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>
<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>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">dojo</span><span class="p">.</span><span class="nx">provide</span><span class="p">(</span><span class="s1">&#39;client.components.TodoForm&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">mulberry</span><span class="p">.</span><span class="nx">component</span><span class="p">(</span><span class="s1">&#39;TodoForm&#39;</span><span class="p">,</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">componentTemplate</span> <span class="o">:</span> <span class="nx">dojo</span><span class="p">.</span><span class="nx">cache</span><span class="p">(</span><span class="s1">&#39;client.components&#39;</span><span class="p">,</span> <span class="s1">&#39;TodoForm/TodoForm.haml&#39;</span><span class="p">),</span>
</span><span class='line'>
</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="k">this</span><span class="p">.</span><span class="nx">connect</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">domNode</span><span class="p">,</span> <span class="s1">&#39;submit&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>      <span class="kd">var</span> <span class="nx">description</span> <span class="o">=</span> <span class="nx">dojo</span><span class="p">.</span><span class="nx">trim</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">descriptionInput</span><span class="p">.</span><span class="nx">value</span><span class="p">),</span>
</span><span class='line'>          <span class="nx">item</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">description</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>      <span class="nx">item</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">description</span> <span class="o">:</span> <span class="nx">description</span> <span class="p">};</span>
</span><span class='line'>      <span class="k">this</span><span class="p">.</span><span class="nx">domNode</span><span class="p">.</span><span class="nx">reset</span><span class="p">();</span>
</span><span class='line'>      <span class="k">this</span><span class="p">.</span><span class="nx">onAdd</span><span class="p">(</span><span class="nx">item</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><span class='line'>  <span class="nx">onAdd</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>


<p>It displays the form (using the template located at
<code>javascript/components/TodoForm/TodoForm.haml</code>), listens for the user to submit
the form, checks to make sure there was some input, and then calls its <code>onAdd</code>
method, which the PageTodos capability has registered its interest in. The
other components are similarly simple.</p>

<p>The Mulberry framework was born out of our experience with making content-rich apps,
but we&#8217;re hard at work making it easy to use Mulberry to build all kinds of
apps &#8211; pretty much anything that might manifest itself as a single-page
JavaScript application. We hope you&#8217;ll <a href="http://mulberry.toura.com/download/">download the 0.3 version</a>, <a href="https://github.com/Toura/mulberry-demos/tree/master/todos">take the Todos demo for a spin</a>, and let us know how we&#8217;re doing.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Announcing Mulberry 0.3: Even Easier Customization]]></title>
    <link href="http://mulberry.toura.com/blog/2012/01/11/mulberry-0.3/"/>
    <updated>2012-01-11T15:39:00-05:00</updated>
    <id>http://mulberry.toura.com/blog/2012/01/11/mulberry-0.3</id>
    <content type="html"><![CDATA[<p>It&#8217;s a new year, and with that comes a new release of <a href="http://mulberry.toura.com/download/">Mulberry</a>! As with the previous release, our goal is to make it easier to get started with Mulberry, and once you&#8217;re up and running, we want to make it easier to customize your app. Some of the highlights:</p>

<ul>
<li><p><strong>Installer scripts for OSX and Windows (Ubuntu is on the way):</strong>
Getting started with Mulberry used to require downloading and installing a lot of other dependencies. While we haven&#8217;t been able to <em>completely</em> automate this, we have made it a whole lot easier. Find the script for your OS in <a href="https://github.com/Toura/mulberry/tree/master/install"><code>/install/&lt;os&gt;/</code></a>, follow the instructions in the README, then run the installer script, and you&#8217;ll be up and running.</p></li>
<li><p><strong>Customizable default theme:</strong>
The &#8220;default&#8221; theme used to be difficult to customize. If you decided to use it you were basically stuck with a <em>lot</em> of gray. Now all the colors and fonts can now be changed from the <code>themes/default/_settings.scss</code> file, so you don&#8217;t have to dig through alot of code or create a completely new theme just to change some colors. The icons are now customizable as well. Simply replace any of the images in <code>themes/default/icons</code> with whatever you want.</p></li>
<li><p><strong>Templates are now &#8220;page_defs&#8221;:</strong>
In 0.2, we had &#8220;templates&#8221; which were yaml files where you&#8217;d define the layout for a page in columns and rows. But these templates also had a lot of non-presentational information, which tended to be confusing. So we changed things so that page layout is handled in CSS (as it should be), and page_defs got a little simpler. We added a few Sass mixins to help with page layout. <a href="http://mulberry.toura.com/docs/page-definitions.html">Read more about page_defs.</a></p></li>
<li><p><strong>New and Improved Code Generators:</strong>
It was already possible to create new routes, but now you can run <code>mulberry create route '/foo/:bar'</code> and it will generate the necessary code and add it to <code>routes.js</code>, which you can then customize. Running <code>mulberry create page_def</code> will now generate a boilerplate scss file and add <code>import</code> directive.</p></li>
</ul>


<p>In addition to all the new stuff, we&#8217;ve got a bug of bugfixes, improved development server stability, and more complete test coverage. For the full story, <a href="http://mulberry.toura.com/docs/0.3-release-notes.html">read the full release notes</a>.</p>

<p>As always, follow us at <a href="http://twitter.com/touradev">@touradev</a> to keep up to date on the latest developments, or get help in the <a href="https://groups.google.com/forum/#!forum/toura-mulberry">Google Group</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Announcing Mulberry 0.2: More Features for Easy Customization]]></title>
    <link href="http://mulberry.toura.com/blog/2011/11/29/mulberry-0.2/"/>
    <updated>2011-11-29T09:21:00-05:00</updated>
    <id>http://mulberry.toura.com/blog/2011/11/29/mulberry-0.2</id>
    <content type="html"><![CDATA[<p><a href="http://mulberry.toura.com/download/">Mulberry 0.2</a> is out today, with several new features to make it
even easier to customize your apps:</p>

<ul>
<li>In Mulberry 0.1, you had to be very verbose when overriding the default
styles. As of 0.2, when an app is scaffolded, the default theme is copied
into the app, where it can be modified directly. To pull any upstream changes
to the built-in themes, we added <code>mulberry update_themes</code> to the CLI.</li>
<li>A new <code>toura.app.Phonegap.registerAPI</code> method lets you create your own
wrappers that make it easier to do development in a browser. <a href="http://mulberry.toura.com/blog/2011/11/16/browser-based-development/">Read more about browser-based development with Mulberry.</a></li>
<li>We beefed up <code>mulberry create component</code>; it now automatically
creates a stub .scss file for the component, and adds an @import statement to
your theme&#8217;s <code>base.scss</code> file.</li>
<li>Now when you add pages to your sitemap, you can just run <code>mulberry scaffold</code>
inside your Mulberry project to create them all at once, rather than having
to remember which ones to create yourself. <a href="http://mulberry.toura.com/docs/Command-Line-Interface.html">Read about all the command line options.</a></li>
<li>It&#8217;s often necessary to repopulate a component or a piece of a component when
it gets new data or its state changes. Mulberry 0.2 introduces the <code>populate</code>
and <code>populateElement</code> methods on components to make this easier &#8211; just pass
it a template and the data for the template, and it handles the rest. <a href="http://mulberry.toura.com/docs/Creating-Custom-Components.html">Read
more about custom components.</a></li>
<li>Lots of people were asking us about how to create custom routes; it was
possible before, but it&#8217;s easier in Mulberry 0.2: we added mulberry.route and
mulberry.routes for defining custom routes. <a href="http://mulberry.toura.com/docs/Javascript-API.html">Read more about defining routes and other aspects of the JavaScript API.</a></li>
</ul>


<p>We also landed a few other features, several bug fixes, some improvements to
the command line, and lots of docs. Read the full release notes
<a href="http://mulberry.toura.com/docs/0.2-Release-Notes.html">here</a>.</p>

<p>As always, you can find us on Twitter <a href="http://twitter.com/touradev">@touradev</a>,
visit us in the #touramulberry channel on irc.freenode.net, or drop us a note
at <a href="mailto:mulberry@toura.com">mulberry@toura.com</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Browser-based development: Fewer builds, better tools]]></title>
    <link href="http://mulberry.toura.com/blog/2011/11/16/browser-based-development/"/>
    <updated>2011-11-16T10:13:00-05:00</updated>
    <id>http://mulberry.toura.com/blog/2011/11/16/browser-based-development</id>
    <content type="html"><![CDATA[<p>I&#8217;m in London after attending the <a href="http://fullfrontal.org">Full Frontal JavaScript Conference</a>,
put on by the fantastic Remy and Julieanne
Sharp in lovely, foggy, chilly Brighton. It was a great chance to meet a ton of
developers from whom I&#8217;m usually separated by an ocean, and of course I spent
a lot of time talking to those developers about Mulberry.</p>

<p>One of the things that seemed to especially get their attention was how
Mulberry lets you do day-to-day development in a browser, avoiding
time-consuming compilations most of the time.  Setting up browser-based
development on a PhoneGap project can be tricky, and development on device or
in a simulator harkens back to the bad old days of IE6.</p>

<p>If you want to develop content-rich native apps that include a non-trivial
amount of JavaScript, you&#8217;re going to want the comforts of a modern browser.
We&#8217;ve solved this in Mulberry in a few different ways.</p>

<h2>Wrappers for PhoneGap APIs</h2>

<p>PhoneGap and PhoneGap plugin APIs don&#8217;t work when you&#8217;re running your code in
a desktop browser &#8211; indeed, if you try to call them, you&#8217;ll usually get an
error that blocks execution of any code that comes next, which can make
debugging a serious pain.</p>

<p>Mulberry solves this by providing an interface for creating wrappers for
PhoneGap APIs and plugins; it also has a few built-in wrappers. For example,
here&#8217;s a wrapper for the notification API:</p>

<pre><code>toura.app.PhoneGap.notification = function(pg, device) {
  return {
    alert : function(msg) {
      if (pg) {
        navigator.notification.alert(msg);
      } else {
        alert(msg);
      }
    }
  }
};
</code></pre>

<p>We set up the built-in wrappers using <code>toura.app.PhoneGap.registerAPI(apiName,
module)</code>, which you can use to create your own wrappers, too. Each wrapper is
simply a function that gets two arguments: a boolean indicating whether
PhoneGap is present, and a device object with information about the device
that&#8217;s being targeted. Wrappers return an object with methods that become
available at <code>toura.app.Phonegap[apiName]</code>.</p>

<p>In the example of the notification API above, once the API is registered we can
call the function <code>toura.app.PhoneGap.notification.alert</code> from anywhere in our
code, and it will &#8220;just work&#8221; whether we&#8217;re developing in a browser or on
device. <a href="https://github.com/Toura/mulberry/blob/master/toura_app/javascript/toura/app/Phonegap/browser.js">Mulberry&#8217;s wrapper around the ChildBrowser plugin</a>
is a more complex example &#8211; it simulates ChildBrowser&#8217;s behavior in a desktop
browser, and handles differences in the Android and iOS implementations behind
the scenes, so opening a new URL in your app requires the exact same code
regardless of the environment.</p>

<h2>Rapid Switching Between Device-Specific Code Paths</h2>

<p>Even though most of your JavaScript can be the same from one device to the
next, sometimes you&#8217;ll need to branch your code to deal with a quirk of
a particular OS. Working on the different code paths can be a challenge when
you&#8217;re developing in the browser, because you need a way to tell your code
which environment you want to be simulating.</p>

<p>Mulberry comes with a built-in server, and the server is set up so that
switching between configurations is as simple as changing the URL. You can work
on the iPad version of your app at http://localhost:3001/ios/tablet/, and then
switch to working on the Android phone version of your app at
http://localhost:3001/android/phone/. All of your code will automatically get
access to information about the &#8220;device&#8221; you&#8217;re working on by calling
<code>toura.app.Config.get('device')</code>, and of course any changes you make to your
code or content will be visible as soon as you reload the page.</p>

<h2>Remote Debugging</h2>

<p>While browser-based development is great, nothing compares to testing your app
on a device, but when you do, you&#8217;re suddenly in a world where <code>console.log</code>
and <code>alert</code> feel like your only friends.</p>

<p>Every development build you make with Mulberry has a button in the lower
right-hand corner of the screen marked &#8220;weinre&#8221;. If you haven&#8217;t seen
<a href="http://phonegap.github.com/weinre/">weinre</a> before, prepare for your life to
be changed, because it lets you debug an app that&#8217;s running on your device from
the comfort of your computer, using the Webkit developer tools you know and
love.</p>

<p>As of this week, Toura is hosting its own version of weinre for Mulberry
developers, and it&#8217;s connected directly to the weinre button in Mulberry apps.
<a href="http://mulberry.toura.com/blog/2011/11/14/hosted-weinre/">Read more about it here</a>.</p>

<h2>More to Come</h2>

<p>The Toura Dev team doesn&#8217;t just work on Mulberry &#8211; we&#8217;ve also shipped more
than 100 apps that use the underlying Mulberry technology, which means we&#8217;re
always trying to make our <em>own</em> experience of the toolkit a pleasant one.
Pretty much every developer-friendly feature we&#8217;ve added so far was added
because we&#8217;re developers, too, and we hate when our tools get in our way. That
said, we know tools can always be better &#8211; if there&#8217;s something we could do to
make your life easier when developing mobile apps, we hope you&#8217;ll let us know.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Weinre: Sane, hosted debugging tools for your Mulberry apps]]></title>
    <link href="http://mulberry.toura.com/blog/2011/11/14/hosted-weinre/"/>
    <updated>2011-11-14T22:40:00-05:00</updated>
    <id>http://mulberry.toura.com/blog/2011/11/14/hosted-weinre</id>
    <content type="html"><![CDATA[<p>At Toura, we perform the vast majority of our day-to-day development in our
desktop WebKit browsers - Chrome and Safari. Although the desktop browsers
are a very close approximation to the mobile browsers, there&#8217;s no substitute
for actually performing final QA and fit &amp; finish checks on the mobile
browsers themselves followed by a final sanity check with a compiled application.</p>

<p>What happens, though, if you find a display bug on device browser that you
don&#8217;t see on the desktop? What about a JavaScript error in the WebView? How would
you go about debugging that? Enter: <a href="http://phonegap.github.com/weinre/">Weinre</a>.</p>

<p>Weinre, written by <a href="https://github.com/pmuellr/weinre">Patrick Mueller</a>, provides
a client/server environment to present you with a familiar &#8220;web inspector&#8221;-like
experience on apps running on mobile device browsers and webviews.</p>

<p>Installing and configuring Weinre is simple enough and you can accomplish this
by following the instructions at the Weinre website. OR, instead of going through
all of that and keeping Weinre running (it requires a local process) and poking
holes in your firewall, you can use our free hosted Weinre service!</p>

<p>To use the hosted Weinre service:</p>

<ol>
<li><p>Boot any app in development mode via:</p>

<p> a. <code>mulberry serve</code> and point your device browser to your local Mulberry server OR</p>

<p> b. <code>mulberry test</code> and run the app in your device simulator/emulator</p></li>
<li><p>In the lower right hand corner, tap the &#8220;Weinre&#8221; button <img src="http://mulberry.toura.com/images/weinre_button.png" alt="weinre button" /></p></li>
<li>Go to <a href="http://api.toura.com/weinre">Toura Weinre</a> and enter the code displayed at the top of the page</li>
<li>Click the provided link and debug away; that&#8217;s it!
<img src="http://mulberry.toura.com/images/weinre_screen.png" width="600px" /></li>
</ol>


<p>Now you can develop on your local browser and perform final checks on your
iOS and Android devices. If you encounter a bug, you can quickly and easily
hook a remote web inspector to your page. Access the Javascript console, edit
HTML, and more - right on the device!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[An Opinionated Framework, Focused on Reuse]]></title>
    <link href="http://mulberry.toura.com/blog/2011/11/03/an-opinionated-framework-focused-on-reuse/"/>
    <updated>2011-11-03T20:31:00-04:00</updated>
    <id>http://mulberry.toura.com/blog/2011/11/03/an-opinionated-framework-focused-on-reuse</id>
    <content type="html"><![CDATA[<p>One of the questions that’s come up several times in talking to other
developers about Mulberry is this: How is Mulberry any different from all of
the other mobile app development frameworks that are out there?</p>

<p>At Toura, we’ve been developing and using the technology behind Mulberry for
more than a year, creating apps for clients that range from museums to major
media companies. Because our core business is centered on the rapid creation of
content-rich apps, we focused our development efforts on reuse from the start.
That focus led us to an <a href="http://stackoverflow.com/questions/802050/what-is-opinionated-software/802093#802093">opinionated</a>
framework, one that makes some assumptions about the kinds of applications
developers will build with it and about how those applications will be built.</p>

<p>Being opinionated results in a framework that dramatically reduces the effort
that’s required to develop an app, and subsequent similar apps are easier
still, because it’s vastly more likely that functionality developed for one app
can be reused down the road.</p>

<p>While many JavaScript developers have come to think of DOM nodes as their
building blocks, in Mulberry, the fundamental building block of an app is
a component. The functionality of an app is described by how components,
arranged on a page, display the app’s content and interact with each other.</p>

<p>Mulberry comes with lots of <a href="https://github.com/Toura/mulberry/wiki/Components">components</a>
and <a href="https://github.com/Toura/mulberry/wiki/Page-Templates">page layouts</a> that use those components
— making it easy to create content-rich applications that incorporate images,
videos, map locations, and more — and it also provides simple APIs for creating
custom components and adding them to the underlying framework. Custom and
built-in components can be arranged into pages, and those pages can be enabled
with pre-defined or custom interactions between components. Components neatly
encapsulate their DOM structure, behavior, and state, and expose predictable
interfaces that make them easy to integrate into applications. Mulberry apps
aren’t about wiring up buttons and lists and grids — they’re about defining the
interactions between far richer components, and then customizing the
presentation layer to create a unique experience.</p>

<p>For Toura, all of this means that creating a particular kind of app has become
a reliably repeatable process; more importantly, adding custom functionality to
individual apps is also a reliably repeatable process <em>whose results can be
readily reused across multiple applications and platforms</em>. Units of
functionality — a Twitter feed component, say, or a component that displays
a location’s name, address, phone number, web site, and map — take the place of
DOM nodes as the building blocks for applications, and they can be mixed and
matched and connected in any combination that makes sense.</p>

<p>We’ve placed a lot of value on being able to define new functionality, creating
APIs like <code>mulberry.component</code> and <code>mulberry.capability</code> that let us set up new
components and interactions without impacting existing functionality. We’ve
also been diligent about keeping our presentation layer very loosely coupled
with the behavior and data layers. All of this means that we can dramatically
alter the “look and feel” of an app while leaving the underlying functionality
largely intact, and create new experiences with shockingly little code.</p>

<p>Mulberry embraces a view of how we should be building apps that moves away from
some of the DOM-centric habits that JavaScript developers have learned over the
last few years — habits that have presented challenges as those same developers
transition from building websites to building full-fledged apps. By rethinking
the nature of apps to emphasize patterns that facilitate smart reuse, Mulberry
makes app development and customization a simple, repeatable, and scalable
endeavor.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Creating Custom Functionality with Mulberry]]></title>
    <link href="http://mulberry.toura.com/blog/2011/10/30/custom-functionality/"/>
    <updated>2011-10-30T14:10:00-04:00</updated>
    <id>http://mulberry.toura.com/blog/2011/10/30/custom-functionality</id>
    <content type="html"><![CDATA[<p>Out of the box, Mulberry&#8217;s great at making simple content-driven apps, but one
of the things we heard loud and clear during the closed alpha was that
developers want to use Mulberry to make more complex, data-driven apps as well.
No worries &#8211; Mulberry has that covered too.</p>

<p>In this post, we&#8217;ll take a look at what&#8217;s involved in creating a Twitter app &#8211;
Twitter is the new &#8220;hello world&#8221;, after all. In the process, we&#8217;ll learn about
creating <strong>custom components, templates, interactions, and routes</strong>. You can
follow along by <a href="http://mulberry.toura.com/download">downloading Mulberry</a> and
heading to the <code>demos/twitter</code> directory.</p>

<p>To start, we&#8217;ll create a new Mulberry project named &#8220;twitter&#8221;. Once you&#8217;ve
downloaded Mulberry and added the location of the binary to your <code>$PATH</code>, you
can run the following command from any location on your filesystem where you
have write permission:</p>

<figure class='code'><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=''><span class='line'>mulberry scaffold twitter</span></code></pre></td></tr></table></div></figure>


<p>This will create a new directory named <code>twitter</code>; you&#8217;ll want to <code>cd twitter</code>
so you&#8217;re inside the project as you follow along.</p>

<h2>An Overview of the App</h2>

<p>The app we&#8217;re building will have two pages:</p>

<ul>
<li>A home page that shows a list of people, and allows users to choose from the
list; choosing a person from the list will show a map of the city where that
person lives, their latest tweet, and their Twitter bio with a link to see
all of their tweets.</li>
<li>A secondary page that shows a person&#8217;s 10 latest tweets.</li>
</ul>


<h2>Creating the Data</h2>

<p>Since this is a data-driven app, the first thing we need to do is provide it
with some seed data to drive it. We&#8217;ll run this command from the root of our
Mulberry project:</p>

<figure class='code'><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=''><span class='line'>mulberry create_data users</span></code></pre></td></tr></table></div></figure>


<p>This creates a data file named <code>users.yml</code> in the <code>assets/data/</code> directory
inside your project. It&#8217;s an empty file, so we&#8217;ll add some information about
our users to the file, in the <a href="http://yaml.org/">YAML</a> format:</p>

<figure class='code'><figcaption><span>demos/twitter/assets/data/users.yml </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>
<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>
</pre></td><td class='code'><pre><code class='yaml'><span class='line'><span class="l-Scalar-Plain">type</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">users</span>
</span><span class='line'><span class="l-Scalar-Plain">users</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Paul Irish</span>
</span><span class='line'>    <span class="l-Scalar-Plain">twitter</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">paul_irish</span>
</span><span class='line'>    <span class="l-Scalar-Plain">location</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="l-Scalar-Plain">lat</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">37.7749295</span>
</span><span class='line'>      <span class="l-Scalar-Plain">lng</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">-122.4194155</span>
</span><span class='line'>    <span class="l-Scalar-Plain">image</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">https://twimg0-a.akamaihd.net/profile_images/1326877605/greenavatar_crop_normal.jpg</span>
</span><span class='line'>  <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Alex Sexton</span>
</span><span class='line'>    <span class="l-Scalar-Plain">twitter</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">SlexAxton</span>
</span><span class='line'>    <span class="l-Scalar-Plain">location</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="l-Scalar-Plain">lat</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">30.267153</span>
</span><span class='line'>      <span class="l-Scalar-Plain">lng</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">-97.7430608</span>
</span><span class='line'>    <span class="l-Scalar-Plain">image</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">https://twimg0-a.akamaihd.net/profile_images/1384837213/SlexAxtonAvatar_normal.jpg</span>
</span><span class='line'>  <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Adam Sontag</span>
</span><span class='line'>    <span class="l-Scalar-Plain">twitter</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">ajpiano</span>
</span><span class='line'>    <span class="l-Scalar-Plain">location</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="l-Scalar-Plain">lat</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">40.7143528</span>
</span><span class='line'>      <span class="l-Scalar-Plain">lng</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">-74.0059731</span>
</span><span class='line'>    <span class="l-Scalar-Plain">image</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">https://twimg0-a.akamaihd.net/profile_images/1396366703/twitpic_pool_normal.png</span>
</span><span class='line'>  <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Rebecca Murphey</span>
</span><span class='line'>    <span class="l-Scalar-Plain">twitter</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">rmurphey</span>
</span><span class='line'>    <span class="l-Scalar-Plain">location</span><span class="p-Indicator">:</span>
</span><span class='line'>      <span class="l-Scalar-Plain">lat</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">35.9940329</span>
</span><span class='line'>      <span class="l-Scalar-Plain">lng</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">-78.898619</span>
</span><span class='line'>    <span class="l-Scalar-Plain">image</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">https://twimg0-a.akamaihd.net/profile_images/1447727594/IMG_8534_normal.jpg</span>
</span></code></pre></td></tr></table></div></figure>


<p>Note that there are two pieces to this data: a <code>type</code> property, and a <code>users</code>
array that contains the actual data. The <code>type</code> property will help us locate
the data later; its presence means that a page can have easy access to many
different kinds of data.</p>

<p>Now that we&#8217;ve added this data to our project, we can move on to setting up the
home page.</p>

<h2>Creating the Home Page</h2>

<p>When you scaffold a Mulberry app, a home page is automatically created in your
project&#8217;s <code>pages/</code> directory. By default, this page uses the <code>home-tablet</code> and
<code>home-phone</code> templates, but we&#8217;ll want to change that, as well as tell the page
that it should have access to the data we created. Here&#8217;s what our <code>home.md</code>
file looks like when we&#8217;re done:</p>

<figure class='code'><figcaption><span>demos/twitter/pages/home.md  </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>
</pre></td><td class='code'><pre><code class='yaml'><span class='line'><span class="nn">---</span>
</span><span class='line'><span class="l-Scalar-Plain">title</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Home</span>
</span><span class='line'><span class="l-Scalar-Plain">template</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">twitter</span>
</span><span class='line'><span class="l-Scalar-Plain">data</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">users.yml</span>
</span><span class='line'><span class="nn">---</span>
</span></code></pre></td></tr></table></div></figure>


<p>Next, let&#8217;s take a closer look at the mockup of the home page. There are four
distinct pieces of functionality on the page, and in Mulberry we refer to these
pieces of functionality as &#8220;components&#8221;:</p>

<p><img src="http://mulberry.toura.com/images/twitter-demo-components.png" alt="Breaking the home page into components" /></p>

<p>Mulberry has a GoogleMap component built in, but we&#8217;ll need to create custom
components for the rest:</p>

<figure class='code'><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=''><span class='line'>mulberry create_component LatestTweet UserInfo UserList</span></code></pre></td></tr></table></div></figure>


<p>Running this command creates skeleton files in the project&#8217;s
<code>javascript/components</code> directory for each of the components, and adds
<code>dojo.require</code> statements to the project&#8217;s <code>javascript/base.js</code> file so that
the components will automatically be available to the rest of your code.</p>

<h3>Writing Our Custom Components</h3>

<p>Components in Mulberry have three jobs:</p>

<ul>
<li>receiving data from an external source</li>
<li>rendering that data</li>
<li>announcing user interaction with the component, if applicable</li>
</ul>


<p>Mulberry automatically provides every component on a page with the information
associated with that page; it puts that information into a component&#8217;s
<code>baseObj</code> property. This means that our components will automatically get
access to the user data we associated with the home page.</p>

<p>Because we remembered to add a <code>type</code> property to that data, fetching the array
of people in the <code>users.yml</code> file from inside a component is easy:</p>

<figure class='code'> <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">baseObj</span><span class="p">.</span><span class="nx">getData</span><span class="p">(</span><span class="s1">&#39;users&#39;</span><span class="p">).</span><span class="nx">users</span>
</span></code></pre></td></tr></table></div></figure>


<p>Let&#8217;s look at the UserList component as an example. Its job is to receive data
(in this case, a list of people); render that data (in this case, as an
unordered list), and then announce user interaction (in this case, when a user
selects a person from the list).</p>

<p>Here&#8217;s what our UserList component ends up looking like:</p>

<figure class='code'><figcaption><span>demos/twitter/javascript/components/UserList.js </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>
<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>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">dojo</span><span class="p">.</span><span class="nx">provide</span><span class="p">(</span><span class="s1">&#39;client.components.UserList&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">mulberry</span><span class="p">.</span><span class="nx">component</span><span class="p">(</span><span class="s1">&#39;UserList&#39;</span><span class="p">,</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">componentTemplate</span> <span class="o">:</span> <span class="nx">dojo</span><span class="p">.</span><span class="nx">cache</span><span class="p">(</span><span class="s1">&#39;client.components&#39;</span><span class="p">,</span> <span class="s1">&#39;UserList/UserList.haml&#39;</span><span class="p">),</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">prep</span> <span class="o">:</span> <span class="kd">function</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">users</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">baseObj</span><span class="p">.</span><span class="nx">getData</span><span class="p">(</span><span class="s1">&#39;users&#39;</span><span class="p">).</span><span class="nx">users</span><span class="p">;</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</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="k">this</span><span class="p">.</span><span class="nx">connect</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">domNode</span><span class="p">,</span> <span class="s1">&#39;click&#39;</span><span class="p">,</span> <span class="s1">&#39;_handleClick&#39;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_handleClick</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="kd">var</span> <span class="nx">target</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">while</span> <span class="p">(</span><span class="nx">target</span> <span class="o">!==</span> <span class="k">this</span><span class="p">.</span><span class="nx">domNode</span> <span class="o">&amp;&amp;</span> <span class="nx">target</span><span class="p">.</span><span class="nx">parentNode</span> <span class="o">!==</span> <span class="k">this</span><span class="p">.</span><span class="nx">domNode</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">target</span> <span class="o">=</span> <span class="nx">target</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="nx">target</span><span class="p">.</span><span class="nx">nodeName</span><span class="p">.</span><span class="nx">toLowerCase</span><span class="p">()</span> <span class="o">!==</span> <span class="s1">&#39;li&#39;</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="nx">dojo</span><span class="p">.</span><span class="nx">hasClass</span><span class="p">(</span><span class="nx">target</span><span class="p">,</span> <span class="s1">&#39;selected&#39;</span><span class="p">))</span> <span class="p">{</span> <span class="k">return</span><span class="p">;</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">query</span><span class="p">(</span><span class="s1">&#39;.selected&#39;</span><span class="p">).</span><span class="nx">removeClass</span><span class="p">(</span><span class="s1">&#39;selected&#39;</span><span class="p">);</span>
</span><span class='line'>    <span class="nx">dojo</span><span class="p">.</span><span class="nx">addClass</span><span class="p">(</span><span class="nx">target</span><span class="p">,</span> <span class="s1">&#39;selected&#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">onSelect</span><span class="p">(</span><span class="nx">dojo</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="nx">target</span><span class="p">,</span> <span class="s1">&#39;data-twitter-username&#39;</span><span class="p">));</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">onSelect</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">username</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="c1">// stub for connection</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>The <code>prep</code> and <code>init</code> methods are called automatically; the <code>prep</code> method is
called before the component&#8217;s DOM structure is created, and the <code>init</code> method
is called after its DOM structure is created.</p>

<p>In the case of the UserList component, we use the <code>prep</code> method to prepare the
data associated with the page. Then, in the <code>init</code> method, we tell the component to
listen for user interaction &#8211; in this case, a click on the component&#8217;s root
DOM node. A click on that node will result in the component&#8217;s <code>_handleClick</code>
method being called; if <code>_handleClick</code> decides that the click was on a list
item, then it will call the component&#8217;s <code>onSelect</code> method, passing it the
username of the person who was selected.</p>

<p>Note that the <code>onSelect</code> method doesn&#8217;t <em>do</em> anything. Later in this post,
we&#8217;ll see how we can &#8220;connect&#8221; to that method from another part of our code,
but it&#8217;s important to understand this key concept in Mulberry apps: components
should <em>never</em> directly affect other pieces of the application. Their job is to
receive, render, and announce &#8211; nothing more.</p>

<p>Some of the components in our app will need to receive data once they&#8217;re
already on the page. We can use &#8220;setter methods&#8221; to make this possible. For
example, the UserInfo component should be able to display a different user
without having to re-create the component from scratch. To allow this, we
create a <code>_setUserAttr</code> method on the UserInfo component</p>

<figure class='code'><figcaption><span>demos/twitter/javascript/components/UserInfo.js </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">dojo</span><span class="p">.</span><span class="nx">provide</span><span class="p">(</span><span class="s1">&#39;client.components.UserInfo&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">mulberry</span><span class="p">.</span><span class="nx">component</span><span class="p">(</span><span class="s1">&#39;UserInfo&#39;</span><span class="p">,</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">componentTemplate</span> <span class="o">:</span> <span class="nx">dojo</span><span class="p">.</span><span class="nx">cache</span><span class="p">(</span><span class="s1">&#39;client.components&#39;</span><span class="p">,</span> <span class="s1">&#39;UserInfo/UserInfo.haml&#39;</span><span class="p">),</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_setUserAttr</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">user</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">nameNode</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">user</span><span class="p">.</span><span class="nx">name</span><span class="p">;</span>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">twitterLinkNode</span><span class="p">.</span><span class="nx">href</span> <span class="o">=</span> <span class="s1">&#39;#/twitter/&#39;</span> <span class="o">+</span> <span class="nx">user</span><span class="p">.</span><span class="nx">twitter</span><span class="p">;</span>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">bioNode</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">user</span><span class="p">.</span><span class="nx">bio</span> <span class="o">||</span> <span class="s1">&#39;&#39;</span><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>This means that any code that has access to an instance of the UserInfo
component can do the following:</p>

<figure class='code'> <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="nx">myUserInfoInstance</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;user&#39;</span><span class="p">,</span> <span class="nx">userObject</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>Whenever the <code>set</code> method is called on a component instance, the component
looks for a setter method that matches the property name passed as the first
argument to <code>set</code>. If it finds a corresponding method, it calls it; if it does
not find a corresponding method, then it simply sets the value of a property on
the component instance.</p>

<p>(This functionality is based entirely on Dojo&#8217;s <code>dijit._WidgetBase</code> &#8211;
<a href="http://jsfiddle.net/rmurphey/76C76/">see how it works here</a>.)</p>

<p>In the UserInfo component, we refer to several properties that do not seem to
be defined anywhere: <code>this.nameNode</code>, <code>this.bioNode</code>, etc. These properties get
set automatically by the component&#8217;s template using &#8220;attach points.&#8221; Here&#8217;s the
UserInfo template, located at <code>javascript/components/UserInfo/UserInfo.haml</code>:</p>

<figure class='code'><figcaption><span>demos/twitter/javascript/components/UserInfo/UserInfo.haml </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>
</pre></td><td class='code'><pre><code class='haml'><span class='line'><span class="nc">.component.user-info</span>
</span><span class='line'>  <span class="nt">%h1</span><span class="p">{</span> <span class="n">dojoAttachPoint</span> <span class="p">:</span> <span class="s1">&#39;nameNode&#39;</span> <span class="p">}</span>
</span><span class='line'>  <span class="nt">%p</span><span class="nc">.bio</span><span class="p">{</span> <span class="n">dojoAttachPoint</span> <span class="p">:</span> <span class="s1">&#39;bioNode&#39;</span> <span class="p">}</span>
</span><span class='line'>  <span class="nt">%p</span>
</span><span class='line'>    <span class="nt">%a</span><span class="p">{</span> <span class="n">dojoAttachPoint</span> <span class="p">:</span> <span class="s1">&#39;twitterLinkNode&#39;</span> <span class="p">}</span> View all tweets
</span></code></pre></td></tr></table></div></figure>


<p>Using attach points greatly reduces the need for querying the DOM; you can
create an attach point on any node, and then refer to that node from inside
your component by using the attach point&#8217;s name:</p>

<figure class='code'> <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">myAttachPointName</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Creating the Page Template</h2>

<p>Once we&#8217;ve created our components (see the demo in the repo for details on how
the rest of the components are set up), it&#8217;s time to assemble them into a page
template. Earlier, we told our home page to use the <code>twitter</code> template; now,
we&#8217;ll ask Mulberry to create that template for us:</p>

<figure class='code'><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=''><span class='line'>mulberry create_template twitter</span></code></pre></td></tr></table></div></figure>


<p>This creates a file at <code>templates/twitter.yml</code> that contains the skeleton of a
template. We&#8217;ll fill it out with the details about how we want our page to
look:</p>

<figure class='code'><figcaption><span>demos/twitter/templates/twitter.yml </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>
<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>
</pre></td><td class='code'><pre><code class='yaml'><span class='line'><span class="l-Scalar-Plain">twitter</span><span class="p-Indicator">:</span>
</span><span class='line'>  <span class="l-Scalar-Plain">screens</span><span class="p-Indicator">:</span>
</span><span class='line'>    <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">index</span>
</span><span class='line'>      <span class="l-Scalar-Plain">regions</span><span class="p-Indicator">:</span>
</span><span class='line'>        <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">size</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">fixed</span>
</span><span class='line'>          <span class="l-Scalar-Plain">components</span><span class="p-Indicator">:</span>
</span><span class='line'>            <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">custom.LatestTweet</span>
</span><span class='line'>        <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">size</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">fixed</span>
</span><span class='line'>          <span class="l-Scalar-Plain">components</span><span class="p-Indicator">:</span>
</span><span class='line'>            <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">GoogleMap</span>
</span><span class='line'>        <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">containerType</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">column</span>
</span><span class='line'>          <span class="l-Scalar-Plain">regions</span><span class="p-Indicator">:</span>
</span><span class='line'>            <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">className</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">user-list</span>
</span><span class='line'>              <span class="l-Scalar-Plain">size</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">fixed</span>
</span><span class='line'>              <span class="l-Scalar-Plain">components</span><span class="p-Indicator">:</span>
</span><span class='line'>              <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">custom.UserList</span>
</span><span class='line'>            <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">className</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">user-info</span>
</span><span class='line'>              <span class="l-Scalar-Plain">size</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">flex</span>
</span><span class='line'>              <span class="l-Scalar-Plain">components</span><span class="p-Indicator">:</span>
</span><span class='line'>              <span class="p-Indicator">-</span> <span class="l-Scalar-Plain">custom.UserInfo</span>
</span></code></pre></td></tr></table></div></figure>


<p>Again, we use YAML here, this time to say that we want a page template named
&#8220;twitter&#8221; that has one screen named &#8220;index&#8221; (page templates can have more than
one screen, with the intention that only one screen is visible at any time, but
the details of that are beyond the scope of this post). That screen is broken
down into regions:</p>

<ul>
<li>The first region will be a fixed height, and it will contain our custom
LatestTweet component.</li>
<li>The second region will be a fixed height, and it will contain the built-in
GoogleMap component.</li>
<li>The third region will be split into two sub-regions, which will be displayed
as columns (that is, side-by-side). The first sub-region will contain the
custom UserList component, and will get the class name <code>user-list</code> so that we
can target it with CSS; the second sub-region will contain the custom
UserInfo component, and will get the class name <code>user-info</code>. The sub-region
that contains UserList will be fixed-width; the UserInfo sub-region will flex
to fill the remaining size.</li>
</ul>


<p>At this point, we should be able to serve our application using the Mulberry
development server:</p>

<figure class='code'><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=''><span class='line'>mulberry serve</span></code></pre></td></tr></table></div></figure>


<p>If you navigate to the <a href="http://localhost:3001/ios/tablet/#/home">home page</a>,
you&#8217;ll see that all of the components display in the proper arrangement, but
not much is happening yet. We need some data.</p>

<h2>Loading the External Data</h2>

<p>We want to create an interface to the Twitter data we&#8217;ll need in order to
populate our pages. For our home page, we&#8217;ll need a user&#8217;s latest tweet, as
well as their bio; for our secondary page, we&#8217;ll need a users 10 most recent
tweets. We can start by asking Mulberry to create a skeleton file for our
datasource:</p>

<figure class='code'><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=''><span class='line'>mulberry create_datasource Twitter</span></code></pre></td></tr></table></div></figure>


<p>This creates a file at <code>javascript/data/Twitter.js</code>, and adds a <code>dojo.require</code>
statement to our project&#8217;s <code>javascript/base.js</code> file. There&#8217;s not much here
(we&#8217;re working on a more elaborate API for remote data sources), so for now
it&#8217;s up to us to fill in the details:</p>

<figure class='code'><figcaption><span>demos/twitter/javascript/data/Twitter.js </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>
<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>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">dojo</span><span class="p">.</span><span class="nx">provide</span><span class="p">(</span><span class="s1">&#39;client.data.Twitter&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">mulberry</span><span class="p">.</span><span class="nx">datasource</span><span class="p">(</span><span class="s1">&#39;Twitter&#39;</span><span class="p">,</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">getLatest</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">username</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">_get</span><span class="p">(</span><span class="nx">username</span><span class="p">,</span> <span class="mi">1</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span><span class="nx">dojo</span><span class="p">.</span><span class="nx">hitch</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s1">&#39;_getLatest&#39;</span><span class="p">));</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">getAll</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">username</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">_get</span><span class="p">(</span><span class="nx">username</span><span class="p">,</span> <span class="mi">10</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span><span class="nx">dojo</span><span class="p">.</span><span class="nx">hitch</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s1">&#39;_getAll&#39;</span><span class="p">));</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_get</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">username</span><span class="p">,</span> <span class="nx">count</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="kd">var</span> <span class="nx">url</span> <span class="o">=</span> <span class="s1">&#39;http://twitter.com/status/user_timeline/${username}.json?count=&#39;</span> <span class="o">+</span> <span class="p">(</span><span class="nx">count</span> <span class="o">||</span> <span class="mi">10</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="nx">dojo</span><span class="p">.</span><span class="nx">io</span><span class="p">.</span><span class="nx">script</span><span class="p">.</span><span class="nx">get</span><span class="p">({</span>
</span><span class='line'>      <span class="nx">url</span> <span class="o">:</span> <span class="nx">toura</span><span class="p">.</span><span class="nx">tmpl</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="p">{</span> <span class="nx">username</span> <span class="o">:</span> <span class="nx">username</span> <span class="p">}),</span>
</span><span class='line'>      <span class="nx">callbackParamName</span> <span class="o">:</span> <span class="s1">&#39;callback&#39;</span>
</span><span class='line'>    <span class="p">});</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_getLatest</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 class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">data</span> <span class="o">||</span> <span class="o">!</span><span class="nx">data</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="kc">false</span><span class="p">;</span> <span class="p">}</span>
</span><span class='line'>    <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">_formatTweet</span><span class="p">(</span><span class="nx">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_getAll</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 class="k">return</span> <span class="nx">dojo</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">data</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">_formatTweet</span><span class="p">);</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_formatTweet</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">tweet</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">text</span> <span class="o">:</span> <span class="nx">tweet</span><span class="p">.</span><span class="nx">text</span><span class="p">,</span>
</span><span class='line'>      <span class="nx">date</span> <span class="o">:</span> <span class="nx">dojo</span><span class="p">.</span><span class="nx">date</span><span class="p">.</span><span class="nx">locale</span><span class="p">.</span><span class="nx">format</span><span class="p">(</span><span class="k">new</span> <span class="nb">Date</span><span class="p">(</span><span class="nx">tweet</span><span class="p">.</span><span class="nx">created_at</span><span class="p">)),</span>
</span><span class='line'>      <span class="nx">bio</span> <span class="o">:</span> <span class="nx">tweet</span><span class="p">.</span><span class="nx">user</span><span class="p">.</span><span class="nx">description</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>There&#8217;s not much that&#8217;s interesting here, except that this code takes advantage
of the fact that all async methods in Dojo &#8211; such as <code>dojo.io.script.get</code> &#8211;
return a &#8220;promise.&#8221; Promises are incredibly useful structures that greatly
facilitate the development of asynchronous processes. A promise is, quite
literally, a promise: a promise object is a guarantee that when the async operation
is completed, the promise will execute any function that was passed to it via
the promise&#8217;s <code>then</code> method.</p>

<p>In this example, the <code>getLatest</code> method receives the promise returned by the
<code>_get</code> method, then attaches a callback to it using the <code>then</code> method of the
promise. The <code>then</code> method ultimately returns another promise, which is resolved
with the return value of the <code>_getLatest</code> method. This means that another piece
of code with access to an instance of the Twitter datasource can do this:</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>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">myTwitterInstance</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;rmurphey&#39;</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">tweets</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;these are the tweets&#39;</span><span class="p">,</span> <span class="nx">tweets</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>


<p>The code inside the function will run once the tweets have been fetched.</p>

<h2>Connecting the Components</h2>

<p>We have our page template, we have our components, and we have our data &#8211; now
it&#8217;s time to glue it all together. Mulberry uses &#8220;capabilities&#8221; to broker
communication between components and datasources. We&#8217;ll ask Mulberry to create
a capability that we&#8217;ll use to encapsulate the functionality of our Twitter
page:</p>

<figure class='code'><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=''><span class='line'>mulberry create_capability Twitter</span></code></pre></td></tr></table></div></figure>


<p>This creates a skeleton file at <code>javascript/capabilities/Twitter.js</code>, and
adds a <code>dojo.require</code> statement to our project&#8217;s <code>javascript/base.js</code> file.</p>

<p>Capabilities have a <code>requirements</code> object that indicates the components that it
expects to be present. It assigns those components names that will be used to
reference the components inside the capability. Capabilities also have a
<code>connects</code> array, which contains zero or more arrays that describe how the
capability will react when a certain method on a component is called. Remember
how we had an empty <code>onSelect</code> method in our UserList component? Our Twitter
capability connects to it, and describes how the rest of the page should react.
Finally, capabilities have an <code>init</code> method, where you can do initial setup of
components that might be page-dependent.</p>

<p>Here&#8217;s the Twitter capability in its entirety; you can see how all of the
pieces we&#8217;ve talked about above come together:</p>

<figure class='code'><figcaption><span>demos/twitter/javascript/capabilities/Twitter.js </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>
<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>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">dojo</span><span class="p">.</span><span class="nx">provide</span><span class="p">(</span><span class="s1">&#39;client.capabilities.Twitter&#39;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="nx">mulberry</span><span class="p">.</span><span class="nx">capability</span><span class="p">(</span><span class="s1">&#39;Twitter&#39;</span><span class="p">,</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">requirements</span> <span class="o">:</span> <span class="p">{</span>
</span><span class='line'>    <span class="nx">latestTweet</span>   <span class="o">:</span> <span class="s1">&#39;custom.LatestTweet&#39;</span><span class="p">,</span>
</span><span class='line'>    <span class="nx">map</span>           <span class="o">:</span> <span class="s1">&#39;GoogleMap&#39;</span><span class="p">,</span>
</span><span class='line'>    <span class="nx">userList</span>      <span class="o">:</span> <span class="s1">&#39;custom.UserList&#39;</span><span class="p">,</span>
</span><span class='line'>    <span class="nx">userInfo</span>      <span class="o">:</span> <span class="s1">&#39;custom.UserInfo&#39;</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">connects</span> <span class="o">:</span> <span class="p">[</span>
</span><span class='line'>    <span class="p">[</span> <span class="s1">&#39;userList&#39;</span><span class="p">,</span> <span class="s1">&#39;onSelect&#39;</span><span class="p">,</span> <span class="s1">&#39;_onUserSelect&#39;</span> <span class="p">],</span>
</span><span class='line'>    <span class="p">[</span> <span class="s1">&#39;map&#39;</span><span class="p">,</span> <span class="s1">&#39;onMapBuilt&#39;</span><span class="p">,</span> <span class="s1">&#39;_onMapBuilt&#39;</span> <span class="p">]</span>
</span><span class='line'>  <span class="p">],</span>
</span><span class='line'>
</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="k">this</span><span class="p">.</span><span class="nx">users</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">baseObj</span><span class="p">.</span><span class="nx">getData</span><span class="p">(</span><span class="s1">&#39;users&#39;</span><span class="p">).</span><span class="nx">users</span><span class="p">;</span>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">twitter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">client</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">Twitter</span><span class="p">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">var</span> <span class="nx">user</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">users</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">userInfo</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;user&#39;</span><span class="p">,</span> <span class="nx">user</span><span class="p">);</span>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">_loadUser</span><span class="p">(</span><span class="nx">user</span><span class="p">);</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_onMapBuilt</span> <span class="o">:</span> <span class="kd">function</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">map</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;center&#39;</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">users</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">location</span><span class="p">);</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_onUserSelect</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">username</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="kd">var</span> <span class="nx">user</span> <span class="o">=</span> <span class="nx">dojo</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">users</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">u</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="k">return</span> <span class="nx">u</span><span class="p">.</span><span class="nx">twitter</span> <span class="o">===</span> <span class="nx">username</span>
</span><span class='line'>    <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">_loadUser</span><span class="p">(</span><span class="nx">user</span><span class="p">);</span>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">map</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;center&#39;</span><span class="p">,</span> <span class="nx">user</span><span class="p">.</span><span class="nx">location</span><span class="p">);</span>
</span><span class='line'>  <span class="p">},</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">_loadUser</span> <span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">user</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="kd">var</span> <span class="nx">req</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">twitter</span><span class="p">.</span><span class="nx">getLatest</span><span class="p">(</span><span class="nx">user</span><span class="p">.</span><span class="nx">twitter</span><span class="p">);</span>
</span><span class='line'>    <span class="nx">req</span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">dojo</span><span class="p">.</span><span class="nx">hitch</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">latestTweet</span><span class="p">,</span> <span class="s1">&#39;set&#39;</span><span class="p">,</span> <span class="s1">&#39;tweet&#39;</span><span class="p">));</span>
</span><span class='line'>    <span class="nx">req</span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">dojo</span><span class="p">.</span><span class="nx">hitch</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">tweet</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">user</span><span class="p">.</span><span class="nx">bio</span> <span class="o">=</span> <span class="nx">tweet</span><span class="p">.</span><span class="nx">bio</span><span class="p">;</span>
</span><span class='line'>      <span class="k">this</span><span class="p">.</span><span class="nx">userInfo</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s1">&#39;user&#39;</span><span class="p">,</span> <span class="nx">user</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>


<h2>Adding a Custom Route for the User Tweets Page</h2>

<p>Our last task before our Twitter app is complete is to create the secondary
page, which shows a specific person&#8217;s recent tweets. We already know how to set
up a page template and a new component, and how to fetch the Twitter data using
the datasource we created, but how do we get the page to figure out which
person&#8217;s Tweets to load?</p>

<p>For the sake of this discussion, let&#8217;s assume that we&#8217;ve created another page
template named <code>user</code>, and that the page template includes a custom component
named <code>Tweets</code>. (You can see this page template and the custom component in the
demo in the repo.)</p>

<p>In the UserInfo component, we indicated that we want to access the page by
visiting <code>#/twitter/&lt;username&gt;</code>. We need to define a custom route that will run
when a user navigates to this kind of page; the route will need to capture the
username from the URL&#8217;s hash, and then get the proper data to the components on
the page. We can add the following to our project&#8217;s <code>javascript/base.js</code>:</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>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">dojo</span><span class="p">.</span><span class="nx">subscribe</span><span class="p">(</span><span class="s1">&#39;/routes/loaded&#39;</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">mulberry</span><span class="p">.</span><span class="nx">app</span><span class="p">.</span><span class="nx">Router</span><span class="p">.</span><span class="nx">registerRoute</span><span class="p">(</span><span class="s1">&#39;/twitter/:username&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">params</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="kd">var</span> <span class="nx">twitter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">client</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">Twitter</span><span class="p">(),</span>
</span><span class='line'>        <span class="nx">page</span> <span class="o">=</span> <span class="nx">mulberry</span><span class="p">.</span><span class="nx">app</span><span class="p">.</span><span class="nx">PageFactory</span><span class="p">.</span><span class="nx">createPage</span><span class="p">({</span>
</span><span class='line'>          <span class="nx">pageController</span> <span class="o">:</span> <span class="s1">&#39;user&#39;</span><span class="p">,</span>
</span><span class='line'>          <span class="nx">tweets</span> <span class="o">:</span> <span class="nx">twitter</span><span class="p">.</span><span class="nx">getAll</span><span class="p">(</span><span class="nx">params</span><span class="p">.</span><span class="nx">username</span><span class="p">),</span>
</span><span class='line'>          <span class="nx">name</span> <span class="o">:</span> <span class="nx">params</span><span class="p">.</span><span class="nx">username</span>
</span><span class='line'>        <span class="p">});</span>
</span><span class='line'>
</span><span class='line'>    <span class="nx">mulberry</span><span class="p">.</span><span class="nx">app</span><span class="p">.</span><span class="nx">UI</span><span class="p">.</span><span class="nx">showPage</span><span class="p">(</span><span class="nx">page</span><span class="p">);</span>
</span><span class='line'>  <span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>


<p>This code tells the Mulberry router to be on the lookout for a URL hash that looks
like <code>/twitter/:username</code>. When the router sees this hash, it should run the
provided function. The provided function receives a <code>params</code> object, which
contains any parameters that were included in the hash. So, in this case, our
<code>params</code> object would have a <code>username</code> property, containing whichever username
was in the URL hash.</p>

<p>Inside the function, we create an instance of our Twitter datasource, and then
we ask the Mulberry PageFactory to create a page for us by passing it an
object. This object will be available to all components on the page; it also
<em>must</em> have a <code>pageController</code> property, which the PageFactory will use to
determine which page template to use in creating the page.</p>

<p>The object that we pass to the PageFactory&#8217;s <code>createPage</code> method also has a
<code>tweets</code> property, and here we see the power of promises again. We use the
<code>tweets</code> property to pass the promise that&#8217;s returned by the Twitter
datasource; by doing this, we allow the Tweets component to receive data
<em>without interacting directly with the datasource</em>. The Tweets component simply
attaches a callback to the promise using the promise&#8217;s <code>then</code> method. When the
promise resolves, it provides an array of tweets to any callbacks that were
attached; the Tweets component uses that array to populate itself.</p>

<h2>Conclusion</h2>

<p>Mulberry&#8217;s built-in components and page templates are focused on facilitating
the rapid creation of static content apps, but the underlying patterns, tools,
and architecture provide powerful tools for building all kinds of apps. If you
build something interesting, we hope you&#8217;ll <a href="mailto:mulberry@toura.com">let us know</a>!</p>
]]></content>
  </entry>
  
</feed>
