tennpipes-helper 3.6.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +239 -0
- data/Rakefile +1 -0
- data/lib/tennpipes-helper.rb +62 -0
- data/lib/tennpipes-helper/asset_tag_helpers.rb +394 -0
- data/lib/tennpipes-helper/form_builder/abstract_form_builder.rb +279 -0
- data/lib/tennpipes-helper/form_builder/standard_form_builder.rb +40 -0
- data/lib/tennpipes-helper/form_helpers.rb +639 -0
- data/lib/tennpipes-helper/form_helpers/errors.rb +138 -0
- data/lib/tennpipes-helper/form_helpers/options.rb +98 -0
- data/lib/tennpipes-helper/form_helpers/security.rb +70 -0
- data/lib/tennpipes-helper/format_helpers.rb +372 -0
- data/lib/tennpipes-helper/locale/cs.yml +103 -0
- data/lib/tennpipes-helper/locale/da.yml +91 -0
- data/lib/tennpipes-helper/locale/de.yml +81 -0
- data/lib/tennpipes-helper/locale/en.yml +103 -0
- data/lib/tennpipes-helper/locale/es.yml +103 -0
- data/lib/tennpipes-helper/locale/fr.yml +79 -0
- data/lib/tennpipes-helper/locale/hu.yml +103 -0
- data/lib/tennpipes-helper/locale/it.yml +89 -0
- data/lib/tennpipes-helper/locale/ja.yml +103 -0
- data/lib/tennpipes-helper/locale/lv.yml +103 -0
- data/lib/tennpipes-helper/locale/nl.yml +82 -0
- data/lib/tennpipes-helper/locale/no.yml +91 -0
- data/lib/tennpipes-helper/locale/pl.yml +95 -0
- data/lib/tennpipes-helper/locale/pt_br.yml +103 -0
- data/lib/tennpipes-helper/locale/ro.yml +103 -0
- data/lib/tennpipes-helper/locale/ru.yml +103 -0
- data/lib/tennpipes-helper/locale/sv.yml +103 -0
- data/lib/tennpipes-helper/locale/tr.yml +103 -0
- data/lib/tennpipes-helper/locale/uk.yml +103 -0
- data/lib/tennpipes-helper/locale/zh_cn.yml +103 -0
- data/lib/tennpipes-helper/locale/zh_tw.yml +103 -0
- data/lib/tennpipes-helper/number_helpers.rb +283 -0
- data/lib/tennpipes-helper/output_helpers.rb +226 -0
- data/lib/tennpipes-helper/output_helpers/abstract_handler.rb +61 -0
- data/lib/tennpipes-helper/output_helpers/erb_handler.rb +27 -0
- data/lib/tennpipes-helper/output_helpers/haml_handler.rb +25 -0
- data/lib/tennpipes-helper/output_helpers/slim_handler.rb +18 -0
- data/lib/tennpipes-helper/render_helpers.rb +63 -0
- data/lib/tennpipes-helper/tag_helpers.rb +294 -0
- data/lib/tennpipes-helper/translation_helpers.rb +36 -0
- data/lib/tennpipes/rendering.rb +369 -0
- data/lib/tennpipes/rendering/erb_template.rb +40 -0
- data/lib/tennpipes/rendering/erubis_template.rb +66 -0
- data/lib/tennpipes/rendering/haml_template.rb +26 -0
- data/lib/tennpipes/rendering/slim_template.rb +20 -0
- data/test/fixtures/apps/render.rb +25 -0
- data/test/fixtures/apps/views/article/comment/show.slim +1 -0
- data/test/fixtures/apps/views/blog/post.erb +1 -0
- data/test/fixtures/apps/views/layouts/specific.erb +1 -0
- data/test/fixtures/apps/views/test/post.erb +1 -0
- data/test/fixtures/layouts/layout.erb +1 -0
- data/test/fixtures/markup_app/app.rb +87 -0
- data/test/fixtures/markup_app/views/button_to.erb +8 -0
- data/test/fixtures/markup_app/views/button_to.haml +5 -0
- data/test/fixtures/markup_app/views/button_to.slim +6 -0
- data/test/fixtures/markup_app/views/capture_concat.erb +14 -0
- data/test/fixtures/markup_app/views/capture_concat.haml +12 -0
- data/test/fixtures/markup_app/views/capture_concat.slim +12 -0
- data/test/fixtures/markup_app/views/content_for.erb +23 -0
- data/test/fixtures/markup_app/views/content_for.haml +19 -0
- data/test/fixtures/markup_app/views/content_for.slim +19 -0
- data/test/fixtures/markup_app/views/content_tag.erb +13 -0
- data/test/fixtures/markup_app/views/content_tag.haml +11 -0
- data/test/fixtures/markup_app/views/content_tag.slim +11 -0
- data/test/fixtures/markup_app/views/current_engine.erb +5 -0
- data/test/fixtures/markup_app/views/current_engine.haml +5 -0
- data/test/fixtures/markup_app/views/current_engine.slim +5 -0
- data/test/fixtures/markup_app/views/fields_for.erb +20 -0
- data/test/fixtures/markup_app/views/fields_for.haml +15 -0
- data/test/fixtures/markup_app/views/fields_for.slim +15 -0
- data/test/fixtures/markup_app/views/form_for.erb +72 -0
- data/test/fixtures/markup_app/views/form_for.haml +59 -0
- data/test/fixtures/markup_app/views/form_for.slim +59 -0
- data/test/fixtures/markup_app/views/form_tag.erb +95 -0
- data/test/fixtures/markup_app/views/form_tag.haml +78 -0
- data/test/fixtures/markup_app/views/form_tag.slim +79 -0
- data/test/fixtures/markup_app/views/link_to.erb +5 -0
- data/test/fixtures/markup_app/views/link_to.haml +4 -0
- data/test/fixtures/markup_app/views/link_to.slim +4 -0
- data/test/fixtures/markup_app/views/mail_to.erb +3 -0
- data/test/fixtures/markup_app/views/mail_to.haml +3 -0
- data/test/fixtures/markup_app/views/mail_to.slim +3 -0
- data/test/fixtures/markup_app/views/meta_tag.erb +3 -0
- data/test/fixtures/markup_app/views/meta_tag.haml +3 -0
- data/test/fixtures/markup_app/views/meta_tag.slim +3 -0
- data/test/fixtures/markup_app/views/partials/_erb.erb +1 -0
- data/test/fixtures/markup_app/views/partials/_haml.haml +1 -0
- data/test/fixtures/markup_app/views/partials/_slim.slim +1 -0
- data/test/fixtures/markup_app/views/simple_partial.erb +1 -0
- data/test/fixtures/markup_app/views/simple_partial.haml +1 -0
- data/test/fixtures/markup_app/views/simple_partial.slim +1 -0
- data/test/fixtures/render_app/app.rb +110 -0
- data/test/fixtures/render_app/views/_deep.erb +3 -0
- data/test/fixtures/render_app/views/_deep.haml +2 -0
- data/test/fixtures/render_app/views/_deep.slim +2 -0
- data/test/fixtures/render_app/views/_partial_block_erb.erb +10 -0
- data/test/fixtures/render_app/views/_partial_block_haml.haml +7 -0
- data/test/fixtures/render_app/views/_partial_block_slim.slim +7 -0
- data/test/fixtures/render_app/views/_unsafe.html.builder +2 -0
- data/test/fixtures/render_app/views/_unsafe_object.html.builder +2 -0
- data/test/fixtures/render_app/views/current_engine.haml +5 -0
- data/test/fixtures/render_app/views/current_engines/_erb.erb +1 -0
- data/test/fixtures/render_app/views/current_engines/_haml.haml +1 -0
- data/test/fixtures/render_app/views/current_engines/_slim.slim +1 -0
- data/test/fixtures/render_app/views/dive_inner_erb.erb +3 -0
- data/test/fixtures/render_app/views/dive_inner_haml.haml +2 -0
- data/test/fixtures/render_app/views/dive_inner_slim.slim +2 -0
- data/test/fixtures/render_app/views/dive_outer_erb.erb +3 -0
- data/test/fixtures/render_app/views/dive_outer_haml.haml +2 -0
- data/test/fixtures/render_app/views/dive_outer_slim.slim +2 -0
- data/test/fixtures/render_app/views/double_capture_erb.erb +3 -0
- data/test/fixtures/render_app/views/double_capture_haml.haml +2 -0
- data/test/fixtures/render_app/views/double_capture_slim.slim +2 -0
- data/test/fixtures/render_app/views/erb/test.erb +1 -0
- data/test/fixtures/render_app/views/explicit_engine.haml +5 -0
- data/test/fixtures/render_app/views/haml/test.haml +1 -0
- data/test/fixtures/render_app/views/render_block_erb.erb +5 -0
- data/test/fixtures/render_app/views/render_block_haml.haml +4 -0
- data/test/fixtures/render_app/views/render_block_slim.slim +4 -0
- data/test/fixtures/render_app/views/ruby_block_capture_erb.erb +1 -0
- data/test/fixtures/render_app/views/ruby_block_capture_haml.haml +1 -0
- data/test/fixtures/render_app/views/ruby_block_capture_slim.slim +1 -0
- data/test/fixtures/render_app/views/template/_user.haml +7 -0
- data/test/fixtures/render_app/views/template/haml_template.haml +1 -0
- data/test/fixtures/render_app/views/template/some_template.haml +2 -0
- data/test/fixtures/render_app/views/wrong_capture_erb.erb +3 -0
- data/test/fixtures/render_app/views/wrong_capture_haml.haml +2 -0
- data/test/fixtures/render_app/views/wrong_capture_slim.slim +2 -0
- data/test/helper.rb +88 -0
- data/test/test_asset_tag_helpers.rb +401 -0
- data/test/test_form_builder.rb +1216 -0
- data/test/test_form_helpers.rb +1056 -0
- data/test/test_format_helpers.rb +251 -0
- data/test/test_helpers.rb +10 -0
- data/test/test_locale.rb +20 -0
- data/test/test_number_helpers.rb +142 -0
- data/test/test_output_helpers.rb +157 -0
- data/test/test_render_helpers.rb +225 -0
- data/test/test_rendering.rb +706 -0
- data/test/test_rendering_extensions.rb +14 -0
- data/test/test_tag_helpers.rb +131 -0
- metadata +299 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
module Tennpipes
|
2
|
+
module Helpers
|
3
|
+
module OutputHelpers
|
4
|
+
class AbstractHandler
|
5
|
+
attr_reader :template, :output_buffer
|
6
|
+
|
7
|
+
def initialize(template)
|
8
|
+
@template = template
|
9
|
+
@output_buffer = template.instance_variable_get(:@_out_buf)
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# Returns true if the block given is of the handler's template type; false otherwise.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# @handler.engine_matches?(block) => true
|
17
|
+
#
|
18
|
+
def engine_matches?(block)
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Captures the html from a block of template code for this handler.
|
23
|
+
#
|
24
|
+
# This method is called to capture content of a block-loving helpers in templates.
|
25
|
+
# Haml has a special method to do this, for Erb and Slim we save original buffer,
|
26
|
+
# call the block and then restore the buffer.
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# @handler.capture_from_template(&block) => "...html..."
|
30
|
+
#
|
31
|
+
def capture_from_template(*args, &block)
|
32
|
+
self.output_buffer, _buf_was = ActiveSupport::SafeBuffer.new, self.output_buffer
|
33
|
+
raw = yield(*args)
|
34
|
+
captured = template.instance_variable_get(:@_out_buf)
|
35
|
+
self.output_buffer = _buf_was
|
36
|
+
engine_matches?(block) && !captured.empty? ? captured : raw.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Outputs the given text to the template.
|
41
|
+
#
|
42
|
+
# This method is called when template uses block-aware helpers. For Slim and Haml such
|
43
|
+
# helpers just return output to use with `=`. For Erb this method is implemented in
|
44
|
+
# ErbHandler by concatenating given text to output buffer.
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
# @handler.concat_to_template("This will be output to the template buffer")
|
48
|
+
#
|
49
|
+
def concat_to_template(text="")
|
50
|
+
text
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
def output_buffer=(val)
|
56
|
+
template.instance_variable_set(:@_out_buf, val)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Tennpipes
|
2
|
+
module Helpers
|
3
|
+
module OutputHelpers
|
4
|
+
##
|
5
|
+
# Handler for Erb template.
|
6
|
+
#
|
7
|
+
class ErbHandler < AbstractHandler
|
8
|
+
##
|
9
|
+
# Outputs the given text to the templates buffer directly.
|
10
|
+
#
|
11
|
+
def concat_to_template(text="")
|
12
|
+
output_buffer << text
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# Returns true if the block is Erb.
|
18
|
+
#
|
19
|
+
def engine_matches?(block)
|
20
|
+
block.binding.eval('defined? __in_erb_template')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
OutputHelpers.register(:erb, ErbHandler)
|
24
|
+
OutputHelpers.register(:erubis, ErbHandler)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Tennpipes
|
2
|
+
module Helpers
|
3
|
+
module OutputHelpers
|
4
|
+
##
|
5
|
+
# Handler for Haml templates.
|
6
|
+
#
|
7
|
+
class HamlHandler < AbstractHandler
|
8
|
+
##
|
9
|
+
# Returns true if the block is for Haml
|
10
|
+
#
|
11
|
+
def engine_matches?(block)
|
12
|
+
template.block_is_haml?(block)
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Captures the html from a block of template code for this handler.
|
17
|
+
#
|
18
|
+
def capture_from_template(*args, &block)
|
19
|
+
engine_matches?(block) ? template.capture_haml(*args, &block) : yield(*args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
OutputHelpers.register(:haml, HamlHandler)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Tennpipes
|
2
|
+
module Helpers
|
3
|
+
module OutputHelpers
|
4
|
+
##
|
5
|
+
# Handler for Slim templates.
|
6
|
+
#
|
7
|
+
class SlimHandler < AbstractHandler
|
8
|
+
##
|
9
|
+
# Returns true if the block is for Slim.
|
10
|
+
#
|
11
|
+
def engine_matches?(block)
|
12
|
+
block.binding.eval('defined? __in_slim_template')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
OutputHelpers.register(:slim, SlimHandler)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Tennpipes
|
2
|
+
module Helpers
|
3
|
+
##
|
4
|
+
# Helpers related to rendering within templates (i.e partials).
|
5
|
+
#
|
6
|
+
module RenderHelpers
|
7
|
+
##
|
8
|
+
# Render a partials with collections support.
|
9
|
+
#
|
10
|
+
# @param [String] template
|
11
|
+
# Relative path to partial template.
|
12
|
+
# @param [Hash] options
|
13
|
+
# Options hash for rendering options.
|
14
|
+
# @option options [Object] :object
|
15
|
+
# Object rendered in partial.
|
16
|
+
# @option options [Array<Object>] :collection
|
17
|
+
# Partial is rendered for each object in this collection.
|
18
|
+
# @option options [Hash] :locals ({})
|
19
|
+
# Local variables accessible in the partial.
|
20
|
+
# @option options [Symbol] :engine
|
21
|
+
# Explicit rendering engine to use for this partial.
|
22
|
+
#
|
23
|
+
# @return [String] The html generated from this partial.
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# partial 'photo/item', :object => @photo
|
27
|
+
# partial 'photo/item', :collection => @photos
|
28
|
+
# partial 'photo/item', :locals => { :foo => :bar }
|
29
|
+
# partial 'photo/item', :engine => :erb
|
30
|
+
#
|
31
|
+
# @note If using this from Sinatra, pass explicit +:engine+ option
|
32
|
+
#
|
33
|
+
def partial(template, options={}, &block)
|
34
|
+
options = { :locals => {}, :layout => false }.update(options)
|
35
|
+
explicit_engine = options.delete(:engine)
|
36
|
+
|
37
|
+
path,_,name = template.to_s.rpartition(File::SEPARATOR)
|
38
|
+
template_path = File.join(path,"_#{name}").to_sym
|
39
|
+
item_name = name.partition('.').first.to_sym
|
40
|
+
|
41
|
+
items, counter = if options[:collection].respond_to?(:inject)
|
42
|
+
[options.delete(:collection), 0]
|
43
|
+
else
|
44
|
+
[[options.delete(:object)], nil]
|
45
|
+
end
|
46
|
+
|
47
|
+
locals = options[:locals]
|
48
|
+
items.each_with_object(ActiveSupport::SafeBuffer.new) do |item,html|
|
49
|
+
locals[item_name] = item if item
|
50
|
+
locals["#{item_name}_counter".to_sym] = counter += 1 if counter
|
51
|
+
content =
|
52
|
+
if block_given?
|
53
|
+
concat_content render(explicit_engine, template_path, options){ capture_html(&block) }
|
54
|
+
else
|
55
|
+
render(explicit_engine, template_path, options)
|
56
|
+
end
|
57
|
+
html.safe_concat content if content
|
58
|
+
end
|
59
|
+
end
|
60
|
+
alias :render_partial :partial
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,294 @@
|
|
1
|
+
module Tennpipes
|
2
|
+
module Helpers
|
3
|
+
##
|
4
|
+
# Helpers related to producing html tags within templates.
|
5
|
+
#
|
6
|
+
module TagHelpers
|
7
|
+
##
|
8
|
+
# Tag values escaped to html entities.
|
9
|
+
#
|
10
|
+
ESCAPE_VALUES = {
|
11
|
+
"&" => "&",
|
12
|
+
"<" => "<",
|
13
|
+
">" => ">",
|
14
|
+
'"' => """
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
##
|
18
|
+
# Cached Regexp for escaping values to avoid rebuilding one
|
19
|
+
# on every escape operation.
|
20
|
+
#
|
21
|
+
ESCAPE_REGEXP = Regexp.union(*ESCAPE_VALUES.keys).freeze
|
22
|
+
|
23
|
+
BOOLEAN_ATTRIBUTES = [
|
24
|
+
:autoplay,
|
25
|
+
:autofocus,
|
26
|
+
:formnovalidate,
|
27
|
+
:checked,
|
28
|
+
:disabled,
|
29
|
+
:hidden,
|
30
|
+
:loop,
|
31
|
+
:multiple,
|
32
|
+
:muted,
|
33
|
+
:readonly,
|
34
|
+
:required,
|
35
|
+
:selected,
|
36
|
+
:declare,
|
37
|
+
:defer,
|
38
|
+
:ismap,
|
39
|
+
:itemscope,
|
40
|
+
:noresize,
|
41
|
+
:novalidate
|
42
|
+
].freeze
|
43
|
+
|
44
|
+
##
|
45
|
+
# Custom data attributes,
|
46
|
+
# feel free to update with yours:
|
47
|
+
#
|
48
|
+
# Tennpipes::Helpers::TagHelpers::DATA_ATTRIBUTES.push(:dialog)
|
49
|
+
# text_field :foo, :dialog => true
|
50
|
+
# # Generates: <input type="text" data-dialog="true" name="foo" />
|
51
|
+
#
|
52
|
+
DATA_ATTRIBUTES = [
|
53
|
+
:method,
|
54
|
+
:remote,
|
55
|
+
:confirm
|
56
|
+
]
|
57
|
+
|
58
|
+
##
|
59
|
+
# A html_safe newline string to avoid allocating a new on each
|
60
|
+
# concatenation.
|
61
|
+
#
|
62
|
+
NEWLINE = "\n".html_safe.freeze
|
63
|
+
|
64
|
+
##
|
65
|
+
# Creates an HTML tag with given name, content, and options.
|
66
|
+
#
|
67
|
+
# @overload content_tag(name, content, options = nil)
|
68
|
+
# @param [Symbol] name
|
69
|
+
# The name of the HTML tag to create.
|
70
|
+
# @param [String] content
|
71
|
+
# The content inside of the tag.
|
72
|
+
# @param [Hash] options
|
73
|
+
# The HTML options to include in this tag.
|
74
|
+
#
|
75
|
+
# @overload content_tag(name, options = nil, &block)
|
76
|
+
# @param [Symbol] name
|
77
|
+
# The name of the HTML tag to create.
|
78
|
+
# @param [Hash] options
|
79
|
+
# The HTML options to include in this tag.
|
80
|
+
# @param [Proc] block
|
81
|
+
# The block returning HTML content.
|
82
|
+
#
|
83
|
+
# @macro [new] global_html_attributes
|
84
|
+
# @option options [String] :id
|
85
|
+
# Specifies a unique identifier for the element.
|
86
|
+
# @option options [String] :class
|
87
|
+
# Specifies the stylesheet class of the element.
|
88
|
+
# @option options [String] :title
|
89
|
+
# Specifies the title for the element.
|
90
|
+
# @option options [String] :accesskey
|
91
|
+
# Specifies a shortcut key to access the element.
|
92
|
+
# @option options [Symbol] :dropzone
|
93
|
+
# Specifies what happens when dragged items are dropped on the element. (:copy, :link, :move)
|
94
|
+
# @option options [Boolean] :hidden
|
95
|
+
# Specifies whether or not the element is hidden from view.
|
96
|
+
# @option options [Boolean] :draggable
|
97
|
+
# Specifies whether or not the element is draggable. (true, false, :auto)
|
98
|
+
# @option options [Boolean] :contenteditable
|
99
|
+
# Specifies whether or not the element is editable.
|
100
|
+
#
|
101
|
+
# @return [String]
|
102
|
+
# Generated HTML with specified +options+.
|
103
|
+
#
|
104
|
+
# @example
|
105
|
+
# content_tag(:p, 'Hello World', :class => 'light')
|
106
|
+
#
|
107
|
+
# # => <p class="light">
|
108
|
+
# # => Hello World
|
109
|
+
# # => </p>
|
110
|
+
#
|
111
|
+
# content_tag(:p, :class => 'dark') do
|
112
|
+
# link_to 'Tennpipes', 'http://www.tennpipesrb.com'
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# # => <p class="dark">
|
116
|
+
# # => <a href="http://www.tennpipesrb.com">Tennpipes</a>
|
117
|
+
# # => </p>
|
118
|
+
#
|
119
|
+
def content_tag(name, content = nil, options = nil, &block)
|
120
|
+
if block_given?
|
121
|
+
options = content if content.is_a?(Hash)
|
122
|
+
content = capture_html(&block)
|
123
|
+
end
|
124
|
+
|
125
|
+
options = parse_data_options(name, options)
|
126
|
+
attributes = tag_attributes(options)
|
127
|
+
output = ActiveSupport::SafeBuffer.new
|
128
|
+
output.safe_concat "<#{name}#{attributes}>"
|
129
|
+
if content.respond_to?(:each) && !content.is_a?(String)
|
130
|
+
content.each{ |item| output.concat item; output.safe_concat NEWLINE }
|
131
|
+
else
|
132
|
+
output.concat content.to_s
|
133
|
+
end
|
134
|
+
output.safe_concat "</#{name}>"
|
135
|
+
|
136
|
+
block_is_template?(block) ? concat_content(output) : output
|
137
|
+
end
|
138
|
+
|
139
|
+
##
|
140
|
+
# Like #content_tag, but assumes its input to be safe and doesn't
|
141
|
+
# escape. It also returns safe HTML.
|
142
|
+
#
|
143
|
+
# @see #content_tag
|
144
|
+
#
|
145
|
+
def safe_content_tag(name, content = nil, options = nil, &block)
|
146
|
+
mark_safe(content_tag(name, mark_safe(content), options, &block))
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# Creates an HTML input field with the given type and options.
|
151
|
+
#
|
152
|
+
# @param [Symbol] type
|
153
|
+
# The type of input to create.
|
154
|
+
# @param [Hash] options
|
155
|
+
# The HTML options to include in this input.
|
156
|
+
#
|
157
|
+
# @option options [String] :id
|
158
|
+
# Specifies a unique identifier for the input.
|
159
|
+
# @option options [String] :class
|
160
|
+
# Specifies the stylesheet class of the input.
|
161
|
+
# @option options [String] :name
|
162
|
+
# Specifies the name of the input.
|
163
|
+
# @option options [String] :accesskey
|
164
|
+
# Specifies a shortcut key to access the input.
|
165
|
+
# @option options [Integer] :tabindex
|
166
|
+
# Specifies the tab order of the input.
|
167
|
+
# @option options [Boolean] :hidden
|
168
|
+
# Specifies whether or not the input is hidden from view.
|
169
|
+
# @option options [Boolean] :spellcheck
|
170
|
+
# Specifies whether or not the input should have it's spelling and grammar checked for errors.
|
171
|
+
# @option options [Boolean] :draggable
|
172
|
+
# Specifies whether or not the input is draggable. (true, false, :auto)
|
173
|
+
# @option options [String] :pattern
|
174
|
+
# Specifies the regular expression pattern that the input's value is checked against.
|
175
|
+
# @option options [Symbol] :autocomplete
|
176
|
+
# Specifies whether or not the input should have autocomplete enabled. (:on, :off)
|
177
|
+
# @option options [Boolean] :autofocus
|
178
|
+
# Specifies whether or not the input should automatically get focus when the page loads.
|
179
|
+
# @option options [Boolean] :required
|
180
|
+
# Specifies whether or not the input is required to be completed before the form is submitted.
|
181
|
+
# @option options [Boolean] :readonly
|
182
|
+
# Specifies whether or not the input is read only.
|
183
|
+
# @option options [Boolean] :disabled
|
184
|
+
# Specifies whether or not the input is disabled.
|
185
|
+
#
|
186
|
+
# @return [String]
|
187
|
+
# Generated HTML with specified +options+.
|
188
|
+
#
|
189
|
+
# @example
|
190
|
+
# input_tag :text, :name => 'handle'
|
191
|
+
# # => <input type="test" name="handle" />
|
192
|
+
#
|
193
|
+
# input_tag :password, :name => 'password', :size => 20
|
194
|
+
# # => <input type="password" name="password" size="20" />
|
195
|
+
#
|
196
|
+
# input_tag :text, :name => 'username', :required => true, :autofocus => true
|
197
|
+
# # => <input type="text" name="username" required autofocus />
|
198
|
+
#
|
199
|
+
# input_tag :number, :name => 'credit_card', :autocomplete => :off
|
200
|
+
# # => <input type="number" name="credit_card" autocomplete="off" />
|
201
|
+
#
|
202
|
+
def input_tag(type, options = {})
|
203
|
+
tag(:input, { :type => type }.update(options))
|
204
|
+
end
|
205
|
+
|
206
|
+
##
|
207
|
+
# Creates an HTML tag with the given name and options.
|
208
|
+
#
|
209
|
+
# @param [Symbol] name
|
210
|
+
# The name of the HTML tag to create.
|
211
|
+
# @param [Hash] options
|
212
|
+
# The HTML options to include in this tag.
|
213
|
+
#
|
214
|
+
# @macro global_html_attributes
|
215
|
+
#
|
216
|
+
# @return [String]
|
217
|
+
# Generated HTML with specified +options+.
|
218
|
+
#
|
219
|
+
# @example
|
220
|
+
# tag :hr, :class => 'dotted'
|
221
|
+
# # => <hr class="dotted" />
|
222
|
+
#
|
223
|
+
# tag :input, :name => 'username', :type => :text
|
224
|
+
# # => <input name="username" type="text" />
|
225
|
+
#
|
226
|
+
# tag :img, :src => 'images/pony.jpg', :alt => 'My Little Pony'
|
227
|
+
# # => <img src="images/pony.jpg" alt="My Little Pony" />
|
228
|
+
#
|
229
|
+
# tag :img, :src => 'sinatra.jpg, :data => { :nsfw => false, :geo => [34.087, -118.407] }
|
230
|
+
# # => <img src="sinatra.jpg" data-nsfw="false" data-geo="34.087 -118.407" />
|
231
|
+
#
|
232
|
+
def tag(name, options = nil, open = false)
|
233
|
+
options = parse_data_options(name, options)
|
234
|
+
attributes = tag_attributes(options)
|
235
|
+
"<#{name}#{attributes}#{open ? '>' : ' />'}".html_safe
|
236
|
+
end
|
237
|
+
|
238
|
+
private
|
239
|
+
|
240
|
+
##
|
241
|
+
# Returns a compiled list of HTML attributes.
|
242
|
+
#
|
243
|
+
def tag_attributes(options)
|
244
|
+
return '' unless options
|
245
|
+
options.inject('') do |all,(key,value)|
|
246
|
+
next all unless value
|
247
|
+
all << ' ' if all.empty?
|
248
|
+
all << if value.is_a?(Hash)
|
249
|
+
nested_values(key, value)
|
250
|
+
elsif BOOLEAN_ATTRIBUTES.include?(key)
|
251
|
+
%(#{key}="#{key}" )
|
252
|
+
else
|
253
|
+
%(#{key}="#{escape_value(value)}" )
|
254
|
+
end
|
255
|
+
end.chomp!(' ')
|
256
|
+
end
|
257
|
+
|
258
|
+
##
|
259
|
+
# Escape tag values to their HTML/XML entities.
|
260
|
+
#
|
261
|
+
def escape_value(string)
|
262
|
+
string.to_s.gsub(ESCAPE_REGEXP) { |char| ESCAPE_VALUES[char] }
|
263
|
+
end
|
264
|
+
|
265
|
+
##
|
266
|
+
# Iterate through nested values.
|
267
|
+
#
|
268
|
+
def nested_values(attribute, hash)
|
269
|
+
hash.inject('') do |all,(key,value)|
|
270
|
+
attribute_with_name = "#{attribute}-#{key.to_s.dasherize}"
|
271
|
+
all << if value.is_a?(Hash)
|
272
|
+
nested_values(attribute_with_name, value)
|
273
|
+
else
|
274
|
+
%(#{attribute_with_name}="#{escape_value(value)}" )
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
##
|
280
|
+
# Parses custom data attributes.
|
281
|
+
#
|
282
|
+
def parse_data_options(tag, options)
|
283
|
+
return unless options
|
284
|
+
parsed_options = options.dup
|
285
|
+
options.each do |key, value|
|
286
|
+
next if !DATA_ATTRIBUTES.include?(key) || (tag.to_s == 'form' && key == :method)
|
287
|
+
parsed_options["data-#{key}"] = parsed_options.delete(key)
|
288
|
+
parsed_options[:rel] = 'nofollow' if key == :method
|
289
|
+
end
|
290
|
+
parsed_options
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|