Your SlideShare is downloading. ×
0
Craig Walker, Chief Technology Officer   www.xero.com
Craig Walker, Chief Technology Officer   www.xero.com
What is Xero?http://www.xero.com/signup/
BlackBerry 6
BlackBerry 6   2nd half 2011
Lots of frameworks…•   Zepto.js•   DynamicX•   SproutCore•   XUI•   Appcelerator•   iUI•   iWebKit•   jQuery Mobile•   jQT...
Sencha Touch
What is Sencha Touch?   A JavaScript framework forbuilding rich mobile applications
Why Sencha Touch?•   Cross-platform•   Looks native, feels native•   Faster, cheaper, easier to build with•   Highly custo...
Yes - but WHY Sencha Touch?
Tap !== Click
Touch Event Manager•   Built on native events•   Abstracted for performance•   Multi-touch & gesture support
Touch Event Manager     Ext.fly("el").on({       tap: function() {          alert("You tapped me");       },       pinch: ...
Scroll Event Manager•   Scrolling with momentum &    bounce physics•   Native & natural•   Hardware accelerated
UI Toolkit
Buttons
FormsSliders
Pickers
Lists
NestedLists
ToolbarsTabs
PanelsCarousels
Maps
Overlays
Layouts•   Container layout specifies how its children    components are rendered
fit
card
vbox
hbox
MVC               Routes              Controllers                            Models      Views                            ...
Theming•   SASS & Compass    – sass-lang.com    – compass-style.org•   CSS3 is awesome – SCSS is awesomer
SCSS                                   CSS$blue: #3bbfce;                         /* line 5, variables.scss */$margin: 16p...
SCSS                                   CSS@mixin add-child($color) {                        /* line 18, mixins.scss */  co...
SCSS                                      CSS@import "compass";                      /* line 5, gradients.scss */         ...
Let’s look at some code...
Demo: From Desktop to Mobile
index.html<!doctype html><html><head>  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  <title>Xero He...
app/xerohelp.js// utilsdocument.write(<script type="text/javascript" src="app/utils/string.js"></script>);// applicationdo...
app/routes.jsExt.Router.draw(function(map) {  map.connect("/help/home", {controller: help, action: home});  map.connect("/...
app/app.jsExt.regApplication({  name: "XERO",  defaultUrl: /help/home,  defaultTarget: "viewport",  icon: resources/images...
XERO.Viewport = Ext.extend(Ext.Panel, {  id: viewport,                                    app/views/viewport.js  layout: c...
setTitle: function(title) {     this.down("#help-toolbar").setTitle(title);  },                                           ...
app/controllers/help.jsExt.regController("help", {  home: function(request) {     this.show(Ext.apply(request, {       id:...
app/models/helpfile.jsExt.regModel("HelpFile", {  fields: [     { name: "id", type: "int" },     "abstractText",     "body"...
app/models/toc.jsExt.regModel("TOC", {  fields: [     "id",     "helpPage",     "href",     "text"  ],  proxy: {    type: ...
XERO.views.HelpCarousel = Ext.extend(Ext.Carousel, {  cls: "cards",                                                      a...
loadHelpPage: function(id, href) {  var bookmark;                                app/views/helpcarousel.js  if(href.indexO...
onTap: function(e, target) {    var id = target.getAttribute(xero:id),        app/views/helpcarousel.js      type = target...
app/views/helppanel.jsXERO.views.HelpPanel = Ext.extend(Ext.Panel, {  cls: "help-panel",  layout: "fit",  scroll: "vertica...
loadHelpPage: function() {    Ext.util.JSONP.request({      url: String.format("{0}/help/", XERO.apiUrl),       app/views/...
XERO.views.TOCPanel = Ext.extend(Ext.NestedList, {  title: "Index",  showAnimation: {                                     ...
Touchable help...
going native
•   Cross-platform•   Open source•   Extensible•   Instantiates chromeless    web view•   Adds JavaScript access    to nat...
Web AppPhoneGap   etc…
Native APIs•   Device identification•   Network access•   Sensors•   Camera/image sources•   Contacts•   File access
Everything else?•   HTML for layout•   JavaScript for accessing device APIs•   CSS for look & feel•   Offline storage for s...
PhoneGap Build
Tips & Tricks
Tools•   Browsers – Safari the best (unfortunately)•   Web Inspector•   RemoteJS (Android debugging)•   Souders’ bookmarkl...
Object-oriented•   Use namespaces to define your library•   Define components – code for reusability•   Extend first, write p...
Events rock!•   Use events to communicate between    components•   Use event delegation
Override appropriately•   Do not edit the library files•   DO NOT EDIT THE LIBRARY FILES!•   Use an overrides file if you ne...
Define a directory structure•   Break your code into small files•   Use build tools to compile for performance•   Use sencha...
Worry about performance•   Understand client-side performance rules &    use them•   Latency bad•   JIT compilers – compil...
Theming/Layouts•   Use SCSS•   Remove unnecessary CSS by only    including required SCSS mixins•   Understand XTemplate•  ...
Sencha.comRead the forums                        Read the docs           Read the source!
Any questions?                 www.xero.com
www.xero.com/careers/
Sencha Touch
Sencha Touch
Sencha Touch
Sencha Touch
Upcoming SlideShare
Loading in...5
×

Sencha Touch

10,084

Published on

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

Published in: Technology
1 Comment
4 Likes
Statistics
Notes
No Downloads
Views
Total Views
10,084
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
306
Comments
1
Likes
4
Embeds 0
No embeds

No notes for slide

Transcript of "Sencha Touch"

  1. 1. Craig Walker, Chief Technology Officer www.xero.com
  2. 2. Craig Walker, Chief Technology Officer www.xero.com
  3. 3. What is Xero?http://www.xero.com/signup/
  4. 4. BlackBerry 6
  5. 5. BlackBerry 6 2nd half 2011
  6. 6. Lots of frameworks…• Zepto.js• DynamicX• SproutCore• XUI• Appcelerator• iUI• iWebKit• jQuery Mobile• jQTouch• And lots more…
  7. 7. Sencha Touch
  8. 8. What is Sencha Touch? A JavaScript framework forbuilding rich mobile applications
  9. 9. Why Sencha Touch?• Cross-platform• Looks native, feels native• Faster, cheaper, easier to build with• Highly customisable• Flexible deployment• HTML5/CSS3 goodness
  10. 10. Yes - but WHY Sencha Touch?
  11. 11. Tap !== Click
  12. 12. Touch Event Manager• Built on native events• Abstracted for performance• Multi-touch & gesture support
  13. 13. 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
  14. 14. Scroll Event Manager• Scrolling with momentum & bounce physics• Native & natural• Hardware accelerated
  15. 15. UI Toolkit
  16. 16. Buttons
  17. 17. FormsSliders
  18. 18. Pickers
  19. 19. Lists
  20. 20. NestedLists
  21. 21. ToolbarsTabs
  22. 22. PanelsCarousels
  23. 23. Maps
  24. 24. Overlays
  25. 25. Layouts• Container layout specifies how its children components are rendered
  26. 26. fit
  27. 27. card
  28. 28. vbox
  29. 29. hbox
  30. 30. MVC Routes Controllers Models Views Stores
  31. 31. Theming• SASS & Compass – sass-lang.com – compass-style.org• CSS3 is awesome – SCSS is awesomer
  32. 32. SCSS CSS$blue: #3bbfce; /* line 5, variables.scss */$margin: 16px; .example1 {$padding: 4px; border-color: #3bbfce; }.example1 { border-color: $blue; /* line 9, variables.scss */} .example2 { margin: 16px;.example2 { color: #3bbfce; margin: $margin; } color: $blue;} /* line 14, variables.scss */ .example3 {.example3 { margin: 32px; margin: ($margin / 2px) * $padding; }}
  33. 33. SCSS CSS@mixin add-child($color) { /* line 18, mixins.scss */ color: $color; .example { background-color: lighten($color, 50); color: red; background-color: white; .child { } padding: 5px; /* line 5, mixins.scss */ .example .child { &:first { padding: 5px; background-color: darken($color, 10) } }; /* line 8, mixins.scss */ .example .child:first { span { background-color: #cc0000; color: mix($color, blue); } } /* line 12, mixins.scss */ } .example .child span {} color: #7f007f; }.example { @include add-child(#F00);}
  34. 34. SCSS CSS@import "compass"; /* line 5, gradients.scss */ .button {$width: 100px; width: 100px; }.button { /* line 8, gradients.scss */ width: $width; .button .round { -moz-border-radius: 5px; .round { -webkit-border-radius: 5px; @include border-radius(5px); -o-border-radius: 5px; } -ms-border-radius: 5px; -khtml-border-radius: 5px; .linear { border-radius: 5px; @include linear-gradient( } color-stops(white, #c39 30%, /* line 12, gradients.scss */ #b7f 70%, #aaa) .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%); }
  35. 35. Let’s look at some code...
  36. 36. Demo: From Desktop to Mobile
  37. 37. index.html<!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>
  38. 38. app/xerohelp.js// 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>);
  39. 39. app/routes.jsExt.Router.draw(function(map) { map.connect("/help/home", {controller: help, action: home}); map.connect("/help/:id", {controller: help, action: show});});
  40. 40. app/app.jsExt.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 }); }});
  41. 41. XERO.Viewport = Ext.extend(Ext.Panel, { id: viewport, app/views/viewport.js 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); }, ...
  42. 42. setTitle: function(title) { this.down("#help-toolbar").setTitle(title); }, app/views/viewport.js 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(); }});
  43. 43. app/controllers/help.jsExt.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); }});
  44. 44. app/models/helpfile.jsExt.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" } ] */});
  45. 45. app/models/toc.jsExt.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 });}());
  46. 46. XERO.views.HelpCarousel = Ext.extend(Ext.Carousel, { cls: "cards", app/views/helpcarousel.js 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 }); } },
  47. 47. loadHelpPage: function(id, href) { var bookmark; app/views/helpcarousel.js 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); }},
  48. 48. onTap: function(e, target) { var id = target.getAttribute(xero:id), app/views/helpcarousel.js 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);
  49. 49. app/views/helppanel.jsXERO.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(); },...
  50. 50. loadHelpPage: function() { Ext.util.JSONP.request({ url: String.format("{0}/help/", XERO.apiUrl), app/views/helppanel.js 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);
  51. 51. XERO.views.TOCPanel = Ext.extend(Ext.NestedList, { title: "Index", showAnimation: { app/views/helppanel.js 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 }); }});
  52. 52. Touchable help...
  53. 53. going native
  54. 54. • Cross-platform• Open source• Extensible• Instantiates chromeless web view• Adds JavaScript access to native APIs
  55. 55. Web AppPhoneGap etc…
  56. 56. Native APIs• Device identification• Network access• Sensors• Camera/image sources• Contacts• File access
  57. 57. Everything else?• HTML for layout• JavaScript for accessing device APIs• CSS for look & feel• Offline 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!
  58. 58. PhoneGap Build
  59. 59. Tips & Tricks
  60. 60. Tools• Browsers – Safari the best (unfortunately)• Web Inspector• RemoteJS (Android debugging)• Souders’ bookmarklets – stevesouders.com/mobileperf• Jdrop – jdrop.org
  61. 61. Object-oriented• Use namespaces to define your library• Define components – code for reusability• Extend first, write plugins second (not at all if possible)
  62. 62. Events rock!• Use events to communicate between components• Use event delegation
  63. 63. 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)
  64. 64. 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
  65. 65. 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!
  66. 66. Theming/Layouts• Use SCSS• Remove unnecessary CSS by only including required SCSS mixins• Understand XTemplate• Understand doComponentLayout
  67. 67. Sencha.comRead the forums Read the docs Read the source!
  68. 68. Any questions? www.xero.com
  69. 69. www.xero.com/careers/
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×