tennpipes-helper 3.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.rdoc +239 -0
  4. data/Rakefile +1 -0
  5. data/lib/tennpipes-helper.rb +62 -0
  6. data/lib/tennpipes-helper/asset_tag_helpers.rb +394 -0
  7. data/lib/tennpipes-helper/form_builder/abstract_form_builder.rb +279 -0
  8. data/lib/tennpipes-helper/form_builder/standard_form_builder.rb +40 -0
  9. data/lib/tennpipes-helper/form_helpers.rb +639 -0
  10. data/lib/tennpipes-helper/form_helpers/errors.rb +138 -0
  11. data/lib/tennpipes-helper/form_helpers/options.rb +98 -0
  12. data/lib/tennpipes-helper/form_helpers/security.rb +70 -0
  13. data/lib/tennpipes-helper/format_helpers.rb +372 -0
  14. data/lib/tennpipes-helper/locale/cs.yml +103 -0
  15. data/lib/tennpipes-helper/locale/da.yml +91 -0
  16. data/lib/tennpipes-helper/locale/de.yml +81 -0
  17. data/lib/tennpipes-helper/locale/en.yml +103 -0
  18. data/lib/tennpipes-helper/locale/es.yml +103 -0
  19. data/lib/tennpipes-helper/locale/fr.yml +79 -0
  20. data/lib/tennpipes-helper/locale/hu.yml +103 -0
  21. data/lib/tennpipes-helper/locale/it.yml +89 -0
  22. data/lib/tennpipes-helper/locale/ja.yml +103 -0
  23. data/lib/tennpipes-helper/locale/lv.yml +103 -0
  24. data/lib/tennpipes-helper/locale/nl.yml +82 -0
  25. data/lib/tennpipes-helper/locale/no.yml +91 -0
  26. data/lib/tennpipes-helper/locale/pl.yml +95 -0
  27. data/lib/tennpipes-helper/locale/pt_br.yml +103 -0
  28. data/lib/tennpipes-helper/locale/ro.yml +103 -0
  29. data/lib/tennpipes-helper/locale/ru.yml +103 -0
  30. data/lib/tennpipes-helper/locale/sv.yml +103 -0
  31. data/lib/tennpipes-helper/locale/tr.yml +103 -0
  32. data/lib/tennpipes-helper/locale/uk.yml +103 -0
  33. data/lib/tennpipes-helper/locale/zh_cn.yml +103 -0
  34. data/lib/tennpipes-helper/locale/zh_tw.yml +103 -0
  35. data/lib/tennpipes-helper/number_helpers.rb +283 -0
  36. data/lib/tennpipes-helper/output_helpers.rb +226 -0
  37. data/lib/tennpipes-helper/output_helpers/abstract_handler.rb +61 -0
  38. data/lib/tennpipes-helper/output_helpers/erb_handler.rb +27 -0
  39. data/lib/tennpipes-helper/output_helpers/haml_handler.rb +25 -0
  40. data/lib/tennpipes-helper/output_helpers/slim_handler.rb +18 -0
  41. data/lib/tennpipes-helper/render_helpers.rb +63 -0
  42. data/lib/tennpipes-helper/tag_helpers.rb +294 -0
  43. data/lib/tennpipes-helper/translation_helpers.rb +36 -0
  44. data/lib/tennpipes/rendering.rb +369 -0
  45. data/lib/tennpipes/rendering/erb_template.rb +40 -0
  46. data/lib/tennpipes/rendering/erubis_template.rb +66 -0
  47. data/lib/tennpipes/rendering/haml_template.rb +26 -0
  48. data/lib/tennpipes/rendering/slim_template.rb +20 -0
  49. data/test/fixtures/apps/render.rb +25 -0
  50. data/test/fixtures/apps/views/article/comment/show.slim +1 -0
  51. data/test/fixtures/apps/views/blog/post.erb +1 -0
  52. data/test/fixtures/apps/views/layouts/specific.erb +1 -0
  53. data/test/fixtures/apps/views/test/post.erb +1 -0
  54. data/test/fixtures/layouts/layout.erb +1 -0
  55. data/test/fixtures/markup_app/app.rb +87 -0
  56. data/test/fixtures/markup_app/views/button_to.erb +8 -0
  57. data/test/fixtures/markup_app/views/button_to.haml +5 -0
  58. data/test/fixtures/markup_app/views/button_to.slim +6 -0
  59. data/test/fixtures/markup_app/views/capture_concat.erb +14 -0
  60. data/test/fixtures/markup_app/views/capture_concat.haml +12 -0
  61. data/test/fixtures/markup_app/views/capture_concat.slim +12 -0
  62. data/test/fixtures/markup_app/views/content_for.erb +23 -0
  63. data/test/fixtures/markup_app/views/content_for.haml +19 -0
  64. data/test/fixtures/markup_app/views/content_for.slim +19 -0
  65. data/test/fixtures/markup_app/views/content_tag.erb +13 -0
  66. data/test/fixtures/markup_app/views/content_tag.haml +11 -0
  67. data/test/fixtures/markup_app/views/content_tag.slim +11 -0
  68. data/test/fixtures/markup_app/views/current_engine.erb +5 -0
  69. data/test/fixtures/markup_app/views/current_engine.haml +5 -0
  70. data/test/fixtures/markup_app/views/current_engine.slim +5 -0
  71. data/test/fixtures/markup_app/views/fields_for.erb +20 -0
  72. data/test/fixtures/markup_app/views/fields_for.haml +15 -0
  73. data/test/fixtures/markup_app/views/fields_for.slim +15 -0
  74. data/test/fixtures/markup_app/views/form_for.erb +72 -0
  75. data/test/fixtures/markup_app/views/form_for.haml +59 -0
  76. data/test/fixtures/markup_app/views/form_for.slim +59 -0
  77. data/test/fixtures/markup_app/views/form_tag.erb +95 -0
  78. data/test/fixtures/markup_app/views/form_tag.haml +78 -0
  79. data/test/fixtures/markup_app/views/form_tag.slim +79 -0
  80. data/test/fixtures/markup_app/views/link_to.erb +5 -0
  81. data/test/fixtures/markup_app/views/link_to.haml +4 -0
  82. data/test/fixtures/markup_app/views/link_to.slim +4 -0
  83. data/test/fixtures/markup_app/views/mail_to.erb +3 -0
  84. data/test/fixtures/markup_app/views/mail_to.haml +3 -0
  85. data/test/fixtures/markup_app/views/mail_to.slim +3 -0
  86. data/test/fixtures/markup_app/views/meta_tag.erb +3 -0
  87. data/test/fixtures/markup_app/views/meta_tag.haml +3 -0
  88. data/test/fixtures/markup_app/views/meta_tag.slim +3 -0
  89. data/test/fixtures/markup_app/views/partials/_erb.erb +1 -0
  90. data/test/fixtures/markup_app/views/partials/_haml.haml +1 -0
  91. data/test/fixtures/markup_app/views/partials/_slim.slim +1 -0
  92. data/test/fixtures/markup_app/views/simple_partial.erb +1 -0
  93. data/test/fixtures/markup_app/views/simple_partial.haml +1 -0
  94. data/test/fixtures/markup_app/views/simple_partial.slim +1 -0
  95. data/test/fixtures/render_app/app.rb +110 -0
  96. data/test/fixtures/render_app/views/_deep.erb +3 -0
  97. data/test/fixtures/render_app/views/_deep.haml +2 -0
  98. data/test/fixtures/render_app/views/_deep.slim +2 -0
  99. data/test/fixtures/render_app/views/_partial_block_erb.erb +10 -0
  100. data/test/fixtures/render_app/views/_partial_block_haml.haml +7 -0
  101. data/test/fixtures/render_app/views/_partial_block_slim.slim +7 -0
  102. data/test/fixtures/render_app/views/_unsafe.html.builder +2 -0
  103. data/test/fixtures/render_app/views/_unsafe_object.html.builder +2 -0
  104. data/test/fixtures/render_app/views/current_engine.haml +5 -0
  105. data/test/fixtures/render_app/views/current_engines/_erb.erb +1 -0
  106. data/test/fixtures/render_app/views/current_engines/_haml.haml +1 -0
  107. data/test/fixtures/render_app/views/current_engines/_slim.slim +1 -0
  108. data/test/fixtures/render_app/views/dive_inner_erb.erb +3 -0
  109. data/test/fixtures/render_app/views/dive_inner_haml.haml +2 -0
  110. data/test/fixtures/render_app/views/dive_inner_slim.slim +2 -0
  111. data/test/fixtures/render_app/views/dive_outer_erb.erb +3 -0
  112. data/test/fixtures/render_app/views/dive_outer_haml.haml +2 -0
  113. data/test/fixtures/render_app/views/dive_outer_slim.slim +2 -0
  114. data/test/fixtures/render_app/views/double_capture_erb.erb +3 -0
  115. data/test/fixtures/render_app/views/double_capture_haml.haml +2 -0
  116. data/test/fixtures/render_app/views/double_capture_slim.slim +2 -0
  117. data/test/fixtures/render_app/views/erb/test.erb +1 -0
  118. data/test/fixtures/render_app/views/explicit_engine.haml +5 -0
  119. data/test/fixtures/render_app/views/haml/test.haml +1 -0
  120. data/test/fixtures/render_app/views/render_block_erb.erb +5 -0
  121. data/test/fixtures/render_app/views/render_block_haml.haml +4 -0
  122. data/test/fixtures/render_app/views/render_block_slim.slim +4 -0
  123. data/test/fixtures/render_app/views/ruby_block_capture_erb.erb +1 -0
  124. data/test/fixtures/render_app/views/ruby_block_capture_haml.haml +1 -0
  125. data/test/fixtures/render_app/views/ruby_block_capture_slim.slim +1 -0
  126. data/test/fixtures/render_app/views/template/_user.haml +7 -0
  127. data/test/fixtures/render_app/views/template/haml_template.haml +1 -0
  128. data/test/fixtures/render_app/views/template/some_template.haml +2 -0
  129. data/test/fixtures/render_app/views/wrong_capture_erb.erb +3 -0
  130. data/test/fixtures/render_app/views/wrong_capture_haml.haml +2 -0
  131. data/test/fixtures/render_app/views/wrong_capture_slim.slim +2 -0
  132. data/test/helper.rb +88 -0
  133. data/test/test_asset_tag_helpers.rb +401 -0
  134. data/test/test_form_builder.rb +1216 -0
  135. data/test/test_form_helpers.rb +1056 -0
  136. data/test/test_format_helpers.rb +251 -0
  137. data/test/test_helpers.rb +10 -0
  138. data/test/test_locale.rb +20 -0
  139. data/test/test_number_helpers.rb +142 -0
  140. data/test/test_output_helpers.rb +157 -0
  141. data/test/test_render_helpers.rb +225 -0
  142. data/test/test_rendering.rb +706 -0
  143. data/test/test_rendering_extensions.rb +14 -0
  144. data/test/test_tag_helpers.rb +131 -0
  145. metadata +299 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 075ac7ae20c2d50474386971a390201859b847b0
4
+ data.tar.gz: 3f8f93db0c3dddd6ccd71935b2680f82ff03f3a6
5
+ SHA512:
6
+ metadata.gz: fc330fdc29804f9e90567e780a596886498f5ced2a161e3fc4b0cbac3247953bee3b5b0657d26a7f37cc2c86d0b4d2278f476275b32f129a6cf4ee5c3cef3542
7
+ data.tar.gz: efeb79da4049d5133d9c726ed5ce480e1d675fdee6976a6cc43054d743a986cb427f8938941341f0fbfcff77fe630380d9220244c4af8de42e3159c405a9c706
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Tennpipes
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,239 @@
1
+ = Application Extensions and Helpers (tennpipes-helper)
2
+
3
+ === Overview
4
+
5
+ This component provides a great deal of view helpers related to html markup generation.
6
+ There are helpers for generating tags, forms, links, images, and more. Most of the basic
7
+ methods should be very familiar to anyone who has used rails view helpers.
8
+
9
+ === Output Helpers
10
+
11
+ Output helpers are a collection of important methods for managing, capturing and displaying output
12
+ in various ways and is used frequently to support higher-level helper functions. There are
13
+ three output helpers worth mentioning: <tt>content_for</tt>, <tt>capture_html</tt>, and <tt>concat_content</tt>
14
+
15
+ The content_for functionality supports capturing content and then rendering this into a different place
16
+ such as within a layout. One such popular example is including assets onto the layout from a template:
17
+
18
+ # app/views/site/index.erb
19
+ ...
20
+ <% content_for :assets do %>
21
+ <%= stylesheet_link_tag 'index', 'custom' %>
22
+ <% end %>
23
+ ...
24
+
25
+ Added to a template, this will capture the includes from the block and allow them to be yielded into the layout:
26
+
27
+ # app/views/layout.erb
28
+ ...
29
+ <head>
30
+ <title>Example</title>
31
+ <%= stylesheet_link_tag 'style' %>
32
+ <%= yield_content :assets %>
33
+ </head>
34
+ ...
35
+
36
+ This will automatically insert the contents of the block (in this case a stylesheet include) into the
37
+ location the content is yielded within the layout. You can also check if content exists for a block using
38
+ <tt>content_for?(true)</tt> which returns true if content exists.
39
+
40
+ The capture_html and the concat_content methods allow content to be manipulated and stored for use in building
41
+ additional helpers accepting blocks or displaying information in a template. One example is the use of
42
+ these in constructing a simplified 'form_tag' helper which accepts a block.
43
+
44
+ # form_tag '/register' do ... end
45
+ def form_tag(url, options={}, &block)
46
+ # ... truncated ...
47
+ inner_form_html = capture_html(&block)
48
+ concat_content '<form>' + inner_form_html + '</form>'
49
+ end
50
+
51
+ This will capture the template body passed into the form_tag block and then append the content
52
+ to the template through the use of <tt>concat_content</tt>. Note have been built to work for both haml and erb
53
+ templates using the same syntax.
54
+
55
+ For more information on using output helpers, check out the guide for
56
+ {Tennpipes Helpers}[http://www.tennpipesrb.com/guides/application-helpers].
57
+
58
+ === Tag Helpers
59
+
60
+ Tag helpers are the basic building blocks used to construct html 'tags' within a view template. There
61
+ are three major functions for this category: <tt>tag</tt>, <tt>content_tag</tt> and <tt>input_tag</tt>.
62
+
63
+ The tag and content_tag are for building arbitrary html tags with a name and specified options. If
64
+ the tag contains 'content' within then <tt>content_tag</tt> is used. For example:
65
+
66
+ tag(:br, :style => 'clear:both') => <br style="clear:both" />
67
+ content_tag(:p, "demo", :class => 'light') => <p class="light">demo</p>
68
+
69
+ The input_tag is used to build tags that are related to accepting input from the user:
70
+
71
+ input_tag :text, :class => "demo" => <input type='text' class='demo' />
72
+ input_tag :password, :value => "secret", :class => "demo"
73
+
74
+ Note that all of these accept html options and result in returning a string containing html tags.
75
+
76
+ For more information on using tag helpers, check out the guide for
77
+ {Tennpipes Helpers}[http://www.tennpipesrb.com/guides/application-helpers].
78
+
79
+ === Asset Helpers
80
+
81
+ Asset helpers are intended to help insert useful html onto a view template such as 'flash' notices,
82
+ hyperlinks, mail_to links, images, stylesheets and javascript. An example of their uses would be on a
83
+ simple view template:
84
+
85
+ # app/views/example.haml
86
+ ...
87
+ %head
88
+ = stylesheet_link_tag 'layout'
89
+ = javascript_include_tag 'application'
90
+ %body
91
+ ...
92
+ = flash_tag :notice
93
+ %p= link_to 'Blog', '/blog', :class => 'example'
94
+ %p Mail me at #{mail_to 'fake@faker.com', "Fake Email Link", :cc => "test@demo.com"}
95
+ %p= image_tag 'tennpipes.png', :width => '35', :class => 'logo'
96
+
97
+ For more information on using asset helpers, check out the guide for
98
+ {Tennpipes Helpers}[http://www.tennpipesrb.com/guides/application-helpers].
99
+
100
+ === Form Helpers
101
+
102
+ Form helpers are the 'standard' form tag helpers you would come to expect when building forms. A simple
103
+ example of constructing a non-object form would be:
104
+
105
+ = form_tag '/destroy', :class => 'destroy-form', :method => 'delete' do
106
+ = flash_tag(:notice)
107
+ = field_set_tag do
108
+ %p
109
+ = label_tag :username, :class => 'first'
110
+ = text_field_tag :username, :value => params[:username]
111
+ %p
112
+ = label_tag :password, :class => 'first'
113
+ = password_field_tag :password, :value => params[:password]
114
+ %p
115
+ = label_tag :strategy
116
+ = select_tag :strategy, :options => ['delete', 'destroy'], :selected => 'delete'
117
+ %p
118
+ = check_box_tag :confirm_delete
119
+ = field_set_tag(:class => 'buttons') do
120
+ = submit_tag "Remove"
121
+
122
+ For more information on using form helpers, check out the guide for
123
+ {Tennpipes Helpers}[http://www.tennpipesrb.com/guides/application-helpers].
124
+
125
+ === FormBuilders
126
+
127
+ Form builders are full-featured objects allowing the construction of complex object-based forms
128
+ using a simple, intuitive syntax.
129
+
130
+ A form_for using these basic fields might look like:
131
+
132
+ = form_for @user, '/register', :id => 'register' do |f|
133
+ = f.error_messages
134
+ %p
135
+ = f.label :username, :caption => "Nickname"
136
+ = f.text_field :username
137
+ %p
138
+ = f.label :email
139
+ = f.text_field :email
140
+ %p
141
+ = f.label :password
142
+ = f.password_field :password
143
+ %p
144
+ = f.label :is_admin, :caption => "Admin User?"
145
+ = f.check_box :is_admin
146
+ %p
147
+ = f.label :color, :caption => "Favorite Color?"
148
+ = f.select :color, :options => ['red', 'black']
149
+ %p
150
+ = fields_for @user.location do |location|
151
+ = location.text_field :street
152
+ = location.text_field :city
153
+ %p
154
+ = f.submit "Create", :class => 'button'
155
+
156
+ Forms can also accept nested attributes using `fields_for` within the form builder in recent releases. Check out the guide for {Tennpipes Helpers}[http://www.tennpipesrb.com/guides/application-helpers] to learn more about nested forms.
157
+
158
+ There is also an additional StandardFormBuilder which builds on the abstract fields that can be used within a form_for.
159
+
160
+ A form_for using these standard fields might be:
161
+
162
+ = form_for @user, '/register', :id => 'register' do |f|
163
+ = f.error_messages
164
+ = f.text_field_block :name, :caption => "Full name"
165
+ = f.text_field_block :email
166
+ = f.check_box_block :remember_me
167
+ = f.select_block :fav_color, :options => ['red', 'blue']
168
+ = f.password_field_block :password
169
+ = f.submit_block "Create", :class => 'button'
170
+
171
+ and would generate this html (with each input contained in a paragraph and containing a label):
172
+
173
+ <form id="register" action="/register" method="post">
174
+ <p><label for="user_name">Full name: </label><input type="text" id="user_name" name="user[name]"></p>
175
+ ...omitted...
176
+ <p><input type="submit" value="Create" class="button"></p>
177
+ </form>
178
+
179
+ You can also easily build your own FormBuilder which allows for customized fields and behavior.
180
+
181
+ For more information on using the Tennpipes form builders, check out the guide for
182
+ {Tennpipes Helpers}[http://www.tennpipesrb.com/guides/application-helpers].
183
+
184
+ === Format Helpers
185
+
186
+ Format helpers are several useful utilities for manipulating the format of text to achieve a goal.
187
+ The four format helpers are <tt>escape_html</tt>, <tt>time_ago_in_words</tt>, and <tt>js_escape_html</tt>.
188
+
189
+ The escape_html and js_escape_html function are for taking an html string and escaping certain characters.
190
+ <tt>escape_html</tt> will escape ampersands, brackets and quotes to their HTML/XML entities. This is useful
191
+ to sanitize user content before displaying this on a template. <tt>js_escape_html</tt> is used for
192
+ passing javascript information from a js template to a javascript function.
193
+
194
+ escape_html('<hello>&<goodbye>') # => &lt;hello&gt;&amp;&lt;goodbye&gt;
195
+
196
+ There is also an alias for escape_html called <tt>h</tt> for even easier usage within templates.
197
+
198
+ Format helpers also includes a number of useful text manipulation functions such as <tt>simple_format</tt>,
199
+ <tt>pluralize</tt>, <tt>word_wrap</tt>, <tt>truncate</tt> and <tt>truncate_words</tt>.
200
+
201
+ simple_format("hello\nworld") # => "<p>hello<br/>world</p>"
202
+ pluralize(2, 'person') => '2 people'
203
+ word_wrap('Once upon a time', :line_width => 8) => "Once upon\na time"
204
+ truncate("Once upon a time in a world far far away", :length => 8) => "Once upon..."
205
+ truncate_words("Once upon a time in a world far far away", :length => 4) => "Once upon a time..."
206
+
207
+ These helpers can be invoked from any route or view within your application.
208
+
209
+ For more information on using the format helpers, check out the guide for
210
+ {Tennpipes Helpers}[http://www.tennpipesrb.com/guides/application-helpers].
211
+
212
+ === Render Helpers
213
+
214
+ This component provides a number of rendering helpers making the process of displaying templates a bit easier.
215
+ This plugin also has support for useful additions such as partials (with support for :collection) for the templating system.
216
+
217
+ Using render plugin helpers is extremely simple. If you want to render an erb template in your view path:
218
+
219
+ render :erb, 'path/to/erb/template'
220
+
221
+ or using haml templates works just as well:
222
+
223
+ render :haml, 'path/to/haml/template'
224
+
225
+ There is also a method which renders the first view matching the path and removes the need to define an engine:
226
+
227
+ render 'path/to/any/template'
228
+
229
+ Finally, we have the all-important partials support for rendering mini-templates onto a page:
230
+
231
+ partial 'photo/_item', :object => @photo, :locals => { :foo => 'bar' }
232
+ partial 'photo/_item', :collection => @photos
233
+
234
+ For more information on using the render and partial helpers, check out the guide for
235
+ {Tennpipes Helpers}[http://www.tennpipesrb.com/guides/application-helpers].
236
+
237
+ == Copyright
238
+
239
+ Copyright (c) 2011-2013 Tennpipes. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../gem_rake_helper')
@@ -0,0 +1,62 @@
1
+ require 'tennpipes-assist'
2
+ require 'i18n'
3
+ require 'enumerator'
4
+ require 'active_support/time_with_zone' # next extension depends on this
5
+ require 'active_support/core_ext/string/conversions' # to_date
6
+ require 'active_support/option_merger' # with_options
7
+ require 'active_support/core_ext/object/with_options' # with_options
8
+ require 'active_support/inflector' # humanize
9
+ require 'active_support/core_ext/hash/except' # Hash#except
10
+ require 'tennpipes/rendering'
11
+
12
+ FileSet.glob_require('tennpipes-helper/**/*.rb', __FILE__)
13
+ I18n.load_path += Dir["#{File.dirname(__FILE__)}/tennpipes-helper/locale/*.yml"]
14
+ I18n.enforce_available_locales = true
15
+
16
+ module Tennpipes
17
+ ##
18
+ # This component provides a variety of view helpers related to html markup generation.
19
+ # There are helpers for generating tags, forms, links, images, and more.
20
+ # Most of the basic methods should be very familiar to anyone who has used rails view helpers.
21
+ #
22
+ module Helpers
23
+ class << self
24
+ ##
25
+ # Registers these helpers into your application:
26
+ #
27
+ # Tennpipes::Helpers::OutputHelpers
28
+ # Tennpipes::Helpers::TagHelpers
29
+ # Tennpipes::Helpers::AssetTagHelpers
30
+ # Tennpipes::Helpers::FormHelpers
31
+ # Tennpipes::Helpers::FormatHelpers
32
+ # Tennpipes::Helpers::RenderHelpers
33
+ # Tennpipes::Helpers::NumberHelpers
34
+ #
35
+ # @param [Sinatra::Application] app
36
+ # The specified Tennpipes application.
37
+ #
38
+ # @example Register the helper module
39
+ # require 'tennpipes-helper'
40
+ # class Tennpipes::Application
41
+ # register Tennpipes::Helpers
42
+ # end
43
+ #
44
+ def registered(app)
45
+ app.register Tennpipes::Rendering
46
+ app.set :default_builder, 'StandardFormBuilder'
47
+ included(app)
48
+ end
49
+
50
+ def included(base)
51
+ base.send :include, Tennpipes::Helpers::OutputHelpers
52
+ base.send :include, Tennpipes::Helpers::TagHelpers
53
+ base.send :include, Tennpipes::Helpers::AssetTagHelpers
54
+ base.send :include, Tennpipes::Helpers::FormHelpers
55
+ base.send :include, Tennpipes::Helpers::FormatHelpers
56
+ base.send :include, Tennpipes::Helpers::RenderHelpers
57
+ base.send :include, Tennpipes::Helpers::NumberHelpers
58
+ base.send :include, Tennpipes::Helpers::TranslationHelpers
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,394 @@
1
+ module Tennpipes
2
+ module Helpers
3
+ ###
4
+ # Helpers related to producing assets (images, stylesheets, js, etc) within templates.
5
+ #
6
+ module AssetTagHelpers
7
+ APPEND_ASSET_EXTENSIONS = ["js", "css"]
8
+ ABSOLUTE_URL_PATTERN = %r{^(https?://)}
9
+ ASSET_FOLDERS = {
10
+ :js => 'javascripts',
11
+ :css => 'stylesheets',
12
+ }
13
+
14
+ ##
15
+ # Creates a div to display the flash of given type if it exists.
16
+ #
17
+ # @param [Symbol] kind
18
+ # The type of flash to display in the tag.
19
+ # @param [Hash] options
20
+ # The html options for this section.
21
+ # use :bootstrap => true to support Twitter's bootstrap dismiss alert button.
22
+ #
23
+ # @return [String] Flash tag html with specified +options+.
24
+ #
25
+ # @example
26
+ # flash_tag(:notice, :id => 'flash-notice')
27
+ # # Generates: <div class="notice" id="flash-notice">flash-notice</div>
28
+ # flash_tag(:error, :success)
29
+ # # Generates: <div class="error">flash-error</div>
30
+ # # <div class="success">flash-success</div>
31
+ #
32
+ def flash_tag(*args)
33
+ options = args.extract_options!
34
+ bootstrap = options.delete(:bootstrap) if options[:bootstrap]
35
+ args.inject(ActiveSupport::SafeBuffer.new) do |html,kind|
36
+ flash_text = ActiveSupport::SafeBuffer.new << flash[kind]
37
+ next html if flash_text.blank?
38
+ flash_text << content_tag(:button, '&times;'.html_safe, {:type => :button, :class => :close, :'data-dismiss' => :alert}) if bootstrap
39
+ html << content_tag(:div, flash_text, { :class => kind }.update(options))
40
+ end
41
+ end
42
+
43
+ ##
44
+ # Creates a link element with given name, url and options.
45
+ #
46
+ # @overload link_to(caption, url, options={})
47
+ # @param [String] caption The text caption.
48
+ # @param [String] url The url href.
49
+ # @param [Hash] options The html options.
50
+ # @overload link_to(url, options={}, &block)
51
+ # @param [String] url The url href.
52
+ # @param [Hash] options The html options.
53
+ # @param [Proc] block The link content.
54
+ #
55
+ # @option options [Boolean] :if
56
+ # If true, the link will appear, otherwise not.
57
+ # @option options [Boolean] :unless
58
+ # If false, the link will appear, otherwise not.
59
+ # @option options [Boolean] :remote
60
+ # If true, this link should be handled by an ajax ujs handler.
61
+ # @option options [String] :confirm
62
+ # Instructs ujs handler to alert confirm message.
63
+ # @option options [Symbol] :method
64
+ # Instructs ujs handler to use different http method (i.e :post, :delete).
65
+ #
66
+ # @return [String] Link tag html with specified +options+.
67
+ #
68
+ # @example
69
+ # link_to('click me', '/dashboard', :class => 'linky')
70
+ # # Generates <a class="linky" href="/dashboard">click me</a>
71
+ #
72
+ # link_to('click me', '/dashboard', :remote => true)
73
+ # # Generates <a href="/dashboard" data-remote="true">click me</a>
74
+ #
75
+ # link_to('click me', '/dashboard', :method => :delete)
76
+ # # Generates <a href="/dashboard" data-method="delete" rel="nofollow">click me</a>
77
+ #
78
+ # link_to('click me', :class => 'blocky') do; end
79
+ # # Generates <a class="blocky" href="#">click me</a>
80
+ #
81
+ # Note that you can pass :+if+ or :+unless+ conditions, but if you provide :current as
82
+ # condition tennpipes return true/false if the request.path_info match the given url.
83
+ #
84
+ def link_to(*args, &block)
85
+ options = args.extract_options!
86
+ name = block_given? ? '' : args.shift
87
+ href = args.first
88
+ options.reverse_merge!(:href => href || '#')
89
+ return name unless parse_conditions(href, options)
90
+ block_given? ? content_tag(:a, options, &block) : content_tag(:a, name, options)
91
+ end
92
+
93
+ ##
94
+ # Creates a link tag that browsers and news readers can use to auto-detect an RSS or ATOM feed.
95
+ #
96
+ # @param [Symbol] mime
97
+ # The mime type of the feed (i.e :atom or :rss).
98
+ # @param [String] url
99
+ # The url for the feed tag to reference.
100
+ # @param[Hash] options
101
+ # The options for the feed tag.
102
+ # @option options [String] :rel ("alternate")
103
+ # Specify the relation of this link.
104
+ # @option options [String] :type
105
+ # Override the auto-generated mime type.
106
+ # @option options [String] :title
107
+ # Specify the title of the link, defaults to the type.
108
+ #
109
+ # @return [String] Feed link html tag with specified +options+.
110
+ #
111
+ # @example
112
+ # feed_tag :atom, url(:blog, :posts, :format => :atom), :title => "ATOM"
113
+ # # Generates: <link type="application/atom+xml" rel="alternate" href="/blog/posts.atom" title="ATOM" />
114
+ # feed_tag :rss, url(:blog, :posts, :format => :rss)
115
+ # # Generates: <link type="application/rss+xml" rel="alternate" href="/blog/posts.rss" title="rss" />
116
+ #
117
+ def feed_tag(mime, url, options={})
118
+ full_mime = (mime == :atom) ? 'application/atom+xml' : 'application/rss+xml'
119
+ tag(:link, options.reverse_merge(:rel => 'alternate', :type => full_mime, :title => mime, :href => url))
120
+ end
121
+
122
+ ##
123
+ # Creates a mail link element with given name and caption.
124
+ #
125
+ # @param [String] email
126
+ # The email address for the link.
127
+ # @param [String] caption
128
+ # The caption for the link.
129
+ # @param [Hash] mail_options
130
+ # The options for the mail link. Accepts html options.
131
+ # @option mail_options [String] cc The cc recipients.
132
+ # @option mail_options [String] bcc The bcc recipients.
133
+ # @option mail_options [String] subject The subject line.
134
+ # @option mail_options [String] body The email body.
135
+ #
136
+ # @return [String] Mail link html tag with specified +options+.
137
+ #
138
+ # @example
139
+ # mail_to "me@demo.com"
140
+ # # Generates: <a href="mailto:me@demo.com">me@demo.com</a>
141
+ #
142
+ # mail_to "me@demo.com", "My Email"
143
+ # # Generates: <a href="mailto:me@demo.com">My Email</a>
144
+ #
145
+ def mail_to(email, caption=nil, mail_options={})
146
+ html_options = mail_options.slice!(:cc, :bcc, :subject, :body)
147
+ mail_query = Rack::Utils.build_query(mail_options).gsub(/\+/, '%20').gsub('%40', '@')
148
+ mail_href = "mailto:#{email}"; mail_href << "?#{mail_query}" if mail_query.present?
149
+ link_to((caption || email), mail_href, html_options)
150
+ end
151
+
152
+ ##
153
+ # Creates a meta element with the content and given options.
154
+ #
155
+ # @param [String] content
156
+ # The content for the meta tag.
157
+ # @param [Hash] options
158
+ # The html options for the meta tag.
159
+ #
160
+ # @return [String] Meta html tag with specified +options+.
161
+ #
162
+ # @example
163
+ # meta_tag "weblog,news", :name => "keywords"
164
+ # # Generates: <meta name="keywords" content="weblog,news" />
165
+ #
166
+ # meta_tag "text/html; charset=UTF-8", 'http-equiv' => "Content-Type"
167
+ # # Generates: <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
168
+ #
169
+ def meta_tag(content, options={})
170
+ options.reverse_merge!("content" => content)
171
+ tag(:meta, options)
172
+ end
173
+
174
+ ##
175
+ # Generates a favicon link. Looks inside images folder
176
+ #
177
+ # @param [String] source
178
+ # The source image path for the favicon link tag.
179
+ # @param [Hash] options
180
+ # The html options for the favicon link tag.
181
+ #
182
+ # @return [String] The favicon link html tag with specified +options+.
183
+ #
184
+ # @example
185
+ # favicon_tag 'favicon.png'
186
+ # favicon_tag 'icons/favicon.png'
187
+ # # or override some options
188
+ # favicon_tag 'favicon.png', :type => 'image/ico'
189
+ #
190
+ def favicon_tag(source, options={})
191
+ type = File.extname(source).sub('.','')
192
+ options = options.dup.reverse_merge!(:href => image_path(source), :rel => 'icon', :type => "image/#{type}")
193
+ tag(:link, options)
194
+ end
195
+
196
+ ##
197
+ # Creates an image element with given url and options.
198
+ #
199
+ # @param [String] url
200
+ # The source path for the image tag.
201
+ # @param [Hash] options
202
+ # The html options for the image tag.
203
+ #
204
+ # @return [String] Image html tag with +url+ and specified +options+.
205
+ #
206
+ # @example
207
+ # image_tag('icons/avatar.png')
208
+ #
209
+ def image_tag(url, options={})
210
+ options.reverse_merge!(:src => image_path(url))
211
+ tag(:img, options)
212
+ end
213
+
214
+ ##
215
+ # Returns a html link tag for each of the sources provided.
216
+ # You can pass in the filename without extension or a symbol and we search it in your +appname.public_folder+
217
+ # like app/public/stylesheets for inclusion. You can provide also a full path.
218
+ #
219
+ # @overload stylesheet_link_tag(*sources, options={})
220
+ # @param [Array<String>] sources Splat of css source paths
221
+ # @param [Hash] options The html options for the link tag
222
+ #
223
+ # @return [String] Stylesheet link html tag for +sources+ with specified +options+.
224
+ #
225
+ # @example
226
+ # stylesheet_link_tag 'style', 'application', 'layout'
227
+ #
228
+ # @api public.
229
+ def stylesheet_link_tag(*sources)
230
+ options = {
231
+ :rel => 'stylesheet',
232
+ :type => 'text/css'
233
+ }.update(sources.extract_options!.symbolize_keys)
234
+ sources.flatten.inject(ActiveSupport::SafeBuffer.new) do |all,source|
235
+ all << tag(:link, { :href => asset_path(:css, source) }.update(options))
236
+ end
237
+ end
238
+
239
+ ##
240
+ # Returns a html script tag for each of the sources provided.
241
+ # You can pass in the filename without extension or a symbol and we search it in your +appname.public_folder+
242
+ # like app/public/javascript for inclusion. You can provide also a full path.
243
+ #
244
+ # @overload javascript_include_tag(*sources, options={})
245
+ # @param [Array<String>] sources Splat of js source paths
246
+ # @param [Hash] options The html options for the script tag
247
+ #
248
+ # @return [String] Script tag for +sources+ with specified +options+.
249
+ #
250
+ # @example
251
+ # javascript_include_tag 'application', :extjs
252
+ #
253
+ def javascript_include_tag(*sources)
254
+ options = {
255
+ :type => 'text/javascript'
256
+ }.update(sources.extract_options!.symbolize_keys)
257
+ sources.flatten.inject(ActiveSupport::SafeBuffer.new) do |all,source|
258
+ all << content_tag(:script, nil, { :src => asset_path(:js, source) }.update(options))
259
+ end
260
+ end
261
+
262
+ ##
263
+ # Returns the path to the image, either relative or absolute. We search it in your +appname.public_folder+
264
+ # like app/public/images for inclusion. You can provide also a full path.
265
+ #
266
+ # @param [String] src
267
+ # The path to the image file (relative or absolute).
268
+ #
269
+ # @return [String] Path to an image given the +kind+ and +source+.
270
+ #
271
+ # @example
272
+ # # Generates: /images/foo.jpg?1269008689
273
+ # image_path("foo.jpg")
274
+ #
275
+ # @api public
276
+ def image_path(src)
277
+ asset_path(:images, src)
278
+ end
279
+
280
+ ##
281
+ # Returns the path to the specified asset (css or javascript).
282
+ #
283
+ # @param [String] kind
284
+ # The kind of asset (i.e :images, :js, :css).
285
+ # @param [String] source
286
+ # The path to the asset (relative or absolute).
287
+ #
288
+ # @return [String] Path for the asset given the +kind+ and +source+.
289
+ #
290
+ # @example
291
+ # # Generates: /javascripts/application.js?1269008689
292
+ # asset_path :js, :application
293
+ #
294
+ # # Generates: /stylesheets/application.css?1269008689
295
+ # asset_path :css, :application
296
+ #
297
+ # # Generates: /images/example.jpg?1269008689
298
+ # asset_path :images, 'example.jpg'
299
+ #
300
+ # # Generates: /uploads/file.ext?1269008689
301
+ # asset_path 'uploads/file.ext'
302
+ #
303
+ def asset_path(kind, source = nil)
304
+ kind, source = source, kind if source.nil?
305
+ source = asset_normalize_extension(kind, URI.escape(source.to_s))
306
+ return source if source =~ ABSOLUTE_URL_PATTERN || source =~ /^\//
307
+ source = File.join(asset_folder_name(kind), source)
308
+ timestamp = asset_timestamp(source)
309
+ result_path = uri_root_path(source)
310
+ "#{result_path}#{timestamp}"
311
+ end
312
+
313
+ private
314
+
315
+ ##
316
+ # Returns the URI root of the application with optional paths appended.
317
+ #
318
+ # @example
319
+ # uri_root_path("/some/path") => "/root/some/path"
320
+ # uri_root_path("javascripts", "test.js") => "/uri/root/javascripts/test.js"
321
+ #
322
+ def uri_root_path(*paths)
323
+ root_uri = self.class.uri_root if self.class.respond_to?(:uri_root)
324
+ File.join(ENV['RACK_BASE_URI'].to_s, root_uri || '/', *paths)
325
+ end
326
+
327
+ ##
328
+ # Returns the timestamp mtime for an asset.
329
+ #
330
+ # @example
331
+ # asset_timestamp("some/path/to/file.png") => "?154543678"
332
+ #
333
+ def asset_timestamp(file_path)
334
+ return nil if file_path =~ /\?/ || (self.class.respond_to?(:asset_stamp) && !self.class.asset_stamp)
335
+ public_path = self.class.public_folder if self.class.respond_to?(:public_folder)
336
+ public_path ||= Tennpipes.root("public") if Tennpipes.respond_to?(:root)
337
+ public_file_path = File.join(public_path, file_path) if public_path
338
+ stamp = File.mtime(public_file_path).to_i if public_file_path && File.exist?(public_file_path)
339
+ stamp ||= Time.now.to_i
340
+ "?#{stamp}"
341
+ end
342
+
343
+ ###
344
+ # Returns the asset folder given a kind.
345
+ #
346
+ # Configureable by setting kind_asset_folder.
347
+ #
348
+ # @example
349
+ # asset_folder_name(:css) => 'stylesheets'
350
+ # asset_folder_name(:js) => 'javascripts'
351
+ # asset_folder_name(:images) => 'images'
352
+ # asset_folder_name(:abrakadabrah) => 'abrakadabrah'
353
+ #
354
+ def asset_folder_name(kind)
355
+ if self.class.respond_to? "#{kind}_asset_folder"
356
+ self.class.send "#{kind}_asset_folder"
357
+ else
358
+ (ASSET_FOLDERS[kind] || kind).to_s
359
+ end
360
+ end
361
+
362
+ ##
363
+ # Normalizes the extension for a given asset.
364
+ #
365
+ # @example
366
+ #
367
+ # asset_normalize_extension(:images, "/foo/bar/baz.png") => "/foo/bar/baz.png"
368
+ # asset_normalize_extension(:js, "/foo/bar/baz") => "/foo/bar/baz.js"
369
+ #
370
+ def asset_normalize_extension(kind, source)
371
+ ignore_extension = !APPEND_ASSET_EXTENSIONS.include?(kind.to_s)
372
+ source << ".#{kind}" unless ignore_extension || source =~ /\.#{kind}/ || source =~ ABSOLUTE_URL_PATTERN
373
+ source
374
+ end
375
+
376
+ ##
377
+ # Parses link_to options for given correct conditions.
378
+ #
379
+ # @example
380
+ # parse_conditions("/some/url", :if => false) => true
381
+ #
382
+ def parse_conditions(url, options)
383
+ if options.has_key?(:if)
384
+ condition = options.delete(:if)
385
+ condition == :current ? url == request.path_info : condition
386
+ elsif condition = options.delete(:unless)
387
+ condition == :current ? url != request.path_info : !condition
388
+ else
389
+ true
390
+ end
391
+ end
392
+ end
393
+ end
394
+ end