SlideShare a Scribd company logo
Create A Mobile Web App
          with
     Sencha Touch
       @ jamespearce
Single device            Multi device
Sedentary user            Mobile user
                                 *


Declarative               Imperative
Thin client               Thick client
Documents                Applications

         * or supine, or sedentary, or passive, or...
A badge for all these ways
   the web is changing
HTML5 is a new version of HTML4,
 XHTML1, and DOM Level 2 HTML
 addressing many of the issues of
 those specifications while at the
  same time enhancing (X)HTML
to more adequately address Web
          applications.
                       - WHATWG Wiki
What is an app?
Consumption vs Creation
      Linkability
    User Experience
     Architecture
WebFont        Video      Audio     Graphics
Device Access
  Camera                   CSS Styling & Layout                Network
  Location                                                      HTTP
                                  JavaScript
  Contacts                                                      AJAX

    SMS                        Semantic HTML                   Events

 Orientation                                                   Sockets
                File Systems      Workers &
                                                  Cross-App
    Gyro         Databases         Parallel                     SSL
                                                  Messaging
                App Caches        Processing



        (all the elements of a modern application platform)
Create a mobile web app with Sencha Touch
Create a mobile web app with Sencha Touch
Introducing
Sencha Touch
A JavaScript framework
       for building
    rich mobile apps
  with web standards
http://sencha.com/touch
Components

    Lists
Theming
Forms
Scrolling
Touch Events
Data access & MVC
Charts
Kitchen Sink




http://sencha.com/x/5e
Hello World
http://sencha.com/x/d5
Create a mobile web app with Sencha Touch
<!DOCTYPE	
  html>
<html>
	
  	
  <head>
	
  	
  
	
  	
  	
  	
  <title>Hello	
  World</title>

	
  	
  	
  	
  <script	
  src="lib/touch/sencha-­‐touch.js"></script>
	
  	
  	
  	
  <script	
  src="app/app.js"></script>
	
  	
  	
  	
  
	
  	
  	
  	
  <link	
  href="lib/touch/resources/css/sencha-­‐touch.css"
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  rel="stylesheet"	
  type="text/css"	
  />
	
  	
  
	
  	
  </head>
	
  	
  <body></body>
</html>
new	
  Ext.Application({

	
  	
  	
  	
  launch:	
  function()	
  {

	
  	
  	
  	
  	
  	
  	
  	
  new	
  Ext.Panel({
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  fullscreen:	
  true,
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  dockedItems:	
  [{xtype:'toolbar',	
  title:'My	
  First	
  App'}],
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  layout:	
  'fit',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  styleHtmlContent:	
  true,
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  html:	
  '<h2>Hello	
  World!</h2>I	
  did	
  it!'
	
  	
  	
  	
  	
  	
  	
  	
  });

	
  	
  	
  	
  }

});
Create a mobile web app with Sencha Touch
Lists
var	
  list	
  =	
  new	
  Ext.List({
	
  	
  	
  	
  store:	
  store,
	
  	
  	
  	
  itemTpl:	
  '{firstName}	
  {lastName}',
	
  	
  	
  	
  grouped:	
  true,
	
  	
  	
  	
  indexBar:	
  true
});
Nested Lists
var	
  list	
  =	
  new	
  Ext.NestedList({
	
  	
  	
  	
  store:	
  store,
	
  	
  	
  	
  displayField:	
  'name',
	
  	
  	
  	
  title:	
  'My	
  List',
	
  	
  	
  	
  updateTitleText:	
  true,
	
  	
  	
  	
  getDetailCard:
	
  	
  	
  	
  	
  	
  	
  	
  function(record,	
  parent)	
  {..}
});
Carousels
var	
  carousel	
  =	
  new	
  Ext.Carousel({
	
  	
  	
  	
  direction:	
  'horizontal',
	
  	
  	
  	
  indicator:	
  true,
	
  	
  	
  	
  items:	
  [
	
  	
  	
  	
  	
  	
  	
  	
  ..
	
  	
  	
  	
  ]
});
Sheets
var	
  sheet	
  =	
  new	
  Ext.ActionSheet({
	
  	
  	
  	
  items:	
  [
	
  	
  	
  	
  	
  	
  	
  	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  text:	
  'Delete	
  draft',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ui:	
  'decline'
	
  	
  	
  	
  	
  	
  	
  	
  },	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  text:	
  'Save	
  draft'
	
  	
  	
  	
  	
  	
  	
  	
  },	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  text:	
  'Cancel',
	
  	
  	
  	
  	
  	
  	
  	
  }
	
  	
  	
  	
  ]
});

sheet.show();
Common patterns
      1
var	
  list	
  =	
  new	
  Ext.List({
	
  	
  	
  	
  store:	
  store,
	
  	
  	
  	
  itemTpl:	
  '{firstName}	
  {lastName}',
	
  	
  	
  	
  grouped:	
  true,
	
  	
  	
  	
  indexBar:	
  true
});


var	
  panel	
  =	
  new	
  Ext.Panel({
	
  	
  	
  	
  fullscreen:	
  true,
	
  	
  	
  	
  layout:	
  'fit',
	
  	
  	
  	
  items:	
  [list]
});
Common patterns
      2
var	
  panel	
  =	
  new	
  Ext.Panel({
	
  	
  	
  	
  fullscreen:	
  true,
	
  	
  	
  	
  layout:	
  'fit',
	
  	
  	
  	
  items:	
  [{
	
  	
  	
  	
  	
  	
  	
  	
  xtype:	
  'list',
	
  	
  	
  	
  	
  	
  	
  	
  store:	
  store,
	
  	
  	
  	
  	
  	
  	
  	
  itemTpl:	
  '{firstName}	
  {lastName}',
	
  	
  	
  	
  	
  	
  	
  	
  grouped:	
  true,
	
  	
  	
  	
  	
  	
  	
  	
  indexBar:	
  true
	
  	
  	
  	
  }]
});
A more complex app
Pre-requisites
                Sencha Touch SDK:
        http://sencha.com/products/touch/

              Yelp developer API key:
  http://www.yelp.com/developers/getting_started/
                   api_overview

              Install Sass and Compass:
        http://sass-lang.com/download.html
         http://compass-style.org/install/
The Valley App




http://senchalearn.github.com/valley
       http://sencha.com/x/dr
https://github.com/
 senchalearn/valley
Development sequence
1 Structure the app   5 Detail page

2 Layout the UI       6 Add a map

3 Model the data      7 More data

4 Load the list       8 Customize theme
1 Structure the app
index.html

<!doctype	
  html>
<html>
	
  	
  	
  	
  <head>
	
  	
  	
  	
  	
  	
  	
  	
  <title>Valley	
  Guide</title>
	
  	
  	
  	
  </head>
                <body></body>
</html>
index.html

<script	
  src="lib/touch/sencha-­‐touch.js"></script>

<script	
  src="app/yelp.js"></script>
<script	
  src="app/app.js"></script>



<link	
  href="lib/touch/resources/css/sencha-­‐touch.css"	
  
	
  	
  	
  	
  	
  	
  rel="stylesheet"	
  type="text/css"	
  />
app.js
va	
  =	
  new	
  Ext.Application({

	
  	
  	
  	
  launch:	
  function()	
  {

	
  	
  	
  	
  	
  	
  	
  	
  this.viewport	
  =	
  new	
  Ext.Panel({

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  layout:	
  'card',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  fullscreen:	
  true,
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  html:	
  "Hello	
  world!"
	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  });

	
  	
  	
  	
  }

});
2 Layout the UI

   toolbar                   toolbar


   dataList

   listCard                 detailCard
              na.viewport
The app...
var	
  va	
  =	
  new	
  Ext.Application({
	
  	
  	
  	
  launch:	
  function()	
  {

	
  	
  	
  	
  	
  	
  	
  	
  this.listCard	
  =	
  new	
  Ext.Panel({
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  html:	
  'I	
  am	
  the	
  list'
	
  	
  	
  	
  	
  	
  	
  	
  });

	
  	
  	
  	
  	
  	
  	
  	
  this.detailCard	
  =	
  new	
  Ext.Panel({
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  html:	
  'I	
  am	
  the	
  detail'
	
  	
  	
  	
  	
  	
  	
  	
  });

	
  	
  	
  	
  	
  	
  	
  	
  this.viewport	
  =	
  new	
  Ext.Panel({
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  layout:	
  'card',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  fullscreen:	
  true,
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  cardSwitchAnimation:	
  'slide',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  items:	
  [this.listCard,	
  this.detailCard]
	
  	
  	
  	
  	
  	
  	
  	
  });
	
  	
  	
  	
  }
});
listCard
this.listCardToolbar	
  =	
  new	
  Ext.Toolbar({
	
  	
  	
  	
  dock:	
  'top',
	
  	
  	
  	
  title:	
  'Valley	
  Guide'
});

this.listCardDataList	
  =	
  new	
  Ext.List({
	
  	
  	
  	
  store:	
  null,
	
  	
  	
  	
  itemTpl:	
  ''
});

this.listCard	
  =	
  new	
  Ext.Panel({
	
  	
  	
  	
  dockedItems:	
  [this.listCardToolbar],
	
  	
  	
  	
  items:	
  [this.listCardDataList],
	
  	
  	
  	
  layout:	
  'fit'
});
detailCard
this.detailCardToolbar	
  =	
  new	
  Ext.Toolbar({
	
  	
  	
  	
  dock:	
  'top',
	
  	
  	
  	
  title:	
  '...'
});

this.detailCard	
  =	
  new	
  Ext.Panel({
	
  	
  	
  	
  dockedItems:	
  [this.detailCardToolbar]
});
3 Model the data

http://api.yelp.com/business_review_search
?ywsid=YELP_KEY
&term=Restaurants
&location=Silicon%20Valley
Create a mobile web app with Sencha Touch
Apigee console
"businesses":	
  [
	
  	
  	
  	
  {
	
  	
  	
  	
  	
  "rating_img_url"	
  :	
  "http://media4.px.yelpcdn.com/...",
	
  	
  	
  	
  	
  "country_code"	
  :	
  "US",
	
  	
  	
  	
  	
  "id"	
  :	
  "BHpAlynD9dIGIaQDRqHCTA",
	
  	
  	
  	
  	
  "is_closed"	
  :	
  false,
	
  	
  	
  	
  	
  "city"	
  :	
  "Nashville",
	
  	
  	
  	
  	
  "mobile_url"	
  :	
  "http://mobile.yelp.com/biz/...",
	
  	
  	
  	
  	
  "review_count"	
  :	
  50,
	
  	
  	
  	
  	
  "zip"	
  :	
  "11231",
	
  	
  	
  	
  	
  "state"	
  :	
  "TN",
	
  	
  	
  	
  	
  "latitude"	
  :	
  40.675758,
	
  	
  	
  	
  	
  "address1"	
  :	
  "253	
  Conover	
  St",
	
  	
  	
  	
  	
  "address2"	
  :	
  "",
	
  	
  	
  	
  	
  "address3"	
  :	
  "",
	
  	
  	
  	
  	
  "phone"	
  :	
  "7186258211",
	
  	
  	
  	
  	
  "state_code"	
  :	
  "TN",
	
  	
  	
  	
  	
  "categories":	
  [
	
  	
  	
  	
  	
  	
  ...",
	
  	
  	
  	
  	
  ],
	
  	
  	
  	
  	
  ...
A data namespace
this.data	
  =	
  {};
The ‘Business’ model
this.data.Business	
  =	
  Ext.regModel('',	
  {
	
  	
  	
  	
  fields:	
  [
	
  	
  	
  	
  	
  	
  	
  	
  {name:	
  "id",	
  type:	
  "int"},
	
  	
  	
  	
  	
  	
  	
  	
  {name:	
  "name",	
  type:	
  "string"},
	
  	
  	
  	
  	
  	
  	
  	
  {name:	
  "latitude",	
  type:	
  "string"},
	
  	
  	
  	
  	
  	
  	
  	
  {name:	
  "longitude",	
  type:	
  "string"},
	
  	
  	
  	
  	
  	
  	
  	
  {name:	
  "address1",	
  type:	
  "string"},
	
  	
  	
  	
  	
  	
  	
  	
  {name:	
  "address2",	
  type:	
  "string"},
	
  	
  	
  	
  	
  	
  	
  	
  {name:	
  "address3",	
  type:	
  "string"},
	
  	
  	
  	
  	
  	
  	
  	
  {name:	
  "phone",	
  type:	
  "string"},
	
  	
  	
  	
  	
  	
  	
  	
  {name:	
  "state_code",	
  type:	
  "string"},
	
  	
  	
  	
  	
  	
  	
  	
  {name:	
  "mobile_url",	
  type:	
  "string"},
	
  	
  	
  	
  	
  	
  	
  	
  {name:	
  "rating_img_url_small",	
  type:	
  "string"},
	
  	
  	
  	
  	
  	
  	
  	
  {name:	
  "photo_url",	
  type:	
  "string"},
	
  	
  	
  	
  ]
});
A store of those models
this.data.restaurants	
  =	
  new	
  Ext.data.Store({
	
  	
  	
  	
  model:	
  this.data.Business,
	
  	
  	
  	
  autoLoad:	
  true,
	
  	
  	
  	
  proxy:	
  {
	
  	
  	
  	
  	
  	
  	
  	
  type:	
  'scripttag',
	
  	
  	
  	
  	
  	
  	
  	
  url:	
  'http://api.yelp.com/business_review_search'	
  +
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  '?ywsid='	
  +	
  YELP_KEY	
  +
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  '&term=Restaurant'	
  +
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  '&location=Silicon%20Valley',
	
  	
  	
  	
  	
  	
  	
  	
  reader:	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  type:	
  'json',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  root:	
  'businesses'
	
  	
  	
  	
  	
  	
  	
  	
  }
	
  	
  	
  	
  }
});
4 Load the list
this.listCardDataList	
  =	
  new	
  Ext.List({
	
  	
  	
  	
  store:	
  this.data.restaurants,
	
  	
  	
  	
  itemTpl:	
  '{name}'
});
A more interesting template
itemTpl:
	
  	
  	
  	
  '<img	
  class="photo"	
  src="{photo_url}"	
  width="40"	
  height="40"/>'	
  +
	
  	
  	
  	
  '{name}<br/>'	
  +
	
  	
  	
  	
  '<img	
  src="{rating_img_url_small}"/>&nbsp;'	
  +
	
  	
  	
  	
  '<small>{address1}</small>'
Hack the style
<style>
	
  	
  	
  	
  .photo	
  {
	
  	
  	
  	
  	
  	
  	
  	
  float:left;
	
  	
  	
  	
  	
  	
  	
  	
  margin:0	
  8px	
  16px	
  0;
	
  	
  	
  	
  	
  	
  	
  	
  border:1px	
  solid	
  #ccc;
	
  	
  	
  	
  	
  	
  	
  	
  -­‐webkit-­‐box-­‐shadow:
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  0	
  2px	
  4px	
  #777;
	
  	
  	
  	
  }
</style>
Get images resized...

       ...width="40"	
  height="40"	
  />
...in the cloud

src="http://src.sencha.io/40/{photo_url}"	
  width="40"	
  height="40"/>
5 Detail page
this.listCardDataList	
  =	
  new	
  Ext.List({
	
  	
  	
  	
  store:	
  this.data.restaurants,
	
  	
  	
  	
  itemTpl:	
  ...
	
  	
  	
  	
  listeners:	
  {
	
  	
  	
  	
  	
  	
  	
  	
  selectionchange:	
  function	
  (selectionModel,	
  records)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (records[0])	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  va.viewport.setActiveItem(va.detailCard);
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  va.detailCardToolbar.setTitle(
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  records[0].get('name')
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  );
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }
	
  	
  	
  	
  	
  	
  	
  	
  }
	
  	
  	
  	
  }
});
A back button
this.detailCardToolbar	
  =	
  new	
  Ext.Toolbar({
	
  	
  	
  	
  dock:	
  'top',
	
  	
  	
  	
  title:	
  '...',
	
  	
  	
  	
  items:	
  [{
	
  	
  	
  	
  	
  	
  	
  	
  text:	
  'Back',
	
  	
  	
  	
  	
  	
  	
  	
  ui:	
  'back',
	
  	
  	
  	
  	
  	
  	
  	
  handler:	
  function	
  ()	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  va.viewport.setActiveItem(
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  va.listCard,
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  {type:	
  'slide',	
  direction:	
  'right'}
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  );
	
  	
  	
  	
  	
  	
  	
  	
  }
	
  	
  	
  	
  }]
});
Detail template
this.detailCard	
  =	
  new	
  Ext.Panel({
	
  	
  	
  	
  dockedItems:	
  [this.detailCardToolbar],
	
  	
  	
  	
  styleHtmlContent:	
  true,
	
  	
  	
  	
  cls:	
  'detail',
	
  	
  	
  	
  tpl:	
  [
	
  	
  	
  	
  	
  	
  	
  	
  '<img	
  class="photo"	
  src="{photo_url}"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  width="100"	
  height="100"/>',
	
  	
  	
  	
  	
  	
  	
  	
  '<h2>{name}</h2>',
	
  	
  	
  	
  	
  	
  	
  	
  '<div	
  class="info">',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  '{address1}<br/>',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  '<img	
  src="{rating_img_url_small}"/>',
	
  	
  	
  	
  	
  	
  	
  	
  '</div>',
	
  	
  	
  	
  	
  	
  	
  	
  '<div	
  class="phone	
  x-­‐button">',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  '<a	
  href="tel:{phone}">{phone}</a>',
	
  	
  	
  	
  	
  	
  	
  	
  '</div>',
	
  	
  	
  	
  	
  	
  	
  	
  '<div	
  class="link	
  x-­‐button">',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  '<a	
  href="{mobile_url}">Read	
  more</a>',
	
  	
  	
  	
  	
  	
  	
  	
  '</div>'
	
  	
  	
  	
  ]
});
A little styling
.x-­‐html	
  h2	
  {
	
  	
  	
  	
  margin-­‐bottom:0;
}
.phone,	
  .link	
  {
	
  	
  	
  	
  clear:both;
	
  	
  	
  	
  font-­‐weight:bold;
	
  	
  	
  	
  display:block;
	
  	
  	
  	
  text-­‐align:center;
	
  	
  	
  	
  margin-­‐top:8px;
}
6 Add a map

      toolbar     toolbar


      dataList   dataList
                 detailCard

      listCard   detailTabs
va.viewport
6 Add a map
va.viewport.setActiveItem(va.detailTabs);

...

this.detailMap	
  =	
  new	
  Ext.Map({});

this.detailTabs	
  =	
  new	
  Ext.TabPanel({
	
  	
  	
  	
  dockedItems:	
  [this.detailCardToolbar],
	
  	
  	
  	
  items:	
  [this.detailCard,	
  this.detailMap]
});

va.viewport	
  =	
  new	
  Ext.Panel({
	
  	
  	
  	
  layout:	
  'card',
	
  	
  	
  	
  fullscreen:	
  true,
	
  	
  	
  	
  cardSwitchAnimation:	
  'slide',
	
  	
  	
  	
  items:	
  [this.listCard,	
  this.detailTabs]
});
Tab titles
this.detailCard	
  =	
  new	
  Ext.Panel({
	
  	
  	
  	
  ...
	
  	
  	
  	
  title:	
  'Info'
});

this.detailMap	
  =	
  new	
  Ext.Map({
	
  	
  	
  	
  title:	
  'Map'
});
Google Maps script
<script	
  type="text/javascript"
	
  	
  src="http://maps.google.com/maps/api/js?sensor=true">
</script>
Update the map location
selectionchange:	
  function	
  (selectionModel,	
  records)	
  {
	
  	
  	
  	
  ...
	
  	
  	
  	
  var	
  map	
  =	
  va.detailMap.map;

	
  	
  	
  	
  if	
  (!map.marker)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  map.marker	
  =	
  new	
  google.maps.Marker();
	
  	
  	
  	
  	
  	
  	
  	
  map.marker.setMap(map);
	
  	
  	
  	
  }

	
  	
  	
  	
  map.setCenter(
	
  	
  	
  	
  	
  	
  	
  	
  new	
  google.maps.LatLng(
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  records[0].get('latitude'),
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  records[0].get('longitude')
	
  	
  	
  	
  	
  	
  	
  	
  )
	
  	
  	
  	
  );

	
  	
  	
  	
  map.marker.setPosition(
	
  	
  	
  	
  	
  	
  	
  	
  map.getCenter()
	
  	
  	
  	
  );
Improve the tab bar
this.detailTabs	
  =	
  new	
  Ext.TabPanel({
	
  	
  	
  	
  dockedItems:	
  [this.detailCardToolbar],
	
  	
  	
  	
  items:	
  [this.detailCard,	
  this.detailMap],

	
  	
  	
  	
  tabBar:	
  {
	
  	
  	
  	
  	
  	
  	
  	
  ui:	
  'light',
	
  	
  	
  	
  	
  	
  	
  	
  layout:	
  {	
  pack:	
  'center'	
  }
	
  	
  	
  	
  }

});
7 More?
More data...
['hotels',	
  'bars',	
  'restaurants'].forEach(	
  function	
  (type)	
  {
	
  	
  	
  	
  va.data[type]	
  =	
  new	
  Ext.data.Store({
	
  	
  	
  	
  	
  	
  	
  	
  model:	
  va.data.Business,
	
  	
  	
  	
  	
  	
  	
  	
  autoLoad:	
  true,
	
  	
  	
  	
  	
  	
  	
  	
  proxy:	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  type:	
  'scripttag',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  url:	
  'http://api.yelp.com/business_review_search'	
  +
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  '?ywsid='	
  +	
  YELP_KEY	
  +
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  '&term='	
  +	
  type	
  +
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  '&location=Silicon%20Valley',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  reader:	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  type:	
  'json',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  root:	
  'businesses'
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }
	
  	
  	
  	
  	
  	
  	
  	
  }
	
  	
  	
  	
  });
});
Make list into a ‘class’
this.ListCardDataList	
  =	
  Ext.extend(Ext.List,	
  {
	
  	
  	
  	
  store:	
  null,
	
  	
  	
  	
  itemTpl:
	
  	
  	
  	
  	
  	
  	
  	
  '<img	
  class="photo"	
  ...
Instantiate that 3 times
this.stayCardDataList	
  =	
  new	
  this.ListCardDataList({
	
  	
  	
  	
  store:	
  this.data.hotels
});

this.eatCardDataList	
  =	
  new	
  this.ListCardDataList({
	
  	
  	
  	
  store:	
  this.data.restaurants
});

this.drinkCardDataList	
  =	
  new	
  this.ListCardDataList({
	
  	
  	
  	
  store:	
  this.data.bars
});




                                            Consider lazy-loading...
Turn container into tabs too
this.listCard	
  =	
  new	
  Ext.TabPanel({
	
  	
  	
  	
  items:	
  [
	
  	
  	
  	
  	
  	
  	
  	
  this.stayCardDataList,	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.eatCardDataList,	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.drinkCardDataList
	
  	
  	
  	
  ],
	
  	
  	
  	
  tabBar:	
  {
	
  	
  	
  	
  	
  	
  	
  	
  ui:	
  'light',
	
  	
  	
  	
  	
  	
  	
  	
  layout:	
  {	
  pack:	
  'center'	
  },
	
  	
  	
  	
  	
  	
  	
  	
  dock:	
  'bottom'
	
  	
  	
  	
  },
	
  	
  	
  	
  cardSwitchAnimation:	
  'flip',
...
And add titles & icons
this.stayCardDataList	
  =	
  new	
  this.ListCardDataList({
	
  	
  	
  	
  store:	
  this.data.hotels,
	
  	
  	
  	
  title:	
  'Stay',
	
  	
  	
  	
  iconCls:	
  'home'
});

this.eatCardDataList	
  =	
  new	
  this.ListCardDataList({
	
  	
  	
  	
  store:	
  this.data.restaurants,
	
  	
  	
  	
  title:	
  'Eat',
	
  	
  	
  	
  iconCls:	
  'locate'
});

this.drinkCardDataList	
  =	
  new	
  this.ListCardDataList({
	
  	
  	
  	
  store:	
  this.data.bars,
	
  	
  	
  	
  title:	
  'Drink',
	
  	
  	
  	
  iconCls:	
  'star'
});
Pull-to-refresh
this.ListCardDataList	
  =	
  Ext.extend(Ext.List,	
  {
	
  	
  	
  	
  ...
	
  	
  	
  	
  plugins:	
  [{
	
  	
  	
  	
  	
  	
  	
  	
  ptype:	
  'pullrefresh'
	
  	
  	
  	
  }]
});
8 Customize theme
http://sass-lang.com/
Variables
/* SCSS */                     /* CSS */

$blue: #3bbfce;                .content-navigation {
$margin: 16px;                   border-color: #3bbfce;
                                 color: #2b9eab;
.content-navigation {          }
  border-color: $blue;
  color:                       .border {
    darken($blue, 9%);           padding: 8px;
}                                margin: 8px;
                                 border-color: #3bbfce;
.border {                      }
  padding: $margin / 2;
  margin: $margin / 2;
  border-color: $blue;
}
$> sudo gem install compass




       http://rubyinstaller.org/
$> compass -v

Compass 0.11.1 (Antares)
Copyright (c) 2008-2011 Chris Eppstein
Released under the MIT License.


$> sass -v

Sass 3.1.1 (Brainy Betty)
Start by copying sencha-touch.scss
config.rb
dir	
  =	
  File.dirname(__FILE__)

load	
  File.join(dir,	
  '..',	
  'lib',	
  'touch',	
  'resources',	
  
'themes')

#	
  Compass	
  configurations
sass_path	
  	
  	
  	
  =	
  dir
css_path	
  	
  	
  	
  	
  =	
  dir
environment	
  	
  =	
  :production
output_style	
  =	
  :compressed

#	
  or	
  :nested,	
  :expanded,	
  :compact
Compile...
$>	
  cd	
  theming

$>	
  compass	
  compile	
  valley.scss
	
  	
  	
  	
  	
  	
  create	
  valley.css


$>	
  compass	
  compile	
  valley.scss
	
  	
  	
  	
  	
  	
  identical	
  valley.css


[edit	
  file]
$>	
  compass	
  compile	
  valley.scss
	
  	
  	
  	
  	
  	
  overwrite	
  valley.css


$>	
  compass	
  watch	
  valley.scss
	
  	
  	
  	
  	
  	
  >>>	
  Change	
  detected	
  to:	
  valley.scss
	
  	
  	
  	
  	
  	
  overwrite	
  valley.css
Link...
<link	
  href="theming/valley.css"	
  rel="stylesheet"
	
  	
  	
  	
  	
  	
  type="text/css"	
  />
valley.scss
@import	
  'sencha-­‐touch/default/all';

@include	
  sencha-­‐panel;
@include	
  sencha-­‐buttons;
@include	
  sencha-­‐sheet;
@include	
  sencha-­‐tabs;
@include	
  sencha-­‐toolbar;
@include	
  sencha-­‐list;
@include	
  sencha-­‐list-­‐pullrefresh;
@include	
  sencha-­‐layout;
@include	
  sencha-­‐loading-­‐spinner;
...
valley.scss
$base-­‐color:	
  #9D9E00;

@import	
  'sencha-­‐touch/default/all';

@include	
  sencha-­‐panel;
@include	
  sencha-­‐buttons;
@include	
  sencha-­‐sheet;
@include	
  sencha-­‐tabs;
@include	
  sencha-­‐toolbar;
@include	
  sencha-­‐list;
@include	
  sencha-­‐list-­‐pullrefresh;
@include	
  sencha-­‐layout;
@include	
  sencha-­‐loading-­‐spinner;
Create a mobile web app with Sencha Touch
Choose own icons
$base-­‐color:	
  #9D9E00;
$include-­‐default-­‐icons:	
  false;

@import	
  'sencha-­‐touch/default/all';

@include	
  sencha-­‐panel;
@include	
  sencha-­‐buttons;
...

@include	
  pictos-­‐iconmask('briefcase1');
@include	
  pictos-­‐iconmask('heart');
@include	
  pictos-­‐iconmask('music1');
Specify iconCls
this.stayCardDataList	
  =	
  new	
  this.ListCardDataList({
	
  	
  	
  	
  store:	
  this.data.hotels,
	
  	
  	
  	
  title:	
  'Stay',
	
  	
  	
  	
  iconCls:	
  'briefcase1'
});

this.eatCardDataList	
  =	
  new	
  this.ListCardDataList({
	
  	
  	
  	
  store:	
  this.data.restaurants,
	
  	
  	
  	
  title:	
  'Eat',
	
  	
  	
  	
  iconCls:	
  'heart'
});

this.drinkCardDataList	
  =	
  new	
  this.ListCardDataList({
	
  	
  	
  	
  store:	
  this.data.bars,
	
  	
  	
  	
  title:	
  'Drink',
	
  	
  	
  	
  iconCls:	
  'music1'
});
_variables.scss
$include-html-style: true;        $base-color: #354F6E;

$include-default-icons: true;     $base-gradient: 'matte';

$include-form-sliders: true;      $alert-color: red;

$include-floating-panels: true;   $confirm-color: #92cf00;

$include-default-uis: true;       $page-bg-color: #eee;

$include-highlights: true;        $global-row-height: 2.6em;

$include-border-radius: true;     $active-color: darken(
                                    saturate($base-color, 55%),
$basic-slider: false;             10%);
http://dev.sencha.com/deploy/touch/docs/theme/
Sass is a superset of CSS
$base-­‐color:	
  #9D9E00;
$include-­‐default-­‐icons:	
  false;

@import	
  'sencha-­‐touch/default/all';
...

@include	
  pictos-­‐iconmask('briefcase1');
@include	
  pictos-­‐iconmask('heart');
@include	
  pictos-­‐iconmask('music1');

.photo	
  {
	
  	
  	
  	
  float:left;
	
  	
  	
  	
  margin:0	
  8px	
  16px	
  0;
	
  	
  	
  	
  border:1px	
  solid	
  #ccc;
	
  	
  	
  	
  -­‐webkit-­‐box-­‐shadow:
	
  	
  	
  	
  	
  	
  	
  	
  0	
  2px	
  4px	
  #777;
}
...
WebFonts
@import	
  url(http://fonts.googleapis.com/css?family=Voltaire);


.x-­‐toolbar-­‐title	
  {
	
  	
  font-­‐family:	
  Voltaire;
	
  	
  font-­‐weight:	
  normal;
	
  	
  font-­‐size:	
  1.7em;
	
  	
  line-­‐height:	
  1.7em;
	
  	
  letter-­‐spacing:	
  0.05em;
}
Done?
Development sequence
1 Structure the app   5 Detail page

2 Layout the UI       6 Add a map

3 Model the data      7 More data

4 Load the list       8 Customize theme
A ‘responsive’ app...




http://sencha.com/x/cv
And if we’d had time...
 Add to home screen
 - Icon
 - Splash screen

 Hybrid app; PhoneGap / NimbleKit
 - Contacts API
 - Geolocation


 http://sencha.com/x/cy
 http://sencha.com/x/de
O ine app
$>	
  phantomjs	
  confess.js	
  http://github/valley/

CACHE	
  MANIFEST

#	
  This	
  manifest	
  was	
  created	
  by	
  confess.js
#	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  Time:	
  Wed	
  Sep	
  14	
  2011	
  10:14:45	
  GMT-­‐0700	
  (PDT)
#	
  	
  	
  	
  User-­‐agent:	
  Mozilla/5.0	
  ...

CACHE:
app/app.js
app/yelp.js
http://cdn.sencha.io/touch/1.1.0/sencha-­‐touch.js
http://maps.google.com/maps/api/js?sensor=true
http://maps.gstatic.com/intl/en_us/mapfiles/api-­‐3/6/4/main.js
theming/valley.css

NETWORK:
*


http://github.com/jamesgpearce/confess
O ine data
Taking Yelp data o ine

Taking images o ine
- src.sencha.io to generate cross-origin B64

Detecting network connection changes




http://sencha.com/x/df
Weinre




http://phonegap.github.com/weinre
built with

Apps vs Web technology
James Pearce
@ jamespearce

More Related Content

PDF
A mobile web app for Android in 75 minutes
PDF
2012.sandiego.wordcamp
PDF
WordPress Admin UI - Future Proofing Your Admin Pages
PPT
Boston Computing Review - Ruby on Rails
PDF
22 j query1
PDF
Secure WordPress Development Practices
PPTX
Design Patterns for JavaScript Web Apps - JavaScript Conference 2012 - OPITZ ...
PDF
Before there was Hoop Dreams, there was McDonald's: Strange and Beautiful
A mobile web app for Android in 75 minutes
2012.sandiego.wordcamp
WordPress Admin UI - Future Proofing Your Admin Pages
Boston Computing Review - Ruby on Rails
22 j query1
Secure WordPress Development Practices
Design Patterns for JavaScript Web Apps - JavaScript Conference 2012 - OPITZ ...
Before there was Hoop Dreams, there was McDonald's: Strange and Beautiful

What's hot (20)

PPTX
Html5 and web technology update
KEY
前端概述
ODP
IBM Lotus Notes Domino XPages and XPages for Mobile
PDF
After max+phonegap
PPTX
Jquery Complete Presentation along with Javascript Basics
PDF
Building sustainable RESTFul services
PDF
GDI Seattle - Intro to JavaScript Class 4
KEY
Html5 For Jjugccc2009fall
PPTX
ADO.NET Entity Framework by Jose A. Blakeley and Michael Pizzo
PDF
QCon 2015 - Thinking in components: A new paradigm for Web UI
PDF
Polymer
PDF
Building iPhone Web Apps using "classic" Domino
PDF
Desenvolvimento web com Ruby on Rails (extras)
PDF
Devoxx 2014-webComponents
PDF
Wordcamp abq cf-cpt
PPTX
2012 SVCodeCamp: In App Payments with HTML5
PPT
WordPress development paradigms, idiosyncrasies and other big words
PDF
Angular JS blog tutorial
PPTX
Geb qa fest2017
PDF
WordCamp ABQ 2013: Making the leap from Designer to Designer/Developer
Html5 and web technology update
前端概述
IBM Lotus Notes Domino XPages and XPages for Mobile
After max+phonegap
Jquery Complete Presentation along with Javascript Basics
Building sustainable RESTFul services
GDI Seattle - Intro to JavaScript Class 4
Html5 For Jjugccc2009fall
ADO.NET Entity Framework by Jose A. Blakeley and Michael Pizzo
QCon 2015 - Thinking in components: A new paradigm for Web UI
Polymer
Building iPhone Web Apps using "classic" Domino
Desenvolvimento web com Ruby on Rails (extras)
Devoxx 2014-webComponents
Wordcamp abq cf-cpt
2012 SVCodeCamp: In App Payments with HTML5
WordPress development paradigms, idiosyncrasies and other big words
Angular JS blog tutorial
Geb qa fest2017
WordCamp ABQ 2013: Making the leap from Designer to Designer/Developer
Ad

Viewers also liked (6)

PPTX
Ext Js introduction and new features in Ext Js 6
PDF
The City Bars App with Sencha Touch 2
PPT
Mobile app with sencha touch
PDF
Mobile Device APIs
PDF
Building Sencha Themes
PPT
Sencha Touch Charts
Ext Js introduction and new features in Ext Js 6
The City Bars App with Sencha Touch 2
Mobile app with sencha touch
Mobile Device APIs
Building Sencha Themes
Sencha Touch Charts
Ad

Similar to Create a mobile web app with Sencha Touch (20)

PDF
Bd conf sencha touch workshop
PDF
Building a Mobile App with Sencha Touch
PPTX
Building AOL's High Performance, Enterprise Wide Mail Application With Silver...
PPSX
Sencha Touch basic concepts, pros and cons
PDF
How to use lekhoniya.pdf
PDF
Mozilla Web Apps - Super-VanJS
PDF
netmind - Primer Contacto con el Desarrollo de Aplicaciones para Windows 8
PDF
An Introduction to Sencha Touch
PPT
Itemscript, a specification for RESTful JSON integration
PPTX
Developing your first application using FIWARE
PPT
CTS Conference Web 2.0 Tutorial Part 2
PDF
Mobile Software Engineering Crash Course - C06 WindowsPhone
PPTX
Ext JS Introduction
PDF
Java Web Programming on Google Cloud Platform [3/3] : Google Web Toolkit
PDF
HTML5 and the dawn of rich mobile web applications pt 1
PDF
Android L01 - Warm Up
PPTX
Silverlight Developer Introduction
PDF
混搭移动开发:PhoneGap+JQurey+Dreamweaver
PDF
Google Web Toolkit
PDF
Wt unit 2 ppts client side technology
Bd conf sencha touch workshop
Building a Mobile App with Sencha Touch
Building AOL's High Performance, Enterprise Wide Mail Application With Silver...
Sencha Touch basic concepts, pros and cons
How to use lekhoniya.pdf
Mozilla Web Apps - Super-VanJS
netmind - Primer Contacto con el Desarrollo de Aplicaciones para Windows 8
An Introduction to Sencha Touch
Itemscript, a specification for RESTful JSON integration
Developing your first application using FIWARE
CTS Conference Web 2.0 Tutorial Part 2
Mobile Software Engineering Crash Course - C06 WindowsPhone
Ext JS Introduction
Java Web Programming on Google Cloud Platform [3/3] : Google Web Toolkit
HTML5 and the dawn of rich mobile web applications pt 1
Android L01 - Warm Up
Silverlight Developer Introduction
混搭移动开发:PhoneGap+JQurey+Dreamweaver
Google Web Toolkit
Wt unit 2 ppts client side technology

More from James Pearce (16)

PDF
An Intro to Mobile HTML5
PDF
A Snapshot of the Mobile HTML5 Revolution
PDF
HTML5 and the dawn of rich mobile web applications pt 2
PDF
Cross platform mobile web apps
PDF
City bars workshop
PDF
San Diego Hackathon
PDF
Building Cross Platform Mobile Web Apps
PDF
Creating and Distributing Mobile Web Applications with PhoneGap
PDF
Theming and Sass
PDF
Source Dev Con Keynote
PDF
Building Cloud-Based Cross-Platform Mobile Web Apps
PDF
Building cross platform mobile web apps
PDF
Building tomorrow's web with today's tools
PDF
HTML5 and the dawn of rich mobile web applications
PDF
Sencha Touch for Rubyists
PDF
Serving Mobile Apps from Content Management Systems
An Intro to Mobile HTML5
A Snapshot of the Mobile HTML5 Revolution
HTML5 and the dawn of rich mobile web applications pt 2
Cross platform mobile web apps
City bars workshop
San Diego Hackathon
Building Cross Platform Mobile Web Apps
Creating and Distributing Mobile Web Applications with PhoneGap
Theming and Sass
Source Dev Con Keynote
Building Cloud-Based Cross-Platform Mobile Web Apps
Building cross platform mobile web apps
Building tomorrow's web with today's tools
HTML5 and the dawn of rich mobile web applications
Sencha Touch for Rubyists
Serving Mobile Apps from Content Management Systems

Recently uploaded (20)

PDF
Encapsulation_ Review paper, used for researhc scholars
PPTX
MYSQL Presentation for SQL database connectivity
PDF
cuic standard and advanced reporting.pdf
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Machine learning based COVID-19 study performance prediction
PPTX
Tartificialntelligence_presentation.pptx
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Accuracy of neural networks in brain wave diagnosis of schizophrenia
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Encapsulation theory and applications.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
A comparative analysis of optical character recognition models for extracting...
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Encapsulation_ Review paper, used for researhc scholars
MYSQL Presentation for SQL database connectivity
cuic standard and advanced reporting.pdf
Per capita expenditure prediction using model stacking based on satellite ima...
Machine learning based COVID-19 study performance prediction
Tartificialntelligence_presentation.pptx
The Rise and Fall of 3GPP – Time for a Sabbatical?
Programs and apps: productivity, graphics, security and other tools
MIND Revenue Release Quarter 2 2025 Press Release
Accuracy of neural networks in brain wave diagnosis of schizophrenia
“AI and Expert System Decision Support & Business Intelligence Systems”
Encapsulation theory and applications.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
Diabetes mellitus diagnosis method based random forest with bat algorithm
Building Integrated photovoltaic BIPV_UPV.pdf
A comparative analysis of optical character recognition models for extracting...
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Reach Out and Touch Someone: Haptics and Empathic Computing
Digital-Transformation-Roadmap-for-Companies.pptx
Build a system with the filesystem maintained by OSTree @ COSCUP 2025

Create a mobile web app with Sencha Touch

  • 1. Create A Mobile Web App with Sencha Touch @ jamespearce
  • 2. Single device Multi device Sedentary user Mobile user * Declarative Imperative Thin client Thick client Documents Applications * or supine, or sedentary, or passive, or...
  • 3. A badge for all these ways the web is changing
  • 4. HTML5 is a new version of HTML4, XHTML1, and DOM Level 2 HTML addressing many of the issues of those specifications while at the same time enhancing (X)HTML to more adequately address Web applications. - WHATWG Wiki
  • 5. What is an app?
  • 6. Consumption vs Creation Linkability User Experience Architecture
  • 7. WebFont Video Audio Graphics Device Access Camera CSS Styling & Layout Network Location HTTP JavaScript Contacts AJAX SMS Semantic HTML Events Orientation Sockets File Systems Workers & Cross-App Gyro Databases Parallel SSL Messaging App Caches Processing (all the elements of a modern application platform)
  • 11. A JavaScript framework for building rich mobile apps with web standards
  • 13. Components Lists
  • 15. Forms
  • 24. <!DOCTYPE  html> <html>    <head>            <title>Hello  World</title>        <script  src="lib/touch/sencha-­‐touch.js"></script>        <script  src="app/app.js"></script>                <link  href="lib/touch/resources/css/sencha-­‐touch.css"                      rel="stylesheet"  type="text/css"  />        </head>    <body></body> </html>
  • 25. new  Ext.Application({        launch:  function()  {                new  Ext.Panel({                        fullscreen:  true,                        dockedItems:  [{xtype:'toolbar',  title:'My  First  App'}],                        layout:  'fit',                        styleHtmlContent:  true,                        html:  '<h2>Hello  World!</h2>I  did  it!'                });        } });
  • 27. Lists var  list  =  new  Ext.List({        store:  store,        itemTpl:  '{firstName}  {lastName}',        grouped:  true,        indexBar:  true });
  • 28. Nested Lists var  list  =  new  Ext.NestedList({        store:  store,        displayField:  'name',        title:  'My  List',        updateTitleText:  true,        getDetailCard:                function(record,  parent)  {..} });
  • 29. Carousels var  carousel  =  new  Ext.Carousel({        direction:  'horizontal',        indicator:  true,        items:  [                ..        ] });
  • 30. Sheets var  sheet  =  new  Ext.ActionSheet({        items:  [                {                        text:  'Delete  draft',                        ui:  'decline'                },  {                        text:  'Save  draft'                },  {                        text:  'Cancel',                }        ] }); sheet.show();
  • 31. Common patterns 1 var  list  =  new  Ext.List({        store:  store,        itemTpl:  '{firstName}  {lastName}',        grouped:  true,        indexBar:  true }); var  panel  =  new  Ext.Panel({        fullscreen:  true,        layout:  'fit',        items:  [list] });
  • 32. Common patterns 2 var  panel  =  new  Ext.Panel({        fullscreen:  true,        layout:  'fit',        items:  [{                xtype:  'list',                store:  store,                itemTpl:  '{firstName}  {lastName}',                grouped:  true,                indexBar:  true        }] });
  • 34. Pre-requisites Sencha Touch SDK:   http://sencha.com/products/touch/  Yelp developer API key:   http://www.yelp.com/developers/getting_started/ api_overview  Install Sass and Compass:   http://sass-lang.com/download.html http://compass-style.org/install/
  • 37. Development sequence 1 Structure the app 5 Detail page 2 Layout the UI 6 Add a map 3 Model the data 7 More data 4 Load the list 8 Customize theme
  • 39. index.html <!doctype  html> <html>        <head>                <title>Valley  Guide</title>        </head> <body></body> </html>
  • 40. index.html <script  src="lib/touch/sencha-­‐touch.js"></script> <script  src="app/yelp.js"></script> <script  src="app/app.js"></script> <link  href="lib/touch/resources/css/sencha-­‐touch.css"              rel="stylesheet"  type="text/css"  />
  • 41. app.js va  =  new  Ext.Application({        launch:  function()  {                this.viewport  =  new  Ext.Panel({                        layout:  'card',                        fullscreen:  true,                        html:  "Hello  world!"                        });        } });
  • 42. 2 Layout the UI toolbar toolbar dataList listCard detailCard na.viewport
  • 43. The app... var  va  =  new  Ext.Application({        launch:  function()  {                this.listCard  =  new  Ext.Panel({                        html:  'I  am  the  list'                });                this.detailCard  =  new  Ext.Panel({                        html:  'I  am  the  detail'                });                this.viewport  =  new  Ext.Panel({                        layout:  'card',                        fullscreen:  true,                        cardSwitchAnimation:  'slide',                        items:  [this.listCard,  this.detailCard]                });        } });
  • 44. listCard this.listCardToolbar  =  new  Ext.Toolbar({        dock:  'top',        title:  'Valley  Guide' }); this.listCardDataList  =  new  Ext.List({        store:  null,        itemTpl:  '' }); this.listCard  =  new  Ext.Panel({        dockedItems:  [this.listCardToolbar],        items:  [this.listCardDataList],        layout:  'fit' });
  • 45. detailCard this.detailCardToolbar  =  new  Ext.Toolbar({        dock:  'top',        title:  '...' }); this.detailCard  =  new  Ext.Panel({        dockedItems:  [this.detailCardToolbar] });
  • 46. 3 Model the data http://api.yelp.com/business_review_search ?ywsid=YELP_KEY &term=Restaurants &location=Silicon%20Valley
  • 49. "businesses":  [        {          "rating_img_url"  :  "http://media4.px.yelpcdn.com/...",          "country_code"  :  "US",          "id"  :  "BHpAlynD9dIGIaQDRqHCTA",          "is_closed"  :  false,          "city"  :  "Nashville",          "mobile_url"  :  "http://mobile.yelp.com/biz/...",          "review_count"  :  50,          "zip"  :  "11231",          "state"  :  "TN",          "latitude"  :  40.675758,          "address1"  :  "253  Conover  St",          "address2"  :  "",          "address3"  :  "",          "phone"  :  "7186258211",          "state_code"  :  "TN",          "categories":  [            ...",          ],          ...
  • 51. The ‘Business’ model this.data.Business  =  Ext.regModel('',  {        fields:  [                {name:  "id",  type:  "int"},                {name:  "name",  type:  "string"},                {name:  "latitude",  type:  "string"},                {name:  "longitude",  type:  "string"},                {name:  "address1",  type:  "string"},                {name:  "address2",  type:  "string"},                {name:  "address3",  type:  "string"},                {name:  "phone",  type:  "string"},                {name:  "state_code",  type:  "string"},                {name:  "mobile_url",  type:  "string"},                {name:  "rating_img_url_small",  type:  "string"},                {name:  "photo_url",  type:  "string"},        ] });
  • 52. A store of those models this.data.restaurants  =  new  Ext.data.Store({        model:  this.data.Business,        autoLoad:  true,        proxy:  {                type:  'scripttag',                url:  'http://api.yelp.com/business_review_search'  +                        '?ywsid='  +  YELP_KEY  +                        '&term=Restaurant'  +                        '&location=Silicon%20Valley',                reader:  {                        type:  'json',                        root:  'businesses'                }        } });
  • 53. 4 Load the list this.listCardDataList  =  new  Ext.List({        store:  this.data.restaurants,        itemTpl:  '{name}' });
  • 54. A more interesting template itemTpl:        '<img  class="photo"  src="{photo_url}"  width="40"  height="40"/>'  +        '{name}<br/>'  +        '<img  src="{rating_img_url_small}"/>&nbsp;'  +        '<small>{address1}</small>'
  • 55. Hack the style <style>        .photo  {                float:left;                margin:0  8px  16px  0;                border:1px  solid  #ccc;                -­‐webkit-­‐box-­‐shadow:                        0  2px  4px  #777;        } </style>
  • 56. Get images resized... ...width="40"  height="40"  />
  • 58. 5 Detail page this.listCardDataList  =  new  Ext.List({        store:  this.data.restaurants,        itemTpl:  ...        listeners:  {                selectionchange:  function  (selectionModel,  records)  {                        if  (records[0])  {                                va.viewport.setActiveItem(va.detailCard);                                va.detailCardToolbar.setTitle(                                        records[0].get('name')                                );                        }                }        } });
  • 59. A back button this.detailCardToolbar  =  new  Ext.Toolbar({        dock:  'top',        title:  '...',        items:  [{                text:  'Back',                ui:  'back',                handler:  function  ()  {                        va.viewport.setActiveItem(                                va.listCard,                                {type:  'slide',  direction:  'right'}                        );                }        }] });
  • 60. Detail template this.detailCard  =  new  Ext.Panel({        dockedItems:  [this.detailCardToolbar],        styleHtmlContent:  true,        cls:  'detail',        tpl:  [                '<img  class="photo"  src="{photo_url}"                            width="100"  height="100"/>',                '<h2>{name}</h2>',                '<div  class="info">',                        '{address1}<br/>',                        '<img  src="{rating_img_url_small}"/>',                '</div>',                '<div  class="phone  x-­‐button">',                        '<a  href="tel:{phone}">{phone}</a>',                '</div>',                '<div  class="link  x-­‐button">',                        '<a  href="{mobile_url}">Read  more</a>',                '</div>'        ] });
  • 61. A little styling .x-­‐html  h2  {        margin-­‐bottom:0; } .phone,  .link  {        clear:both;        font-­‐weight:bold;        display:block;        text-­‐align:center;        margin-­‐top:8px; }
  • 62. 6 Add a map toolbar toolbar dataList dataList detailCard listCard detailTabs va.viewport
  • 63. 6 Add a map va.viewport.setActiveItem(va.detailTabs); ... this.detailMap  =  new  Ext.Map({}); this.detailTabs  =  new  Ext.TabPanel({        dockedItems:  [this.detailCardToolbar],        items:  [this.detailCard,  this.detailMap] }); va.viewport  =  new  Ext.Panel({        layout:  'card',        fullscreen:  true,        cardSwitchAnimation:  'slide',        items:  [this.listCard,  this.detailTabs] });
  • 64. Tab titles this.detailCard  =  new  Ext.Panel({        ...        title:  'Info' }); this.detailMap  =  new  Ext.Map({        title:  'Map' });
  • 65. Google Maps script <script  type="text/javascript"    src="http://maps.google.com/maps/api/js?sensor=true"> </script>
  • 66. Update the map location selectionchange:  function  (selectionModel,  records)  {        ...        var  map  =  va.detailMap.map;        if  (!map.marker)  {                map.marker  =  new  google.maps.Marker();                map.marker.setMap(map);        }        map.setCenter(                new  google.maps.LatLng(                        records[0].get('latitude'),                        records[0].get('longitude')                )        );        map.marker.setPosition(                map.getCenter()        );
  • 67. Improve the tab bar this.detailTabs  =  new  Ext.TabPanel({        dockedItems:  [this.detailCardToolbar],        items:  [this.detailCard,  this.detailMap],        tabBar:  {                ui:  'light',                layout:  {  pack:  'center'  }        } });
  • 69. More data... ['hotels',  'bars',  'restaurants'].forEach(  function  (type)  {        va.data[type]  =  new  Ext.data.Store({                model:  va.data.Business,                autoLoad:  true,                proxy:  {                        type:  'scripttag',                        url:  'http://api.yelp.com/business_review_search'  +                                '?ywsid='  +  YELP_KEY  +                                '&term='  +  type  +                                '&location=Silicon%20Valley',                        reader:  {                                type:  'json',                                root:  'businesses'                        }                }        }); });
  • 70. Make list into a ‘class’ this.ListCardDataList  =  Ext.extend(Ext.List,  {        store:  null,        itemTpl:                '<img  class="photo"  ...
  • 71. Instantiate that 3 times this.stayCardDataList  =  new  this.ListCardDataList({        store:  this.data.hotels }); this.eatCardDataList  =  new  this.ListCardDataList({        store:  this.data.restaurants }); this.drinkCardDataList  =  new  this.ListCardDataList({        store:  this.data.bars }); Consider lazy-loading...
  • 72. Turn container into tabs too this.listCard  =  new  Ext.TabPanel({        items:  [                this.stayCardDataList,                  this.eatCardDataList,                  this.drinkCardDataList        ],        tabBar:  {                ui:  'light',                layout:  {  pack:  'center'  },                dock:  'bottom'        },        cardSwitchAnimation:  'flip', ...
  • 73. And add titles & icons this.stayCardDataList  =  new  this.ListCardDataList({        store:  this.data.hotels,        title:  'Stay',        iconCls:  'home' }); this.eatCardDataList  =  new  this.ListCardDataList({        store:  this.data.restaurants,        title:  'Eat',        iconCls:  'locate' }); this.drinkCardDataList  =  new  this.ListCardDataList({        store:  this.data.bars,        title:  'Drink',        iconCls:  'star' });
  • 74. Pull-to-refresh this.ListCardDataList  =  Ext.extend(Ext.List,  {        ...        plugins:  [{                ptype:  'pullrefresh'        }] });
  • 77. Variables /* SCSS */ /* CSS */ $blue: #3bbfce; .content-navigation { $margin: 16px; border-color: #3bbfce; color: #2b9eab; .content-navigation { } border-color: $blue; color: .border { darken($blue, 9%); padding: 8px; } margin: 8px; border-color: #3bbfce; .border { } padding: $margin / 2; margin: $margin / 2; border-color: $blue; }
  • 78. $> sudo gem install compass http://rubyinstaller.org/
  • 79. $> compass -v Compass 0.11.1 (Antares) Copyright (c) 2008-2011 Chris Eppstein Released under the MIT License. $> sass -v Sass 3.1.1 (Brainy Betty)
  • 80. Start by copying sencha-touch.scss
  • 81. config.rb dir  =  File.dirname(__FILE__) load  File.join(dir,  '..',  'lib',  'touch',  'resources',   'themes') #  Compass  configurations sass_path        =  dir css_path          =  dir environment    =  :production output_style  =  :compressed #  or  :nested,  :expanded,  :compact
  • 82. Compile... $>  cd  theming $>  compass  compile  valley.scss            create  valley.css $>  compass  compile  valley.scss            identical  valley.css [edit  file] $>  compass  compile  valley.scss            overwrite  valley.css $>  compass  watch  valley.scss            >>>  Change  detected  to:  valley.scss            overwrite  valley.css
  • 83. Link... <link  href="theming/valley.css"  rel="stylesheet"            type="text/css"  />
  • 84. valley.scss @import  'sencha-­‐touch/default/all'; @include  sencha-­‐panel; @include  sencha-­‐buttons; @include  sencha-­‐sheet; @include  sencha-­‐tabs; @include  sencha-­‐toolbar; @include  sencha-­‐list; @include  sencha-­‐list-­‐pullrefresh; @include  sencha-­‐layout; @include  sencha-­‐loading-­‐spinner; ...
  • 85. valley.scss $base-­‐color:  #9D9E00; @import  'sencha-­‐touch/default/all'; @include  sencha-­‐panel; @include  sencha-­‐buttons; @include  sencha-­‐sheet; @include  sencha-­‐tabs; @include  sencha-­‐toolbar; @include  sencha-­‐list; @include  sencha-­‐list-­‐pullrefresh; @include  sencha-­‐layout; @include  sencha-­‐loading-­‐spinner;
  • 87. Choose own icons $base-­‐color:  #9D9E00; $include-­‐default-­‐icons:  false; @import  'sencha-­‐touch/default/all'; @include  sencha-­‐panel; @include  sencha-­‐buttons; ... @include  pictos-­‐iconmask('briefcase1'); @include  pictos-­‐iconmask('heart'); @include  pictos-­‐iconmask('music1');
  • 88. Specify iconCls this.stayCardDataList  =  new  this.ListCardDataList({        store:  this.data.hotels,        title:  'Stay',        iconCls:  'briefcase1' }); this.eatCardDataList  =  new  this.ListCardDataList({        store:  this.data.restaurants,        title:  'Eat',        iconCls:  'heart' }); this.drinkCardDataList  =  new  this.ListCardDataList({        store:  this.data.bars,        title:  'Drink',        iconCls:  'music1' });
  • 89. _variables.scss $include-html-style: true; $base-color: #354F6E; $include-default-icons: true; $base-gradient: 'matte'; $include-form-sliders: true; $alert-color: red; $include-floating-panels: true; $confirm-color: #92cf00; $include-default-uis: true; $page-bg-color: #eee; $include-highlights: true; $global-row-height: 2.6em; $include-border-radius: true; $active-color: darken( saturate($base-color, 55%), $basic-slider: false; 10%);
  • 91. Sass is a superset of CSS $base-­‐color:  #9D9E00; $include-­‐default-­‐icons:  false; @import  'sencha-­‐touch/default/all'; ... @include  pictos-­‐iconmask('briefcase1'); @include  pictos-­‐iconmask('heart'); @include  pictos-­‐iconmask('music1'); .photo  {        float:left;        margin:0  8px  16px  0;        border:1px  solid  #ccc;        -­‐webkit-­‐box-­‐shadow:                0  2px  4px  #777; } ...
  • 92. WebFonts @import  url(http://fonts.googleapis.com/css?family=Voltaire); .x-­‐toolbar-­‐title  {    font-­‐family:  Voltaire;    font-­‐weight:  normal;    font-­‐size:  1.7em;    line-­‐height:  1.7em;    letter-­‐spacing:  0.05em; }
  • 93. Done?
  • 94. Development sequence 1 Structure the app 5 Detail page 2 Layout the UI 6 Add a map 3 Model the data 7 More data 4 Load the list 8 Customize theme
  • 96. And if we’d had time... Add to home screen - Icon - Splash screen Hybrid app; PhoneGap / NimbleKit - Contacts API - Geolocation http://sencha.com/x/cy http://sencha.com/x/de
  • 97. O ine app $>  phantomjs  confess.js  http://github/valley/ CACHE  MANIFEST #  This  manifest  was  created  by  confess.js #                    Time:  Wed  Sep  14  2011  10:14:45  GMT-­‐0700  (PDT) #        User-­‐agent:  Mozilla/5.0  ... CACHE: app/app.js app/yelp.js http://cdn.sencha.io/touch/1.1.0/sencha-­‐touch.js http://maps.google.com/maps/api/js?sensor=true http://maps.gstatic.com/intl/en_us/mapfiles/api-­‐3/6/4/main.js theming/valley.css NETWORK: * http://github.com/jamesgpearce/confess
  • 98. O ine data Taking Yelp data o ine Taking images o ine - src.sencha.io to generate cross-origin B64 Detecting network connection changes http://sencha.com/x/df
  • 100. built with Apps vs Web technology