City bars workshop

3,847 views

Published on

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

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,847
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
47
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

City bars workshop

  1. 1. James Pearce Director, Developer Relations @jamespearce jamesp@sencha.com
  2. 2. Build A Mobile Web App with CSSHTML JS
  3. 3. http://www.sencha.com/products/touch Sencha Touch A JavaScript framework for building rich mobile apps with web standards
  4. 4. 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/
  5. 5. CityBars http://sencha.com/x/bu
  6. 6. http://sencha.com/x/bv
  7. 7. 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
  8. 8. 1 Structure the app
  9. 9. index.html <!doctype  html> <html>        <head>                <title>City  Guide</title>        </head> <body></body> </html>
  10. 10. 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"  />
  11. 11. app.js cb  =  new  Ext.Application({        launch:  function()  {                new  Ext.Panel({                        layout        :  'card',                        fullscreen:  true,                        html:  "Hello  world!"                        });        } });
  12. 12. cb.cards 2 Layout the UI listCard detailCard toolbar toolbar dataList
  13. 13. index.html cb  =  new  Ext.Application({        launch:  function()  {                cb.cards  =  new  Ext.Panel({                        layout        :  'card',                        fullscreen:  true,                        cardSwitchAnimation:  'slide',                        items:  [                                {id:  'listCard'  ...},                                  {id:  'detailCard'  ...}                        ]                        });        } });
  14. 14. listCard {        id:  'listCard',        layout:  'fit',        dockedItems:  [{                dock  :  'top',                xtype:  'toolbar',                title:  'Please  wait'        }],        items:  [{                id:  'dataList',                xtype:  'list',                store:  null,                itemTpl:  '{name}'        }] }
  15. 15. detailCard {        id:  'listCard',        dockedItems:  [{                dock  :  'top',                xtype:  'toolbar',                title:  ''        }] }
  16. 16. 3 Model the data http://api.yelp.com/business_review_search ?ywsid=YELP_KEY &term=BUSINESS_TYPE &location=CITY
  17. 17. Apigee console
  18. 18. "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":  [            ...",          ],          ...
  19. 19. index.html <script  type="text/javascript">        YELP_KEY  =  'G3HueY_I5a8WZX-­‐_bFo3Mw';        DEFAULT_CITY  =  'New  York';        BUSINESS_TYPE  =  'Bars'; </script>
  20. 20. app.js Ext.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"},        ] });
  21. 21. app.js Ext.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'                }        },
  22. 22. app.js listeners:  {        'afterrender':  function  ()  {                cb.getCity(function  (city)  {                        cb.getBusinesses(city,  function  (store)  {                                console.log(store.data.items);                        });                });        } }
  23. 23. app.js getCity:  function  (callback)  {        callback(DEFAULT_CITY); }, getBusinesses:  function  (city,  callback)  {        Ext.regModel("Business",  {...});        Ext.regStore("businesses",  {                ...                listeners:  {                        'load':  function  (store)  {                                callback(store);                        }                }        }) }
  24. 24. 4 Load the list
  25. 25. app.js var  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);        }); });
  26. 26. app.js cards.setLoading(true); ... cards.setLoading(false);
  27. 27. 5 Attach events A more interesting list template ‘selection’ event to switch to detail
  28. 28. app.js itemTpl:    '<img  class="photo"  src="{photo_url}"  width="40"  height="40"/>'  +    '{name}<br/>'  +    '<img  src="{rating_img_url_small}"/>&nbsp;'  +    '<small>{address1}</small>'
  29. 29. index.html <style>        .photo  {                float:left;                margin:0  8px  16px  0;                border:1px  solid  #ccc;                -­‐webkit-­‐box-­‐shadow:                        0  2px  4px  #777;        } </style>
  30. 30. app.js listeners:  {        selectionchange:  function  (selectionModel,  records)  {                if  (records[0])  {                        cb.cards.setActiveItem(cb.cards.detailCard);                        cb.cards.detailCard.update(records[0].data);                }        } }
  31. 31. 6 Detail page Template for the detail card Back button with tap to switch back to list
  32. 32. app.js 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>' ]
  33. 33. app.js dockedItems:  [{        dock  :  'top',        xtype:  'toolbar',        title:  '',        items:  [{                text:  'Back',                ui:  'back',                listeners:  {                        tap:  function  ()  {                                cb.cards.setActiveItem(                                        cb.cards.listCard,                                        {type:'slide',  direction:  'right'}                                );                        }                }        }] }],
  34. 34. index.html .x-­‐html  h2  {        margin-­‐bottom:0; } .phone,  .link  {        clear:both;        font-­‐weight:bold;        display:block;        text-­‐align:center;        margin-­‐top:8px; }
  35. 35. 7 Add mapping Change detail page to tabbed Add map control Update data on both tabs
  36. 36. app.js {        id:  'detailCard',        xtype:  'tabpanel',        dockedItems:  [...]        items:  [                {                        title:  'Contact',                        tpl:  [...]                },                {                        title:  'Map',                        xtype:  'map',                        ...                        marker:                        new  google.maps.Marker()                }        ] }
  37. 37. index.html <script  src="http://maps.google.com/maps/api/js?sensor=true"                type="text/javascript"> </script>
  38. 38. 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);        }, }
  39. 39. app.js tabBar:  {        dock:  'top',        ui:  'light',        layout:  {  pack:  'center'  } }
  40. 40. app.js update:  function(data)  {        Ext.each(this.items.items,  function(item)  {                item.update(data);        });        this.getDockedItems()[0].setTitle(data.name); }
  41. 41. 8 Customize theme Sass & Compass Compile & link new theme
  42. 42. http://sass-lang.com/
  43. 43. /* 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
  44. 44. $> sudo gem install compass http://rubyinstaller.org/
  45. 45. $> 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)
  46. 46. 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;
  47. 47. $>  compass  compile  citybars.scss overwrite  citybars.css  
  48. 48. index.html <link    href="theming/citybars.css"    rel="stylesheet"  type="text/css" />
  49. 49. James Pearce Director, Developer Relations @jamespearce jamesp@sencha.com

×