fortitude 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.travis.yml +28 -22
  4. data/CHANGES.md +50 -0
  5. data/CONTRIBUTORS.md +1 -0
  6. data/doc/.gitignore +18 -0
  7. data/doc/Gemfile +21 -0
  8. data/doc/config.rb +92 -0
  9. data/doc/source/images/background.png +0 -0
  10. data/doc/source/images/middleman.png +0 -0
  11. data/doc/source/images/why/icon_button.png +0 -0
  12. data/doc/source/images/why/icon_button@2x.png +0 -0
  13. data/doc/source/images/why/modal_dialog@2x.png +0 -0
  14. data/doc/source/index.html.pcss +96 -0
  15. data/doc/source/index.html.rb +66 -0
  16. data/doc/source/javascripts/all.js +1 -0
  17. data/doc/source/javascripts/highlight.pack.js +1 -0
  18. data/doc/source/layouts/layout.rb +55 -0
  19. data/doc/source/portable/fortitude-bootstrap.rb +53 -0
  20. data/doc/source/shared/base.pcss +62 -0
  21. data/doc/source/shared/base.rb +30 -0
  22. data/doc/source/shared/common.rb +55 -0
  23. data/doc/source/shared/standard_page.rb +40 -0
  24. data/doc/source/stylesheets/_shared_prefix.scss +25 -0
  25. data/doc/source/stylesheets/all.css.scss +7 -0
  26. data/doc/source/stylesheets/basics.css.scss +20 -0
  27. data/doc/source/stylesheets/bootstrap_importer.css.scss +1 -0
  28. data/doc/source/stylesheets/highlight/arta.css +140 -0
  29. data/doc/source/stylesheets/highlight/ascetic.css +52 -0
  30. data/doc/source/stylesheets/highlight/atelier-dune.dark.css +95 -0
  31. data/doc/source/stylesheets/highlight/atelier-dune.light.css +95 -0
  32. data/doc/source/stylesheets/highlight/atelier-forest.dark.css +95 -0
  33. data/doc/source/stylesheets/highlight/atelier-forest.light.css +95 -0
  34. data/doc/source/stylesheets/highlight/atelier-heath.dark.css +95 -0
  35. data/doc/source/stylesheets/highlight/atelier-heath.light.css +95 -0
  36. data/doc/source/stylesheets/highlight/atelier-lakeside.dark.css +95 -0
  37. data/doc/source/stylesheets/highlight/atelier-lakeside.light.css +95 -0
  38. data/doc/source/stylesheets/highlight/atelier-seaside.dark.css +95 -0
  39. data/doc/source/stylesheets/highlight/atelier-seaside.light.css +95 -0
  40. data/doc/source/stylesheets/highlight/brown_paper.css +104 -0
  41. data/doc/source/stylesheets/highlight/brown_papersq.png +0 -0
  42. data/doc/source/stylesheets/highlight/codepen-embed.css +108 -0
  43. data/doc/source/stylesheets/highlight/color-brewer.css +168 -0
  44. data/doc/source/stylesheets/highlight/dark.css +104 -0
  45. data/doc/source/stylesheets/highlight/default.css +152 -0
  46. data/doc/source/stylesheets/highlight/docco.css +135 -0
  47. data/doc/source/stylesheets/highlight/far.css +111 -0
  48. data/doc/source/stylesheets/highlight/foundation.css +136 -0
  49. data/doc/source/stylesheets/highlight/github.css +124 -0
  50. data/doc/source/stylesheets/highlight/googlecode.css +147 -0
  51. data/doc/source/stylesheets/highlight/hybrid.css +170 -0
  52. data/doc/source/stylesheets/highlight/idea.css +125 -0
  53. data/doc/source/stylesheets/highlight/ir_black.css +109 -0
  54. data/doc/source/stylesheets/highlight/kimbie.dark.css +96 -0
  55. data/doc/source/stylesheets/highlight/kimbie.light.css +96 -0
  56. data/doc/source/stylesheets/highlight/magula.css +121 -0
  57. data/doc/source/stylesheets/highlight/mono-blue.css +69 -0
  58. data/doc/source/stylesheets/highlight/monokai.css +127 -0
  59. data/doc/source/stylesheets/highlight/monokai_sublime.css +154 -0
  60. data/doc/source/stylesheets/highlight/obsidian.css +153 -0
  61. data/doc/source/stylesheets/highlight/paraiso.dark.css +95 -0
  62. data/doc/source/stylesheets/highlight/paraiso.light.css +95 -0
  63. data/doc/source/stylesheets/highlight/pojoaque.css +107 -0
  64. data/doc/source/stylesheets/highlight/pojoaque.jpg +0 -0
  65. data/doc/source/stylesheets/highlight/railscasts.css +187 -0
  66. data/doc/source/stylesheets/highlight/rainbow.css +108 -0
  67. data/doc/source/stylesheets/highlight/school_book.css +112 -0
  68. data/doc/source/stylesheets/highlight/school_book.png +0 -0
  69. data/doc/source/stylesheets/highlight/solarized_dark.css +108 -0
  70. data/doc/source/stylesheets/highlight/solarized_light.css +108 -0
  71. data/doc/source/stylesheets/highlight/sunburst.css +164 -0
  72. data/doc/source/stylesheets/highlight/tomorrow-night-blue.css +95 -0
  73. data/doc/source/stylesheets/highlight/tomorrow-night-bright.css +94 -0
  74. data/doc/source/stylesheets/highlight/tomorrow-night-eighties.css +94 -0
  75. data/doc/source/stylesheets/highlight/tomorrow-night.css +95 -0
  76. data/doc/source/stylesheets/highlight/tomorrow.css +92 -0
  77. data/doc/source/stylesheets/highlight/vs.css +93 -0
  78. data/doc/source/stylesheets/highlight/xcode.css +158 -0
  79. data/doc/source/stylesheets/highlight/zenburn.css +118 -0
  80. data/doc/source/why/a_larger_view.html.rb +774 -0
  81. data/doc/source/why/a_simple_helper.html.rb +332 -0
  82. data/doc/source/why/building_a_rich_modal_dialog.html.rb +156 -0
  83. data/doc/source/why/commonality_and_inheritance.html.rb +564 -0
  84. data/doc/source/why/example_list.rb +60 -0
  85. data/doc/source/why/example_page.rb +116 -0
  86. data/doc/source/why/index.html.rb +86 -0
  87. data/doc/source/why/other_benefits.html.rb +110 -0
  88. data/fortitude.gemspec +6 -1
  89. data/lib/fortitude/doctypes/html4_tags_strict.rb +1 -0
  90. data/lib/fortitude/doctypes/html5.rb +1 -0
  91. data/lib/fortitude/method_templates/tag_method_template.rb.smpl +27 -14
  92. data/lib/fortitude/rails/helpers.rb +2 -2
  93. data/lib/fortitude/rendering_context.rb +10 -1
  94. data/lib/fortitude/tags/tag.rb +3 -2
  95. data/lib/fortitude/tags/tag_support.rb +8 -3
  96. data/lib/fortitude/tilt/fortitude_template.rb +6 -2
  97. data/lib/fortitude/version.rb +1 -1
  98. data/lib/fortitude/widget.rb +2 -0
  99. data/lib/fortitude/widget/convenience.rb +30 -0
  100. data/lib/fortitude/widget/files.rb +22 -11
  101. data/lib/fortitude/widget/needs.rb +5 -3
  102. data/spec/helpers/system_helpers.rb +1 -0
  103. data/spec/rails/development_mode_system_spec.rb +0 -1
  104. data/spec/rails/rendering_system_spec.rb +20 -1
  105. data/spec/rails/templates/rendering_system_spec/app/controllers/rendering_system_spec_controller.rb +13 -0
  106. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/render_hash_subclass.rb +18 -0
  107. data/spec/rails/templates/rendering_system_spec/lib/my_hash.rb +5 -0
  108. data/spec/system/convenience_methods_system_spec.rb +166 -0
  109. data/spec/system/formatting_system_spec.rb +25 -1
  110. data/spec/system/tag_rendering_system_spec.rb +73 -0
  111. data/spec/system/tilt_system_spec.rb +31 -0
  112. data/spec/system/widget_class_from_spec.rb +20 -4
  113. metadata +92 -4
@@ -0,0 +1,332 @@
1
+ require 'source/why/example_page'
2
+
3
+ module Views
4
+ module Why
5
+ class ASimpleHelper < Views::Why::ExamplePage
6
+ def example_intro
7
+ p %{Fortitude expresses your view code as Ruby itself, using a simple DSL patterned
8
+ after HTML. One big benefit of this approach is its consistency: views, helpers,
9
+ and partials are all written in the exact same language, Ruby.}
10
+
11
+ p %{Ruby is a great deal nicer to
12
+ work with than either an HTML templating language or the string interpolation of traditional
13
+ helper methods. We’ll see the difference this can make in the following example.}
14
+ end
15
+
16
+ def example_description
17
+ p %{The following ERb code was extracted from a real-world application, and is a great, simple
18
+ example of where Fortitude can help the most.}
19
+
20
+ erb <<-EOS
21
+ ...
22
+ <a href='<%= conditional_refresh_url(:user => @user) %>'
23
+ class="button icon refresh" onclick="javascript:handleRefreshClick();">
24
+ <div class="button_text">
25
+ <p>Refresh this page if:</p>
26
+ <ul>
27
+ <li>Content has changed</li>
28
+ <li>Local data is <%= @out_of_date_condition %></li>
29
+ </ul>
30
+ </div>
31
+ </a>
32
+ ...
33
+ EOS
34
+
35
+ p %{Combined with appropriate CSS, this code creates an “icon button” — a small icon, with a tooltip available:}
36
+
37
+ featured_image 'why/icon_button.png'
38
+
39
+ p {
40
+ text %{Unsurprisingly, this button gets used in }; em "many"; text %{ places throughout the application. }
41
+ text %{Using ERb, let’s see what we can do to factor out this common pattern.}
42
+ }
43
+ end
44
+
45
+ def using_standard_engines
46
+ refactoring_choices
47
+ using_a_helper
48
+ using_a_partial
49
+ end
50
+
51
+ def refactoring_choices
52
+ p %{Using traditional templating engines, we have two choices:}
53
+
54
+ ul {
55
+ li {
56
+ text "We can create a "; em "helper"; text ", which is written using Ruby string interpolation and called "
57
+ text "like a traditional Ruby method;"
58
+ }
59
+ li {
60
+ text "Or we can create a "; em "partial"; text ", which is written using our templating language of choice "
61
+ text "and called using "; code "render :partial => ..."; text "."
62
+ }
63
+ }
64
+
65
+ p %{In either case, we’ll need to make sure we allow for several variations in our desired output:}
66
+
67
+ ul {
68
+ li {
69
+ text "The URL (the "; code "href"; text " parameter) is, of course, different in almost every case."
70
+ }
71
+ li {
72
+ text %{Sometimes we need to add additional attributes }; em "(e.g."; text ", "; code "onclick"; text ", "
73
+ code "data-*"; text ", "; em "etc."; text ") to the "; code "a"; text " element, and sometimes not."
74
+ }
75
+ li {
76
+ text %{What’s inside the tooltip varies: it can be plain text or HTML, it can have variable substitutions —
77
+ really, it can be anything at all.}
78
+ }
79
+ }
80
+
81
+ p %{Given these constraints, let’s see how each of these looks.}
82
+ end
83
+
84
+ def using_a_helper
85
+ h5 "Using a Helper"
86
+
87
+ p %{Here’s what our new helper method looks like:}
88
+
89
+ ruby "application_helper.rb", <<-EOS
90
+ def icon_button(icon_name, target, tooltip_html, additional_attributes_string = "")
91
+ "<a href=\"\#{target}\" class="button icon \#{icon_name}" \#{additional_attributes_string}><div class="button_text">\#{tooltip_html}</div></a>"
92
+ end
93
+ EOS
94
+
95
+ p %{And here’s how we’d call it for the example above:}
96
+
97
+ erb <<-EOS
98
+ ...
99
+ <%= icon_button(:refresh, conditional_refresh_url(:user => @user), "<p>Refresh this page if:</p><ul><li>Content has changed</li><li>Local data is \#{h(@out_of_date_condition)}</li></ul>", "onclick=\"javascript:handleRefreshClick();\"")
100
+ EOS
101
+
102
+ p "What’s good and what’s bad about this?"
103
+
104
+ ul {
105
+ li {
106
+ strong "Concise"; text ": Both the caller and helper are quite short; but:"
107
+ }
108
+ li {
109
+ strong "Inconsistent"; text ": Suddenly, we’re forced to write both the helper method "; em "and"
110
+ text " the HTML for the interior of the button using Ruby string interpolation, rather than ERb — "
111
+ text "which leads to:"
112
+ }
113
+ li {
114
+ strong "Messy"; text ": We have significant stretches of HTML sitting around in Ruby strings, "
115
+ text "which is quite hard to read;"
116
+ }
117
+ li {
118
+ strong "Bad Formatting"; text ": Because of this, the generated HTML will be quite poorly formatted, "
119
+ text "with the HTML in those strings all run-together. But, most importantly:"
120
+ }
121
+ li {
122
+ strong { em "Dangerous (XSS Potential)" }; text ": We’re now responsible for worrying about HTML escaping "
123
+ text "in a way we weren’t before: "; em "every single caller"; text " needs to make sure that any user "
124
+ text "data in the "; code "additional_attributes_string"; text " is escaped "; em "before"; text " being "
125
+ text "passed. Similarly, we need to remember to call "; code "h()"; text " on the variable being "
126
+ text "interpolated into the "; code "tooltip_html"; text " string before passing it, or else we’ll be "
127
+ text "vulnerable to XSS attacks again."
128
+ }
129
+ }
130
+
131
+ p {
132
+ text "Yikes. We’ve factored out this helper method, which cleans up our calling code, but at a rather significant "
133
+ text "expense. Perhaps we can do better by creating an actual partial, instead?"
134
+ }
135
+ end
136
+
137
+ def using_a_partial
138
+ h5 "Using a Partial"
139
+
140
+ p %{Here’s what our new partial looks like:}
141
+
142
+ erb <<-EOS
143
+ <a href="<%= target %>" class="button icon <%= icon_name %>"
144
+ <%= (defined?(additional_attributes) ? additional_attributes || '') %>">
145
+ <div class="button_text">
146
+ <%= tooltip_html %>
147
+ </div>
148
+ </a>
149
+ EOS
150
+
151
+ p %{And here’s how we’d call it for the example above:}
152
+
153
+ erb <<-EOS
154
+ <%= render :partial => '/shared/buttons/icon_button', :locals => {
155
+ :target => conditional_refresh_url(:user => @user),
156
+ :icon_name => 'refresh',
157
+ :additional_attributes => 'onclick="javascript:handleRefreshClick();"'.html_safe,
158
+ :tooltip_html => %{<p>Refresh this page if:</p>
159
+ <ul>
160
+ <li>Content has changed</li>
161
+ <li>Local data is \#{h(@out_of_date_condition)}</li>
162
+ </ul>}.html_safe
163
+ } %>
164
+ EOS
165
+
166
+ p "Again, what’s good and what’s bad about this?"
167
+
168
+ ul {
169
+ li {
170
+ strong "Consistency/Inconsistency"; text ": on one hand, at least now the partial itself is expressed using "
171
+ code "ERb"; text ", not a Ruby string. On the other hand, we still have to use a Ruby string for the HTML we’re "
172
+ text "passing in to it."
173
+ }
174
+ li {
175
+ strong "Verbose and Messy"; text ": we’ve actually managed to create a caller that is 33% "
176
+ em "longer"; text " than the original code it replaced, and is actually quite a lot harder to read at "
177
+ text "first glance. (The helper method was a lot better here.)"
178
+ }
179
+ li {
180
+ strong "Formatting"; text ": the resulting HTML will at least look a lot better than in our earlier example;"
181
+ }
182
+ li {
183
+ strong "Method Signature"; text ": when reading the new "; code "_icon_button.html.erb"; text "partial, "
184
+ text "how can you easily tell which variables you need to pass in, and which of those are optional? "
185
+ em "You can’t"; text " — except by reading through the entire text of the partial and thinking about "
186
+ text "each use carefully, which is really painful. (In this, the helper method was certainly "
187
+ text "a lot cleaner, too.)"
188
+ }
189
+ li {
190
+ strong { em "Dangerous (XSS Potential)" }; text ": Once again, we’re now responsible for worrying about "
191
+ text "HTML escaping in a way we weren’t before: "; em "every single caller"; text " needs to make sure that "
192
+ text "any user data in the "; code "tooltip_html"; text " string is correctly escaped using "; code "h()"
193
+ text " before being passed in. (We also need to make sure we call "; code "#html_safe"; text " on the "
194
+ text "value we pass to "; code "additional_attributes"; text ", too; this is less dangerous, but also very "
195
+ text "easy to forget, and will cause corrupt HTML if we forget about it.)"
196
+ }
197
+ }
198
+ end
199
+
200
+ def standard_engine_issues
201
+ p {
202
+ text "Both cases above are far from perfect. Helper methods are more succinct to call, yet also a lot "
203
+ text "messier to both write and call when passing around HTML, and have serious XSS risks. Partials mitigate "
204
+ text "some of those problems, but introduce others, and are "; em "really"; text " verbose and messy to call."
205
+ }
206
+
207
+ p {
208
+ text "Ironically, some of the issues above may feel a little unfamiliar, and it’s probably because of this: "
209
+ em "nobody does this"; text " — because both these approaches have such serious tradeoffs, most teams, "
210
+ text "developers, or designers just leave well enough alone for small(ish) examples like this, and "
211
+ text "repeat the original HTML everywhere, over "
212
+ text "and over. And when it comes time to change the "
213
+ text "HTML structure of this “icon button” element that’s been repeated all over the site, we either just "
214
+ text "bite the bullet and do a really painful global search and repeated manual modificaftion, or give up, "
215
+ text "hack on CSS to make it do sort of what we want it to do, and then leave "; em "that"
216
+ text " mess in place."
217
+ }
218
+
219
+ p {
220
+ text "We imagine that this is "; em "just the way views are"; text ". "
221
+ text "In fact, these problems are all because we generally don’t have the right tools to do a better job. "
222
+ text "Views don’t need to be like this, any more than "; em "any"; text " code needs to be like this."
223
+ }
224
+ end
225
+
226
+ def using_fortitude
227
+ p %{To see what Fortitude brings to this example, let’s start by looking at Fortitude code for the original
228
+ example, before we try to refactor it:}
229
+
230
+ fortitude <<-EOS
231
+ ...
232
+ a(:href => conditional_refresh_url(:user => @user),
233
+ :class => 'button icon refresh') {
234
+ div(:class => 'button_text') {
235
+ p "Refresh this page if:"
236
+ ul {
237
+ li "Content has changed"
238
+ li "Local data is \#{@out_of_date_condition}"
239
+ }
240
+ }
241
+ }
242
+ ...
243
+ EOS
244
+
245
+ p {
246
+ text %{We won’t delve more deeply into Fortitude’s syntax immediately, but it should be clear that
247
+ Fortitude expresses HTML using a very simple Ruby DSL that’s easy to grasp.}
248
+ }
249
+
250
+ p {
251
+ text %{Using this syntax, we can now factor out this shared code as a “helper method” that
252
+ we can easily make available on any view that needs it.}
253
+ }
254
+
255
+ p {
256
+ text "(We put “helper method” in quotes because "
257
+ text "this isn’t a traditional helper that we’d put into something like "
258
+ code "app/helpers/application_helper.rb"; text " and write using Ruby string interpolation. Rather, it’s a "
259
+ text "method we define in a module, and mix into any view class that needs it — Fortitude views are actually "
260
+ text "just normal Ruby classes — or into our base view class to make it magically available everywhere.)"
261
+ }
262
+
263
+ p {
264
+ text "Using this strategy, we can create the following “helper method”:"
265
+ }
266
+
267
+ fortitude <<-EOS
268
+ def icon_button(icon_name, target, additional_attributes = { })
269
+ a(additional_attributes.merge(
270
+ :href => target, :class => "button icon \#{icon_name}")) {
271
+ div(:class => :button_text) {
272
+ yield
273
+ }
274
+ }
275
+ end
276
+ EOS
277
+
278
+ p "And the calling code for the example above now looks like this:"
279
+
280
+ fortitude <<-EOS
281
+ ...
282
+ icon_button('refresh', conditional_refresh_url(:user => @user),
283
+ :onclick => 'javascript:handleRefreshClick();') {
284
+ p "Refresh this page if:"
285
+ ul {
286
+ li "Content has changed"
287
+ li "Local data is \#{@out_of_date_condition}"
288
+ }
289
+ }
290
+ ...
291
+ EOS
292
+ end
293
+
294
+ def fortitude_benefits
295
+ p %{Let’s take a look at how much cleaner this is. A few of the most obvious improvements:}
296
+
297
+ ul {
298
+ li {
299
+ strong "Concise"; text %{: The calling code is now actually both much }; em "shorter"; text " and "
300
+ em "more expressive"; text " than the code it replaced."
301
+ }
302
+ li {
303
+ strong "Consistent"; text ": both the new “helper method” and its caller are written in the same "
304
+ text "language — which is the same language you use for all Fortitude code and the entire rest of your "
305
+ text "application, Ruby."
306
+ }
307
+ li {
308
+ strong "Well-Formatted"; text ": Because Fortitude is not interpolating strings, but, rather, understands the "
309
+ text "structure of the HTML, all output is perfectly formatted. (In development, it’s indented correctly, "
310
+ text "no matter how the code is written; in production, it is automatically produced with minimal spacing, "
311
+ text "to reduce the size of the HTML transmitted across the network.)"
312
+ }
313
+ li {
314
+ strong "Clean and Clear"; text ": Because it’s a Ruby method, any Ruby programmer will instantly understand "
315
+ text "what needs to be passed to it; because all of the code is Ruby, it all reads cleanly and clearly."
316
+ }
317
+ li {
318
+ strong { em "Safe" }; text ": at no point does any caller, nor the method itself, need to worry about HTML "
319
+ text "escaping; all data will be escaped properly without worrying about it."
320
+ }
321
+ }
322
+
323
+ p {
324
+ text "However, one of the biggest improvements we’ve made is slightly more subtle: by creating this new "
325
+ code "icon_button"; text " method, we’ve started slowly building up a "; em "customized view language"
326
+ text " that is specific to our needs and our application. As we proceed through further examples, we’ll see "
327
+ text "how powerful this can be in creating clean, concise, maintainable views that are a joy to use."
328
+ }
329
+ end
330
+ end
331
+ end
332
+ end
@@ -0,0 +1,156 @@
1
+ require 'source/why/example_page'
2
+
3
+ module Views
4
+ module Why
5
+ class BuildingARichModalDialog < Views::Why::ExamplePage
6
+ def example_intro
7
+ p {
8
+ text "In our last example, we saw how using inheritance lets you easily solve view-factoring problems "
9
+ text "with Fortitude that remain painful in traditional templating engines. In this example, we’ll see "
10
+ text "how Fortitude’s widget classes let us create specialized contexts for rendering views that are "
11
+ text "very powerful. In effect, they become little mini-languages, introducing view primitives exactly "
12
+ text "when you need them and providing an elegant language for you to describe what your view should "
13
+ text "look like."
14
+ }
15
+ end
16
+
17
+ def example_description
18
+ p {
19
+ text "Almost everybody knows the concept of a "; em "modal dialog"; text " — a “layer” of HTML that "
20
+ text "requests some kind of input or confirmation from the user before proceeding, and which obscures "
21
+ text "the rest of the web page so that the user is forced to provide this input or confirmation before "
22
+ text "proceeding. They’re often also known as a "; em "lightbox"; text ", "; em "modal window"; text ", or "
23
+ em "heavy window"; text ", and have become a staple of modern Web design."
24
+ }
25
+
26
+ p {
27
+ text "Here’s an example of a modal dialog that appears in Google Docs when you choose “Make a Copy”: "
28
+ }
29
+
30
+ featured_image 'why/modal_dialog.png'
31
+
32
+ p {
33
+ text "This simple example has a number of features that modal dialogs tend to share:"
34
+ }
35
+
36
+ ul {
37
+ li "A clear border, often with a drop shadow, around the entire dialog."
38
+ li "A large layer that dims or otherwise obscures the rest of the page behind the dialog."
39
+ li "Some kind of “close” or “dismiss” control, often in the upper-right-hand corner."
40
+ li "A title of some kind at the top — sometimes styled, sometimes not."
41
+ li "Primary content, which can be more-or-less arbitraily complex."
42
+ li "At the bottom, at least one button (“OK”), and often more than one."
43
+ }
44
+
45
+ p {
46
+ text "These simple dialogs present an interesting challenge for view builders. Even the frame of the dialog "
47
+ text "will consist of multiple elements (usually "; code "div"; text "s), with some important CSS classes "
48
+ text "applied. There will be a standard way of creating tht title, and likely a container that the primary "
49
+ text "content needs to go into. The buttons at the bottom will typically have their own container and styles, "
50
+ text "and standard ways of rendering them."
51
+ }
52
+
53
+ p {
54
+ text "Let’s look at an example modal dialog in completely non-refactored (one-off) HTML:"
55
+ }
56
+
57
+ erb 'app/views/docs/copy_document.html.erb', <<-EOS
58
+ <div class="modal-background">
59
+ <div class="modal-dialog">
60
+ <div class="window-controls"><span class="dialog-control">X</span></div>
61
+ <div class="modal-title">
62
+ <h3>Copy document</h3>
63
+ </div>
64
+
65
+ <div class="modal-contents">
66
+ <form class="modal-form">
67
+ <label for="document_name">Enter a new document name:</label>
68
+ <input type="text" name="document_name">Copy of Untitled document</input>
69
+ <span class="form-input-footnote">Comments will not be copied to the new document.</span>
70
+
71
+ <input type="checkbox" name="copy_sharing"></input>
72
+ <label for="copy_sharing">Share it with the same people</label>
73
+ </form>
74
+ </div>
75
+
76
+ <div class="modal-actions">
77
+ <button name="OK" value="ok" class="modal-button">OK</button>
78
+ <button name="Cancel" value="cancel" class="modal-button">Cancel</button>
79
+ </div>
80
+ </div>
81
+ </div>
82
+ EOS
83
+ end
84
+
85
+ def using_standard_engines
86
+ p {
87
+ text "Using traditional templating engines, what’s the best we can do with this? In many ways, it’s similar "
88
+ text "to our previous example: we can either use partials/helpers for shared structural elements and count "
89
+ text "on calling them in the right order, or use "; code "capture"; text " to construct blocks of HTML and "
90
+ text "pass them into a shared view."
91
+ }
92
+
93
+ p {
94
+ text "One of the big differences here is that the chunks of HTML we pass in themselves need certain "
95
+ text "predefined structure. For example, the modal title may need to be in a certain format (at least most "
96
+ text "of the time), and the set of buttons at the bottom may need certain classes, and so on."
97
+ }
98
+
99
+ p {
100
+ text "Without further ado, let’s see what the end result looks like:"
101
+ }
102
+
103
+
104
+ erb 'app/views/docs/copy_document.html.erb', <<-EOS
105
+ <% the_modal_title = capture do %>
106
+ <%= modal_title("Copy document") %>
107
+ <% end %>
108
+
109
+ <% the_modal_contents = capture do %>
110
+ <%= modal_form do %>
111
+ <label for="document_name">Enter a new document name:</label>
112
+ <input type="text" name="document_name">Copy of Untitled document</input>
113
+ <span class="form-input-footnote">Comments will not be copied to the new document.</span>
114
+
115
+ <input type="checkbox" name="copy_sharing"></input>
116
+ <label for="copy_sharing">Share it with the same people</label>
117
+ <% end %>
118
+ <% end %>
119
+ <div class="modal-title">
120
+ <h3 class="modal-title">Copy document</h3>
121
+ </div>
122
+
123
+ <div class="modal-contents">
124
+ <form class="modal-form">
125
+ <label for="document_name">Enter a new document name:</label>
126
+ <input type="text" name="document_name">Copy of Untitled document</input>
127
+ <span class="form-input-footnote">Comments will not be copied to the new document.</span>
128
+
129
+ <input type="checkbox" name="copy_sharing"></input>
130
+ <label for="copy_sharing">Share it with the same people</label>
131
+ </form>
132
+ </div>
133
+
134
+ <div class="modal-actions">
135
+ <button name="OK" value="ok" class="modal-button">OK</button>
136
+ <button name="Cancel" value="cancel" class="modal-button">Cancel</button>
137
+ </div>
138
+ </div>
139
+ </div>
140
+ EOS
141
+ end
142
+
143
+ def standard_engine_issues
144
+
145
+ end
146
+
147
+ def using_fortitude
148
+
149
+ end
150
+
151
+ def fortitude_benefits
152
+
153
+ end
154
+ end
155
+ end
156
+ end