shway 3.0

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 (43) hide show
  1. data/CHANGELOG +11 -0
  2. data/Manifest +41 -0
  3. data/README +14 -0
  4. data/Rakefile +47 -0
  5. data/init.rb +2 -0
  6. data/install.rb +0 -0
  7. data/install_files/javascripts/iepngfix.htc +193 -0
  8. data/install_files/javascripts/iepngfix_tilebg.js +155 -0
  9. data/install_files/stylesheets/reset.css +47 -0
  10. data/install_files/templates/example_presenter.rb +12 -0
  11. data/install_files/templates/example_stylesheet.css.rb +20 -0
  12. data/lib/rubygems/commands/shway_init_command.rb +112 -0
  13. data/lib/rubygems_plugin.rb +3 -0
  14. data/lib/shway/controllers/shway_controller.rb +22 -0
  15. data/lib/shway/css/css_helper.rb +221 -0
  16. data/lib/shway/css/css_parser.rb +155 -0
  17. data/lib/shway/css/css_styles.rb +368 -0
  18. data/lib/shway/extensions/routing_extensions.rb +22 -0
  19. data/lib/shway/helpers/html_helper.rb +54 -0
  20. data/lib/shway/helpers/shway_controller_helper.rb +51 -0
  21. data/lib/shway/helpers/shway_helper.rb +187 -0
  22. data/lib/shway/presenters/shway_model_presenter.rb +10 -0
  23. data/lib/shway/presenters/shway_presenter.rb +184 -0
  24. data/lib/shway/test/shway_test_helper.rb +78 -0
  25. data/lib/shway.rb +129 -0
  26. data/shway.gemspec +31 -0
  27. data/templates/css.html.erb +3 -0
  28. data/templates/css.rhtml +3 -0
  29. data/test/shway_core/css_config_test.rb +186 -0
  30. data/test/shway_core/css_helper_test.rb +655 -0
  31. data/test/shway_core/css_parser_test.rb +219 -0
  32. data/test/shway_core/html_helper_test.rb +32 -0
  33. data/test/shway_core/shway_controller_test.rb +44 -0
  34. data/test/shway_core/shway_core_test_helper.rb +45 -0
  35. data/test/shway_core/shway_helper_test.rb +280 -0
  36. data/test/shway_core/shway_presenter_test.rb +173 -0
  37. data/test/shway_core/shway_routes_test.rb +31 -0
  38. data/test/shway_core/views/mock_foos/_list_header.html.erb +1 -0
  39. data/test/shway_core/views/mock_foos/_list_item.html.erb +5 -0
  40. data/test/shway_core/views/model_list/list_for_action.html.erb +1 -0
  41. data/test/shway_core/views/model_list/list_item_for_action.html.erb +1 -0
  42. data/test/shway_core/views/shway_helper_test.html.erb +24 -0
  43. metadata +123 -0
@@ -0,0 +1,368 @@
1
+ module Shway
2
+
3
+ def self.define_styles(&block)
4
+ Shway::Css::CssStyles.class_eval &block
5
+ end
6
+
7
+
8
+ module Css
9
+
10
+ #this has changed to no longer accept strings, you must use hashes.
11
+ #I suppose I could parse strings.... I'll do that when I actually need it.
12
+ #you can supply the symbol for a previously defined hash or a new hash
13
+ class CssStyles
14
+ @@css_pseudo_classes = [:link,:visited,:active,:hover]
15
+
16
+ class << self
17
+
18
+ def load_styles
19
+ path = File.join(RAILS_ROOT, 'app', 'stylesheets')
20
+ load_styles_from(path) if File.exist?(path)
21
+ end
22
+
23
+ def load_styles_from(dir)
24
+ return unless File.directory?(dir)
25
+ Dir.glob(File.join(dir, "*.css.rb")).sort.each do |file|
26
+ load file
27
+ # CssStyles.class_eval(File.read(file))
28
+ end
29
+ end
30
+
31
+ def reload_styles
32
+ clear_styles
33
+ load_styles
34
+ end
35
+
36
+ def clear_styles
37
+ @@css_segments = {}
38
+ @@css_hashes = {}
39
+ @@css_caches = {}
40
+ @@css_styles = {}
41
+ @@css_styles[:main] = {}
42
+ @@css_styles[:ie7] = {}
43
+ @@css_styles[:ie6] = {}
44
+ @@css_styles[:safari] = {}
45
+ @@css_values = {}
46
+ @@css_configs = {}
47
+ @@css_finalized_configs = {}
48
+ @@included_styles = []
49
+ #this is just a list of tag style names (with the preceding tag__) so we can find them among the other styles
50
+ @@css_tag_styles = []
51
+ end
52
+
53
+ def cache
54
+ @@css_caches
55
+ end
56
+
57
+ #for now, for simplicity, we're just prefixing the tag name with tag__, storing the name in an array, and doing the rest as normal
58
+ #hopefully this makes things easier, but I plan on making this nicer at some point
59
+ def css_tag_style(tag_name, *css_hashes)
60
+ tag_name = "tag__#{tag_name.to_s}"
61
+ if @@css_tag_styles.include? tag_name
62
+ # puts "**WARNING: css_tag_style already defined for '#{tag_name}'"
63
+ else
64
+ @@css_tag_styles << tag_name
65
+ end
66
+ css_style(tag_name, *css_hashes)
67
+ end
68
+ def selector(selector, *css_hashes)
69
+ css_tag_style(selector, *css_hashes)
70
+ end
71
+
72
+ #TODO name this better. These styles are the ones we DON'T want to raise an error if they aren't defined.
73
+ def include_style(*css_names)
74
+ css_names.each do |name|
75
+ @@included_styles << name unless @@included_styles.include? name
76
+ end
77
+ end
78
+
79
+ #TODO this is mostly just for testing for now. Should I reload all the styles on each test somehow?
80
+ def remove_style(*css_names)
81
+ css_names.each do |name|
82
+ @@included_styles.delete name if @@included_styles.include? name
83
+ end
84
+ end
85
+
86
+ def style(name, *css_hashes)
87
+ include_style(name) #TODO just added this so that empty style hashes will still add the style
88
+ css_style(name, *css_hashes)
89
+ end
90
+ def css_style(name, *css_hashes)
91
+ raise "You must supply a name to 'css_style', not just a hash." if name.kind_of?(Hash)
92
+ name = name.to_s
93
+ #TODO make this logging optional. but turn it off for now.
94
+ # puts "**WARNING: css_style already defined for '#{name}'" if name.index('tag__') != 0 && @@css_hashes[name]
95
+ style_segments = []
96
+ style_hash = {}
97
+ #this is here so that the blank? checks won't fail on things that contain only links or pseudo styles, which both get extracted.
98
+ css_hashes << {:use_style => true}
99
+ #all actual hashes (not references/symbols) passed in are merged together to form a single "segment"
100
+ #this way any brower specific hash keys are merged into the segment, and the segments can be treated the same as typical style hashes.
101
+ references_and_merged_hashes = []
102
+ merged_hashes = {}
103
+ css_hashes.each do |symbol_or_hash|
104
+ if symbol_or_hash.kind_of? Symbol
105
+ references_and_merged_hashes << symbol_or_hash
106
+ else
107
+ raise "You can't merge in a nil hash to a css_style ('#{name}')" unless symbol_or_hash
108
+ raise "You must pass a Symbol or a hash to css_style. You passed a #{symbol_or_hash.class}" unless symbol_or_hash.kind_of? Hash
109
+ merge_style_hashes!(merged_hashes,symbol_or_hash)
110
+ end
111
+ end
112
+
113
+ references_and_merged_hashes << merged_hashes
114
+ #NOTE that this way of looping and merging means you don't need to clone incoming hashes that may be shared outside of here
115
+ references_and_merged_hashes.each do |hash|
116
+ style_segments << hash
117
+ if hash.kind_of? Symbol
118
+ style_reference = hash.to_s
119
+ hash = @@css_hashes[style_reference]
120
+ raise "Shway has no style defined for the reference '#{style_reference.inspect}'." unless hash
121
+ end
122
+ merge_style_hashes!(style_hash,hash)
123
+ end
124
+ @@css_segments[name] = style_segments
125
+ @@css_hashes[name] = style_hash
126
+ # style_is_psuedo_class = @@css_pseudo_classes.include? name.intern
127
+ #extract the various browser hashes and loop over them to build the styles
128
+ for_each_browser_hash style_hash do |browser,browser_hash|
129
+ next unless browser_hash
130
+ #define any pseudo_classes as separate styles in each browser.
131
+ #pseudo classes are appended after a double underscore in the name. eg. text_style__hover = .text_style:hover
132
+ CssStyles.for_each_css_pseudo_class do |pseudo_class|
133
+ pseudo_style = browser_hash[pseudo_class]
134
+ pseudo_style[:use_style] = true if pseudo_style
135
+ @@css_styles[browser]["#{name}__#{pseudo_class}"] = Shway::Css::CssHelper.internal_css_for_hash(browser,pseudo_style) unless pseudo_style.blank?
136
+ end
137
+
138
+ #add styles in each browser, rejecting pseudo styles as they are handled above.
139
+ # do browser specific key/value substitutions here, so that we have access to the other styles:
140
+ if browser_hash.delete :alpha_filter
141
+ raise "alpha_filter can only be specified for an ie6 style. (#{name})" unless browser == :ie6
142
+ background = style_hash[:background]
143
+ raise "alpha_filter can only be specified for a style with a background supplied in its main style. (#{name})" unless background
144
+ browser_hash[:background_image] = :none
145
+ #"url(/images/shirt_mask_small.png) no-repeat" =~ /\((.*)\)/
146
+ match = /\((.*)\)/.match(background)
147
+ raise "alpha_filter can only be specified for a background of the form url(/path/image_name.png). (#{background})" unless match
148
+ background = match[1]
149
+ browser_hash[:filter] = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='#{background}',sizingMethod='image');"
150
+ end
151
+ @@css_styles[browser][name] = Shway::Css::CssHelper.internal_css_for_hash(browser,reject_pseudo_class_styles(browser_hash))
152
+ end
153
+ end
154
+
155
+ #since the style hases nest other hashes (browser hashes and pseudo class hashes) the merge needs to account for those specially.
156
+ def merge_style_hashes!(hash_one, hash_two)
157
+ #allow for symbols as the second hash
158
+ hash_two = @@css_hashes[hash_two.to_s] if hash_two.kind_of? Symbol
159
+
160
+ #first we get all the hash_two styles separated into discreet browser style_hashes
161
+ hash_two_processed = {}
162
+ for_each_browser_hash hash_two do |key,browser_hash|
163
+ if browser_hash
164
+ #allow for symbols
165
+ browser_hash = @@css_hashes[browser_hash.to_s] if browser_hash.kind_of? Symbol
166
+ hash_two_processed[key] = browser_hash
167
+ end
168
+ end
169
+ #then we loop over hash_one and merge things in
170
+ for_each_browser_hash hash_one do |key,browser_hash|
171
+ next unless hash_two_processed[key]
172
+ if key == :main
173
+ #point to the main hash itself so that the merge! will work (reject returns a copy)
174
+ browser_hash = hash_one
175
+ else
176
+ #initialize the browser hash (except for main, since it always exists, and we don't want a :main => {} entry in our style)
177
+ browser_hash ||= {}
178
+ hash_one[key] ||= browser_hash
179
+ end
180
+ #TODO idea... could I just loop and only merge things that aren't hashes? and then merge the hashes with their counterpart? nested? seems messy.
181
+ #merge in everything but the pseudo classes, since they are hashes.
182
+ browser_hash.merge! reject_pseudo_class_styles(hash_two_processed[key])
183
+ #now merge the pseudo classes
184
+ CssStyles.for_each_css_pseudo_class do |pseudo_class|
185
+ next unless hash_two_processed[key][pseudo_class]
186
+ browser_hash[pseudo_class] ||= {}
187
+ pseudo_hash = hash_two_processed[key][pseudo_class]
188
+ #allow for symbols as the pseudo_hash
189
+ pseudo_hash = @@css_hashes[pseudo_hash.to_s] if pseudo_hash.kind_of? Symbol
190
+ browser_hash[pseudo_class].merge! pseudo_hash if pseudo_hash
191
+ end
192
+ end
193
+ end
194
+
195
+ # **CONVERT ALL OF THIS TO USE CssStyle class, and fix this weird bug while I'm at it'
196
+ def for_each_browser_hash(style_hash, &block)
197
+ #extract the various browser hashes and loop over them
198
+ { :ie7 => style_hash[:ie7],
199
+ :ie6 => style_hash[:ie6],
200
+ :safari => style_hash[:safari],
201
+ :main => style_hash.reject {|key, value| [:ie7,:ie6,:safari].include? key }
202
+ }.each do |key,browser_hash|
203
+ yield key,browser_hash
204
+ end
205
+ end
206
+
207
+ def reject_pseudo_class_styles(style_hash)
208
+ return nil unless style_hash
209
+ style_hash.reject {|key, value| @@css_pseudo_classes.include? key }
210
+ end
211
+
212
+ def for_each_css_pseudo_class(&block)
213
+ @@css_pseudo_classes.each do |pseudo_class|
214
+ yield pseudo_class
215
+ end
216
+ end
217
+
218
+ def value(args)
219
+ values(args)
220
+ end
221
+ def values(args)
222
+ args.each do |key,value|
223
+ # puts "**WARNING: css_value already defined for '#{key}'" if @@css_values[key.to_s]
224
+ @@css_values[key.to_s] = value
225
+ end
226
+ end
227
+
228
+ def css_config(name, config_hash)
229
+ name = name.to_s
230
+ merged_hash = @@css_configs[name] || {}
231
+ merged_hash = merged_hash.merge config_hash
232
+ @@css_configs[name] = merged_hash
233
+ end
234
+
235
+ def finalize_css_config(name)
236
+ return unless @@css_configs[name]
237
+ config = @@css_configs[name].clone
238
+ config.each do |key,value|
239
+ config[key] = get_css_value_or_symbol(value) if value.kind_of? Symbol
240
+ end
241
+ @@css_finalized_configs[name] = config
242
+ end
243
+
244
+ def css_style_exists?(name,browser=nil)
245
+ name = name.to_s
246
+ pseudo_class = nil
247
+ for_each_css_pseudo_class do |pc|
248
+ if name =~ /__#{pc}$/
249
+ pseudo_class = pc
250
+ name = name.chomp "__#{pc}"
251
+ break
252
+ end
253
+ end
254
+ if pseudo_class
255
+ style_hash = @@css_hashes[name][pseudo_class]
256
+ else
257
+ style_hash = @@css_hashes[name]
258
+ end
259
+
260
+ return false if style_hash.blank?
261
+ case browser
262
+ when :ie7
263
+ style_hash = style_hash[:ie7]
264
+ when :ie6
265
+ style_hash = style_hash[:ie6]
266
+ when :safari
267
+ style_hash = style_hash[:safari]
268
+ end
269
+ #if it's the main hash, and anything is defined, then include it
270
+ !style_hash.blank?
271
+ end
272
+
273
+ def get_css_style(name,browser=nil)
274
+ name = name.intern if name.respond_to? :intern
275
+ exists = css_style_exists?(name,browser)
276
+ raise "Shway has no style defined for: #{name.inspect}" unless css_style_exists?(name,browser) || @@included_styles.include?(name)
277
+ style = shared_get_css_style(name,browser)
278
+ style
279
+ end
280
+
281
+ #return the name (to_s) if the value isn't set. Useful for things like :bold, :right, :auto, etc.
282
+ def get_css_value(name)
283
+ name = name.to_s
284
+ value = @@css_values[name] ? @@css_values[name] : name.dasherize
285
+ end
286
+
287
+ #this method keeps the given name intact instead of converting it to a string
288
+ def get_css_value_or_symbol(name)
289
+ key = name.to_s
290
+ value = @@css_values[key] ? @@css_values[key] : name
291
+ end
292
+
293
+ def get_css_config(name)
294
+ name = name.to_s
295
+ finalize_css_config name unless @@css_finalized_configs[name]
296
+ raise "There is no css config for the name given. (#{name})" unless @@css_finalized_configs[name]
297
+ @@css_finalized_configs[name]
298
+ end
299
+
300
+ def get_css_hash(name)
301
+ name = name.to_s
302
+ #TODO get rid of this :use_style hack eventually in a nice refactor.
303
+ if @@css_hashes[name]
304
+ hash = @@css_hashes[name]
305
+ hash.delete :use_style
306
+ hash
307
+ else
308
+ nil
309
+ end
310
+ end
311
+
312
+ def css_styles_from_namespace_stylesheet(stylesheet)
313
+ css_browser = browser_for_stylesheet(stylesheet)
314
+ #for now, we're ignoring the namespace and just returning ALL styles... so there is currently only a global namespace
315
+ # namespace = stylesheet.gsub('stylesheets/','\'').chomp("-#{css_browser}")
316
+ #this is obviously a hack. I REALLY need to get rid of these hashes and use CssStyle objects.
317
+ styles = @@css_styles[css_browser].keys.delete_if do |style_name|
318
+ is_pseudo_class = false
319
+ %w{__link __visited __active __hover}.each do |pseudo_class|
320
+ next unless style_name.chomp(pseudo_class) != style_name
321
+ is_pseudo_class = true
322
+ break;
323
+ end
324
+ is_pseudo_class
325
+ end
326
+
327
+ return styles,css_browser
328
+ end
329
+
330
+ def browser_for_stylesheet(stylesheet)
331
+ css_browser = nil
332
+ [:main,:safari,:ie6,:ie7].each do |browser|
333
+ browser_string = "-#{browser}"
334
+ if stylesheet.rindex(browser_string) == stylesheet.length-browser_string.length
335
+ css_browser = browser
336
+ stylesheet.chomp! browser_string
337
+ break;
338
+ end
339
+ end
340
+ css_browser || :main
341
+ end
342
+
343
+ private
344
+
345
+ def shared_get_css_style(name,browser=nil)
346
+ browser_styles = nil
347
+ case browser
348
+ when :ie7
349
+ browser_styles = @@css_styles[:ie7]
350
+ when :ie6
351
+ browser_styles = @@css_styles[:ie6]
352
+ when :safari
353
+ browser_styles = @@css_styles[:safari]
354
+ else
355
+ browser_styles = @@css_styles[:main]
356
+ end
357
+ browser_styles[name.to_s]
358
+ end
359
+
360
+ end
361
+
362
+ clear_styles
363
+
364
+ end #class CssStyles
365
+
366
+ end
367
+
368
+ end
@@ -0,0 +1,22 @@
1
+ module Shway
2
+
3
+ module Extensions
4
+
5
+ module Routing
6
+
7
+ module MapperExtensions
8
+
9
+ def shway_css(options={})
10
+ with_options(:controller => "shway") do |shway_map|
11
+ shway_map.css '/stylesheets/:css.css', :action => 'css'
12
+ # shway_map.css_style_reload '/css_reload', :action => 'css_style_reload'
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,54 @@
1
+ module Shway
2
+
3
+ module Helpers
4
+
5
+ #various html/css helpers. counters. default_head_contents, etc.
6
+ module HtmlHelper
7
+
8
+ def css_namespace_stylesheet(namespace,browser=nil)
9
+ namespace = "#{namespace}-#{browser}" if browser
10
+ namespace
11
+ end
12
+
13
+ def html_attribute(name, value)
14
+ value ? %{#{name}="#{value}"} : ''
15
+ end
16
+
17
+ def default_head_contents(*args)
18
+ stylesheet,main_stylesheet,hash = ShwayHelper.arrange_args 3, *args
19
+ main_stylesheet = true if main_stylesheet.nil?
20
+ html = []
21
+ html << %{
22
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
23
+ <meta http-equiv="Pragma" content="no-cache" />
24
+ <meta http-equiv="Expires" content="-1" />
25
+ #{javascript_include_tag :defaults}
26
+ }
27
+ #eventually these will need to get the namespace and set it here. For now it's all global so it doesn't matter what it's called.
28
+ namespace = 'global'
29
+ html << %{
30
+ #{stylesheet_link_tag('shway/reset')}
31
+ #{stylesheet_link_tag(css_namespace_stylesheet(namespace, :main))}
32
+ <!--[if lt IE 7]> #{stylesheet_link_tag(css_namespace_stylesheet(namespace, :ie6))}<![endif]-->
33
+ <!--[if IE 7]> #{stylesheet_link_tag(css_namespace_stylesheet(namespace, :ie7))}<![endif]-->
34
+ }
35
+ html << javascript_tag(%{
36
+ function isSafari(){
37
+ var app = navigator.userAgent;
38
+ if (app.indexOf('Safari') != -1) {
39
+ document.write(" #{stylesheet_link_tag(css_namespace_stylesheet(namespace, :safari)).gsub('"','\"')} ");
40
+ }
41
+ }
42
+ isSafari();
43
+ })
44
+ html << %{
45
+ <script type="text/javascript" src="/javascripts/shway/iepngfix_tilebg.js"></script>
46
+ }
47
+ html.join
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,51 @@
1
+ module Shway
2
+
3
+ module Helpers
4
+
5
+ module ShwayControllerHelper #this is not named ShwayHelper since we want ShwayHelper to be used for other things throughout apps.
6
+
7
+ def css_page_for_filename(filename)
8
+ styles, browser = Shway::Css::CssHelper.css_styles_from_namespace_stylesheet(filename)
9
+ generate_css_page(styles, browser)
10
+ end
11
+
12
+ private
13
+
14
+ def generate_css_page(styles,browser)
15
+ #always add the pseudo classes since they aren't explicitly referenced with div(:hover), etc.
16
+ # styles.concat %w{__link __visited __active __hover}
17
+ css_styles = []
18
+ styles.each do |style_name|
19
+ next unless Shway::Css::CssStyles.css_style_exists?(style_name,browser)
20
+ style = Shway::Css::CssStyles.get_css_style(style_name,browser)
21
+ if (style_name.index('tag__') == 0)
22
+ name = style_name[5..style_name.size]
23
+ css_styles << "#{name} {#{style}}"# unless style.blank?
24
+ #for now we check for pseudo classes by looping. This could all be much better.
25
+ Shway::Css::CssStyles.for_each_css_pseudo_class do |pseudo_class|
26
+ css_pseudo_class_name = "#{style_name}__#{pseudo_class}"
27
+ if Shway::Css::CssStyles.css_style_exists?(css_pseudo_class_name,browser)
28
+ pseudo_style = Shway::Css::CssStyles.get_css_style(css_pseudo_class_name,browser)
29
+ css_styles << "#{name}:#{pseudo_class} {#{pseudo_style}}"
30
+ end
31
+ end
32
+ else
33
+ css_styles << ".#{style_name} {#{style}}"# unless style.blank?
34
+ #for now we check for pseudo classes by looping. This could all be much better.
35
+ Shway::Css::CssStyles.for_each_css_pseudo_class do |pseudo_class|
36
+ css_pseudo_class_name = "#{style_name}__#{pseudo_class}"
37
+ if Shway::Css::CssStyles.css_style_exists?(css_pseudo_class_name,browser)
38
+ pseudo_style = Shway::Css::CssStyles.get_css_style(css_pseudo_class_name,browser)
39
+ css_styles << ".#{style_name} a:#{pseudo_class} {#{pseudo_style}}"
40
+ end
41
+ end
42
+ end
43
+ end
44
+ css_styles.join("\n")
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,187 @@
1
+ module Shway
2
+
3
+ module Helpers
4
+
5
+ module ShwayHelper
6
+
7
+
8
+ def presenter(options={}, &block)
9
+ #the current_shway_presenter is set up by a before filter and stored on the controller. So we need to get there depending on where this module was included.
10
+ current_shway_presenter = if @current_shway_presenter
11
+ @current_shway_presenter
12
+ elsif self.kind_of? ActionView::Base
13
+ self.controller.instance_variable_get :@current_shway_presenter
14
+ elsif self.kind_of? ActionController::Base
15
+ self.instance_variable_get :@current_shway_presenter
16
+ elsif self.kind_of? ShwayPresenter
17
+ self.shared_instance_variable :@current_shway_presenter
18
+ else
19
+ raise "the current_shway_presenter could not be found. Be sure not to override the before_filter method 'setup_shway_presenter'."
20
+ end
21
+ current_shway_presenter.setup_options options
22
+ yield current_shway_presenter if block
23
+ current_shway_presenter
24
+ end
25
+
26
+
27
+ %w{div span body ul ol li h1 h2 h3 h4 h5 h6 b hr table tr th td a}.each do |tag|
28
+ class_eval %{
29
+ def #{tag}(name=nil,options={}, &block)
30
+ render_tag '#{tag}', name, options, &block
31
+ end
32
+ def _#{tag}(options={})
33
+ comment = options.delete :comment
34
+ comment = "<!-- // \#{comment} -->" if comment
35
+ "</#{tag}>\#{comment}"
36
+ end
37
+ }
38
+ end
39
+
40
+ #NOTE this sort of goes with form_for_tag, which is in shway_control, but I think this is an ok place for it.
41
+ def _form
42
+ '</form>'
43
+ end
44
+
45
+ def _br
46
+ '<BR />'
47
+ end
48
+
49
+ def css_class_for(model)
50
+ model.class.name.underscore
51
+ end
52
+
53
+ #this will create an id that looks like model_name_12.
54
+ #If a css_class is provided, it will be prepended like so: css_class_name_model_name_12. This allows you to have unique ids for different segments based on the same model.
55
+ def css_id_for(model, css_class=nil)
56
+ model_id = "#{css_class ? "#{css_class}_" : nil}#{css_class_for(model)}_#{model.id}"
57
+ end
58
+
59
+ #this allows us to render things in either a controller or helper consistently
60
+ def render_partial_to_string(options={})
61
+ if respond_to? :render_to_string
62
+ render_to_string :partial => options[:partial], :locals => options[:locals]
63
+ else
64
+ render :partial => options[:partial], :locals => options[:locals]
65
+ end
66
+ end
67
+
68
+ def render_tag(type, name=nil, options={}, &block)
69
+ raise "Shway no longer accepts blocks to the #{type} method." if block_given?
70
+ if (name.kind_of? Hash)
71
+ options = name
72
+ name = nil
73
+ end
74
+ options = options.clone
75
+
76
+ if options[:for]
77
+ model = options.delete(:for)
78
+ raise "render_tag :for expects an ActiveRecord::Base model object. (#{model.class.name} was given)" unless model.kind_of? ActiveRecord::Base
79
+ raise "render_tag :for cannot be used when an :id is specified. (:#{options[:id]} was specified)" if options[:id]
80
+ id = css_id_for(model, name)
81
+ name ||= css_class_for(model)
82
+ end
83
+
84
+ id ||= options.delete(:id)
85
+ class_name ||= options.delete(:class)
86
+
87
+ onclick = options.delete(:onclick)
88
+ onload = options.delete(:onload)
89
+ text = options.delete(:text)
90
+ raise "You can supply :text or :partial when rendering a tag with Shway, but not both." if text && options[:partial]
91
+ text = render_partial_to_string(:partial => options.delete(:partial), :locals => options.delete(:locals)) if options[:partial]
92
+ close = options.delete(:close)
93
+ style = options.delete(:style) || ''
94
+ cellpadding = options.delete(:cellpadding)
95
+ cellspacing = options.delete(:cellspacing)
96
+ rowspan = options.delete(:rowspan)
97
+ colspan = options.delete(:colspan)
98
+ href = options.delete(:href)
99
+ nowrap = options.delete(:nowrap)
100
+ align = options.delete(:align)
101
+ valign = options.delete(:valign)
102
+ title = options.delete(:title)
103
+ #merge :additional_classes and :additional_class into a single array of classes
104
+ options[:additional_classes] = [options[:additional_classes]] unless options[:additional_classes].is_a?(Array)
105
+ options[:additional_class] = [options[:additional_class]] unless options[:additional_class].is_a?(Array)
106
+ additional_classes = options.delete(:additional_classes).compact.concat options.delete(:additional_class).compact
107
+ raise "You can't specify a name and a class for a tag: (:#{name}, :class => #{class_name})" if name && class_name
108
+ class_name ||= name
109
+ class_name = [class_name].concat(additional_classes).join ' '
110
+
111
+ html = []
112
+ html << %{<#{type.to_s}}
113
+ html << %{ id="#{id}"} unless id.blank?
114
+ html << %{ cellpadding="#{cellpadding}"} unless cellpadding.blank?
115
+ html << %{ cellspacing="#{cellspacing}"} unless cellspacing.blank?
116
+ html << %{ rowspan="#{rowspan}"} unless rowspan.blank?
117
+ html << %{ colspan="#{colspan}"} unless colspan.blank?
118
+ html << %{ align="#{align}"} unless align.blank?
119
+ html << %{ href="#{href == :void ? "javascript:void(0)" : href}"} unless href.blank?
120
+ html << %{ nowrap} if nowrap
121
+ html << %{ valign="#{valign}"} unless valign.blank?
122
+ html << %{ title="#{title}"} unless title.blank?
123
+ #we just call this to allow it to raise the exception if its needed. I know, I know.. add a beter method. I will later.
124
+ Shway::Css::CssStyles.get_css_style(name) unless name.blank?
125
+ html << %{ class="#{class_name}"} unless class_name.blank?
126
+ html << %{ style="#{style};#{css_for_hash(options)}"} unless options.blank? && style.blank?
127
+ html << %{ onclick="#{onclick}"} unless onclick.blank?
128
+ html << %{ onload="#{onload}"} unless onload.blank?
129
+ html << '>'
130
+ html << text unless text.blank?
131
+ # html << capture(&block) if block_given?
132
+ html << %{</#{type.to_s}>} if text || close
133
+ html.join
134
+ end
135
+
136
+ def get_css_value(name)
137
+ Shway::Css::CssStyles.get_css_value(name)
138
+ end
139
+
140
+ def get_css_style(name)
141
+ Shway::Css::CssStyles.get_css_style(name)
142
+ end
143
+
144
+ def get_css_config(name)
145
+ Shway::Css::CssStyles.get_css_config(name)
146
+ end
147
+
148
+ def get_css_hash(name)
149
+ Shway::Css::CssStyles.get_css_hash(name)
150
+ end
151
+
152
+ def arrange_args(count, *args)
153
+ ShwayHelper.arrange_args(count, *args)
154
+ end
155
+ ######################################
156
+ # ARGUMENT MANIPULATION
157
+ # these let you manipulate method arguments so you can create flexible method ignatures more easily
158
+ ######################################
159
+
160
+ #this method lets you define a bunch of nil arguments in a method signature, and then push the first Hash to the last argument.
161
+ #this allows you to have optional parameters that you can leave off, but still collect the end hash correctly.
162
+ #normally you have to do this with a series of "if nil" checks, or the somewhat non-trivial technique we have here.
163
+ #so the method ignatures can be more flexible, without a ton of parameter manipulating at the top
164
+ #EX: id,a,b,c,hash = arrange_args 5, *args
165
+ #The nuber is the TOTAL number of args, INCLUDING the hash.
166
+ def self.arrange_args(count, *args)
167
+ (count-args.size).times { args.push nil }
168
+ new_args = []
169
+ hash = nil
170
+ args.each do |arg|
171
+ if arg.kind_of? Hash || hash
172
+ hash ||= arg
173
+ new_args.push nil
174
+ else
175
+ new_args.push arg
176
+ end
177
+ end
178
+ new_args.pop
179
+ new_args.push(hash || {})
180
+ return *new_args
181
+ end
182
+
183
+ end
184
+
185
+ end
186
+
187
+ end