Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SpreeConf 2012: Spree themes with Deface

Brian Quinn
February 19, 2012

SpreeConf 2012: Spree themes with Deface

Overview of Spree's new core theme, and a deep dive into Deface.

Brian Quinn

February 19, 2012
Tweet

More Decks by Brian Quinn

Other Decks in Technology

Transcript

  1. Brian Quinn
    Co-founder & CTO of Spree Commerce, Inc.
    @briandq
    bdq

    View full-size slide

  2. spree/spree_reviews

    View full-size slide

  3. spree/spree_reviews
    • Fork it

    View full-size slide

  4. spree/spree_reviews
    • Fork it
    • sign in to Travis-CI

    View full-size slide

  5. spree/spree_reviews
    • Fork it
    • sign in to Travis-CI
    • Test Hook

    View full-size slide

  6. spree/spree_reviews
    • Fork it
    • sign in to Travis-CI
    • Test Hook
    @joshkalderimis

    View full-size slide

  7. Creating
    Spree Themes
    with Deface

    View full-size slide

  8. We’re going to cover
    • Intro to themes
    • Theme design principals
    • Walkthrough the core base theme
    • Deep dive into Deface
    • Features
    • Internals
    • Examples
    • Tricks
    • The future!

    View full-size slide

  9. Going to presume
    • You’re a Rails Developer
    • You’re comfortable with HTML, CSS
    • You’ve already worked with Spree
    • You’ll stop me if you have a question!

    View full-size slide

  10. What is a Spree
    theme?

    View full-size slide

  11. Theme == Engine

    View full-size slide

  12. app/
    assets/
    javascripts/

    View full-size slide

  13. app/
    assets/
    javascripts/
    stylesheets/

    View full-size slide

  14. app/
    assets/
    javascripts/
    stylesheets/
    images/

    View full-size slide

  15. app/
    assets/
    javascripts/
    stylesheets/
    images/
    overrides/

    View full-size slide

  16. app/
    assets/
    javascripts/
    stylesheets/
    images/
    overrides/
    views/

    View full-size slide

  17. Themes are
    containers

    View full-size slide

  18. - Maintainable

    View full-size slide

  19. Overrides should
    use :original

    View full-size slide

  20. - Extension Aware

    View full-size slide

  21. spree-rdr-theme
    • spree-social
    • spree-wishlist
    • spree-recently-viewed
    • spree-related-products
    • spree-paypal-express

    View full-size slide

  22. Rails.application.railties.all.map(&:railtie_name)
    .include? "spree_related_products"

    View full-size slide

  23. Redefine Overrides

    View full-size slide

  24. Versionfile
    "1.0.x" => { :branch => "master" }
    "0.70.x" => { :ref => "4aedfg" }

    View full-size slide

  25. - NEVER EVER
    include feature(s)

    View full-size slide

  26. Skeleton
    http://getskeleton.com

    View full-size slide

  27. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

    View full-size slide


  28. <% if content_for?(:sidebar) %>

    <%= yield :sidebar %>

    <% end %>
    4
    Skeleton
    app/views/spree/layouts/spree_application.html.erb
    1
    2
    3
    4
    5
    6
    7

    View full-size slide


  29. <% if content_for?(:sidebar) %>

    <%= yield :sidebar %>

    <% end %>
    4
    Skeleton
    app/views/spree/layouts/spree_application.html.erb
    1
    2
    3
    4
    5
    6
    7

    View full-size slide


  30. <% if content_for?(:sidebar) %>

    <%= yield :sidebar %>

    <% end %>
    4
    Skeleton
    app/views/spree/layouts/spree_application.html.erb
    1
    2
    3
    4
    5
    6
    7

    View full-size slide

  31. 1 column = 40px

    View full-size slide

  32. 1 column = 28px

    View full-size slide

  33. All columns are
    420px

    View full-size slide

  34. All columns are
    420px
    3

    View full-size slide

  35. 3
    All columns are
    420px

    View full-size slide

  36. /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */
    @media only screen and (min-width: 480px) and (max-width: 767px) {
    ul#products {
    margin-left: 0;
    margin-right: -20px;
    li {
    width: 133px;
    margin-right: 10px;
    }
    }
    Media Query
    core/app/assets/stylesheets/store/screen.css.scss

    View full-size slide

  37. /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */
    @media only screen and (min-width: 480px) and (max-width: 767px) {
    ul#products {
    margin-left: 0;
    margin-right: -20px;
    li {
    width: 133px;
    margin-right: 10px;
    }
    }
    Media Query
    core/app/assets/stylesheets/store/screen.css.scss

    View full-size slide

  38. /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */
    @media only screen and (min-width: 480px) and (max-width: 767px) {
    ul#products {
    margin-left: 0;
    margin-right: -20px;
    li {
    width: 133px;
    margin-right: 10px;
    }
    }
    Media Query
    core/app/assets/stylesheets/store/screen.css.scss

    View full-size slide

  39. All columns are
    300px

    View full-size slide

  40. /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */
    @media only screen and (max-width: 479px) {
    ul#products {
    margin-left: 0;
    margin-right: -20px;
    li {
    width: 140px;
    margin-right: 10px;
    }
    }
    Media Query
    core/app/assets/stylesheets/store/screen.css.scss

    View full-size slide

  41. /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */
    @media only screen and (max-width: 479px) {
    ul#products {
    margin-left: 0;
    margin-right: -20px;
    li {
    width: 140px;
    margin-right: 10px;
    }
    }
    Media Query
    core/app/assets/stylesheets/store/screen.css.scss

    View full-size slide

  42. /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */
    @media only screen and (max-width: 479px) {
    ul#products {
    margin-left: 0;
    margin-right: -20px;
    li {
    width: 140px;
    margin-right: 10px;
    }
    }
    Media Query
    core/app/assets/stylesheets/store/screen.css.scss

    View full-size slide

  43. HTML5
    • header
    • footer
    • nav
    • aside
    • figure

    View full-size slide

  44. HTML5 Reset V2
    http://html5reset.org/

    View full-size slide

  45. html5shiv
    http://code.google.com/p/html5shiv/

    View full-size slide

  46. html5shiv
    http://code.google.com/p/html5shiv/

    View full-size slide

  47. formalize
    http://formalize.me/

    View full-size slide

  48. github.com/railsdog/deface
    deface

    View full-size slide

  49. deface::override
    Deface::Override

    View full-size slide

  50. Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#thumbnails",
    :erb => %q{Hello World})
    app/overrides/tweak_thumbs.rb

    View full-size slide

  51. Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#thumbnails",
    :erb => %q{Hello World})
    app/overrides/tweak_thumbs.rb

    View full-size slide

  52. Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#thumbnails",
    :erb => %q{Hello World})
    app/overrides/tweak_thumbs.rb

    View full-size slide

  53. (options)
    options

    View full-size slide

  54. :virtual_path

    View full-size slide

  55. • spree/products/show
    :virtual_path

    View full-size slide

  56. • spree/products/show
    • spree/shared/_nav_bar
    :virtual_path

    View full-size slide

  57. • spree/products/show
    • spree/shared/_nav_bar
    • spree/admin/orders/index
    :virtual_path

    View full-size slide

  58. • spree/products/show
    • spree/shared/_nav_bar
    • spree/admin/orders/index
    • pirates/new
    :virtual_path

    View full-size slide

  59. • replace_product_list
    :name

    View full-size slide

  60. • replace_product_list
    • add_help_text
    :name

    View full-size slide

  61. • replace_product_list
    • add_help_text
    • does_anyone_really_care
    :name

    View full-size slide

  62. :remove
    :replace
    :replace_contents
    :surround
    :surround_contents
    :insert_after
    :insert_before
    :insert_top
    :insert_bottom
    :set_attributes
    Actions

    View full-size slide

  63. :remove
    :replace
    :replace_contents
    :surround
    :surround_contents
    :insert_after
    :insert_before
    :insert_top
    :insert_bottom
    :set_attributes
    Actions
    :action => “css selector”

    View full-size slide

  64. :text
    :erb
    :haml
    :parital
    :template
    Source

    View full-size slide

  65. :text
    :erb
    :haml
    :parital
    :template
    Source
    :source => “markup”

    View full-size slide

  66. Under the hood
    (under the hood)

    View full-size slide

  67. Rails Deface
    Original
    ERB

    View full-size slide

  68. Rails Deface
    Original
    ERB
    Deface
    Pre-parser

    View full-size slide

  69. Rails Deface
    Original
    ERB
    Deface
    Pre-parser
    Pseudo
    ERB
    XML

    View full-size slide


  70. <% if @product.present? %>
    <%= render :partial => 'thumbnails' %>
    <% end %>

    Original ERB
    1
    2
    3
    4
    5

    View full-size slide


  71. <% if @product.present? %>
    <%= render :partial => 'thumbnails' %>
    <% end %>

    Original ERB
    Pseudo ERB / XML

    if @product.present?
    render :partial => 'thumbnails'
    end

    1
    2
    3
    4
    5
    1
    2
    3
    4
    5

    View full-size slide


  72. <% if @product.present? %>
    <%= render :partial => 'thumbnails' %>
    <% end %>

    Original ERB
    Pseudo ERB / XML

    if @product.present?
    render :partial => 'thumbnails'
    end

    1
    2
    3
    4
    5
    1
    2
    3
    4
    5

    View full-size slide


  73. <% if @product.present? %>
    <%= render :partial => 'thumbnails' %>
    <% end %>

    Original ERB
    Pseudo ERB / XML

    if @product.present?
    render :partial => 'thumbnails'
    end

    1
    2
    3
    4
    5
    1
    2
    3
    4
    5

    View full-size slide


  74. <% if @product.present? %>
    <%= render :partial => 'thumbnails' %>
    <% end %>

    Original ERB
    Pseudo ERB / XML

    if @product.present?
    render :partial => 'thumbnails'
    end

    1
    2
    3
    4
    5
    1
    2
    3
    4
    5

    View full-size slide


  75. <% if @product.present? %>
    <%= render :partial => 'thumbnails' %>
    <% end %>

    Original ERB
    Pseudo ERB / XML

    if @product.present?
    render :partial => 'thumbnails'
    end

    1
    2
    3
    4
    5
    1
    2
    3
    4
    5

    View full-size slide

  76. Original ERB

    Product Name

    1
    2
    3

    View full-size slide


  77. Product Name

    Original ERB
    Pseudo ERB / XML

    Product Name

    1
    2
    3
    1
    2
    3

    View full-size slide


  78. Product Name

    Original ERB
    Pseudo ERB / XML

    Product Name

    1
    2
    3
    1
    2
    3

    View full-size slide


  79. Product Name

    Original ERB
    Pseudo ERB / XML

    Product Name

    1
    2
    3
    1
    2
    3

    View full-size slide

  80. Original ERB
    <%= show_attrs %>>
    Product description

    1
    2
    3

    View full-size slide

  81. data-erb-1="<%= show_attrs %>">
    Product description

    Original ERB
    Pseudo ERB / XML
    <%= show_attrs %>>
    Product description

    1
    2
    3
    1
    2
    3

    View full-size slide

  82. data-erb-1="<%= show_attrs %>">
    Product description

    Original ERB
    Pseudo ERB / XML
    <%= show_attrs %>>
    Product description

    1
    2
    3
    1
    2
    3

    View full-size slide

  83. data-erb-1="<%= show_attrs %>">
    Product description

    Original ERB
    Pseudo ERB / XML
    <%= show_attrs %>>
    Product description

    1
    2
    3
    1
    2
    3

    View full-size slide

  84. Deface needs
    well-formed
    erb / html

    View full-size slide

  85. Rails Deface
    Original
    ERB
    Deface
    Pre-parser
    Pseudo
    ERB
    XML

    View full-size slide

  86. Rails Deface
    Original
    ERB
    Deface
    Pre-parser
    Pseudo
    ERB
    XML
    Nokogiri

    View full-size slide

  87. Rails Deface
    Original
    ERB
    Deface
    Pre-parser
    Pseudo
    ERB
    XML
    Nokogiri
    Deface
    Overrides

    View full-size slide

  88. Rails Deface
    Original
    ERB
    Deface
    Pre-parser
    Pseudo
    ERB
    XML
    Nokogiri
    Deface
    Overrides

    View full-size slide

  89. Rails Deface
    Original
    ERB
    Deface
    Pre-parser
    Pseudo
    ERB
    XML
    Nokogiri
    Deface
    Overrides
    Deface
    Post-
    parser

    View full-size slide

  90. Rails Deface
    Original
    ERB
    Deface
    Pre-parser
    Pseudo
    ERB
    XML
    Nokogiri
    Deface
    Overrides
    Deface
    Post-
    parser
    Final
    ERB

    View full-size slide

  91. (examples)
    Examples

    View full-size slide

  92. (the basics)
    The Basics

    View full-size slide

  93. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    View full-size slide

  94. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",

    View full-size slide

  95. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",

    View full-size slide

  96. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :insert_bottom => "div#thumbnails",

    View full-size slide

  97. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :insert_bottom => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  98. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :insert_bottom => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  99. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    9
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :insert_bottom => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  100. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    9
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :insert_bottom => "div#thumbnails",
    :erb => %q{Hello World})
    Hello World

    View full-size slide

  101. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    9
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    Hello World
    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :insert_top => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  102. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    9
    app/views/spree/products/show.html.erb


    <%= render 'image' %>

    Hello World

    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :insert_before => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  103. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    9
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>

    Hello World

    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :insert_after => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  104. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    app/views/spree/products/show.html.erb


    <%= render 'image' %>

    Hello World

    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  105. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    Hello World


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace_contents => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  106. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :remove => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  107. (surround)
    surround

    View full-size slide



  108. <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    1
    2
    3
    4
    5
    6
    7
    app/overrides/tweak_thumbs.rb
    app/views/spree/products/show.html.erb
    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :surround => "div#thumbnails",
    :erb => %q{
    Images
    <%= render_original %>
    })
    1
    2
    3
    4
    5
    6
    7
    8

    View full-size slide



  109. <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    1
    2
    3
    4
    5
    6
    7
    app/overrides/tweak_thumbs.rb
    app/views/spree/products/show.html.erb
    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :surround => "div#thumbnails",
    :erb => %q{
    Images
    <%= render_original %>
    })
    1
    2
    3
    4
    5
    6
    7
    8

    View full-size slide



  110. <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    1
    2
    3
    4
    5
    6
    7
    app/overrides/tweak_thumbs.rb
    app/views/spree/products/show.html.erb
    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :surround => "div#thumbnails",
    :erb => %q{
    Images
    <%= render_original %>
    })
    1
    2
    3
    4
    5
    6
    7
    8

    View full-size slide

  111. 1
    2
    3
    4
    5
    6
    7
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    Images

    <%= render 'thumbnails', :product => @product %>



    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :surround => "div#thumbnails",
    :erb => %q{
    Images
    <%= render_original %>
    })

    View full-size slide

  112. 1
    2
    3
    4
    5
    6
    7
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    Images

    <%= render 'thumbnails', :product => @product %>



    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :surround => "div#thumbnails",
    :erb => %q{
    Images
    <%= render_original %>
    })

    View full-size slide

  113. 1
    2
    3
    4
    5
    app/overrides/tweak_thumbs.rb
    app/views/spree/products/show.html.erb


    <%= render 'image' %>



    <%= render 'thumbnails', :product => @product %>



    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :surround_contents => "div#thumbnails",
    :erb => %q{<%= render_original %>})
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    View full-size slide

  114. 1
    2
    3
    4
    5
    app/overrides/tweak_thumbs.rb
    app/views/spree/products/show.html.erb


    <%= render 'image' %>



    <%= render 'thumbnails', :product => @product %>



    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :surround_contents => "div#thumbnails",
    :erb => %q{<%= render_original %>})
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    View full-size slide

  115. (set_attributes)
    seT_aTTribuTes

    View full-size slide

  116. 1
    2
    3
    4
    5
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :set_attributes => "div#thumbnails",
    :attributes => { :alt => "blah"
    :id => "thumbs"})

    View full-size slide

  117. 1
    2
    3
    4
    5
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :set_attributes => "div#thumbnails",
    :attributes => { :alt => "blah"
    :id => "thumbs"})

    View full-size slide

  118. 1
    2
    3
    4
    5
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :set_attributes => "div#thumbnails",
    :attributes => { :alt => "blah"
    :id => "thumbs"})

    View full-size slide

  119. (sequence)
    sequence

    View full-size slide

  120. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    app/views/spree/products/show.html.erb


    <%= render 'image' %>

    Hello World

    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  121. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    app/views/spree/products/show.html.erb


    <%= render 'image' %>

    Goodbye World

    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#thumbnails",
    :erb => %q{Hello World})
    1
    2
    3
    4
    5
    app/overrides/cry_for_help.rb
    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "cry_for_help",
    :replace_contents => "#product-images span",
    :erb => “Goodbye World”,
    :sequence => {:after => ‘tweak_thumbs’})

    View full-size slide

  122. (closing_selector)
    closing_selector

    View full-size slide

  123. 1
    2
    3
    4
    5
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#main-image",
    :closing_selector => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  124. 1
    2
    3
    4
    5
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#main-image",
    :closing_selector => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  125. 1
    2
    3
    4
    5
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#main-image",
    :closing_selector => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  126. 1
    2
    3
    4
    5
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    app/views/spree/products/show.html.erb
    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#main-image",
    :closing_selector => "div#thumbnails",
    :erb => %q{Hello World})

    Hello World

    View full-size slide

  127. 1
    2
    3
    4
    5
    6
    7
    views/spree/products/index.html.erb (pseudo)
    1
    2
    3
    4
    5
    6
    7
    views/spree/products/index.html.erb
    <% content_for :sidebar do %>

    <% if "products" == @current_controller %>
    <%= render :partial => 'spree/shared/taxonomies' %>
    <% end %>

    <% end %>
    content_for :sidebar do

    if “products” == @current_controller
    render :partial => 'spree/shared/filters'
    end

    end

    View full-size slide

  128. 1
    2
    3
    4
    5
    6
    7
    views/spree/products/index.html.erb (pseudo)
    1
    2
    3
    4
    5
    6
    7
    views/spree/products/index.html.erb
    <% content_for :sidebar do %>

    <% if "products" == @current_controller %>
    <%= render :partial => 'spree/shared/taxonomies' %>
    <% end %>

    <% end %>
    content_for :sidebar do

    if “products” == @current_controller
    render :partial => 'spree/shared/filters'
    end

    end

    View full-size slide

  129. 1
    2
    3
    4
    5
    6
    7
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    views/spree/products/index.html.erb (pseudo)
    content_for :sidebar do

    if “products” == @current_controller
    render :partial => 'spree/shared/filters'
    end

    end
    Deface::Override.new(:virtual_path => "products/show",
    :name => "tweak_thumbs",
    :replace =>
    %q{code[erb-silent]:contains(‘if “products” == @current_controller’)},
    :closing_selector =>
    %q{code[erb-silent]:contains(‘end’)},
    :erb => %q{Hello World})

    View full-size slide

  130. 1
    2
    3
    4
    5
    6
    7
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    views/spree/products/index.html.erb (pseudo)
    content_for :sidebar do

    if “products” == @current_controller
    render :partial => 'spree/shared/filters'
    end

    end
    Deface::Override.new(:virtual_path => "products/show",
    :name => "tweak_thumbs",
    :replace =>
    %q{code[erb-silent]:contains(‘if “products” == @current_controller’)},
    :closing_selector =>
    %q{code[erb-silent]:contains(‘end’)},
    :erb => %q{Hello World})

    View full-size slide

  131. 1
    2
    3
    4
    5
    6
    7
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    views/spree/products/index.html.erb (pseudo)
    content_for :sidebar do

    if “products” == @current_controller
    render :partial => 'spree/shared/filters'
    end

    end
    Deface::Override.new(:virtual_path => "products/show",
    :name => "tweak_thumbs",
    :replace =>
    %q{code[erb-silent]:contains(‘if “products” == @current_controller’)},
    :closing_selector =>
    %q{code[erb-silent]:contains(‘end’)},
    :erb => %q{Hello World})

    View full-size slide

  132. 1
    2
    3
    4
    5
    6
    7
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    views/spree/products/index.html.erb (pseudo)
    content_for :sidebar do

    if “products” == @current_controller
    render :partial => 'spree/shared/filters'
    end

    end
    Deface::Override.new(:virtual_path => "products/show",
    :name => "tweak_thumbs",
    :replace =>
    %q{code[erb-silent]:contains(‘if “products” == @current_controller’)},
    :closing_selector =>
    %q{code[erb-silent]:contains(‘end’)},
    :erb => %q{Hello World})

    View full-size slide

  133. 1
    2
    3
    4
    5
    6
    7
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    views/spree/products/index.html.erb (pseudo)
    content_for :sidebar do

    if “products” == @current_controller
    render :partial => 'spree/shared/filters'
    end

    end
    Deface::Override.new(:virtual_path => "products/show",
    :name => "tweak_thumbs",
    :replace =>
    %q{code[erb-silent]:contains(‘if “products” == @current_controller’)},
    :closing_selector =>
    %q{code[erb-silent]:contains(‘end’)},
    :erb => %q{Hello World})

    View full-size slide

  134. 1
    2
    3
    4
    5
    6
    7
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    views/spree/products/index.html.erb (pseudo)
    content_for :sidebar do
    Hello World
    end
    Deface::Override.new(:virtual_path => "products/show",
    :name => "tweak_thumbs",
    :replace =>
    %q{code[erb-silent]:contains(‘if “products” == @current_controller’)},
    :closing_selector =>
    %q{code[erb-silent]:contains(‘end’)},
    :erb => %q{Hello World})

    View full-size slide

  135. CSS General
    Sibling Selector

    View full-size slide

  136. code[erb-silent]:contains(‘if “products” == current_controller’)
    ~ code[erb-silent]:contains(‘end’)

    View full-size slide

  137. (original)
    original

    View full-size slide

  138. 1
    2
    3
    4
    5
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    app/views/spree/products/show.html.erb


    <%= render 'image' %>

    Hello World

    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#thumbnails",
    :erb => %q{Hello World},
    :original => %q{<%= render 'thumbnails', :product => @product %>})

    View full-size slide

  139. 1
    2
    3
    4
    5
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    app/views/spree/products/show.html.erb


    <%= render 'image' %>

    Hello World

    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#thumbnails",
    :erb => %q{Hello World},
    :original => %q{<%= render 'thumbnails', :product => @product %>})
    $ Deface [WARNING]: The original source for 'tweak_thumbs' has
    changed, this override should be reviewed to ensure it's still valid.

    View full-size slide

  140. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    app/views/spree/products/show.html.erb


    <%= render 'image' %>

    Hello World

    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  141. $ Deface [WARNING]: No :original defined for 'tweak_thumbs', you
    should change its definition to include:
    :original => 'eb3fa668cd98b6a1c75c36420ef1b238a1fc55ac'.
    1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    app/views/spree/products/show.html.erb


    <%= render 'image' %>

    Hello World

    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#thumbnails",
    :erb => %q{Hello World})

    View full-size slide

  142. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    app/views/spree/products/show.html.erb


    <%= render 'image' %>

    Hello World

    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :replace => "div#thumbnails",
    :erb => %q{Hello World},
    :original => "eb3fa668cd98b6a1c75c36420ef1b238a1fc55ac")

    View full-size slide

  143. (data-hook)
    data-hook

    View full-size slide

  144. 1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    View full-size slide

  145. 1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    [data-hook=‘product_images’]

    View full-size slide

  146. 1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    [data-hook=‘product_images’]
    #thumbnails[data-hook]

    View full-size slide

  147. #thumbnails[data-hook], [data-hook=‘thumbnails’]

    View full-size slide

  148. (haml support)
    haml support

    View full-size slide

  149. Rails Deface
    Original
    Haml

    View full-size slide

  150. Rails Deface
    Original
    Haml
    Deface
    Haml
    Converter

    View full-size slide

  151. Rails Deface
    Original
    Haml
    Deface
    Haml
    Converter
    Converted
    ERB

    View full-size slide

  152. Rails Deface
    Deface
    Pre-parser
    Pseudo
    ERB
    XML
    Nokogiri
    Deface
    Overrides
    Deface
    Post-
    parser
    Final
    ERB
    Original
    Haml
    Deface
    Haml
    Converter
    Converted
    ERB

    View full-size slide

  153. Rails Deface
    Deface
    Pre-parser
    Pseudo
    ERB
    XML
    Nokogiri
    Deface
    Overrides
    Deface
    Post-
    parser
    Final
    ERB
    Original
    Haml
    Deface
    Haml
    Converter
    Converted
    ERB

    View full-size slide

  154. 1
    2
    3
    app/views/spree/shared/_nav_bar.html.erb

    <%= render :partial => 'spree/shared/search' %>

    View full-size slide

  155. 1
    2
    3
    app/views/spree/shared/_nav_bar.html.erb

    <%= render :partial => 'spree/shared/search' %>


    render :partial => 'spree/shared/search'

    Pseudo ERB / XML
    1
    2
    3

    View full-size slide

  156. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    app/views/spree/shared/_nav_bar.html.erb
    Deface::Override.new(:name => 'insert_blog_link_in_nav_bar',
    :virtual_path => 'spree/shared/_nav_bar',
    :insert_after => '#search-bar[data-hook]',
    :haml => %q{%li{:id => 'blog'}= link_to 'Blog', blog_path})

    <%= render :partial => 'spree/shared/search' %>


    render :partial => 'spree/shared/search'

    Pseudo ERB / XML
    1
    2
    3

    View full-size slide

  157. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    app/views/spree/shared/_nav_bar.html.erb
    Deface::Override.new(:name => 'insert_blog_link_in_nav_bar',
    :virtual_path => 'spree/shared/_nav_bar',
    :insert_after => '#search-bar[data-hook]',
    :haml => %q{%li{:id => 'blog'}= link_to 'Blog', blog_path})

    <%= render :partial => 'spree/shared/search' %>


    render :partial => 'spree/shared/search'

    Pseudo ERB / XML
    1
    2
    3

    View full-size slide

  158. 1
    2
    app/views/spree/shared/_nav_bar.html.haml
    %li#search-bar{"data-hook" => ""}
    = render :partial => 'spree/shared/search'
    1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    Deface::Override.new(:name => 'insert_blog_link_in_nav_bar',
    :virtual_path => 'spree/shared/_nav_bar',
    :insert_after => '#search-bar[data-hook]',
    :haml => %q{%li{:id => 'blog'}= link_to 'Blog', blog_path})

    render :partial => 'spree/shared/search'

    Pseudo ERB / XML
    1
    2
    3

    View full-size slide

  159. 1
    2
    app/views/spree/shared/_nav_bar.html.haml
    %li#search-bar{"data-hook" => ""}
    = render :partial => 'spree/shared/search'
    1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    Deface::Override.new(:name => 'insert_blog_link_in_nav_bar',
    :virtual_path => 'spree/shared/_nav_bar',
    :insert_after => '#search-bar[data-hook]',
    :haml => %q{%li{:id => 'blog'}= link_to 'Blog', blog_path})

    render :partial => 'spree/shared/search'

    Pseudo ERB / XML
    1
    2
    3

    View full-size slide

  160. (production & precompiling)
    production & precompiling

    View full-size slide

  161. rake deface:precompile

    View full-size slide

  162. app/compiled_views

    View full-size slide

  163. Deface::Override.new(:virtual_path => "spree/shared/_store_menu",
    :name => "remove_home_link",
    :remove => "#home-link[data-hook]")
    app/overrides/remove_home_link.rb

    View full-size slide

  164. Deface::Override.new(:virtual_path => "spree/shared/_store_menu",
    :name => "remove_home_link",
    :remove => "#home-link[data-hook]")
    app/overrides/remove_home_link.rb
    app/spree/shared/_store_menu.html.erb
    <%= link_to t(:home), root_path %>
    <%= link_to_cart %>

    View full-size slide

  165. Deface::Override.new(:virtual_path => "spree/shared/_store_menu",
    :name => "remove_home_link",
    :remove => "#home-link[data-hook]")
    app/overrides/remove_home_link.rb
    app/spree/shared/_store_menu.html.erb
    <%= link_to t(:home), root_path %>
    <%= link_to_cart %>
    app/compiled_views/_store_menu.html.erb
    <%= link_to_cart %>

    View full-size slide

  166. YourApplication::Application.configure do
    ...
    #disable deface
    config.deface.enabled = false
    end
    config/environments/production.rb

    View full-size slide

  167. [WARNING] Precompiled views present and Deface is
    enabled, this can result in overrides being applied twice.

    View full-size slide

  168. rake deface:clean

    View full-size slide

  169. (tools & tricks)
    tool & Tricks

    View full-size slide

  170. Redefining Overrides

    View full-size slide

  171. 1
    2
    3
    4
    spree_social/app/overrides/add_icons.rb
    Deface::Override.new(:virtual_path => "spree/users/new",
    :name => "add_icons",
    :replace => "[data-hook=‘user_form’]",
    :erb => %q{})
    1
    2
    3
    app/overrides/tweak_social_icons.rb
    Deface::Override.new(:virtual_path => "spree/users/new",
    :name => "add_icons",
    :erb => %q{})

    View full-size slide

  172. http://deface.heroku.com

    View full-size slide

  173. https://github.com/BDQ/deface-this

    View full-size slide

  174. Render No More

    View full-size slide

  175. Started GET "/" for 127.0.0.1 at Mon Jan 16 12:01:29 +0000 2012
    Processing by Spree::HomeController#index as */*
    Rendered /spree/core/app/views/spree/shared/_taxonomies.html.erb (9.0ms)
    Rendered /spree/core/app/views/spree/shared/_products.html.erb (26.7ms)
    Rendered /spree/core/app/views/spree/home/index.html.erb within /spree/layouts/spree_application (36.6ms)
    Rendered /spree/core/app/views/spree/shared/_head.html.erb (1.6ms)
    Rendered /spree/core/app/views/spree/shared/_search.html.erb (2.1ms)
    Rendered /spree/core/app/views/spree/shared/_store_menu.html.erb (0.7ms)
    Rendered /spree/core/app/views/spree/shared/_nav_bar.html.erb (3.9ms)
    Rendered /spree/core/app/views/spree/shared/_google_analytics.html.erb (0.8ms)
    Completed 200 OK in 48ms (Views: 43.2ms | ActiveRecord: 2.2ms)

    View full-size slide

  176. Started GET "/" for 127.0.0.1 at Mon Jan 16 12:01:29 +0000 2012
    Processing by Spree::HomeController#index as */*
    Rendered /spree/core/app/views/spree/shared/_taxonomies.html.erb (9.0ms)
    Rendered /spree/core/app/views/spree/shared/_products.html.erb (26.7ms)
    Rendered /spree/core/app/views/spree/home/index.html.erb within /spree/layouts/spree_application (36.6ms)
    Rendered /spree/core/app/views/spree/shared/_head.html.erb (1.6ms)
    Rendered /spree/core/app/views/spree/shared/_search.html.erb (2.1ms)
    Rendered /spree/core/app/views/spree/shared/_store_menu.html.erb (0.7ms)
    Rendered /spree/core/app/views/spree/shared/_nav_bar.html.erb (3.9ms)
    Rendered /spree/core/app/views/spree/shared/_google_analytics.html.erb (0.8ms)
    Completed 200 OK in 48ms (Views: 43.2ms | ActiveRecord: 2.2ms)
    Started GET "/" for 127.0.0.1 at Mon Jan 16 11:51:29 +0000 2012
    Processing by Spree::HomeController#index as */*
    Rendered /spree/core/app/views/spree/home/index.html.erb within /spree/layouts/spree_application (27.5ms)
    Completed 200 OK in 36ms (Views: 31.8ms | ActiveRecord: 1.8ms)

    View full-size slide

  177. 1
    2
    3
    4
    app/overrides/render_no_more.rb
    1
    2
    3
    views/spree/layouts/spree_application.html.erb

    <%= render :partial => 'spree/shared/head' %>

    Deface::Override.new(:virtual_path => 'spree/layouts/spree_application',
    :name => 'render_no_more',
    :replace => "code:contains('spree/shared/head')",
    :partial => 'spree/shared/head')
    https://gist.github.com/1345a8603b4c90e26540

    View full-size slide

  178. No Renders With Renders
    Avg (ms) 77.62 92.61
    Max (ms) 313.7 435.4
    Min (ms) 28.9 31.3
    Total (mins) 12.94 15.44

    View full-size slide

  179. $ rake deface:get_result[spree/shared/_store_menu]

    View full-size slide

  180. ---------------- Before ----------------
    <%= link_to t(:home), root_path %>
    <%= link_to_cart %>
    ---------------- Overrides (1)--------
    - 'remove_home_link' will be applied.
    ---------------- After ----------------
    <%= link_to_cart %>
    ---------------- Diff -----------------
    -<%= link_to t(:home), root_path %>
    <%= link_to_cart %>

    View full-size slide

  181. $ rake deface:test_selector[
    spree/shared/_store_menu, ‘li’]

    View full-size slide

  182. $ rake deface:test_selector[
    spree/shared/_store_menu, ‘li’]
    Querying 'spree/shared/_store_menu' for 'li'
    ---------------- Match 1 ----------------
    <%= link_to t(:home), root_path %>
    ---------------- Match 2 ----------------
    <%= link_to_cart %>

    View full-size slide

  183. Never Gonna’

    View full-size slide

  184. 1
    2
    3
    4
    app/overrides/never_gonna.rb
    Deface::Override.new(:virtual_path => "products/show",
    :name => "never_gonna",
    :set_attributes => "a",
    :attributes => {:href => "http://youtu.be/dQw4w9WgXcQ"})

    View full-size slide

  185. 1
    2
    3
    4
    app/overrides/never_gonna.rb
    Deface::Override.new(:virtual_path => "products/show",
    :name => "never_gonna",
    :set_attributes => "a",
    :attributes => {:href => "http://youtu.be/dQw4w9WgXcQ"})

    View full-size slide

  186. (the future)
    The future

    View full-size slide

  187. More actions!
    • :cut
    • :copy

    View full-size slide

  188. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :cut => "div#main-image",
    :insert_bottom => "div#thumbnails")

    View full-size slide

  189. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :cut => "div#main-image",
    :insert_bottom => "div#thumbnails")

    View full-size slide

  190. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'thumbnails', :product => @product %>

    <%= render 'image' %>



    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :cut => "div#main-image",
    :insert_bottom => "div#thumbnails")

    View full-size slide

  191. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :copy => "div#main-image",
    :insert_bottom => "div#thumbnails")

    View full-size slide

  192. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    app/views/spree/products/show.html.erb


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>


    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :copy => "div#main-image",
    :insert_bottom => "div#thumbnails")

    View full-size slide

  193. 1
    2
    3
    4
    app/overrides/tweak_thumbs.rb
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    app/views/spree/products/show.html.erb
    Deface::Override.new(:virtual_path => "spree/products/show",
    :name => "tweak_thumbs",
    :cut => "div#main-image",
    :insert_bottom => "div#thumbnails")


    <%= render 'image' %>


    <%= render 'thumbnails', :product => @product %>

    <%= render 'image' %>



    View full-size slide

  194. Exception
    on :original
    mismatch

    View full-size slide