$30 off During Our Annual Pro Sale. View Details »

A Spree Themer's Toolkit

A Spree Themer's Toolkit

My slides from Spreeconf 2012

Wynn Netherland

February 16, 2012
Tweet

More Decks by Wynn Netherland

Other Decks in Programming

Transcript

  1. View Slide

  2. Developer?
    Store owner?
    Both?

    View Slide

  3. ~ ⚡ whoami
    Wynn Netherland

    View Slide

  4. View Slide

  5. View Slide

  6. I’m

    View Slide

  7. 175 slides, 45 minutes

    View Slide

  8. LET'S DO THIS!

    View Slide

  9. Titles are the new bullets.

    View Slide

  10. 3.5 years ago...

    View Slide

  11. View Slide

  12. View Slide

  13. View Slide

  14. Polyphonic

    View Slide

  15. having two or more independent but
    harmonically related melodic parts
    sounding together
    pol·y·phon·ic
    adjective:

    View Slide

  16. Are you listening to your store?

    View Slide

  17. Cha-ching!

    View Slide

  18. View Slide

  19. Click-a-click-click-whiff!

    View Slide

  20. View Slide

  21. Click-a-click-click-boom!

    View Slide

  22. View Slide

  23. View Slide

  24. Click-a-chug-a-chug-a

    View Slide

  25. Wasn't Jeff Casimir's talk great?

    View Slide

  26. Polymorphic

    View Slide

  27. occurring in or having many forms or
    shapes or appearances
    pol·y·morph·ic
    adjective:

    View Slide

  28. View Slide

  29. View Slide

  30. Why?

    View Slide

  31. your store != my store

    View Slide

  32. your business != my business

    View Slide

  33. Branding, trust.

    View Slide

  34. View Slide

  35. View Slide

  36. Geographic sensibilities

    View Slide

  37. View Slide

  38. Methods of Spree customization

    View Slide

  39. Extensions

    View Slide

  40. Extensions refer to discrete packages of code that
    provide new functionality to a Spree application,
    while extensions may affect the appearance of a Spree
    application they generally only provide additional
    interfaces to enable users to interact with the new
    functionality provided.

    View Slide

  41. Extensions refer to discrete packages of code that
    provide new functionality to a Spree application,
    while extensions may affect the appearance of a Spree
    application they generally only provide additional
    interfaces to enable users to interact with the new
    functionality provided.

    View Slide

  42. Themes

    View Slide

  43. Themes are discrete packages of code that only
    affect the appearance of a Spree application (and
    generally only the front-end store). Themes do not
    generally include any logic customizations.

    View Slide

  44. Themes are discrete packages of code that only
    affect the appearance of a Spree application (and
    generally only the front-end store). Themes do not
    generally include any logic customizations.

    View Slide

  45. Powered by Rails Engines
    Wasn't Ryan Bigg's talk great?

    View Slide

  46. (Good conferences aren't DRY)

    View Slide

  47. The Asset Pipeline

    View Slide

  48. We rename
    Und now vee dance.

    View Slide

  49. View Slide

  50. precompile is your friend

    View Slide

  51. bundle exec rake assets:precompile RAILS_ENV=development

    View Slide

  52. drwxr-xr-x 17 wynn staff 578 Nov 2 08:36 .
    drwxr-xr-x 8 wynn staff 272 Nov 2 08:35 ..
    drwxr-xr-x 16 wynn staff 544 Nov 2 08:36 admin
    -rw-r--r-- 1 wynn staff 155 Nov 2 08:30 application.css
    -rw-r--r-- 1 wynn staff 143 Nov 2 08:30 application.css.gz
    drwxr-xr-x 7 wynn staff 238 Nov 2 08:36 creditcards
    drwxr-xr-x 3 wynn staff 102 Nov 2 08:36 datepicker
    -rw-r--r-- 1 wynn staff 1150 Nov 2 08:19 favicon.ico
    drwxr-xr-x 6 wynn staff 204 Nov 2 08:36 icons
    drwxr-xr-x 4 wynn staff 136 Nov 2 08:36 jqPlot
    drwxr-xr-x 15 wynn staff 510 Nov 2 08:36 jquery-ui
    drwxr-xr-x 3 wynn staff 102 Nov 2 08:35 jquery.alerts
    drwxr-xr-x 3 wynn staff 102 Nov 2 08:35 jquery.jstree
    -rw-r--r-- 1 wynn staff 6694 Nov 2 08:36 manifest.yml
    drwxr-xr-x 5 wynn staff 170 Nov 2 08:36 noimage
    -rw-r--r-- 1 wynn staff 1608 Nov 2 08:19 spinner.gif
    drwxr-xr-x 6 wynn staff 204 Nov 2 08:36 store

    View Slide

  53. active_reload is a must
    Included in Rails 3.2

    View Slide

  54. View Slide

  55. View Slide

  56. Anatomy of a theme

    View Slide

  57. spree_rdr_theme [ master: ✔ ] 6d ⚡ tree -d

    View Slide

  58. spree_rdr_theme [ master: ✔ ] 6d ⚡ tree -d
    .
    ├── app
    │ ├── assets
    │ │ ├── images
    │ │ │ └── store
    │ │ │ └── icons
    │ │ ├── javascripts
    │ │ │ └── store
    │ │ └── stylesheets
    │ │ └── store
    │ ├── overrides
    │ └── views
    │ └── spree
    │ ├── shared
    │ └── wishlists
    ├── lib
    │ └── generators
    │ └── spree_rdr_theme
    │ └── install
    └── vendor
    └── assets
    ├── images
    │ └── fancybox
    ├── javascripts
    └── stylesheets

    View Slide

  59. spree_rdr_theme [ master: ✔ ] 6d ⚡ tree -d
    .
    ├── app
    │ ├── assets
    │ │ ├── images
    │ │ │ └── store
    │ │ │ └── icons
    │ │ ├── javascripts
    │ │ │ └── store
    │ │ └── stylesheets
    │ │ └── store
    │ ├── overrides
    │ └── views
    │ └── spree
    │ ├── shared
    │ └── wishlists
    ├── lib
    │ └── generators
    │ └── spree_rdr_theme
    │ └── install
    └── vendor
    └── assets
    ├── images
    │ └── fancybox
    ├── javascripts
    └── stylesheets
    Your stuff

    View Slide

  60. spree_rdr_theme [ master: ✔ ] 6d ⚡ tree -d
    .
    ├── app
    │ ├── assets
    │ │ ├── images
    │ │ │ └── store
    │ │ │ └── icons
    │ │ ├── javascripts
    │ │ │ └── store
    │ │ └── stylesheets
    │ │ └── store
    │ ├── overrides
    │ └── views
    │ └── spree
    │ ├── shared
    │ └── wishlists
    ├── lib
    │ └── generators
    │ └── spree_rdr_theme
    │ └── install
    └── vendor
    └── assets
    ├── images
    │ └── fancybox
    ├── javascripts
    └── stylesheets
    Your Stylesheets, images, JavaScripts

    View Slide

  61. spree_rdr_theme [ master: ✔ ] 6d ⚡ tree -d
    .
    ├── app
    │ ├── assets
    │ │ ├── images
    │ │ │ └── store
    │ │ │ └── icons
    │ │ ├── javascripts
    │ │ │ └── store
    │ │ └── stylesheets
    │ │ └── store
    │ ├── overrides
    │ └── views
    │ └── spree
    │ ├── shared
    │ └── wishlists
    ├── lib
    │ └── generators
    │ └── spree_rdr_theme
    │ └── install
    └── vendor
    └── assets
    ├── images
    │ └── fancybox
    ├── javascripts
    └── stylesheets
    Your Deface overrides

    View Slide

  62. Deface
    Wasn't Brian Quinn's talk great?

    View Slide

  63. Deface::Override.new(:virtual_path => "posts/_form",
    :name => "example-1",
    :replace => "h1",
    :text => "New Post")
    Deface::Override.new(:virtual_path => "posts/_form",
    :name => "example-1",
    :replace => "h1") do
    "New Post"
    end In a block

    View Slide

  64. spree_rdr_theme [ master: ✔ ] 6d ⚡ tree -d
    .
    ├── app
    │ ├── assets
    │ │ ├── images
    │ │ │ └── store
    │ │ │ └── icons
    │ │ ├── javascripts
    │ │ │ └── store
    │ │ └── stylesheets
    │ │ └── store
    │ ├── overrides
    │ └── views
    │ └── spree
    │ ├── shared
    │ └── wishlists
    ├── lib
    │ └── generators
    │ └── spree_rdr_theme
    │ └── install
    └── vendor
    └── assets
    ├── images
    │ └── fancybox
    ├── javascripts
    └── stylesheets
    Your custom views

    View Slide

  65. spree_rdr_theme [ master: ✔ ] 6d ⚡ tree -d
    .
    ├── app
    │ ├── assets
    │ │ ├── images
    │ │ │ └── store
    │ │ │ └── icons
    │ │ ├── javascripts
    │ │ │ └── store
    │ │ └── stylesheets
    │ │ └── store
    │ ├── overrides
    │ └── views
    │ └── spree
    │ ├── shared
    │ └── wishlists
    ├── lib
    │ └── generators
    │ └── spree_rdr_theme
    │ └── install
    └── vendor
    └── assets
    ├── images
    │ └── fancybox
    ├── javascripts
    └── stylesheets
    Third party libraries and frameworks

    View Slide

  66. Polyglotnic
    Ok, so I made that one up

    View Slide

  67. A person having a speaking, reading,
    or writing knowledge of several
    languages
    pol·y·glot
    adjective:

    View Slide

  68. CSS3

    View Slide

  69. border-radius

    View Slide

  70. border-image

    View Slide

  71. www.zurb.com/playground/awesome-overlays

    View Slide

  72. background-size

    View Slide

  73. gradients

    View Slide

  74. RGBA, HSL, HSLA colors
    rgba (0,0,0,1) is the new black!

    View Slide

  75. text-shadow

    View Slide

  76. box-shadow

    View Slide

  77. word
    wrap

    View Slide

  78. outline

    View Slide

  79. columns

    View Slide

  80. @font-face
    Typographic freedom!
    means

    View Slide

  81. New selectors
    Cool

    View Slide

  82. *
    E
    .class
    #id
    E F
    E > F
    E + F
    E[attribute]
    E[attribute=value]
    E[attribute~=value]
    E[attribute|=value]
    :first-child
    :link
    :visited
    :lang()
    :before
    ::before
    :after
    ::after
    :first-letter
    ::first-letter
    :first-line
    ::first-line
    E[attribute^=value]
    E[attribute$=value]
    E[attribute*=value]
    E ~ F
    :root
    :last-child
    :only-child
    :nth-child()
    :nth-last-child()
    :first-of-type
    :last-of-type
    :only-of-type
    :nth-of-type()
    :nth-last-of-type()
    :empty
    :not()
    :target
    :enabled
    :disabled
    :checked
    CSS3 selectors (and some golden oldies)
    :header
    Steal this from jQuery, please

    View Slide

  83. CSS Frameworks

    View Slide

  84. View Slide

  85. View Slide

  86. Percentage-based grid, screenshot in Firefox 4.0
    http://host.sonspring.com/yui3_grid

    View Slide

  87. View Slide

  88. View Slide

  89. View Slide

  90. Sass

    View Slide

  91. Nested rules

    View Slide

  92. table.users tr td {background: #111}
    table.users tr td a {color: #333}
    Nested rules - selectors

    View Slide

  93. table.users {
    tr {
    td {
    background: #d1d1d;
    a {
    color: #111;
    }
    }
    }
    }
    Nested rules - selectors

    View Slide

  94. table.users {
    tr {
    td {
    color: #111;
    &.alt {
    color: #333;
    }
    &:hover {
    color: #666;
    }
    }
    }
    }
    Nested rules - selectors

    View Slide

  95. .users {
    font: {
    size: 1.2em;
    style: italics;
    weight: bold;
    }
    }
    Nested rules - properties

    View Slide

  96. Syntax options

    View Slide

  97. table.users {
    tr {
    td {
    background: #d1d1d;
    a {
    color: #111;
    }
    }
    }
    }
    Syntax options - SCSS Sassy CSS!

    View Slide

  98. table.users
    tr
    td
    background: #d1d1d
    a
    color: #111
    Syntax options - Indented I — whitespace

    View Slide

  99. Variables

    View Slide

  100. .user {
    background: #333;
    border-size: 2px;
    }
    .owner {
    background: #333;
    border-size: 2px;
    }
    .admin {
    background: #666;
    border-size: 4px;
    }
    Variables

    View Slide

  101. $gray: #333;
    $default_border: 2px;
    .user { background: $gray; border-size: $default_border;}
    .owner { background: $gray; border-size: $default_border;}
    .admin {
    background: $gray + #333;
    border-size: $default_border + 2px;
    }
    Variables
    Even math!
    and color mixing!

    View Slide

  102. Mixins

    View Slide

  103. .avatar {
    padding: 2px;
    border: solid 1px #ddd;
    position: absolute;
    top: 5px;
    left: 5px;
    }
    p img {
    padding: 2px;
    border: solid 1px #ddd;
    }
    Mixins

    View Slide

  104. @mixin frame($padding_width: 2px, $border_color: #ddd) {
    padding: $padding_width;
    border: {
    width: 1px;
    style: solid;
    color $border_color;
    }
    }
    .avatar {
    @include frame;
    position: absolute;
    top: 5px;
    left: 5px;
    }
    p img { @include frame(1px, #ccc);}
    Mixins
    defines the mixin
    mixes in the rules

    View Slide

  105. Extend

    View Slide

  106. .flash {
    padding: 5px;
    border-width: 1px;
    font-weight: bold;
    }
    .error {
    color: #8a1f11;
    background: #fbe3e4;
    }
    .notice {
    color: #514721;
    background: #fff6bf;
    }
    Mixins

    View Slide

  107. .flash {
    padding: 5px;
    border-width: 1px;
    font-weight: bold;
    }
    .error {
    @extend .flash;
    color: #8a1f11;
    background: #fbe3e4;
    }
    .notice {
    @extend .flash;
    color: #514721;
    background: #fff6bf;
    }
    Mixins

    View Slide

  108. .flash,
    .error,
    .notice { padding: 5px; border-width: 1px; font-weight: bold; }
    .error { color: #8a1f11; background: #fbe3e4; }
    .notice { color: #514721; background: #fff6bf; }
    Mixins
    now we can use a single class in our markup

    View Slide

  109. Imports

    View Slide

  110. @import url(/css/reset.css)
    @import url(/css/typography.css)
    @import url(/css/layout.css)
    Imports
    parent + 3 @imports = 4 HTTP requests

    View Slide

  111. @import "reset.scss" # _reset.scss
    @import "typography" # _typography.scss
    @import "layout.css" # url(layout.css)
    Imports
    Included at compile time -
    just one http request

    View Slide

  112. Imports + Mixins
    Now it gets fun!

    View Slide

  113. A brief detour

    View Slide

  114. Vendor prefixes
    and the growing -webkit monoculture

    View Slide

  115. Every Time You Call a
    Proprietary Feature “CSS3,”
    a Kitten Dies
    by L E A V E R O U

    View Slide

  116. Prefix or Posthack
    by E R I C M E Y E R

    View Slide

  117. “It’s time to abolish all vendor prefixes.
    They’ve become solutions for which there is no
    problem, and they are actively harming web
    standards.”
    — Peter-Paul Koch aka @ppk
    http://www.quirksmode.org/blog/archives/2010/03/css_vendor_pref.html

    View Slide

  118. Ummm. Not so fast.

    View Slide

  119. @import "compass/css3.scss";
    .callout {
    @include border-radius(5px);
    @include linear-gradient("left top", "left bottom", #fff, #ddd);
    }
    .callout {
    -moz-border-radius: 5px;
    -webkit-border-radius: 5px;
    -border-radius: 5px;
    background-image: -moz-linear-gradient(top, bottom, from(#fff),
    to(#ddd));
    background-image: -webkit-gradient(linear, left top, left bottom,
    color-stop(0.00, #fff), color-stop(1.00, #ddd));
    }
    Compass CSS3 mixins
    very different syntax

    View Slide

  120. “Well, reactions to my proposal to abolish
    vendor prefixes are mixed, and I might have
    overshot my target here.”
    -Peter-Paul Koch aka @ppk
    http://www.quirksmode.org/blog/archives/2010/03/css_vendor_pref_1.html

    View Slide

  121. Solutions?

    View Slide

  122. beta-new-css8-property-dilly
    isn't that just like not having it?
    ...and we're back.

    View Slide

  123. Vendor specific stylesheets
    Maybe. But I'd like to retain
    Internet Explorer's special status unto itself

    View Slide

  124. CSS preprocesors
    Hey, funny you should ask!

    View Slide

  125. Bring your favorite CSS Framework

    View Slide




  126. ...


    ...



    ...



    A Blueprint example
    boo? / Yay?

    View Slide

  127. #wrapper {
    @include container;
    #content {
    @include column(7);
    @include append(1);
    #featured {
    @include column(5, true);
    }
    }
    #sidebar {
    @include column(3, true);
    @include prepend(1);
    }
    }
    A Blueprint example

    View Slide

  128. Look, Ma! No math!

    View Slide

  129. Functions

    View Slide

  130. Very. Powerful. Functions.

    View Slide

  131. 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%) => #d1b72d
    Sass 2.4 color functions
    http://nex-3.com/posts/89-powerful-color-manipulation-with-sass

    View Slide

  132. 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
    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 color functions with alpha support!
    http://nex-3.com/posts/89-powerful-color-manipulation-with-sass

    View Slide

  133. View Slide

  134. Sass and Compass
    CSS extensions &
    compiler
    Patterns &
    plugins

    View Slide

  135. ...like peas and carrots.

    View Slide

  136. A quick survey of Compass

    View Slide

  137. CSS3

    View Slide

  138. CSS3
    ★ Appearance
    ★ Background Clip
    ★ Background Origin
    ★ Background Size
    ★ Border Radius
    ★ Box
    ★ Box Shadow
    ★ Box Sizing
    ★ CSS3 Pie
    ★ Columns
    ★ Font Face
    ★ Gradient
    ★ Images
    ★ Inline Block
    ★ Opacity
    ★ Shared Utilities
    ★ Text Shadow
    ★ Transform
    ★ Transform (legacy)
    ★ Transition

    View Slide

  139. Image sprites

    View Slide

  140. @import "icon/*.png"
    .actions
    .new
    +icon-sprite(new)
    .edit
    +icon-sprite(edit)
    .save
    +icon-sprite(save)
    .delete
    +icon-sprite(delete)
    Image sprites
    .icon-sprite,
    .actions .new,
    .actions .edit,
    .actions .save,
    .actions .delete
    { background: url('/images/icon-34fe0604ab.png') no-repeat; }
    .actions .new { background-position: 0 -64px; }
    .actions .edit { background-position: 0 -32px; }
    .actions .save { background-position: 0 -96px; }
    .actions .delete { background-position: 0 0; }
    @import "icon/*.png"
    public/images/icon/new.png
    public/images/icon/edit.png
    public/images/icon/save.png
    public/images/icon/delete.png
    1.
    2.
    3.
    I like the Sprite in you®

    View Slide

  141. URL helpers

    View Slide

  142. #nav
    background: image-url("nav_bg.png") repeat-x top center
    DEVELOPMENT
    #nav {
    background: url("/images/nav_bg.png") repeat-x top center;
    }
    PRODUCTION
    #nav {
    background: url("http://assets.example.com/images/nav_bg.png")
    repeat-x top center;
    }
    URL helpers
    relative paths for development,
    absolute for production

    View Slide

  143. stylesheet-url($path)
    font-url($path)
    image-url($path)
    URL helpers

    View Slide

  144. Share your patterns

    View Slide

  145. http://brandonmathis.com/projects/fancy-buttons/

    View Slide

  146. @import "fancy-buttons"
    button,
    a.button
    +fancy-button(#2966a8)

    View Slide

  147. compass-960

    View Slide

  148. $ninesixty-columns: 16
    #wrap
    +grid-container
    #left-nav
    +alpha
    +grid(5)
    #main-content
    +grid-prefix(1)
    +grid(10)
    +omega
    Compass 960
    https://github.com/chriseppstein/compass-960-plugin

    View Slide

  149. compass-wordpress

    View Slide

  150. $ gem install compass-wordpress
    CRANK OUT A NEW SASS-Y WORDPRESS THEME
    $ compass -r compass-wordpress \
    -f wordpress -p thematic \
    --sass-dir=sass --css-dir=css \
    -s compressed my_awesome_theme
    AUTOCOMPILE YOUR CHANGES
    $ compass --watch
    Compass and WordPress shameless plug

    View Slide

  151. compass-formalize

    View Slide

  152. View Slide

  153. Isn’t she Sassy, folks?
    GET
    THE
    BOOK.

    View Slide

  154. sass40
    Save 40% and get early access!
    Sadly, sass100 is not a valid code.

    View Slide

  155. Haml

    View Slide

  156. <%= "boo" %>

    View Slide

  157. #profile
    .left.column
    #date= print_date
    #address= current_user.address
    .right.column
    #email= current_user.email
    #bio= current_user.bio
    HAML


    <%= print_date %>
    <%= current_user.address %>
    div>


    <%= current_user.email %>
    <%= current_user.bio %>


    ERB

    View Slide

  158. Think and work in CSS selectors

    View Slide

  159. Never chase that again

    View Slide

  160. COFFEESCRIPT

    View Slide

  161. It's still just JavaScript.

    View Slide

  162. Compiles right in the AP

    View Slide

  163. charity [ master: ✔ ] 1d ⚡ tree app/assets/
    app/assets/javascripts/
    ├── application.js.coffee
    ├── ie8.js.coffee
    ├── media.js.coffee
    ├── mobile.js.coffee
    ├── pc
    │ ├── _boot.js.coffee
    │ ├── models
    │ │ ├── campaign.js.coffee
    │ │ ├── campaigns.js.coffee
    │ │ ├── project.js.coffee
    │ │ ├── projects.js.coffee
    │ │ └── scoreboard.js.coffee
    │ ├── routers
    │ │ └── discover.js.coffee
    │ └── views
    │ ├── calc.js.coffee
    │ ├── cropper.js.coffee
    │ ├── data_table.js.coffee
    │ ├── discover
    │ │ ├── app.js.coffee
    │ │ ├── campaigns_panel.js.coffee
    │ │ ├── map.js.coffee

    View Slide

  164. var foo = function () {
    }
    foo = () ->
    I’d rather write this.
    JAVASCRIPT COFFEESCRIPT

    View Slide

  165. 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

    View Slide

  166. button = Titanium.UI.createButton
    title: 'I am a Button'
    height: 40
    width: 200
    top: 10
    button.addEventListener 'click', (e) ->
    alert "Oooh, that tickles!"
    COFFEESCRIPT

    View Slide

  167. It's about more than aesthetics
    ;{ }
    For me,

    View Slide

  168. Some of my favorite features...

    View Slide

  169. 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

    View Slide

  170. for own key, value of query
    uri += "#{ key }=#{ escape(value) }&"
    COFFEESCRIPT
    Comprehensions

    View Slide

  171. for own key, value of query
    uri += "#{ key }=#{ escape(value) }&"
    COFFEESCRIPT
    Interpolation

    View Slide

  172. courseButtonSubhead = Ti.UI.createLabel
    className: 'optRowSubhead'
    text: "#{GolfStatus.App.currentGame?.green?.name}"
    COFFEESCRIPT
    The Existential Operator

    View Slide

  173. 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
    Simple inheritance pattern

    View Slide

  174. 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
    COFFEESCRIPT
    @

    View Slide

  175. 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
    COFFEESCRIPT
    Default values

    View Slide

  176. 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
    COFFEESCRIPT
    More human conditionals

    View Slide

  177. GolfStatus.Models.Game::PlayingForTypes =
    brag: 'Bragging Rights'
    cash: 'Status Cash'
    GolfStatus.Models.Game::ScoringFormats =
    low_net: 'Low Net'
    low_grows: 'Low Gross'
    COFFEESCRIPT
    Easy object.prototype

    View Slide

  178. noticeHTML ='''



    '''
    noticeHTML += "#{noticeText}"
    noticeHTML += '''


    '''
    COFFEESCRIPT
    Heredocs

    View Slide

  179. Because string building sucks.

    View Slide

  180. And so much more.

    View Slide

  181. http://wynn.fm/2Y

    View Slide

  182. GET
    THE
    BOOK.
    http://wynn.fm/g8

    View Slide

  183. JavaScript Frameworks

    View Slide

  184. https://github.com/documentcloud/underscore
    From Jeremy Ashkenas,
    the creator of CoffeeScript.
    https://github.com/documentcloud/backbone

    View Slide

  185. QUESTIONS?
    http://spkr8.com/t/9283

    View Slide