Bd conf sencha touch workshop
-
Upload
james-pearce -
Category
Technology
-
view
3.889 -
download
3
description
Transcript of Bd conf sencha touch workshop
James Pearce Director, Developer Relations @ jamespearce [email protected]
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}"/> ' + '<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 [email protected]