Welcome!

Please download (or fork) the course materials if you haven't already

https://github.com/petele/webapp-codelab

  -  

Of course we're using Geolocation!

Who?

+


@

The craze for native apps is a short one and we are already seeing it on the wane.
  • Launched in June, 2011
  • Over 1 million unique users
  • 2.5 times more likely to subscribe
  • Drove digital subscriptions to beyond 250,000
  • In January 2012, Financial Times bought Assanka
  • Simplifying development with the web app as the basis for all platforms

Agenda

Web Application Fundamentals

Checklist for identifying web apps

  • Debug HTML, CSS, JavaScript, Networking & more
  • Live edit and save in Resources
  • Pretty print minified scripts
  • Add break points, watches, etc
  • Console supports $("div")

WReader: Code Lab

Time to play!

  1. Exercise 1

Web Application Architecture

MVC fundamentals

Model View Controllers help to separate the data, from the business layer and the views.

MVC controller
view model

WReader's MVC Architecture: Models

// Ember Object model for entry items
WReader.Item = Em.Object.extend({
  read: false,
  starred: false,
  item_id: null,
  title: null,
  pub_name: null,
  pub_author: null,
  pub_date: new Date(0),
  short_desc: null,
  content: null,
  feed_link: null,
  item_link: null
});

WReader's MVC Architecture: Controller

WReader.dataController = Em.ArrayController.create({
  content: [],

  addItem: function(item) {
    /* a little magic */
  },

  binarySearch: function(value, low, high) {
    /* a little magic */
    return mid;
  },

  itemCount: function() {
    return this.get('length');
  }.property('@each')
});

WReader's MVC Architecture: Views

WReader.EntryItemView = Em.View.extend({
  tagName: 'article',
  contentBinding: 'WReader.selectedItemController.selectedItem',
  classNames: ['well', 'entry'],
  classNameBindings: ['active', 'read', 'prev', 'next'],

  active: function() {
    return true;
  }.property('WReader.selectedItemController.selectedItem'),

  read: function() {
    var read = this.get('content').get('read');
    return read;
  }.property('WReader.itemsController.@each.read')
});

WReader: Code Lab

Time to play!

  1. Exercise 2
  2. Exercise 3
  3. Exercise 4

Getting Data Via Cross Domain Requests

HTTP Request

GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: ...

HTTP Response

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

WReader: Code Lab

Time to play!

  1. Exercise 5

Building Beautiful User Interfaces

Flex Box Model for application layout

.parent-box {
  display: -webkit-box;
  -webkit-box-orient: horizontal;
  overflow: hidden;
}
.box {
  overflow-y: scroll;
  -webkit-box-flex: 1;
}
.box.three {
  -webkit-box-flex: 3;
}
Box 1
1
2
3
4
5
6
Box 2
1
2
3
4
5
6
Box 3
1
2
3
4
5
6

Style from scatch?

Please, please, please - take some time to customize your apps!

WReader: Code Lab

Time to play!

  1. Exercise 6
  2. Exercise 7
  3. Exercise 8

Adding 'Offline' Scenarios

More than offline

Adding 'offline' scenarios means more than just a disconnected user

Tools for building offline scenarios

Application Cache to enable the application

<html manifest="cache.appcache">

Store data locally

window.requestFileSystem(PERSISTENT, 1048576, initFs, fsError);
var idbRequest = window.indexedDB.open('Database Name');
localStorage["key"] = "value";

Track online and offline states

window.addEventListener('online', function(e) {
  // Re-sync data with server.
}, false);

Adding offline to WReader

Create the Lawnchair instance

var store = new Lawnchair({name: 'entries', record: 'entry'},
  function() {});

Add items to the Lawnchair database

store.save(item);

Get all the items from the database

var items = store.all(function(arr) {
  arr.forEach(function(entry) {
    var item = WReader.Item.create(entry);
    WReader.dataController.addItem(item);
  });
});

WReader: Code Lab

Time to play!

  1. Exercise 9
  2. Exercise 10

Improving the user experience

Make it easy to try & use

Use responsive layout for different form factors

Media Queries for Style Sheets

<link rel="stylesheet" media="all" href="/static/css/base.min.css" />
<link rel="stylesheet" media="only screen and (max-width: 800px)"
  href="/static/css/mobile.min.css" />

Testing CSS media queries in JavaScript with window.matchMedia()

if (window.matchMedia('only screen and (max-width: 480px)').matches) {
  // Asynchronously provide experience optimized for phone
} else if (window.matchMedia('only screen and (min-width: 481px) and ' +
                             '(max-width: 1024px)').matches) {
  // Asynchronously provide experience optimized for table or smaller screen
} else {
  // Asynchronously provide full screen experience
}

Allow for deep linking & single page navigation

window.history.pushState(state, title, url);
window.addEventListener('popstate', handlePopState, false);
function handlePopState(event) {
  if (event.state != null) {
    WReader.selectedItemController.select(event.state);
  }
};

Let the user tell you what they want

<input type="text" x-webkit-speech />
function startSearch(event) {
  if (event.target.results.length > 1) {
    var second = event.target.results[1].utterance;
    document.getElementById("second_best").value = second;
  }
  event.target.form.submit();
}

WReader: Code Lab

Time to play!

  1. Exercise 11
  2. Experiment with anything else!

Treat performance like a feature

Top 3 Perf Improvement Tips

  • Minimize the HTTP requests
  • Use a content delivery network
  • Enable caching from the server
  • Stylesheets at the top, scripts at the bottom
  • Minify your JavaScript and CSS
  • More at developer.yahoo.com/performance/rules.html

WReader: Code Lab

Time to play!

  1. Exercise 12

One last thing...

Aim for a great experience, everything else will follow.

Thanks!

Questions?

Slides:
Feedback: