city bars workshop

Post on 12-Jan-2015

3.864 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

The mobile web app workshop at Flash and the City, June 2011.

TRANSCRIPT

James Pearce Director, Developer Relations @ jamespearce jamesp@sencha.com

Build AMobile Web App

with

CSSHTML JS

http://www.sencha.com/products/touch

Sencha TouchA JavaScript framework for building

rich mobile apps with web standards

Pre-requisitesSencha 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/

CityBars

http://sencha.com/x/bu

http://sencha.com/x/bv

Development sequence

1 Structure the app

2 Layout the UI

3 Model the data

4 Load the list

5 Attach events

6 Detail page

7 Add mapping

8 Customize theme

1 Structure the app

index.html

<!doctype  html><html>        <head>                <title>City  Guide</title>        </head>

<body></body></html>

index.html<script  src="lib/touch/sencha-­‐touch.js"                  type="text/javascript"></script>

<script  type="text/javascript">        YELP_KEY  =  'G3HueY_I5a8WZX-­‐_bFo3Mw';        ...</script>

<script  src="app/app.js"                type="text/javascript"></script>

<link  href="lib/touch/resources/css/sencha-­‐touch.css"              rel="stylesheet"  type="text/css"  />

app.jscb  =  new  Ext.Application({

       launch:  function()  {                new  Ext.Panel({

                       layout        :  'card',                        fullscreen:  true,

                       html:  "Hello  world!"                        });        }

});

cb.cards

2 Layout the UI

listCard detailCard

toolbar toolbar

dataList

index.htmlcb  =  new  Ext.Application({        launch:  function()  {                cb.cards  =  new  Ext.Panel({                        layout        :  'card',                        fullscreen:  true,

                       cardSwitchAnimation:  'slide',

                       items:  [                                {id:  'listCard'  ...},                                  {id:  'detailCard'  ...}                        ]                        });        }});

listCard{        id:  'listCard',        layout:  'fit',        dockedItems:  [{                dock  :  'top',                xtype:  'toolbar',                title:  'Please  wait'        }],        items:  [{                id:  'dataList',                xtype:  'list',                store:  null,                itemTpl:  '{name}'        }]}

detailCard{        id:  'listCard',        dockedItems:  [{                dock  :  'top',                xtype:  'toolbar',                title:  ''        }]}

3 Model the data

http://api.yelp.com/business_review_search?ywsid=YELP_KEY&term=BUSINESS_TYPE&location=CITY

Apigee console

"businesses":  [        {          "rating_img_url"  :  "http://media4.px.yelpcdn.com/...",          "country_code"  :  "US",          "id"  :  "BHpAlynD9dIGIaQDRqHCTA",          "is_closed"  :  false,          "city"  :  "Brooklyn",          "mobile_url"  :  "http://mobile.yelp.com/biz/...",          "review_count"  :  50,          "zip"  :  "11231",          "state"  :  "NY",          "latitude"  :  40.675758,          "address1"  :  "253  Conover  St",          "address2"  :  "",          "address3"  :  "",          "phone"  :  "7186258211",          "state_code"  :  "NY",          "categories":  [            ...",          ],          ...

index.html<script  type="text/javascript">        YELP_KEY  =  'G3HueY_I5a8WZX-­‐_bFo3Mw';        DEFAULT_CITY  =  'New  York';        BUSINESS_TYPE  =  'Bars';</script>

app.jsExt.regModel("Business",  {        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"},        ]});

app.jsExt.regStore("businesses",  {        model:  'Business',        autoLoad:  true,        proxy:  {                type:  'scripttag',                url:  'http://api.yelp.com/business_review_search'  +                        '?ywsid='  +  YELP_KEY  +                        '&term='  +  escape(BUSINESS_TYPE)  +                        '&location='  +  escape(city)                ,                reader:  {                        type:  'json',                        root:  'businesses'                }        },

app.jslisteners:  {

       'afterrender':  function  ()  {

               cb.getCity(function  (city)  {

                       cb.getBusinesses(city,  function  (store)  {

                               console.log(store.data.items);

                       });                });

       }}

app.jsgetCity:  function  (callback)  {        callback(DEFAULT_CITY);},

getBusinesses:  function  (city,  callback)  {        Ext.regModel("Business",  {...});

       Ext.regStore("businesses",  {                ...                listeners:  {                        'load':  function  (store)  {                                callback(store);                        }                }        })}

4 Load the list

app.jsvar  cards  =  this;cards.listCard  =  cards.getComponent('listCard');cards.dataList  =  cards.listCard.getComponent('dataList');cards.detailCard  =  cards.getComponent('detailCard');

cb.getCity(function  (city)  {

       cards.listCard.getDockedItems()[0]                  .setTitle(city  +  '  '  +  BUSINESS_TYPE);

       cb.getBusinesses(city,  function  (store)  {

               cards.dataList.bindStore(store);                cards.setActiveItem(cards.listCard);

       });});

app.jscards.setLoading(true);

...

cards.setLoading(false);

5 Attach events

A more interesting list template

‘selection’ event to switch to detail

app.jsitemTpl:    '<img  class="photo"  src="{photo_url}"  width="40"  height="40"/>'  +    '{name}<br/>'  +    '<img  src="{rating_img_url_small}"/>&nbsp;'  +    '<small>{address1}</small>'

index.html<style>        .photo  {                float:left;                margin:0  8px  16px  0;                border:1px  solid  #ccc;                -­‐webkit-­‐box-­‐shadow:                        0  2px  4px  #777;        }</style>

app.jslisteners:  {

       selectionchange:  function  (selectionModel,  records)  {

               if  (records[0])  {                        cb.cards.setActiveItem(cb.cards.detailCard);                        cb.cards.detailCard.update(records[0].data);                }

       }

}

6 Detail page

Template for the detail card

Back button with tap to switch back to list

app.jsstyleHtmlContent:  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>']

app.jsdockedItems:  [{        dock  :  'top',        xtype:  'toolbar',        title:  '',        items:  [{                text:  'Back',                ui:  'back',                listeners:  {                        tap:  function  ()  {                                cb.cards.setActiveItem(                                        cb.cards.listCard,                                        {type:'slide',  direction:  'right'}                                );                        }                }        }]}],

index.html.x-­‐html  h2  {        margin-­‐bottom:0;}.phone,  .link  {        clear:both;        font-­‐weight:bold;        display:block;        text-­‐align:center;        margin-­‐top:8px;}

7 Add mapping

Change detail page to tabbed

Add map control

Update data on both tabs

app.js{        id:  'detailCard',        xtype:  'tabpanel',        dockedItems:  [...]        items:  [                {                        title:  'Contact',                        tpl:  [...]                },                {                        title:  'Map',                        xtype:  'map',                        ...                        marker:                        new  google.maps.Marker()                }        ]}

index.html<script  src="http://maps.google.com/maps/api/js?sensor=true"                type="text/javascript"></script>

app.js{        xtype:  'map',        ...        update:  function  (data)  {

               this.map.setCenter(                        new  google.maps.LatLng(data.latitude,  data.longitude                ));                this.marker.setPosition(                        this.map.getCenter()                );

               this.marker.setMap(this.map);        },}

app.jstabBar:  {        dock:  'top',        ui:  'light',        layout:  {  pack:  'center'  }}

app.jsupdate:  function(data)  {

       Ext.each(this.items.items,  function(item)  {                item.update(data);        });

       this.getDockedItems()[0].setTitle(data.name);

}

8 Customize theme

Sass & Compass

Compile & link new theme

http://sass-lang.com/

/* SCSS */

$blue: #3bbfce;$margin: 16px;

.content-navigation { border-color: $blue; color: darken($blue, 9%);}

.border { padding: $margin / 2; margin: $margin / 2; border-color: $blue;}

/* CSS */

.content-navigation { border-color: #3bbfce; color: #2b9eab;}

.border { padding: 8px; margin: 8px; border-color: #3bbfce;}

Variables

$> sudo gem install compass

http://rubyinstaller.org/

$> compass -v

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

$> sass -v

Sass 3.1.1 (Brainy Betty)

citybars.scss$base-­‐color:  #666;$base-­‐gradient:  'glossy';$include-­‐default-­‐icons:  false;

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

@include  sencha-­‐panel;@include  sencha-­‐buttons;@include  sencha-­‐tabs;@include  sencha-­‐toolbar;@include  sencha-­‐list;@include  sencha-­‐layout;@include  sencha-­‐loading-­‐spinner;

$>  compass  compile  citybars.scss

overwrite  citybars.css  

index.html<link    href="theming/citybars.css"    rel="stylesheet"  type="text/css"/>

James Pearce Director, Developer Relations @ jamespearce jamesp@sencha.com

top related