erector 0.8.3 → 0.9.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. data/Gemfile +21 -0
  2. data/Rakefile +171 -0
  3. data/VERSION.yml +3 -2
  4. data/lib/erector.rb +3 -5
  5. data/lib/erector/abstract_widget.rb +76 -31
  6. data/lib/erector/attributes.rb +34 -0
  7. data/lib/erector/caching.rb +1 -0
  8. data/lib/erector/convenience.rb +12 -4
  9. data/lib/erector/dependency.rb +2 -1
  10. data/lib/erector/element.rb +113 -0
  11. data/lib/erector/erect/erect.rb +10 -7
  12. data/lib/erector/externals.rb +2 -1
  13. data/lib/erector/html.rb +6 -340
  14. data/lib/erector/html_widget.rb +300 -0
  15. data/lib/erector/inline.rb +1 -1
  16. data/lib/erector/output.rb +39 -12
  17. data/lib/erector/promise.rb +137 -0
  18. data/lib/erector/rails2/extensions/rails_widget.rb +1 -1
  19. data/lib/erector/rails3.rb +1 -1
  20. data/lib/erector/sass.rb +14 -19
  21. data/lib/erector/tag.rb +65 -0
  22. data/lib/erector/text.rb +123 -0
  23. data/lib/erector/version.rb +1 -1
  24. data/lib/erector/widget.rb +52 -12
  25. data/lib/erector/widgets/page.rb +12 -10
  26. data/lib/erector/xml_widget.rb +131 -0
  27. data/spec/erector/caching_spec.rb +1 -0
  28. data/spec/erector/externals_spec.rb +0 -1
  29. data/spec/erector/html_spec.rb +9 -25
  30. data/spec/erector/output_spec.rb +102 -9
  31. data/spec/erector/promise_spec.rb +173 -0
  32. data/spec/erector/sass_spec.rb +1 -1
  33. data/spec/erector/tag_spec.rb +67 -0
  34. data/spec/erector/widget_spec.rb +53 -2
  35. data/spec/erector/xml_widget_spec.rb +74 -0
  36. data/spec/rails2/rails_app/Gemfile +1 -0
  37. data/spec/rails2/rails_app/spec/rails_spec_helper.rb +2 -0
  38. data/spec/rails_root/Gemfile +11 -0
  39. data/spec/rails_root/README +256 -0
  40. data/spec/rails_root/Rakefile +7 -0
  41. data/spec/rails_root/app/controllers/application.rb +6 -0
  42. data/spec/rails_root/app/controllers/application_controller.rb +3 -0
  43. data/spec/rails_root/app/helpers/application_helper.rb +2 -0
  44. data/spec/rails_root/app/views/layouts/application.html.erb +14 -0
  45. data/spec/rails_root/app/views/test/_erb.erb +1 -0
  46. data/spec/rails_root/app/views/test/_erector.rb +5 -0
  47. data/spec/rails_root/app/views/test/_partial_with_locals.rb +7 -0
  48. data/spec/rails_root/app/views/test/bare.rb +5 -0
  49. data/spec/rails_root/app/views/test/erb_from_erector.html.rb +5 -0
  50. data/spec/rails_root/app/views/test/erector_from_erb.html.erb +1 -0
  51. data/spec/rails_root/app/views/test/erector_with_locals_from_erb.html.erb +6 -0
  52. data/spec/rails_root/app/views/test/implicit_assigns.html.rb +5 -0
  53. data/spec/rails_root/app/views/test/needs.html.rb +7 -0
  54. data/spec/rails_root/app/views/test/needs_subclass.html.rb +5 -0
  55. data/spec/rails_root/app/views/test/protected_instance_variable.html.rb +5 -0
  56. data/spec/rails_root/app/views/test/render_default.html.rb +5 -0
  57. data/spec/rails_root/app/views/test/render_partial.html.rb +5 -0
  58. data/spec/rails_root/config.ru +4 -0
  59. data/spec/rails_root/config/application.rb +42 -0
  60. data/spec/rails_root/config/boot.rb +13 -0
  61. data/spec/rails_root/config/database.yml +22 -0
  62. data/spec/rails_root/config/environment.rb +5 -0
  63. data/spec/rails_root/config/environments/development.rb +22 -0
  64. data/spec/rails_root/config/environments/production.rb +49 -0
  65. data/spec/rails_root/config/environments/test.rb +35 -0
  66. data/spec/rails_root/config/initializers/backtrace_silencers.rb +7 -0
  67. data/spec/rails_root/config/initializers/inflections.rb +10 -0
  68. data/spec/rails_root/config/initializers/mime_types.rb +5 -0
  69. data/spec/rails_root/config/initializers/secret_token.rb +7 -0
  70. data/spec/rails_root/config/initializers/session_store.rb +8 -0
  71. data/spec/rails_root/config/locales/en.yml +5 -0
  72. data/spec/rails_root/config/routes.rb +58 -0
  73. data/spec/rails_root/db/seeds.rb +7 -0
  74. data/spec/rails_root/doc/README_FOR_APP +2 -0
  75. data/spec/rails_root/log/development.log +17 -0
  76. data/spec/rails_root/log/test.log +3750 -0
  77. data/spec/rails_root/public/404.html +26 -0
  78. data/spec/rails_root/public/422.html +26 -0
  79. data/spec/rails_root/public/500.html +26 -0
  80. data/spec/rails_root/public/dispatch.cgi +10 -0
  81. data/spec/rails_root/public/dispatch.fcgi +24 -0
  82. data/spec/rails_root/public/dispatch.rb +10 -0
  83. data/spec/rails_root/public/favicon.ico +0 -0
  84. data/spec/rails_root/public/images/rails.png +0 -0
  85. data/spec/rails_root/public/index.html +262 -0
  86. data/spec/rails_root/public/javascripts/application.js +2 -0
  87. data/spec/rails_root/public/javascripts/controls.js +965 -0
  88. data/spec/rails_root/public/javascripts/dragdrop.js +974 -0
  89. data/spec/rails_root/public/javascripts/effects.js +1123 -0
  90. data/spec/rails_root/public/javascripts/prototype.js +6001 -0
  91. data/spec/rails_root/public/javascripts/rails.js +175 -0
  92. data/spec/rails_root/public/robots.txt +5 -0
  93. data/spec/rails_root/script/about +3 -0
  94. data/spec/rails_root/script/console +3 -0
  95. data/spec/rails_root/script/destroy +3 -0
  96. data/spec/rails_root/script/generate +3 -0
  97. data/spec/rails_root/script/performance/benchmarker +3 -0
  98. data/spec/rails_root/script/performance/profiler +3 -0
  99. data/spec/rails_root/script/performance/request +3 -0
  100. data/spec/rails_root/script/plugin +3 -0
  101. data/spec/rails_root/script/process/inspector +3 -0
  102. data/spec/rails_root/script/process/reaper +3 -0
  103. data/spec/rails_root/script/process/spawner +3 -0
  104. data/spec/rails_root/script/rails +6 -0
  105. data/spec/rails_root/script/runner +3 -0
  106. data/spec/rails_root/script/server +3 -0
  107. data/spec/rails_root/spec/form_builder_spec.rb +21 -0
  108. data/spec/rails_root/spec/rails_helpers_spec.rb +220 -0
  109. data/spec/rails_root/spec/rails_spec_helper.rb +10 -0
  110. data/spec/rails_root/spec/rails_widget_spec.rb +83 -0
  111. data/spec/rails_root/spec/render_spec.rb +298 -0
  112. data/spec/rails_root/test/performance/browsing_test.rb +9 -0
  113. data/spec/rails_root/test/test_helper.rb +13 -0
  114. data/spec/spec_helper.rb +3 -1
  115. metadata +202 -66
@@ -73,6 +73,7 @@ module Erector
73
73
  cache && block.nil? && self.class.cachable?
74
74
  end
75
75
 
76
+ protected
76
77
  def _render(options = {})
77
78
  if should_cache?
78
79
  cache[self.class, assigns, options[:content_method_name]] ||= super
@@ -4,7 +4,7 @@ module Erector
4
4
  # You may just want to call to_html(:prettyprint => true)
5
5
  # so you can pass in other rendering options as well.
6
6
  def to_pretty(options = {})
7
- to_html(options.merge(:prettyprint => true))
7
+ render(options.merge(:prettyprint => true))
8
8
  end
9
9
 
10
10
  # Render (like to_html) but stripping all tags and inserting some
@@ -25,12 +25,20 @@ module Erector
25
25
  # which are rendered, or strings, which are html-escaped and output.
26
26
  def join(array, separator)
27
27
  first = true
28
- array.each do |widget_or_text|
28
+ array.each do |item|
29
29
  if !first
30
- text separator
30
+ if separator.is_a? Widget
31
+ widget separator
32
+ else
33
+ text separator
34
+ end
31
35
  end
32
36
  first = false
33
- text widget_or_text
37
+ if item.is_a? Widget
38
+ widget item
39
+ else
40
+ text item
41
+ end
34
42
  end
35
43
  end
36
44
 
@@ -23,7 +23,8 @@ module Erector
23
23
  end
24
24
 
25
25
  def hash
26
- # this is a fairly inefficient hash function but it does the trick for now
26
+ # this is a fairly inefficient hash function but it does the trick for
27
+ # now
27
28
  "#{type}#{text}#{options}".hash
28
29
  end
29
30
  end
@@ -0,0 +1,113 @@
1
+ require 'erector/abstract_widget'
2
+ require 'erector/promise'
3
+
4
+ # todo: unit test
5
+ module Erector
6
+ module Element
7
+ # Internal method used to emit an HTML/XML element, including an open tag,
8
+ # attributes (optional, via the default hash), contents (also optional),
9
+ # and close tag.
10
+ #
11
+ # Using the arcane powers of Ruby, there are magic methods that call
12
+ # +element+ for all the standard HTML tags, like +a+, +body+, +p+, and so
13
+ # forth. Look at the source of erector/html.rb for the full list.
14
+ # Unfortunately, this big mojo confuses rdoc, so we can't see each method
15
+ # in this rdoc page, but trust us, they're there.
16
+ #
17
+ # When calling one of these magic methods, put attributes in the default
18
+ # hash. If there is a string parameter, then it is used as the contents.
19
+ # If there is a block, then it is executed (yielded), and the string
20
+ # parameter is ignored. The block will usually be in the scope of the
21
+ # child widget, which means it has access to all the methods of Widget,
22
+ # which will eventually end up appending text to the +output+ string. See
23
+ # how elegant it is? Not confusing at all if you don't think about it.
24
+ #
25
+ def element(*args, &block)
26
+ _element(*args, &block)
27
+ end
28
+
29
+ # Internal method used to emit a self-closing HTML/XML element, including
30
+ # a tag name and optional attributes (passed in via the default hash).
31
+ #
32
+ # Using the arcane powers of Ruby, there are magic methods that call
33
+ # +empty_element+ for all the standard HTML tags, like +img+, +br+, and so
34
+ # forth. Look at the source of #self_closing_tags for the full list.
35
+ # Unfortunately, this big mojo confuses rdoc, so we can't see each method
36
+ # in this rdoc page, but trust us, they're there.
37
+ #
38
+ def empty_element(*args, &block)
39
+ _empty_element(*args, &block)
40
+ end
41
+
42
+ # moved to Promise
43
+ # # Emits an open tag, comprising '<', tag name, optional attributes, and '>'
44
+ # def open_tag(promise)
45
+ # output.newline if newliney?(promise._tag_name) && !output.at_line_start?
46
+ # output << promise._open_tag
47
+ # output.indent
48
+ # end
49
+ #
50
+ # # Emits a close tag, consisting of '<', '/', tag name, and '>'
51
+ # def close_tag(promise)
52
+ # output.undent
53
+ # output << promise._close_tag
54
+ # if newliney?(promise._tag_name)
55
+ # output.newline
56
+ # end
57
+ # end
58
+ #
59
+ # def inside_tag value, block
60
+ # if block
61
+ # block.call
62
+ # else
63
+ # text value
64
+ # end
65
+ # end
66
+
67
+ def _element(tag_name, *args, &block)
68
+ if args.length > 2
69
+ raise ArgumentError, "too many args"
70
+ end
71
+ attributes, value = nil, nil
72
+ arg0 = args[0]
73
+ if arg0.is_a?(Hash)
74
+ attributes = arg0
75
+ else
76
+ value = arg0
77
+ arg1 = args[1]
78
+ if arg1.is_a?(Hash)
79
+ attributes = arg1
80
+ end
81
+ end
82
+
83
+ if block && value
84
+ raise ArgumentError, "You can't pass both a block and a value to #{tag_name} -- please choose one."
85
+ end
86
+
87
+ attributes ||= {}
88
+ promise = if !value.nil?
89
+ Promise.new(output, tag_name, attributes, false, newliney?(tag_name)) do
90
+ if value.is_a? AbstractWidget
91
+ widget value
92
+ else
93
+ text value
94
+ end
95
+ end
96
+ elsif block
97
+ Promise.new(output, tag_name, attributes, false, newliney?(tag_name), &block)
98
+ else
99
+ Promise.new(output, tag_name, attributes, false, newliney?(tag_name))
100
+ end
101
+ promise._render
102
+ promise
103
+ end
104
+
105
+ def _empty_element(tag_name, attributes={})
106
+ promise = Promise.new(output, tag_name, attributes, true, newliney?(tag_name))
107
+ promise._render
108
+ promise
109
+ end
110
+
111
+
112
+ end
113
+ end
@@ -1,5 +1,4 @@
1
1
  require "optparse"
2
- require "rake"
3
2
  require "erector/erect/erected" # pull this out so we don't recreate the grammar every time
4
3
 
5
4
  module Erector
@@ -70,23 +69,27 @@ module Erector
70
69
 
71
70
  #todo: unit test
72
71
  def explode_dirs
73
- exploded_files = FileList.new
72
+ exploded_files = []
74
73
  files.each do |file|
75
74
  if File.directory?(file)
76
- exploded_files.add(explode(file))
75
+ exploded_files << explode(file)
77
76
  else
78
- exploded_files.add(file)
77
+ exploded_files << file
79
78
  end
80
79
  end
81
- @files = exploded_files
80
+ @files = exploded_files.flatten
82
81
  end
83
82
 
84
83
  def explode(dir)
85
84
  case mode
86
85
  when :to_erector
87
- FileList["#{dir}/**/*.rhtml", "#{dir}/**/*.html", "#{dir}/**/*.html.erb"]
86
+ ["#{dir}/**/*.rhtml",
87
+ "#{dir}/**/*.html",
88
+ "#{dir}/**/*.html.erb"].map do |pattern|
89
+ Dir.glob pattern
90
+ end.flatten
88
91
  when :to_html
89
- FileList["#{dir}/**/*.rb"]
92
+ Dir.glob "#{dir}/**/*.rb"
90
93
  end
91
94
  end
92
95
 
@@ -87,7 +87,8 @@ module Erector
87
87
  output = Erector::Output.new
88
88
  self.to_a(:output => output) # render all the externals onto this new output buffer
89
89
  nested_widgets = output.widgets.to_a
90
- renderer = ExternalRenderer.new({:classes => nested_widgets}.merge(options_to_external_renderer))
90
+ options_to_external_renderer = {:classes => nested_widgets}.merge(options_to_external_renderer)
91
+ renderer = ExternalRenderer.new(options_to_external_renderer)
91
92
  externals = renderer.to_a(:output => output)
92
93
  output.to_a
93
94
  end
@@ -1,346 +1,12 @@
1
+ require "erector/element"
2
+ require "erector/attributes"
3
+ require "erector/promise"
4
+ require "erector/text"
5
+ require "erector/tag"
6
+
1
7
  module Erector
2
8
  module HTML
3
- module ClassMethods
4
- # Tags which are always self-closing. Click "[show source]" to see the full list.
5
- def empty_tags
6
- ['area', 'base', 'br', 'col', 'embed', 'frame',
7
- 'hr', 'img', 'input', 'link', 'meta', 'param']
8
- end
9
-
10
- # Tags which can contain other stuff. Click "[show source]" to see the full list.
11
- def full_tags
12
- [
13
- 'a', 'abbr', 'acronym', 'address', 'article', 'aside', 'audio',
14
- 'b', 'bdo', 'big', 'blockquote', 'body', 'button',
15
- 'canvas', 'caption', 'center', 'cite', 'code', 'colgroup', 'command',
16
- 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'div', 'dl', 'dt',
17
- 'em',
18
- 'fieldset', 'figure', 'footer', 'form', 'frameset',
19
- 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'html', 'i',
20
- 'iframe', 'ins', 'keygen', 'kbd', 'label', 'legend', 'li',
21
- 'map', 'mark', 'meter',
22
- 'nav', 'noframes', 'noscript',
23
- 'object', 'ol', 'optgroup', 'option',
24
- 'p', 'pre', 'progress',
25
- 'q', 'ruby', 'rt', 'rp', 's',
26
- 'samp', 'script', 'section', 'select', 'small', 'source', 'span', 'strike',
27
- 'strong', 'style', 'sub', 'sup',
28
- 'table', 'tbody', 'td', 'textarea', 'tfoot',
29
- 'th', 'thead', 'time', 'title', 'tr', 'tt',
30
- 'u', 'ul',
31
- 'var', 'video'
32
- ]
33
- end
34
-
35
- def all_tags
36
- full_tags + empty_tags
37
- end
38
-
39
- def def_empty_tag_method(tag_name)
40
- self.class_eval(<<-SRC, __FILE__, __LINE__ + 1)
41
- def #{tag_name}(*args, &block)
42
- __empty_element__('#{tag_name}', *args, &block)
43
- end
44
- SRC
45
- end
46
-
47
- def def_full_tag_method(tag_name)
48
- self.class_eval(<<-SRC, __FILE__, __LINE__ + 1)
49
- def #{tag_name}(*args, &block)
50
- __element__(false, '#{tag_name}', *args, &block)
51
- end
52
-
53
- def #{tag_name}!(*args, &block)
54
- __element__(true, '#{tag_name}', *args, &block)
55
- end
56
- SRC
57
- end
58
- end
59
-
60
- def self.included(base)
61
- base.extend ClassMethods
62
-
63
- base.full_tags.each do |tag_name|
64
- base.def_full_tag_method(tag_name)
65
- end
66
-
67
- base.empty_tags.each do |tag_name|
68
- base.def_empty_tag_method(tag_name)
69
- end
70
- end
71
-
72
- # Internal method used to emit an HTML/XML element, including an open tag,
73
- # attributes (optional, via the default hash), contents (also optional),
74
- # and close tag.
75
- #
76
- # Using the arcane powers of Ruby, there are magic methods that call
77
- # +element+ for all the standard HTML tags, like +a+, +body+, +p+, and so
78
- # forth. Look at the source of #full_tags for the full list.
79
- # Unfortunately, this big mojo confuses rdoc, so we can't see each method
80
- # in this rdoc page, but trust us, they're there.
81
- #
82
- # When calling one of these magic methods, put attributes in the default
83
- # hash. If there is a string parameter, then it is used as the contents.
84
- # If there is a block, then it is executed (yielded), and the string
85
- # parameter is ignored. The block will usually be in the scope of the
86
- # child widget, which means it has access to all the methods of Widget,
87
- # which will eventually end up appending text to the +output+ string. See
88
- # how elegant it is? Not confusing at all if you don't think about it.
89
- #
90
- def element(*args, &block)
91
- __element__(false, *args, &block)
92
- end
93
-
94
- # Like +element+, but string parameters are not escaped.
95
- def element!(*args, &block)
96
- __element__(true, *args, &block)
97
- end
98
-
99
- # Internal method used to emit a self-closing HTML/XML element, including
100
- # a tag name and optional attributes (passed in via the default hash).
101
- #
102
- # Using the arcane powers of Ruby, there are magic methods that call
103
- # +empty_element+ for all the standard HTML tags, like +img+, +br+, and so
104
- # forth. Look at the source of #empty_tags for the full list.
105
- # Unfortunately, this big mojo confuses rdoc, so we can't see each method
106
- # in this rdoc page, but trust us, they're there.
107
- #
108
- def empty_element(*args, &block)
109
- __empty_element__(*args, &block)
110
- end
111
-
112
- # Returns an HTML-escaped version of its parameter. Leaves the output
113
- # string untouched. This method is idempotent: h(h(text)) will not
114
- # double-escape text. This means that it is safe to do something like
115
- # text(h("2<4")) -- it will produce "2&lt;4", not "2&amp;lt;4".
116
- def h(content)
117
- if content.respond_to?(:html_safe?) && content.html_safe?
118
- content
119
- else
120
- raw(CGI.escapeHTML(content.to_s))
121
- end
122
- end
123
-
124
- # Emits an open tag, comprising '<', tag name, optional attributes, and '>'
125
- def open_tag(tag_name, attributes={})
126
- output.newline if newliney?(tag_name) && !output.at_line_start?
127
- output << raw("<#{tag_name}#{format_attributes(attributes)}>")
128
- output.indent
129
- end
130
-
131
- # Emits a close tag, consisting of '<', '/', tag name, and '>'
132
- def close_tag(tag_name)
133
- output.undent
134
- output << raw("</#{tag_name}>")
135
- if newliney?(tag_name)
136
- output.newline
137
- end
138
- end
139
-
140
- # Returns text which will *not* be HTML-escaped.
141
- def raw(value)
142
- RawString.new(value.to_s)
143
- end
144
-
145
- # Emits text. If a string is passed in, it will be HTML-escaped. If the
146
- # result of calling methods such as raw is passed in, the HTML will not be
147
- # HTML-escaped again. If another kind of object is passed in, the result
148
- # of calling its to_s method will be treated as a string would be.
149
- #
150
- # You shouldn't pass a widget in to this method, as that will cause
151
- # performance problems (as well as being semantically goofy). Use the
152
- # #widget method instead.
153
- def text(value)
154
- if value.is_a? Widget
155
- widget value
156
- else
157
- output << h(value)
158
- end
159
- nil
160
- end
161
-
162
- # Emits text which will *not* be HTML-escaped. Same effect as text(raw(s))
163
- def text!(value)
164
- text raw(value)
165
- end
166
-
167
- alias rawtext text!
168
-
169
- # Returns a copy of value with spaces replaced by non-breaking space characters.
170
- # With no arguments, return a single non-breaking space.
171
- # The output uses the escaping format '&#160;' since that works
172
- # in both HTML and XML (as opposed to '&nbsp;' which only works in HTML).
173
- def nbsp(value = " ")
174
- raw(h(value).gsub(/ /,'&#160;'))
175
- end
176
-
177
- # Return a character given its unicode code point or unicode name.
178
- def character(code_point_or_name)
179
- if code_point_or_name.is_a?(Symbol)
180
- require "erector/unicode"
181
- found = Erector::CHARACTERS[code_point_or_name]
182
- if found.nil?
183
- raise "Unrecognized character #{code_point_or_name}"
184
- end
185
- raw("&#x#{sprintf '%x', found};")
186
- elsif code_point_or_name.is_a?(Integer)
187
- raw("&#x#{sprintf '%x', code_point_or_name};")
188
- else
189
- raise "Unrecognized argument to character: #{code_point_or_name}"
190
- end
191
- end
192
-
193
- # Emits an XML instruction, which looks like this: <?xml version=\"1.0\" encoding=\"UTF-8\"?>
194
- def instruct(attributes={:version => "1.0", :encoding => "UTF-8"})
195
- output << raw("<?xml#{format_sorted(sort_for_xml_declaration(attributes))}?>")
196
- end
197
-
198
- # Emits an HTML comment (&lt;!-- ... --&gt;) surrounding +text+ and/or the output of +block+.
199
- # see http://www.w3.org/TR/html4/intro/sgmltut.html#h-3.2.4
200
- #
201
- # If +text+ is an Internet Explorer conditional comment condition such as "[if IE]",
202
- # the output includes the opening condition and closing "[endif]". See
203
- # http://www.quirksmode.org/css/condcom.html
204
- #
205
- # Since "Authors should avoid putting two or more adjacent hyphens inside comments,"
206
- # we emit a warning if you do that.
207
- def comment(text = '')
208
- puts "Warning: Authors should avoid putting two or more adjacent hyphens inside comments." if text =~ /--/
209
-
210
- conditional = text =~ /\[if .*\]/
211
-
212
- rawtext "<!--"
213
- rawtext text
214
- rawtext ">" if conditional
215
-
216
- if block_given?
217
- rawtext "\n"
218
- yield
219
- rawtext "\n"
220
- end
221
-
222
- rawtext "<![endif]" if conditional
223
- rawtext "-->\n"
224
- end
225
-
226
- # Emits a javascript block inside a +script+ tag, wrapped in CDATA
227
- # doohickeys like all the cool JS kids do.
228
- def javascript(value = nil, attributes = {})
229
- if value.is_a?(Hash)
230
- attributes = value
231
- value = nil
232
- elsif block_given? && value
233
- raise ArgumentError, "You can't pass both a block and a value to javascript -- please choose one."
234
- end
235
-
236
- script(attributes.merge(:type => "text/javascript")) do
237
- # Shouldn't this be a "cdata" HtmlPart?
238
- # (maybe, but the syntax is specific to javascript; it isn't
239
- # really a generic XML CDATA section. Specifically,
240
- # ]]> within value is not treated as ending the
241
- # CDATA section by Firefox2 when parsing text/html,
242
- # although I guess we could refuse to generate ]]>
243
- # there, for the benefit of XML/XHTML parsers).
244
- output << raw("\n// <![CDATA[\n")
245
- if block_given?
246
- yield
247
- else
248
- output << raw(value)
249
- end
250
- output << raw("\n// ]]>")
251
- output.append_newline # this forces a newline even if we're not in pretty mode
252
- end
253
-
254
- output << raw("\n")
255
- end
256
-
257
- protected
258
- def __element__(raw, tag_name, *args, &block)
259
- if args.length > 2
260
- raise ArgumentError, "Cannot accept more than four arguments"
261
- end
262
- attributes, value = nil, nil
263
- arg0 = args[0]
264
- if arg0.is_a?(Hash)
265
- attributes = arg0
266
- else
267
- value = arg0
268
- arg1 = args[1]
269
- if arg1.is_a?(Hash)
270
- attributes = arg1
271
- end
272
- end
273
- attributes ||= {}
274
- open_tag tag_name, attributes
275
- begin
276
- if block && value
277
- raise ArgumentError, "You can't pass both a block and a value to #{tag_name} -- please choose one."
278
- end
279
- if block
280
- block.call
281
- elsif raw
282
- text! value
283
- else
284
- text value
285
- end
286
- ensure
287
- close_tag tag_name
288
- end
289
- end
290
-
291
- def __empty_element__(tag_name, attributes={})
292
- output << raw("<#{tag_name}#{format_attributes(attributes)} />")
293
- output.newline if newliney?(tag_name)
294
- end
295
-
296
- def format_attributes(attributes)
297
- if !attributes || attributes.empty?
298
- ""
299
- else
300
- format_sorted(sorted(attributes))
301
- end
302
- end
303
-
304
- def format_sorted(sorted)
305
- results = ['']
306
- sorted.each do |key, value|
307
- if value
308
- if value.is_a?(Array)
309
- value = value.flatten
310
- next if value.empty?
311
- value = value.join(' ')
312
- end
313
- results << "#{key}=\"#{h(value)}\""
314
- end
315
- end
316
- results.join(' ')
317
- end
318
-
319
- def sorted(attributes)
320
- stringized = []
321
- attributes.each do |key, value|
322
- stringized << [key.to_s, value]
323
- end
324
- stringized.sort
325
- end
326
-
327
- def sort_for_xml_declaration(attributes)
328
- # correct order is "version, encoding, standalone" (XML 1.0 section 2.8).
329
- # But we only try to put version before encoding for now.
330
- stringized = []
331
- attributes.each do |key, value|
332
- stringized << [key.to_s, value]
333
- end
334
- stringized.sort{|a, b| b <=> a}
335
- end
336
9
 
337
- NON_NEWLINEY = {'i' => true, 'b' => true, 'small' => true,
338
- 'img' => true, 'span' => true, 'a' => true,
339
- 'input' => true, 'textarea' => true, 'button' => true, 'select' => true
340
- }
341
10
 
342
- def newliney?(tag_name)
343
- !NON_NEWLINEY.include?(tag_name)
344
- end
345
11
  end
346
12
  end