TITANIUM DEVELOPMENT WITHAccelerated     COFFEESCRIPT, COMPASS, AND SASS                         WYNNNETHERLAND
$ whoami
NETHERLAND
Mobile?Web?Both?
Nice to meet ya.
PIXELS IVE PUSHEDWith some very talented folks.
Play golf?Find this dude andget in on the beta.!
Titanium powered kiosk!
A polyglotsTITANIUM STACK
COFFEESCRIPT
Its still just JavaScript.
var foo = function () {                                foo = () ->  }JAVASCRIPT                  COFFEESCRIPT             ...
var button = Titanium.UI.createButton({    title: I am a Button,    height: 40,    width: 200,    top: 10  });  button.add...
button = Titanium.UI.createButton    title: I am a Button    height: 40    width: 200    top: 10  button.addEventListener ...
For me,Its about more than aesthetics                                  ; {}
Some of my favorite features...
for own key, value of query    uri += "#{ key }=#{ escape(value) }&"COFFEESCRIPT  var key, value;  var __hasProp = Object....
Comprehensions  for own key, value of query    uri += "#{ key }=#{ escape(value) }&"COFFEESCRIPT
Interpolation  for own key, value of query    uri += "#{ key }=#{ escape(value) }&"COFFEESCRIPT
The Existential Operator  courseButtonSubhead = Ti.UI.createLabel    className: optRowSubhead    text: "#{GolfStatus.App.c...
Simple inheritance pattern  class GolfStatus.Models.Game     constructor: (@owner,                   @course,             ...
@  class GolfStatus.Models.Game     constructor: (@owner,                   @course,                   @playingFor=brag,  ...
Default values  class GolfStatus.Models.Game     constructor: (@owner,                   @course,                   @playi...
More human conditionals  class GolfStatus.Models.Game     constructor: (@owner,                   @course,                ...
Easy object.prototype   GolfStatus.Models.Game::PlayingForTypes =     brag: Bragging Rights     cash: Status Cash   GolfSt...
Heredocs   noticeHTML =               <html>               <head></head>               <body>                  noticeHTML ...
Because string building sucks.
And so much more.
http://wynn.fm/2Y
GETTHEBOOK.        http://wynn.fm/g8
STYLESHEETS
Are you using JSS?
JSS works like CSS.
Why do we have CSS?
<ul class=wynning>  <li class=logo-mark>    <a href=/about>Wynn Netherland</a>    on design, development, and general geek...
A   example
var buttonOne = Titanium.UI.createButton({    title:I am a Button,    height:40,    width:200,    top:10  });  var buttonT...
var buttonOne = Titanium.UI.createButton({    title:I am a Button,    height:40,    width:200,                            ...
var buttonOne = Titanium.UI.createButton({  id: "buttonOne",                                 JAVASCRIPT           Behavior...
var buttonOne = Titanium.UI.createButton({  id: "buttonOne",                                JAVASCRIPT  className: "button...
JSSTheres a better way to write CSS.
Patte                                  rns &             io n s &        plugins  SS e xtensC     co mpiler               ...
gem install compass
Is it JSS or Sassy CSS?   #buttonOne {     title: I am a Button;     width: 200;     height: 40;     top: 10   }   #button...
I prefer Sass original indented, whitespace aware syntax.    #buttonOne      title: I am a Button      width: 200      hei...
Which do you prefer?
#buttonOne {    title: I am a Button;    width: 200;    height: 40;    top: 10  }  #buttonTwo {    title: I am also a Butt...
#buttonOne    title: I am a Button    width: 200    height: 40    top: 10  #buttonTwo    title: I am also a Button    imag...
Pick one. Or not. Mix and match.
Organize with partials.
stylesheets├── _activity.sass├── _base.sass├── _confirmation.sass├── _course.scss├── _courses.sass├── _friends.scss├── _ga...
stylesheets                         Mix scss with sass├── _activity.sass├── _base.sass├── _confirmation.sass              ...
Dont Repeat Yourself
.user-info    bottom: 1    color: #333    font-size: 11    font-weight: bold    height: auto    left: 0    shadowColor: #f...
DRY it up.               Nesting  .user-info    bottom: 1    color: #333    font:      size: 11      weight: bold    heigh...
#buttonOne    title: I am a Button    width: 200    height: 40    top: 10  #buttonTwo    title: I am also a Button    imag...
DRY it up.                        Mixins  =button    height: 40    width: 200  #buttonOne    +button    title: I am a Butt...
DRY it up.                          Mixins with params  =bottom-right($height: 40, $width: 200)    height: $size    width:...
#buttonOne    title: I am a Button    width: 200    height: 40    top: 10  #buttonTwo    title: I am also a Button    imag...
DRY it up.                        @extend  .button    height: 40    width: 200  #buttonOne    @extend .button    title: I ...
DRY it up.                                          @extend      .button, #buttonOne, #buttonTwo {        height: 40;     ...
Craft themes with color functions.
variables  $button-base: #a7a7a7  #buttonOne    color: $button-base    title: "Button 1"  #buttonTwo    color: $button-bas...
variables  $button-base: #a7a7a7  #buttonOne    color: $button-base    title: "Button 1"  #buttonTwo    color: $button-bas...
color functions  $button-base: #a7a7a7  #buttonOne    color: $button-base    title: "Button 1"  #buttonTwo    color: darke...
color functions  $button-base: #a7a7a7  #buttonOne    color: $button-base    title: "Button 1"  #buttonTwo    color: darke...
more color functions  hue(#cc3) # => 60deg  saturation(#cc3) # => 60%  lightness(#cc3) # => 50%  adjust-hue(#cc3, 20deg) #...
even more color functions  mix(rgba(51, 255, 51, 0.75), #f00) # => rgba(178, 95, 19, 0.875)  mix(rgba(51, 255, 51, 0.90), ...
Building a hybrid native+web app?
Share your stylesheet variables!
No more vendor namespaces.Selector inheritance.URL helpers.So much more.
I could write a book.
Oh wait. We did!
Isn’t she Sassy, folks?GETTHEBOOK.                        http://wynn.fm/ti-sass
Save 40% and get early access!           sass40Sadly, sass100 is not a valid code.                             http://wynn...
Patterns
Web languages. Native apps.
Stateful.
Event driven.
MVC?
Views...
... are really ViewControllers.
So we create View factories...
... and Model factories ...
...and factories that make miniature                 models of factories.
The Titanium WayTM
button = Titanium.UI.createButton    title: I am a Button    height: 40                             Look familiar?    widt...
So how do you manufacture your own views?
Compose from other views.
MyApp.Views.createLoginWindow = (opts={}) ->     window = Ti.UI.createWindow(opts)     button = Titanium.UI.createButton  ...
MyApp.Views.createLoginWindow = (opts={}) ->     window = Ti.UI.createWindow(opts)     button = Titanium.UI.createButton  ...
MyApp.Views.createLoginWindow = (opts={}) ->     window = Ti.UI.createWindow(opts)     button = Titanium.UI.createButton  ...
MyApp.Views.createLoginWindow = (opts={}) ->     window = Ti.UI.createWindow(opts)     button = Titanium.UI.createButton  ...
MyApp.Views.createLoginWindow = (opts={}) ->     window = Ti.UI.createWindow(opts)     button = Titanium.UI.createButton  ...
MyApp.Views.createLoginWindow = (opts={}) ->     window = Ti.UI.createWindow(opts)     button = Titanium.UI.createButton  ...
Models
CoffeeScript classes
class GolfStatus.Models.Game    constructor: (@owner,                  @course,                  @playingFor=brag,        ...
API Wrappers
CoffeeScript class  class GolfStatus.API    # Initialize with login and password    constructor: (@login, @password) ->COF...
URI building  ...    # Build the full API URI for a request    requestURI: (path, query={}) ->        uri = "#{GolfStatus....
HTTP Request building    # Common request handling across all verbs    request: (path, options, authenticated=true) ->    ...
High level methods for HTTP verbs    # High level method for GET requests    get: (path, options, authenticated=true) ->  ...
Higher level API methods    # ### Authenticate the user ###    authenticate: (options) ->      Ti.API.debug "GolfStatus.AP...
Folder structure
.├──   Resources                 #   Titanium root│     └── vendor                #   JavaScript frameworks├──   src      ...
Stitching it all together
app.js
GolfStatus =    Models: {}    Views:      Account: {}      Activity: {}      Courses: {}      Leaderboard: {}      Play: {...
GolfStatus =    Models: {}    Views:              Set up your namespaces      Account: {}      Activity: {}      Courses: ...
GolfStatus =    Models: {}    Views:      Account: {}      Activity: {}      Courses: {}                             third...
GolfStatus =    Models: {}    Views:      Account: {}      Activity: {}      Courses: {}      Leaderboard: {}      Play: {...
GolfStatus =    Models: {}    Views:      Account: {}      Activity: {}      Courses: {}      Leaderboard: {}      Play: {...
Lean app.js makes for flexibility
Tapping through to test deep screens bites!
# GolfStatus.App.init()  window = GolfStatus.Views.Play.createGameWindow()  window.open()                                 ...
make
run-iphone:&   @DEVICE_TYPE=iphone make runtest-iphone:&   @DEVICE_TYPE=iphone make testrun-ipad:&   @DEVICE_TYPE=ipad mak...
Im a Rubyist, so I speak        rake
Compile
def compile_sass    puts "Compiling stylesheets".blue    input = "stylesheets/app.sass"    output = "Resources/app.jss"   ...
def compile_coffee    paths = `find src/golf_status -name *.coffee`.split("n")    compilation = (      puts "Compiling Cof...
def compile_coffee    paths = `find src/golf_status -name *.coffee`.split("n")    compilation = (      puts "Compiling Cof...
def compile_coffee    paths = `find src/golf_status -name *.coffee`.split("n")    compilation = (      puts "Compiling Cof...
Build
def build(options={})    return unless compile    options[:device] ||= iphone    puts "Building with Titanium...  (DEVICE_...
def build(options={})    return unless compile    options[:device] ||= iphone    puts "Building with Titanium...  (DEVICE_...
def build(options={})    return unless compile    options[:device] ||= iphone    puts "Building with Titanium...  (DEVICE_...
Choose what works for you.
JavaScript Frameworks
Underscore.jshttps://github.com/documentcloud/underscore                     From Jeremy Ashkenas,                   the c...
Dont Repeat Yourself Not Repeating Yourself
Ti GEMAutomating these patterns. A work in progress.
gem install ti
Generate.
ti new <name> <id> <platform>
ti new codestrong-app com.codestrong.app iphone
├──   Coffeefile├──   Guardfile├──   LICENSE├──   Rakefile├──   Readme.mkd├──   Resources│     ├── app.js│     ├── app.jss...
ti generate <model/controller/view> <name>
Golf.Views.GamePlay.createScoreCardView = (options) ->  view = Ti.UI.createView (options)  view
ti scaffold <window/tabgroup/view> <domain> <name>
Compile.
ti compile <all/coffee/sass>
Build.
ti build <all/iphone/android/ipad/desktop/>
Ti GEM@revans               @baldrailers            @rupakg
Get involved!
Weve got BIG ideas.
Testing.
Jasmine
Jasminehttps://github.com/akahigeg/jasmine-titanium
XIB
xib2jshttps://github.com/daoki2/xib2js
js2coffeehttp://ricostacruz.com/js2coffee/
QUESTIONS?http://spkr8.com/t/8342
Wynn Netherland: Accelerating Titanium Development with CoffeeScript, Compass, and Sass
Wynn Netherland: Accelerating Titanium Development with CoffeeScript, Compass, and Sass
Wynn Netherland: Accelerating Titanium Development with CoffeeScript, Compass, and Sass
Wynn Netherland: Accelerating Titanium Development with CoffeeScript, Compass, and Sass
Wynn Netherland: Accelerating Titanium Development with CoffeeScript, Compass, and Sass
Wynn Netherland: Accelerating Titanium Development with CoffeeScript, Compass, and Sass
Wynn Netherland: Accelerating Titanium Development with CoffeeScript, Compass, and Sass
Wynn Netherland: Accelerating Titanium Development with CoffeeScript, Compass, and Sass
Wynn Netherland: Accelerating Titanium Development with CoffeeScript, Compass, and Sass
Wynn Netherland: Accelerating Titanium Development with CoffeeScript, Compass, and Sass
Upcoming SlideShare
Loading in...5
×

Wynn Netherland: Accelerating Titanium Development with CoffeeScript, Compass, and Sass

2,370

Published on

JavaScript and Titanium's JavaScript Stylesheets would be the quickest way to develop native mobile applications if it weren't for CoffeeScript and Sass. This talk will show you how to speed up your dev cycles and use CoffeeScript and Sass not only to write code faster, but better organize your JavaScript and JSS.

Published in: Technology, Business
1 Comment
3 Likes
Statistics
Notes
  • This is a gold mine of tips. I am a Desktop MVC developer moving into the mobile realm. I knew in generic terms what I needed, but this talk in an apprenticeship in 40 minutes. It provided the specific detail I needed to go off on my own empowered to do serious mobile app development seriously. Must Watch.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
2,370
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
33
Comments
1
Likes
3
Embeds 0
No embeds

No notes for slide

Wynn Netherland: Accelerating Titanium Development with CoffeeScript, Compass, and Sass

  1. 1. TITANIUM DEVELOPMENT WITHAccelerated COFFEESCRIPT, COMPASS, AND SASS WYNNNETHERLAND
  2. 2. $ whoami
  3. 3. NETHERLAND
  4. 4. Mobile?Web?Both?
  5. 5. Nice to meet ya.
  6. 6. PIXELS IVE PUSHEDWith some very talented folks.
  7. 7. Play golf?Find this dude andget in on the beta.!
  8. 8. Titanium powered kiosk!
  9. 9. A polyglotsTITANIUM STACK
  10. 10. COFFEESCRIPT
  11. 11. Its still just JavaScript.
  12. 12. var foo = function () { foo = () -> }JAVASCRIPT COFFEESCRIPT I’d rather write this.
  13. 13. var button = Titanium.UI.createButton({ title: I am a Button, height: 40, width: 200, top: 10 }); button.addEventListener(click, function(e) { alert("Oooh, that tickles!"); });JAVASCRIPT
  14. 14. button = Titanium.UI.createButton title: I am a Button height: 40 width: 200 top: 10 button.addEventListener click, (e) -> alert "Oooh, that tickles!"COFFEESCRIPT
  15. 15. For me,Its about more than aesthetics ; {}
  16. 16. Some of my favorite features...
  17. 17. for own key, value of query uri += "#{ key }=#{ escape(value) }&"COFFEESCRIPT var key, value; var __hasProp = Object.prototype.hasOwnProperty; for (key in query) { if (!__hasProp.call(query, key)) continue; value = query[key]; uri += "" + key + "=" + (escape(value)) + "&"; }JAVASCRIPT
  18. 18. Comprehensions for own key, value of query uri += "#{ key }=#{ escape(value) }&"COFFEESCRIPT
  19. 19. Interpolation for own key, value of query uri += "#{ key }=#{ escape(value) }&"COFFEESCRIPT
  20. 20. The Existential Operator courseButtonSubhead = Ti.UI.createLabel className: optRowSubhead text: "#{GolfStatus.App.currentGame?.green?.name}"COFFEESCRIPT
  21. 21. Simple inheritance pattern class GolfStatus.Models.Game constructor: (@owner, @course, @playingFor=brag, @scoringFormat=low_net) -> @players = {} @addPlayer @owner if @owner @green = @course.greens[0] if @course @currentHole = 1 @maxHolePlayed = 1 # elsewhere game = new GolfStatus.Models.Game(...)COFFEESCRIPT
  22. 22. @ class GolfStatus.Models.Game constructor: (@owner, @course, @playingFor=brag, @scoringFormat=low_net) -> @players = {} @addPlayer @owner if @owner @green = @course.greens[0] if @course @currentHole = 1 @maxHolePlayed = 1COFFEESCRIPT
  23. 23. Default values class GolfStatus.Models.Game constructor: (@owner, @course, @playingFor=brag, @scoringFormat=low_net) -> @players = {} @addPlayer @owner if @owner @green = @course.greens[0] if @course @currentHole = 1 @maxHolePlayed = 1COFFEESCRIPT
  24. 24. More human conditionals class GolfStatus.Models.Game constructor: (@owner, @course, @playingFor=brag, @scoringFormat=low_net) -> @players = {} @addPlayer @owner if @owner @green = @course.greens[0] if @course @currentHole = 1 @maxHolePlayed = 1COFFEESCRIPT
  25. 25. Easy object.prototype GolfStatus.Models.Game::PlayingForTypes = brag: Bragging Rights cash: Status Cash GolfStatus.Models.Game::ScoringFormats = low_net: Low Net low_grows: Low GrossCOFFEESCRIPT
  26. 26. Heredocs noticeHTML = <html> <head></head> <body> noticeHTML += "<div>#{noticeText}</div>" noticeHTML += </body> </html> COFFEESCRIPT
  27. 27. Because string building sucks.
  28. 28. And so much more.
  29. 29. http://wynn.fm/2Y
  30. 30. GETTHEBOOK. http://wynn.fm/g8
  31. 31. STYLESHEETS
  32. 32. Are you using JSS?
  33. 33. JSS works like CSS.
  34. 34. Why do we have CSS?
  35. 35. <ul class=wynning> <li class=logo-mark> <a href=/about>Wynn Netherland</a> on design, development, and general geekery. </li> <li> <a class=gowalla href=http://gowalla.com/pengwynn>Gowalla</a> </li> <li> <a class=facebook href=http://facebook.com/pengwynn>Facebook</a> content </li> <li> <a class=dribbble href=http://dribbble.com/pengwynn>Dribbble</a> </li> <li> <a class=linked-in href=http://linkedin.com/in/netherland>LinkedIn</a> </li> <li> <a class=github href=http://github.com/pengwynn>GitHub</a> </li> <li> <a class=twitter href=http://twitter.com/pengwynn>Twitter</a> </li>... You gotta keep em separated.✂ presentation
  36. 36. A example
  37. 37. var buttonOne = Titanium.UI.createButton({ title:I am a Button, height:40, width:200, top:10 }); var buttonTwo = Titanium.UI.createButton({ title:I am also a Button, image:../images/chat.png, width:200, height:40, top:60 });JAVASCRIPT
  38. 38. var buttonOne = Titanium.UI.createButton({ title:I am a Button, height:40, width:200, Presentation top:10 }); var buttonTwo = Titanium.UI.createButton({ title:I am also a Button, image:../images/chat.png, width:200, height:40, top:60 });JAVASCRIPT
  39. 39. var buttonOne = Titanium.UI.createButton({ id: "buttonOne", JAVASCRIPT Behavior and composition in className: "button"});var buttonTwo = Titanium.UI.createButton({ id: "buttonTwo", className: "button"}); .js#buttonOne { title:I am a Button; JSS width:200; height:40; top:10}#buttonTwo { Presentation in title:I am also a Button; image:../images/chat.png; width:200; height:40; .jss top:60}.button { height: 40; width: 200;}
  40. 40. var buttonOne = Titanium.UI.createButton({ id: "buttonOne", JAVASCRIPT className: "button" Style hooks});var buttonTwo = Titanium.UI.createButton({ id: "buttonTwo", className: "button"});#buttonOne { title:I am a Button; JSS width:200; height:40; top:10}#buttonTwo { title:I am also a Button; image:../images/chat.png; width:200; height:40; top:60}.button { height: 40; width: 200;}
  41. 41. JSSTheres a better way to write CSS.
  42. 42. Patte rns & io n s & plugins SS e xtensC co mpiler &
  43. 43. gem install compass
  44. 44. Is it JSS or Sassy CSS? #buttonOne { title: I am a Button; width: 200; height: 40; top: 10 } #buttonTwo { title: I am also a Button; image: ../images/chat.png; width: 200; height: 40; top: 60 } .button { height: 40; width: 200; }JSS / SCSS Yes?
  45. 45. I prefer Sass original indented, whitespace aware syntax. #buttonOne title: I am a Button width: 200 height: 40 top: 10 #buttonTwo title: I am also a Button image: ../images/chat.png width: 200 height: 40 top: 60 .button height: 40 width: 200 SASS
  46. 46. Which do you prefer?
  47. 47. #buttonOne { title: I am a Button; width: 200; height: 40; top: 10 } #buttonTwo { title: I am also a Button; image: ../images/chat.png; width: 200; height: 40; top: 60 } .button { height: 40; width: 200; }SCSS
  48. 48. #buttonOne title: I am a Button width: 200 height: 40 top: 10 #buttonTwo title: I am also a Button image: ../images/chat.png width: 200 height: 40 top: 60 .button height: 40 width: 200SASS
  49. 49. Pick one. Or not. Mix and match.
  50. 50. Organize with partials.
  51. 51. stylesheets├── _activity.sass├── _base.sass├── _confirmation.sass├── _course.scss├── _courses.sass├── _friends.scss├── _gameplay.sass├── _leaderboard.sass├── _leaders.sass├── _login.sass├── _requests.sass @import base├── _tourcard.sass @import login└── app.sass @import activity @import course @import courses @import friends @import leaderboard @import leaders @import requests @import tourcard @import confirmation @import gameplayResources├── app.js├── app.jss...
  52. 52. stylesheets Mix scss with sass├── _activity.sass├── _base.sass├── _confirmation.sass if youre so inclined.├── _course.scss├── _courses.sass├── _friends.scss├── _gameplay.sass├── _leaderboard.sass├── _leaders.sass├── _login.sass├── _requests.sass @import base├── _tourcard.sass @import login└── app.sass @import activity @import course @import courses @import friends @import leaderboard @import leaders @import requests @import tourcard @import confirmation @import gameplayResources├── app.js├── app.jss...
  53. 53. Dont Repeat Yourself
  54. 54. .user-info bottom: 1 color: #333 font-size: 11 font-weight: bold height: auto left: 0 shadowColor: #fff shadowOffset-x: 0 shadowOffset-y: -1 text-align: center width: 92SASS
  55. 55. DRY it up. Nesting .user-info bottom: 1 color: #333 font: size: 11 weight: bold height: auto left: 0 shadowColor: #fff shadowOffset: x: 0 y: -1 text-align: center width: 92SASS
  56. 56. #buttonOne title: I am a Button width: 200 height: 40 top: 10 #buttonTwo title: I am also a Button image: ../images/chat.png width: 200 height: 40 top: 60 .button height: 40 width: 200SASS
  57. 57. DRY it up. Mixins =button height: 40 width: 200 #buttonOne +button title: I am a Button top: 10 #buttonTwo +button title: I am also a Button image: ../images/chat.png top: 60SASS
  58. 58. DRY it up. Mixins with params =bottom-right($height: 40, $width: 200) height: $size width: $size right: 0 bottom: 0 #buttonOne +bottom-right title: I am a Button #buttonTwo +bottom-right(50, 300) title: I am also a Button image: ../images/chat.pngSASS
  59. 59. #buttonOne title: I am a Button width: 200 height: 40 top: 10 #buttonTwo title: I am also a Button image: ../images/chat.png width: 200 height: 40 top: 60 .button height: 40 width: 200SASS
  60. 60. DRY it up. @extend .button height: 40 width: 200 #buttonOne @extend .button title: I am a Button top: 10 #buttonTwo @extend .button title: I am also a Button image: ../images/chat.png top: 60SASS
  61. 61. DRY it up. @extend .button, #buttonOne, #buttonTwo { height: 40; width: 200; } #buttonOne { title: I am a Button; width: 200; } #buttonTwo { title: I am also a Button; image: ../images/chat.png; One less class in our .js top: 60 }JSS
  62. 62. Craft themes with color functions.
  63. 63. variables $button-base: #a7a7a7 #buttonOne color: $button-base title: "Button 1" #buttonTwo color: $button-base title: "Button 2"SASS
  64. 64. variables $button-base: #a7a7a7 #buttonOne color: $button-base title: "Button 1" #buttonTwo color: $button-base title: "Button 2"SASS
  65. 65. color functions $button-base: #a7a7a7 #buttonOne color: $button-base title: "Button 1" #buttonTwo color: darken($button-base, 20%) title: "Button 2"SASS
  66. 66. color functions $button-base: #a7a7a7 #buttonOne color: $button-base title: "Button 1" #buttonTwo color: darken($button-base, 20%) title: "Button 2"SASS
  67. 67. more color functions hue(#cc3) # => 60deg saturation(#cc3) # => 60% lightness(#cc3) # => 50% adjust-hue(#cc3, 20deg) # => #9c3 saturate(#cc3, 10%) # => #d9d926 desaturate(#cc3, 10%) # => #bfbf40 lighten(#cc3, 10%) # => #d6d65c darken(#cc3, 10%) # => #a3a329 grayscale(#cc3) # => desaturate(#cc3, 100%) = #808080 complement(#cc3) # => adjust-hue(#cc3, 180deg) = #33c mix(#cc3, #00f) # => #e56619 mix(#cc3, #00f, 10%) # => #f91405 mix(#cc3, #00f, 90%) # => #d1b72dSASS
  68. 68. even more color functions mix(rgba(51, 255, 51, 0.75), #f00) # => rgba(178, 95, 19, 0.875) mix(rgba(51, 255, 51, 0.90), #f00) # => rgba(163, 114, 22, 0.95) alpha(rgba(51, 255, 51, 0.75)) # => 0.75 opacity(rgba(51, 255, 51, 0.75)) # => 0.75 with alpha support! opacify(rgba(51, 255, 51, 0.75), 0.1) # => rgba(51, 255, 51, 0.85) fade-in(rgba(51, 255, 51, 0.75), 0.1) # => rgba(51, 255, 51, 0.85) transparentize(rgba(51, 255, 51, 0.75), 0.1) # => rgba(51, 255, 51, 0.65) fade-out(rgba(51, 255, 51, 0.75), 0.1) # => rgba(51, 255, 51, 0.65)SASS
  69. 69. Building a hybrid native+web app?
  70. 70. Share your stylesheet variables!
  71. 71. No more vendor namespaces.Selector inheritance.URL helpers.So much more.
  72. 72. I could write a book.
  73. 73. Oh wait. We did!
  74. 74. Isn’t she Sassy, folks?GETTHEBOOK. http://wynn.fm/ti-sass
  75. 75. Save 40% and get early access! sass40Sadly, sass100 is not a valid code. http://wynn.fm/ti-sass
  76. 76. Patterns
  77. 77. Web languages. Native apps.
  78. 78. Stateful.
  79. 79. Event driven.
  80. 80. MVC?
  81. 81. Views...
  82. 82. ... are really ViewControllers.
  83. 83. So we create View factories...
  84. 84. ... and Model factories ...
  85. 85. ...and factories that make miniature models of factories.
  86. 86. The Titanium WayTM
  87. 87. button = Titanium.UI.createButton title: I am a Button height: 40 Look familiar? width: 200 top: 10 button.addEventListener click, (e) -> alert "Oooh, that tickles!"COFFEESCRIPT
  88. 88. So how do you manufacture your own views?
  89. 89. Compose from other views.
  90. 90. MyApp.Views.createLoginWindow = (opts={}) -> window = Ti.UI.createWindow(opts) button = Titanium.UI.createButton title: I am a Button height: 40 width: 200 top: 10 window.add button # methods say = (msg) -> alert(msg) # event handlers button.addEventListener click, -> say(hello) windowCOFFEESCRIPT
  91. 91. MyApp.Views.createLoginWindow = (opts={}) -> window = Ti.UI.createWindow(opts) button = Titanium.UI.createButton title: I am a Button height: 40 width: 200 Create the factory method in the appropriate namespace. top: 10 window.add button # methods say = (msg) -> alert(msg) # event handlers button.addEventListener click, -> say(hello) windowCOFFEESCRIPT
  92. 92. MyApp.Views.createLoginWindow = (opts={}) -> window = Ti.UI.createWindow(opts) button = Titanium.UI.createButton title: I am a Button height: 40 width: 200 Compose the view from top: 10 window.add button Titanium types or others of # methods your own say = (msg) -> alert(msg) # event handlers button.addEventListener click, -> say(hello) windowCOFFEESCRIPT
  93. 93. MyApp.Views.createLoginWindow = (opts={}) -> window = Ti.UI.createWindow(opts) button = Titanium.UI.createButton title: I am a Button height: 40 width: 200 top: 10 window.add button Methods in familiar place # methods say = (msg) -> alert(msg) # event handlers button.addEventListener click, -> say(hello) windowCOFFEESCRIPT
  94. 94. MyApp.Views.createLoginWindow = (opts={}) -> window = Ti.UI.createWindow(opts) button = Titanium.UI.createButton title: I am a Button height: 40 width: 200 top: 10 window.add button And event handlers... # methods say = (msg) -> alert(msg) # event handlers button.addEventListener click, -> say(hello) windowCOFFEESCRIPT
  95. 95. MyApp.Views.createLoginWindow = (opts={}) -> window = Ti.UI.createWindow(opts) button = Titanium.UI.createButton title: I am a Button height: 40 width: 200 top: 10 window.add button Return your view # methods say = (msg) -> alert(msg) # event handlers button.addEventListener click, -> say(hello) windowCOFFEESCRIPT
  96. 96. Models
  97. 97. CoffeeScript classes
  98. 98. class GolfStatus.Models.Game constructor: (@owner, @course, @playingFor=brag, @scoringFormat=low_net) -> serialize: -> deserialize: (data) -> save: -> resume: -> dataForSubmit: () -> submit: (error) -> ...COFFEESCRIPT
  99. 99. API Wrappers
  100. 100. CoffeeScript class class GolfStatus.API # Initialize with login and password constructor: (@login, @password) ->COFFEESCRIPT
  101. 101. URI building ... # Build the full API URI for a request requestURI: (path, query={}) -> uri = "#{GolfStatus.API_ENDPOINT}#{path}.json?" for own key, value of query uri += "#{ key }=#{ escape(value) }&" uriCOFFEESCRIPT
  102. 102. HTTP Request building # Common request handling across all verbs request: (path, options, authenticated=true) -> # Default to GET options.method ?= GET options.query ?= {} options.success ?= -> Ti.API.info options.error ?= -> Ti.API.error xhr = Ti.Network.createHTTPClient() xhr.onreadystatechange = (e) -> ... # Default event handlers # Basic auth # other common stuff ... if options.body data = JSON.stringify(options.body) Ti.API.debug data xhr.send(data) else xhr.send()COFFEESCRIPT
  103. 103. High level methods for HTTP verbs # High level method for GET requests get: (path, options, authenticated=true) -> options.method = GET @request path, options, authenticated # High level method for POST requests post: (path, options, authenticated=true) -> options.method = POST @request path, options, authenticated # High level method for DELETE requests delete: (path, options, authenticated=true) -> options.method = DELETE @request path, options, authenticatedCOFFEESCRIPT
  104. 104. Higher level API methods # ### Authenticate the user ### authenticate: (options) -> Ti.API.debug "GolfStatus.API.authenticate" @get /me, options # ### Logout the user ### logout: (options) -> Ti.API.debug "GolfStatus.API.logout" @delete /logout, options # ### Forgot password forgotPassword: (email, options) -> Ti.API.debug "GolfStatus.API.forgotPassword" options.query = {} options.query.email = email @post /passwords, options, false # ### Convenience method to get current user info ### me: (options) -> Ti.API.debug "GolfStatus.API.me" @authenticate optionsCOFFEESCRIPT
  105. 105. Folder structure
  106. 106. .├── Resources # Titanium root│   └── vendor # JavaScript frameworks├── src # CoffeeScript root│   └── golf_status # App root│   ├── models│   └── views│   ├── account # App domains│   ├── activity│   ├── courses│   ├── leaderboard│   └── play└── stylesheets # Sass
  107. 107. Stitching it all together
  108. 108. app.js
  109. 109. GolfStatus = Models: {} Views: Account: {} Activity: {} Courses: {} Leaderboard: {} Play: {} Ti.include(vendor/date.js) Ti.include(vendor/underscore.js) Ti.include(golf_status.js) GolfStatus.App.init()COFFEESCRIPT
  110. 110. GolfStatus = Models: {} Views: Set up your namespaces Account: {} Activity: {} Courses: {} Leaderboard: {} Play: {} Ti.include(vendor/date.js) Ti.include(vendor/underscore.js) Ti.include(golf_status.js) GolfStatus.App.init()COFFEESCRIPT
  111. 111. GolfStatus = Models: {} Views: Account: {} Activity: {} Courses: {} third party frameworks Leaderboard: {} Play: {} Ti.include(vendor/date.js) Ti.include(vendor/underscore.js) Ti.include(golf_status.js) GolfStatus.App.init()COFFEESCRIPT
  112. 112. GolfStatus = Models: {} Views: Account: {} Activity: {} Courses: {} Leaderboard: {} Play: {} Ti.include(vendor/date.js) Ti.include(vendor/underscore.js) Ti.include(golf_status.js) GolfStatus.App.init() All of our app in just one fileCOFFEESCRIPT
  113. 113. GolfStatus = Models: {} Views: Account: {} Activity: {} Courses: {} Leaderboard: {} Play: {} Ti.include(vendor/date.js) Ti.include(vendor/underscore.js) Ti.include(golf_status.js) GolfStatus.App.init() Fire up the app and first windowCOFFEESCRIPT
  114. 114. Lean app.js makes for flexibility
  115. 115. Tapping through to test deep screens bites!
  116. 116. # GolfStatus.App.init() window = GolfStatus.Views.Play.createGameWindow() window.open() Comment out init and fire up the deepest view.COFFEESCRIPT
  117. 117. make
  118. 118. run-iphone:& @DEVICE_TYPE=iphone make runtest-iphone:& @DEVICE_TYPE=iphone make testrun-ipad:& @DEVICE_TYPE=ipad make runtest-ipad:& @DEVICE_TYPE=ipad make testrun:& @if [ "${DEVICE_TYPE}" == "" ]; then& & echo "Please run "make run-[iphone|ipad]" instead.";& & exit 1;& fi& @mkdir -p ${PROJECT_ROOT}/${PROJECT_NAME}/Resources/test/& @echo "" > ${PROJECT_ROOT}/${PROJECT_NAME}/Resources/test/enabled.js& @make launch-titanium guilhermechapiewski (Guilherme Chapiewski) http://wynn.fm/g9
  119. 119. Im a Rubyist, so I speak rake
  120. 120. Compile
  121. 121. def compile_sass puts "Compiling stylesheets".blue input = "stylesheets/app.sass" output = "Resources/app.jss" system "sass --compass -C -t expanded #{input} > #{output}" endRAKEFILE
  122. 122. def compile_coffee paths = `find src/golf_status -name *.coffee`.split("n") compilation = ( puts "Compiling CoffeeScript (golf_status.js)".blue output = "Resources/golf_status.js" system "coffee --join #{output} -b -c #{paths.join( )}" and puts "Compiling CoffeeScript (app.js)".blue system "coffee -p --bare src/app.coffee > Resources/app.js" ) if compilation puts "Successfully compiled CoffeeScript".green else puts "Error compiling CoffeeScript".red end compilation endRAKEFILE
  123. 123. def compile_coffee paths = `find src/golf_status -name *.coffee`.split("n") compilation = ( puts "Compiling CoffeeScript (golf_status.js)".blue output = "Resources/golf_status.js" system "coffee --join #{output} -b -c #{paths.join( )}" puts "Compiling CoffeeScript (app.js)".blue system "coffee -p --bare src/app.coffee > Resources/app.js" ) if compilation puts "Successfully compiled CoffeeScript".green else puts "Error compiling CoffeeScript".red end compilation endRAKEFILE Compile App namespaces to single file
  124. 124. def compile_coffee paths = `find src/golf_status -name *.coffee`.split("n") compilation = ( puts "Compiling CoffeeScript (golf_status.js)".blue output = "Resources/golf_status.js" system "coffee --join #{output} -b -c #{paths.join( )}" puts "Compiling CoffeeScript (app.js)".blue system "coffee -p --bare src/app.coffee > Resources/app.js" ) if compilation puts "Successfully compiled CoffeeScript".green else puts "Error compiling CoffeeScript".red end compilation endRAKEFILE Compile app.js which includes the app library
  125. 125. Build
  126. 126. def build(options={}) return unless compile options[:device] ||= iphone puts "Building with Titanium... (DEVICE_TYPE:#{options[:device]})".blue sh %Q{bash -c "#{TI_BUILD} run #{PROJECT_ROOT}/ #{IPHONE_SDK_VERSION} #{APP_ID} #{APP_NAME} #{APP_DEVICE}" | perl -pe s/^[DEBUG].*$/e[35m$&e[0m/g;s/^[INFO].*$/e[36m $&e[0m/g;s/^[WARN].*$/e[33m$&e[0m/g;s/^[ERROR].*$/e[31m $&e[0m/g;} endRAKEFILE
  127. 127. def build(options={}) return unless compile options[:device] ||= iphone puts "Building with Titanium... (DEVICE_TYPE:#{options[:device]})".blue sh %Q{bash -c "#{TI_BUILD} run #{PROJECT_ROOT}/ #{IPHONE_SDK_VERSION} #{APP_ID} #{APP_NAME} #{APP_DEVICE}" | perl -pe s/^[DEBUG].*$/e[35m$&e[0m/g;s/^[INFO].*$/e[36m $&e[0m/g;s/^[WARN].*$/e[33m$&e[0m/g;s/^[ERROR].*$/e[31m $&e[0m/g;} endRAKEFILE Build with Titanium Python command line
  128. 128. def build(options={}) return unless compile options[:device] ||= iphone puts "Building with Titanium... (DEVICE_TYPE:#{options[:device]})".blue sh %Q{bash -c "#{TI_BUILD} run #{PROJECT_ROOT}/ #{IPHONE_SDK_VERSION} #{APP_ID} #{APP_NAME} #{APP_DEVICE}" | perl -pe s/^[DEBUG].*$/e[35m$&e[0m/g;s/^[INFO].*$/e[36m $&e[0m/g;s/^[WARN].*$/e[33m$&e[0m/g;s/^[ERROR].*$/e[31m $&e[0m/g;} end Pipe to PERL for some colored terminal goodnessRAKEFILE
  129. 129. Choose what works for you.
  130. 130. JavaScript Frameworks
  131. 131. Underscore.jshttps://github.com/documentcloud/underscore From Jeremy Ashkenas, the creator of CoffeeScript.
  132. 132. Dont Repeat Yourself Not Repeating Yourself
  133. 133. Ti GEMAutomating these patterns. A work in progress.
  134. 134. gem install ti
  135. 135. Generate.
  136. 136. ti new <name> <id> <platform>
  137. 137. ti new codestrong-app com.codestrong.app iphone
  138. 138. ├── Coffeefile├── Guardfile├── LICENSE├── Rakefile├── Readme.mkd├── Resources│   ├── app.js│   ├── app.jss│   ├── images│   │   ├── KS_nav_ui.png│   │   └── KS_nav_views.png│   ├── lsrc.js│   └── vendor├── app│   ├── app.coffee│   └── lsrc│   ├── api.coffee│   ├── app.coffee│   ├── helpers│   │   └── application.coffee│   ├── models│   ├── stylesheets│   │   ├── app.sass│   │   └── partials│   └── views├── build├── config│   └── config.rb├── docs├── spec│   ├── app_spec.coffee│   ├── helpers│   ├── models│   └── views├── tiapp.xml└── tmp
  139. 139. ti generate <model/controller/view> <name>
  140. 140. Golf.Views.GamePlay.createScoreCardView = (options) -> view = Ti.UI.createView (options) view
  141. 141. ti scaffold <window/tabgroup/view> <domain> <name>
  142. 142. Compile.
  143. 143. ti compile <all/coffee/sass>
  144. 144. Build.
  145. 145. ti build <all/iphone/android/ipad/desktop/>
  146. 146. Ti GEM@revans @baldrailers @rupakg
  147. 147. Get involved!
  148. 148. Weve got BIG ideas.
  149. 149. Testing.
  150. 150. Jasmine
  151. 151. Jasminehttps://github.com/akahigeg/jasmine-titanium
  152. 152. XIB
  153. 153. xib2jshttps://github.com/daoki2/xib2js
  154. 154. js2coffeehttp://ricostacruz.com/js2coffee/
  155. 155. QUESTIONS?http://spkr8.com/t/8342
  1. A particular slide catching your eye?

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

×