bd conf sencha touch workshop

Post on 17-Nov-2014

3.894 Views

Category:

Technology

3 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

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

BuildingMobile Web Apps

with

CSSHTML JS

One PC

Multiple devices

Sedentary usage

Mobile usage

Documents

Applications

Declarative HTML

Programmatic JS

Thin client

Thick client

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.

A New Mobile App Stack

JavaScript

Semantic HTML

CSS Styling & Layout

WebFonts Video Audio Graphics

Worker Parallel

Processing

File SystemsDBs

App Cache

x-AppMessaging

Device Access

Camera

Location

Contacts

SMS

Orientation

Gyro

Server & Services

HTTP

AJAX

Events

Sockets

SSL

More...

Rich Media & StylingFull Resource Access

Parallel ProcessingInter-App Communication

Full O!ine Capability A COMPLETE MODERN RUNTIME

WebKit FOEs

HTML5 SupportIE 10 PR Chrome 10 Safari 5 Firefox 4 iOS4.31 Playbook Honeycomb

@font-faceCanvasHTML5 Audio & Videorgba(), hsla()border-image:border-radius:box-shadow:text-shadow:opacity:Multiple backgroundsFlexible Box ModelCSS AnimationsCSS ColumnsCSS GradientsCSS ReflectionsCSS 2D TransformsCSS 3D TransformsCSS TransitionsGeolocation APIlocal/sessionStorageSVG/SVG ClippingSMILInline SVGDrag and DrophashchangeX-window MessagingHistory ManagementapplicationCacheWeb SocketsWeb WorkersWeb SQL DatabaseWebGLIndexedDB

Stay on top of diversityCan I Use?http://caniuse.com

Modernizrhttp://modernizr.com

DeviceAtlashttp://deviceatlas.com

Capability

Div

ersi

tyPearce’s Universal Law of

Mobile Web Browsers

(for all T)

Capability

Supp

ort

Pearce’s Universal Law of Mobile Web Browsers

(for all T)

Capability

Supp

ort

JavaScript frameworks,polyfills & shims

Evolving the web for mobile

HTML, CSS...

Models

Controllers

Views

Models

Controllers

Mobile

DesktopSw

itch

er HTML, CSS...

Evolving the web for mobile

JSON

Models

Controllers

Mobile

DesktopSw

itch

ers

RESTonce

Evolving the web for mobile

The classic web stack

Storage

Business logic

User interfacereq/res

Rendering

An alternative web stack

Storage

Security Business logic

User interfacesync

Storage

Write once,run anywhere?

The Mobile Webis not a

320px Web

Proxies

Models

Controllers

Stores

Views Views

json

Thick client, thin server

The shortfall in the cloud

Location Services

Image Serving

AnalyticsAdaptation

Video Serving

Data SyncWeb Fonts

Ad Serving

Commerce$

Network APIs

http://mysite.com/myimage.png

http://src.sencha.io/http://mysite.com/myimage.png

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

Sencha TouchA JavaScript framework for building

rich mobile apps with web standards

Get Sencha Touch

http://sencha.com/touch

Components

Theming

Forms

Scrolling

Touch Events

Data access & MVC

Charts

Kitchen Sink

http://sencha.com/x/5e

Your First App

<!DOCTYPE html><html>

<head>

<title>Hello World</title>

<script src="sencha-touch.js" type="text/javascript"></script>

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

<script type="text/javascript"> ... </script>

</head>

<body></body>

</html>

Your First Appnew 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!' });

}

});

Listvar list = new Ext.List({ store: store, itemTpl: '{firstName} {lastName}', grouped: true, indexBar: true});

Nested Listvar list = new Ext.NestedList({ store: store, displayField: 'name', title: 'My List', updateTitleText: true, getDetailCard: function(record, parent) {..}});

Carouselvar car = new Ext.Carousel({ direction: 'horizontal', indicator: true, items: [ .. ]});

Sheetsvar sheet = new Ext.ActionSheet({ items: [ { text: 'Delete draft', ui: 'decline' }, { text: 'Save draft' }, { text: 'Cancel', } ]});sheet.show();

Get Started!

http://sencha.com/x/d5

Pre-requisites for todaySencha 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 Nashville App

http://sencha.com/x/buhttp://sencha.com/x/dg

http://github.com/jamesgpearce/nashville

Development sequence

1 Structure the app

2 Layout the UI

3 Model the data

4 Load the list

5 Detail page

6 Add a map

7 More data

8 Customize theme

1 Structure the app

index.html

<!doctype  html><html>        <head>                <title>Nashville  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.jsnv  =  new  Ext.Application({

       launch:  function()  {

               this.viewport  =  new  Ext.Panel({

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

       }

});

nv.viewport

2 Layout the UI

listCard detailCard

toolbar toolbar

dataList

The app...nv  =  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]                });        }});

listCardthis.listCardToolbar  =  new  Ext.Toolbar({        dock:  'top',        title:  'Nashville  Guide'});

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

this.listCard  =  new  Ext.Panel({        dockedItems:  [this.listCardToolbar],        items:  [this.listCardDataList],        layout:  'fit'});

detailCardthis.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=Nashville,TN

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 namespacethis.data  =  {};

The ‘Business’ modelthis.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 modelsthis.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=Nashville,TN',                reader:  {                        type:  'json',                        root:  'businesses'                }        }});

4 Load the listthis.listCardDataList  =  new  Ext.List({        store:  this.data.restaurants,        itemTpl:  '{name}'});

A more interesting templateitemTpl:        '<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 pagethis.listCardDataList  =  new  Ext.List({        store:  this.data.restaurants,        itemTpl:  ...        listeners:  {                selectionchange:  function  (selectionModel,  records)  {                        if  (records[0])  {                                nv.viewport.setActiveItem(nv.detailCard);                                nv.detailCardToolbar.setTitle(                                        records[0].get('name')                                );                        }                }        }});

A back buttonthis.detailCardToolbar  =  new  Ext.Toolbar({        dock:  'top',        title:  '...',        items:  [{                text:  'Back',                ui:  'back',                handler:  function  ()  {                        nv.viewport.setActiveItem(                                nv.listCard,                                {type:  'slide',  direction:  'right'}                        );                }        }]});

Detail templatethis.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

nv.viewport

listCard detailTabs

toolbar toolbar

dataList dataListdetailCard

6 Add a map

nv.viewport.setActiveItem(nv.detailTabs);

...

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

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

nv.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 locationselectionchange:  function  (selectionModel,  records)  {        ...        var  map  =  nv.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 barthis.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)  {        nv.data[type]  =  new  Ext.data.Store({                model:  nv.data.Business,                autoLoad:  true,                proxy:  {                        type:  'scripttag',                        url:  'http://api.yelp.com/business_review_search'  +                                '?ywsid='  +  YELP_KEY  +                                '&term='  +  type  +                                '&location=Nashville,TN',                        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 timesthis.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 toothis.listCard  =  new  Ext.TabPanel({        items:  [                this.stayCardDataList,                  this.eatCardDataList,                  this.drinkCardDataList        ],        tabBar:  {                ui:  'light',                layout:  {  pack:  'center'  },                dock:  'bottom'        },        cardSwitchAnimation:  'flip',...

And add titles & iconsthis.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-refreshthis.ListCardDataList  =  Ext.extend(Ext.List,  {        ...        plugins:  [{                ptype:  'pullrefresh'        }]});

8 Customize 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)

Start by copying sencha-touch.scss

config.rbdir  =  File.dirname(__FILE__)

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

#  Compass  configurationssass_path        =  dircss_path          =  direnvironment    =  :productionoutput_style  =  :compressed

#  or  :nested,  :expanded,  :compact

Compile...$>  cd  theming

$>  compass  compile  nashville.scss            create  nashville.css

$>  compass  compile  nashville.scss            identical  nashville.css

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

$>  compass  watch  nashville.scss            >>>  Change  detected  to:  nashville.scss            overwrite  nashville.css

Link...<link  href="theming/nashville.css"  rel="stylesheet"            type="text/css"  />

nashville.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;...

nashville.scss$base-­‐color:  #849;

@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;

Choose own icons$base-­‐color:  #849;$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 iconClsthis.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;

$include-default-icons: true;

$include-form-sliders: true;

$include-floating-panels: true;

$include-default-uis: true;

$include-highlights: true;

$include-border-radius: true;

$basic-slider: false;

$base-color: #354F6E;

$base-gradient: 'matte';

$alert-color: red;

$confirm-color: #92cf00;

$page-bg-color: #eee;

$global-row-height: 2.6em;

$active-color: darken( saturate($base-color, 55%), 10%);

http://dev.sencha.com/deploy/touch/docs/theme/

Sass is a superset of CSS$base-­‐color:  #849;$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=Smokum);

.x-­‐toolbar-­‐title  {    font-­‐family:  Smokum;    font-­‐weight:  normal;    font-­‐size:  1.7em;    line-­‐height:  1.7em;    letter-­‐spacing:  0.05em;}

Done?

Development sequence

1 Structure the app

2 Layout the UI

3 Model the data

4 Load the list

5 Detail page

6 Add a map

7 More data

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 - Packaging

http://sencha.com/x/cy

http://sencha.com/x/de

O!ine app

http://github.com/jamesg

pearce/confess

$>  phantomjs  confess.js  http://github/nashville/

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.jsapp/yelp.jshttp://cdn.sencha.io/touch/1.1.0/sencha-­‐touch.jshttp://maps.google.com/maps/api/js?sensor=truehttp://maps.gstatic.com/intl/en_us/mapfiles/api-­‐3/6/4/main.jstheming/nashville.css

NETWORK:*

O!ine data

http://sencha.com/x/df

Taking Yelp data o"ine

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

Detecting network connection changes

Weinre

http://phonegap.github.c

om/weinre/

Apps vs Web technologybuilt with

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

top related