sencha touch

73
Craig Walker, Chief Technology Officer www.xero.com

Upload: craig-walker

Post on 17-Nov-2014

10.748 views

Category:

Technology


3 download

DESCRIPTION

Talk I did at the Wellington JS Meetup on 24 Feb 2011 on Sencha Touch and PhoneGap.

TRANSCRIPT

Page 1: Sencha Touch

Craig Walker, Chief Technology Officer www.xero.com

Page 2: Sencha Touch

Craig Walker, Chief Technology Officer www.xero.com

Page 3: Sencha Touch

http://www.xero.com/signup/

What is Xero?

Page 4: Sencha Touch
Page 5: Sencha Touch
Page 6: Sencha Touch
Page 7: Sencha Touch

BlackBerry 6

Page 8: Sencha Touch

BlackBerry 6 2nd half 2011

Page 9: Sencha Touch

Lots of frameworks…

• Zepto.js• DynamicX• SproutCore• XUI• Appcelerator• iUI• iWebKit• jQuery Mobile• jQTouch• And lots more…

Page 10: Sencha Touch

Sencha Touch

Page 11: Sencha Touch

What is Sencha Touch?A JavaScript framework for

building rich mobile applications

Page 12: Sencha Touch

Why Sencha Touch?

• Cross-platform• Looks native, feels native• Faster, cheaper, easier to build with• Highly customisable• Flexible deployment• HTML5/CSS3 goodness

Page 13: Sencha Touch

Yes - but WHY Sencha Touch?

Page 14: Sencha Touch

Tap !== Click

Page 15: Sencha Touch

Touch Event Manager

• Built on native events• Abstracted for performance• Multi-touch & gesture support

Page 16: Sencha Touch

Touch Event Manager

Ext.fly("el").on({ tap: function() { alert("You tapped me"); }, pinch: function() { alert("You pinched me"); }, swipe: function() { alert("Stop touching me...") }});28

Page 17: Sencha Touch
Page 18: Sencha Touch

Scroll Event Manager

• Scrolling with momentum & bounce physics

• Native & natural• Hardware accelerated

Page 19: Sencha Touch

UI Toolkit

Page 20: Sencha Touch

Buttons

Page 21: Sencha Touch

FormsSliders

Page 22: Sencha Touch

Pickers

Page 23: Sencha Touch

Lists

Page 24: Sencha Touch

NestedLists

Page 25: Sencha Touch

ToolbarsTabs

Page 26: Sencha Touch

PanelsCarousels

Page 27: Sencha Touch

Maps

Page 28: Sencha Touch

Overlays

Page 29: Sencha Touch

Layouts

• Container layout specifies how its children components are rendered

Page 30: Sencha Touch

fit

Page 31: Sencha Touch

card

Page 32: Sencha Touch

vbox

Page 33: Sencha Touch

hbox

Page 34: Sencha Touch

ModelsViews

Controllers

Stores

RoutesMVC

Page 35: Sencha Touch

Theming

• SASS & Compass – sass-lang.com– compass-style.org

• CSS3 is awesome – SCSS is awesomer

Page 36: Sencha Touch

SCSS CSS

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

.example1 { border-color: $blue;}

.example2 { margin: $margin; color: $blue;}

.example3 { margin: ($margin / 2px) * $padding;}

/* line 5, variables.scss */.example1 { border-color: #3bbfce;}

/* line 9, variables.scss */.example2 { margin: 16px; color: #3bbfce;}

/* line 14, variables.scss */.example3 { margin: 32px;}

Page 37: Sencha Touch

@mixin add-child($color) { color: $color; background-color: lighten($color, 50); .child { padding: 5px; &:first { background-color: darken($color, 10) }; span { color: mix($color, blue); } }}

.example { @include add-child(#F00);}

/* line 18, mixins.scss */.example { color: red; background-color: white;}/* line 5, mixins.scss */.example .child { padding: 5px;}/* line 8, mixins.scss */.example .child:first { background-color: #cc0000;}/* line 12, mixins.scss */.example .child span { color: #7f007f;}

SCSS CSS

Page 38: Sencha Touch

@import "compass";

$width: 100px;

.button { width: $width; .round { @include border-radius(5px); } .linear { @include linear-gradient( color-stops(white, #c39 30%, #b7f 70%, #aaa) ); }}

/* line 5, gradients.scss */.button { width: 100px;}/* line 8, gradients.scss */.button .round { -moz-border-radius: 5px; -webkit-border-radius: 5px; -o-border-radius: 5px; -ms-border-radius: 5px; -khtml-border-radius: 5px; border-radius: 5px;}/* line 12, gradients.scss */.button .linear { background-image: -webkit-gradient( linear, 0% 0%, 0% 100%, color-stop(0%, #ffffff), color-stop(50%, #cc3399), color-stop(100%, #bb77ff)); background-image: -moz-linear-gradient(top, #ffffff 0%, #cc3399 50%, #bb77ff 100%); background-image: linear-gradient(top, #ffffff 0%, #cc3399 50%, #bb77ff 100%);}

SCSS CSS

Page 39: Sencha Touch

Let’s look at some code...

Page 40: Sencha Touch

Demo: From Desktop to Mobile

Page 41: Sencha Touch

<!doctype html><html><head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Xero Help</title> <link rel="stylesheet" href="resources/css/xerohelp.css" type="text/css"></head><body> <script type="text/javascript" src="lib/sencha-touch-debug.js"></script> <script type="text/javascript" src="app/xerohelp.js"></script></body></html>

index.html

Page 42: Sencha Touch

// utilsdocument.write('<script type="text/javascript" src="app/utils/string.js"></script>');

// applicationdocument.write('<script type="text/javascript" src="app/routes.js"></script>');document.write('<script type="text/javascript" src="app/app.js"></script>');

// modelsdocument.write('<script type="text/javascript" src="app/models/TOC.js"></script>');document.write('<script type="text/javascript" src="app/models/HelpFile.js"></script>');

// viewsdocument.write('<script type="text/javascript" src="app/views/Viewport.js"></script>');document.write('<script type="text/javascript" src="app/views/TOCPanel.js"></script>');document.write('<script type="text/javascript" src="app/views/HelpCarousel.js"></script>');document.write('<script type="text/javascript" src="app/views/HelpPanel.js"></script>');

// controllersdocument.write('<script type="text/javascript" src="app/controllers/help.js"></script>');

app/xerohelp.js

Page 43: Sencha Touch

Ext.Router.draw(function(map) { map.connect("/help/home", {controller: 'help', action: 'home'}); map.connect("/help/:id", {controller: 'help', action: 'show'});});

app/routes.js

Page 44: Sencha Touch

Ext.regApplication({ name: "XERO", defaultUrl: '/help/home', defaultTarget: "viewport", icon: 'resources/images/icon.png', glossOnIcon: false, region: "NZ", apiUrl: "http://help.stage.xero.com/api", launch: function() { this.viewport = new XERO.Viewport({ application: this }); } });

app/app.js

Page 45: Sencha Touch

XERO.Viewport = Ext.extend(Ext.Panel, {

id: 'viewport', layout: 'card', fullscreen: true,

initComponent: function() { Ext.apply(this, { dockedItems: [{ xtype: "toolbar", dock : "top", title: "Help Center", itemId: "help-toolbar" },{ xtype: "toolbar", dock: "bottom", items: [{ xtype: "button", text: "Index", handler: this.onTOCButtonTap, scope: this },{ xtype: "spacer" }, { xtype: "button", text: "Switch Region", handler: this.onSwitchRegionTap, scope: this }] }] }); XERO.Viewport.superclass.initComponent.apply(this, arguments); }, ...

app/views/viewport.js

Page 46: Sencha Touch

setTitle: function(title) { this.down("#help-toolbar").setTitle(title); }, onTOCButtonTap: function() { if(! this.tocPanel) { this.tocPanel = Ext.create({ xtype: "tocpanel" }); } this.tocPanel.show(); }, onSwitchRegionTap: function() { if(! this.regionPicker) { this.regionPicker = new Ext.Picker({ slots: [{ name : 'region', title: 'Switch Region', data : [ {text: 'New Zealand', value: "NZ"}, {text: 'Australia', value: "AUS"}, {text: 'United Kingdom', value: "UK"}, {text: 'Global', value: "INT"} ] }] }); } this.regionPicker.show(); }});

app/views/viewport.js

Page 47: Sencha Touch

Ext.regController("help", {

home: function(request) { this.show(Ext.apply(request, { id: "home" })); }, show: function(request) { if(! this.helpCarousel) { this.helpCarousel = this.render({ xtype: 'helpcarousel' }); } XERO.viewport.setActiveItem(this.helpCarousel); XERO.viewport.setTitle("Loading..."); this.helpCarousel.loadHelpPage(request.id, request.historyUrl); }});

app/controllers/help.js

Page 48: Sencha Touch

Ext.regModel("HelpFile", { fields: [ { name: "id", type: "int" }, "abstractText", "body", "heading", "helpPage", { name: "createdDateUTC", type: "date", format: "M$" }, { name: "success", type: "boolean" } ] /*, validations: [ { type: "presence", field: "helpPage" } ],

hasMany: [ { model: "Region", name: "regions" } ] */});

app/models/helpfile.js

Page 49: Sencha Touch

Ext.regModel("TOC", { fields: [ "id", "helpPage", "href", "text" ], proxy: { type: 'scripttag', url: String.format("{0}/toc/", XERO.apiUrl), reader: { type: "tree", root: "items" } }});

(function() { new Ext.data.TreeStore({ storeId: "TOCStore", model: "TOC", autoLoad: true });}());

app/models/toc.js

Page 50: Sencha Touch

XERO.views.HelpCarousel = Ext.extend(Ext.Carousel, {

cls: "cards", layout: "fit",

initComponent: function() { XERO.views.HelpCarousel.superclass.initComponent.apply(this, arguments); }, onRender: function() { XERO.views.HelpCarousel.superclass.onRender.apply(this, arguments); if(this.el) { this.mon(this.el, { tap: this.onTap, click: Ext.emptyFn, delegate: "a", stopEvent: true, scope: this }); this.mon(this, { cardswitch: function() { this.onHelpSwitch(this.getActiveItem().helpPage); }, scope: this }); } },

app/views/helpcarousel.js

Page 51: Sencha Touch

loadHelpPage: function(id, href) { var bookmark; if(href.indexOf("$") != -1) { bookmark = href.right(href.length - href.indexOf("$") - 1); } var item = this.getComponent(id); if(item) { this.setActiveItem(item); if(bookmark){ item.scrollToBookmark(bookmark); } } else { var panel = this.add({ xtype: "helppanel", id: id, goToBookmark: bookmark, listeners: { helploaded: this.onHelpSwitch, single: true, scope: this } }); this.doComponentLayout(); this.setActiveItem(panel); } },

app/views/helpcarousel.js

Page 52: Sencha Touch

app/views/helpcarousel.js onTap: function(e, target) { var id = target.getAttribute('xero:id'), type = target.getAttribute('xero:type'), bookmark = target.getAttribute('xero:bookmark'), url = target.getAttribute('xero:path'); if(type && type.toLowerCase() == "help") { if(bookmark) { this.getActiveItem().scrollToBookmark(bookmark); } else { Ext.dispatch({ controller: "help", action: "show", id: id, historyUrl: target.href }); } } else { if(target.href.toLowerCase().startsWith("mailto:")) { location.href = target.href; } else { window.open(target.href); } } }});

Ext.reg('helpcarousel', XERO.views.HelpCarousel);

Page 53: Sencha Touch

XERO.views.HelpPanel = Ext.extend(Ext.Panel, {

cls: "help-panel", layout: "fit", scroll: "vertical", styleHtmlContent: true, goToBookmark: null, html: '<div class="loading-indicator"> </div>', initComponent: function() { this.addEvents("helploaded"); XERO.views.HelpPanel.superclass.initComponent.apply(this, arguments); }, onRender: function() { XERO.views.HelpPanel.superclass.onRender.apply(this, arguments); this.loadHelpPage(); },...

app/views/helppanel.js

Page 54: Sencha Touch

loadHelpPage: function() { Ext.util.JSONP.request({ url: String.format("{0}/help/", XERO.apiUrl), callbackKey: "callback", params: { helpPage: this.id }, callback: function(doc) { this.helpPage = doc; this.title = doc.heading; this.update(this.helpPage.body); if(this.goToBookmark) { this.scrollToBookmark(this.goToBookmark); } this.fireEvent("helploaded", this.helpPage); }, scope: this }); },

scrollToBookmark: function(bookmark) { var el = this.getEl().down(String.format('a[name="{0}"]', bookmark)); if (el) { this.scrollIntoView(el); } }, }); Ext.reg('helppanel', XERO.views.HelpPanel);

app/views/helppanel.js

Page 55: Sencha Touch

XERO.views.TOCPanel = Ext.extend(Ext.NestedList, { title: "Index", showAnimation: { type: "slide", direction: "up" }, floating: true,

initComponent: function() { this.store = Ext.getStore("TOCStore"); this.toolbar = {...}; XERO.views.TOCPanel.superclass.initComponent.apply(this, arguments); this.mon(this, { selectionchange: function(list, selection) { var record = selection[0]; if(record.get("leaf") === true) { Ext.dispatch({ controller: "help", action: "show", id: record.get("helpPage"), historyUrl: String.format("/help/{0}", record.get("helpPage")) }); this.hide(); } }, scope: this }); }});

app/views/helppanel.js

Page 56: Sencha Touch

Touchable help...

Page 57: Sencha Touch

going native

Page 58: Sencha Touch

• Cross-platform• Open source• Extensible• Instantiates chromeless

web view• Adds JavaScript access

to native APIs

Page 59: Sencha Touch

PhoneGap

Web App

etc…

Page 60: Sencha Touch

Native APIs

• Device identification• Network access• Sensors• Camera/image sources• Contacts• File access

Page 61: Sencha Touch

Everything else?

• HTML for layout

• JavaScript for accessing device APIs

• CSS for look & feel

• Offline storage for standalone clients

• Ajax, JSONP for syncing to the cloud– Runs on file:// protocol which is exempt from same-origin

policy

• Just use Sencha Touch!

Page 62: Sencha Touch

PhoneGap Build

Page 63: Sencha Touch

Tips & Tricks

Page 64: Sencha Touch

Tools

• Browsers – Safari the best (unfortunately)• Web Inspector• RemoteJS (Android debugging)• Souders’ bookmarklets

– stevesouders.com/mobileperf• Jdrop

– jdrop.org

Page 65: Sencha Touch

Object-oriented

• Use namespaces to define your library• Define components – code for reusability• Extend first, write plugins second (not at all

if possible)

Page 66: Sencha Touch

Events rock!

• Use events to communicate between components

• Use event delegation

Page 67: Sencha Touch

Override appropriately

• Do not edit the library files• DO NOT EDIT THE LIBRARY FILES!• Use an overrides file if you need to override

the framework• Do the same with CSS (but you should be

using cls, ui properties)

Page 68: Sencha Touch

Define a directory structure

• Break your code into small files• Use build tools to compile for performance• Use sencha-touch-debug.js during dev (but

never prod!)• Keep the framework up-to-date – upgrade as

often as you can

Page 69: Sencha Touch

Worry about performance

• Understand client-side performance rules & use them

• Latency bad• JIT compilers – compilation time relates to

size of file the method exists in• Keep DOM light• Destroy components that aren’t visible• concatenate, minify, compress!

Page 70: Sencha Touch

Theming/Layouts

• Use SCSS• Remove unnecessary CSS by only

including required SCSS mixins• Understand XTemplate• Understand doComponentLayout

Page 71: Sencha Touch

Sencha.com

Read the forums

Read the docs

Read the source!

Page 72: Sencha Touch

Any questions?

www.xero.com