Building a Todo app for Firefox OS, part 1

This is the first part out of two in a tutorial series where we will build a Todo app for Firefox OS from scratch. I assume you have some understanding of HTML5, CSS3, JavaScript, jQuery/Zepto, and Backbone.js. In this part we will handcraft a properly structured and semantic UI of a Todo app using best practices for designing UIs for mobile.

The source for the Todo app is available on GitHub.

Setting Up the Environment

We will use volo as our package manager and build tool.

Step 1

First you need to install Node.js because volo depends on it. Windows and Mac users can download it from here. But for Linux users, I recommend you use the package manager: instructions for installation using package manager on different distros.

Step 2

Install volo using the following command.

npm install -g volo

Make sure you use `sudo` before above command in *nix environment.

Step 3

Create a blank project fos-todo-app using `volo create` command.

volo create fos-todo-app

This will create a folder fos-todo-app and copy required volo project files from GitHub.

Remember we will work only with the files in fos-todo-app/www directory. If you have never worked with volo before, [Streamline your Process with Volo](http://net.tutsplus.com/tutorials/javascript-ajax/streamline-your-process-with-volo/) is a recommended read.

Step 4

Make sure you have the latest stable version of Firefox installed. Then [install the Firefox OS simulator add-on](https://addons.mozilla.org/en-US/firefox/addon/firefox-os-simulator/). At the end of this article we will test UI of our app in this simulator.

Step 5

Get the [MozTT font](https://github.com/mozilla-b2g/moztt/tree/master/MozTT) and install it. MozTT is the font used in Firefox OS. It’s an optional step but it’s better to install this font on your system so you can get consistent look and feel in the Firefox OS Simulator and the real phone.

Todo View

The first UI that we will build will show a title in the header, Add/Delete buttons in the footer and a todo list. This view will be used for viewing, editing, mark as complete, and deleting tasks.

Todo View - Firefox OS

Add role="application" attribute to the `body` element and write following HTML for the Todo View.

<section id="view-todos" role="region">
  <header>
    <h1>Todos</h1>
  </header>
 
  <article class="view-content">
    <ul class="todo-list reset-list" role="list">
      <li role="listitem">
        <label>
          <input type="checkbox">
          <span>My task 1</span>
        </label>
        <input type="text" aria-hidden="true">
      </li>
      <li role="listitem">
        <label>
          <input type="checkbox" checked>
          <span>My task 2</span>
        </label>
        <input type="text" aria-hidden="true">
      </li>
    </ul>
  </article>
 
  <footer>
    <menu role="toolbar">
      <button role="menuitem" class="btn-add"><span>Add</span></button>
      <button role="menuitem" class="btn-del" disabled><span>Delete</span></button>
    </menu>
  </footer>
</section><!--end view-todos-->

Each view is assigned a role="region". Within the view, you can have header, footer and any container element having the view-content class which will contain the contents of the view.

In the above view’s content, we have ul[role=list] which contains tasks entered by user. For testing purposes, I added two dummy tasks so you can understand each list item’s (`li[role=listitem]`) structure. Within each list item we have a label element containing a <input type="checkbox"> and a span element containing the text of task. The second element in the list item contains a <input type="text"> element which is initially hidden using attribute aria-hidden="true".

Note: Of course it’s not magic. We will write CSS for all these attributes. Check out ARIA and Progressive Enhancement if you are new to WAI-ARIA.

The purpose of placing the label in the list item is to display each task’s text and input[type=text] (which is initially hidden) will be used to edit that text. Each task will be entered in edit mode when user the doubleTap on it. Similarly, tasks are “marked as completed” when user singleTap on it.

In the footer we have menu[role=toolbar] containing Add/Delete buttons. Later using CSS for these buttons, we will display a svg icon in background and hide an inner span in it.

Add View

The second and final view in our app will be used to add tasks to the todo list.

Add View

In this view we have a textbox for entering a task’s text, and a insert contact link will be used to add the contact number using Web Activities. Here’s the HTML for Add View.

<section id="view-add" role="region">
  <header>
    <h1>[+] Todo</h1>
  </header>
 
  <section class="view-content">
    <div class="wrapper">
      <menu class="options">
        <ul class="reset-list" role="list">
          <li role="listitem"><a href="#"><label for="task">[Insert Contact]</label></a></li>
        </ul>
      </menu>
 
      <form aria-owns="btn-add-done">
        <input type="text" name="task" id="task" required>
      </form>
    </div>
  </section>
 
  <footer>
    <menu role="toolbar">
      <button id="btn-add-done" role="menuitem" class="btn-done" disabled><span>Done</span></button>
      <button role="menuitem" class="btn-del"><span>Cancel</span></button>
    </menu>
  </footer>
</section><!--end view-add-->

Note that the contents in section.view-content is wrapped using div.wrapper so we can limit its max-width and right align menu.options.

Second thing to note here is the aria-owns attribute on form element. This attribute relates to the form with btn-add-done.

Element Styles

Let’s write the CSS for the HTML elements. An explanation is given in comments above each selector.

/* Stretch vertically */
html, body { height: 100%; }
 
body {
  background: radial-gradient(ellipse at center, rgba(231,76,60,1) 0%,rgba(192,57,43,1) 100%);
  color: #fff;
  font-family: MozTT, sans-serif;
 
  /* Reset base size */
  font-size: 16px;
 
  /* Set font size relative to base size */
  /* Check <a href="http://snook.ca/archives/html_and_css/font-size-with-rem">this</a> article on rem usage */
  font-size: 1.4rem;
 
  font-weight: 300;
 
  /* Remove spacing */
  margin: 0;
}
 
h1, h2, h3, h4, h5, h6 { font-weight: 300; }
 
h1 { font-size: 3rem; }
 
a {
  color: #FFA49E;
  text-decoration: none;
  text-shadow: 0px 1px 1px rgba(0,0,0,.3);
}
a:hover { color: #fff; }
 
input, button, select, textarea {
  border-radius: 0;
  box-shadow: none;
}
input[type=text], textarea, select {
  border: none;
  font-family: MozTT, sans-serif;
  font-size: 1.3rem;
  font-weight: 300;
  padding: .7rem .8rem;
}

Module Styles

View Module

/* All views have region role so selecting them with attribute selector  */
[role=region] {
  background: radial-gradient(ellipse at center, rgba(231,76,60,1) 0%,rgba(192,57,43,1) 100%);
 
  /* Stretch both vertically/horizontally */
  top: 0; right: 0; bottom: 0; left: 0;
 
  position: fixed;
  overflow-x: hidden;
}
[role=region] > header {
  margin: .5rem 0 1rem 0;
  text-align: center;
}
[role=region] > header > h1 {
  margin: 0;
  text-shadow: 0px 1px 1px rgba(0,0,0,.4);
}
[role=region] > .view-content {
  margin: 0 1rem 4rem 1rem;
}
[role=region] > footer {
  background: rgba(0,0,0,.2);
  right: 0; bottom: 0; left: 0;
  position: fixed;
  text-align: center;
}
[role=region] > footer > menu[role=toolbar] {
  margin: 0;
  padding: 0;
}

Toolbar Module

menu[role=toolbar] > [role=menuitem] {
  border: none;
  width: 3.5rem;
  height: 3.5rem;
}
menu[role=toolbar] > [role=menuitem] > span {
  display: none;
}
menu[role=toolbar] > [role=menuitem]:disabled {
  opacity: .2;
}
menu[role=toolbar] > [role=menuitem]:hover {
  background-color: rgba(255,255,255,.1);
}
menu[role=toolbar] > .btn-done {
  background: url(../img/check.svg) no-repeat center center;
}
menu[role=toolbar] > .btn-add {
  background: url(../img/add.svg) no-repeat center center;
}
menu[role=toolbar] > .btn-del {
  background: url(../img/del.svg) no-repeat center center;
}

Todo List Module

.todo-list > li {
  border-bottom: 1px solid rgba(255,255,255,.1);
}
.todo-list label {
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
  display: block;
  padding: 1rem;
}
.todo-list > li:last-child,
.todo-list > li:last-child > label {
  border-bottom: none;
}
.todo-list label > span {
  transition: all .5s;
}
 
/***
  This selector is interesting. It creates a line-through and
  decrease opacity of text in span when checkbox is checked
***/
.todo-list label > input[type=checkbox]:checked + span {
  text-decoration: line-through;
  opacity: .4;
}

Utility Styles

.reset-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
[aria-hidden=true] {
  display: none;
}

Animations

Following are a few animation effects that we will use to animate our views. Although we will use Zepto.js which on run-time generates CSS3 animations using JavaScript, I prefer to write my own animations using CSS3 and make use of it by applying/removing CSS classes on DOM elements.

Zepto is a minimalist JavaScript library for modern browsers with a largely jQuery-compatible API. If you use jQuery, you already know how to use Zepto. ? zeptojs.com

Check out the How to use CSS Animations tutorial for understanding CSS3 Animations better.

.slide-up-in {
  animation-name: slide-up-in;
  animation-duration: .6s;
  transform: translateY(0%);
  opacity: 1;
}
@keyframes slide-up-in {
  0% { transform: translateY(30%); opacity: 0; }
  100% { transform: translateY(0%); opacity: 1; }
}
 
.slide-down-out {
  animation-name: slide-down-out;
  animation-duration: .6s;
  transform: translateY(30%);
  opacity: 0;
}
@keyframes slide-down-out {
  0% { transform: translateY(0%); opacity: 1; }
  100% { transform: translateY(30%); opacity: 0; }
}

Testing in Firefox OS Simulator

Firefox OS Simulator

You can pretty easily test the UI we have developed using the Firefox OS Simulator. All you need is a manifest.webapp file in root directory (fos-todo-app/www). Add the following json in it.

{
  "version": "0.1",
  "name": "Todos",
  "description": "Awesome todo app by iFadey",
  "launch_path": "/index.html",
  "icons": {
    "16": "/img/icons/icon-16.png",
    "48": "/img/icons/icon-48.png",
    "128": "/img/icons/icon-128.png"
  },
  "developer": {
    "name": "Fawad Hassan",
    "url": "http://ifadey.com"
  },
  "installs_allowed_from": ["*"],
  "appcache_path": "/cache.manifest",
  "default_locale": "en"
}

Currently I haven’t added an app icon but don’t worry about it. Firefox OS adds a default app icon if it doesn’t find one mentioned in the manifest file. Now open the simulator tab from Tools > Web Developer > Firefox OS Simulator. Then click Add Directory button and select the manifest file from our app directory. This will add our app in the simulator.

End of part 1

Now you have gotten started with the Todo app and have gotten going with a few easy steps. In next part we will add life in our app using JavaScript (Backbone/Zepto). We will create Todo model, collection, and views and for the sake of simplicity, we will only store our todo collection in IndexedDB. We will also make use of Web Activities to inject contact number in text of todo task.

View full post on Mozilla Hacks – the Web developer blog

Tagged on: , , ,

Leave a Reply