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.
- data/CHANGELOG +11 -0
- data/Manifest +41 -0
- data/README +14 -0
- data/Rakefile +47 -0
- data/init.rb +2 -0
- data/install.rb +0 -0
- data/install_files/javascripts/iepngfix.htc +193 -0
- data/install_files/javascripts/iepngfix_tilebg.js +155 -0
- data/install_files/stylesheets/reset.css +47 -0
- data/install_files/templates/example_presenter.rb +12 -0
- data/install_files/templates/example_stylesheet.css.rb +20 -0
- data/lib/rubygems/commands/shway_init_command.rb +112 -0
- data/lib/rubygems_plugin.rb +3 -0
- data/lib/shway/controllers/shway_controller.rb +22 -0
- data/lib/shway/css/css_helper.rb +221 -0
- data/lib/shway/css/css_parser.rb +155 -0
- data/lib/shway/css/css_styles.rb +368 -0
- data/lib/shway/extensions/routing_extensions.rb +22 -0
- data/lib/shway/helpers/html_helper.rb +54 -0
- data/lib/shway/helpers/shway_controller_helper.rb +51 -0
- data/lib/shway/helpers/shway_helper.rb +187 -0
- data/lib/shway/presenters/shway_model_presenter.rb +10 -0
- data/lib/shway/presenters/shway_presenter.rb +184 -0
- data/lib/shway/test/shway_test_helper.rb +78 -0
- data/lib/shway.rb +129 -0
- data/shway.gemspec +31 -0
- data/templates/css.html.erb +3 -0
- data/templates/css.rhtml +3 -0
- data/test/shway_core/css_config_test.rb +186 -0
- data/test/shway_core/css_helper_test.rb +655 -0
- data/test/shway_core/css_parser_test.rb +219 -0
- data/test/shway_core/html_helper_test.rb +32 -0
- data/test/shway_core/shway_controller_test.rb +44 -0
- data/test/shway_core/shway_core_test_helper.rb +45 -0
- data/test/shway_core/shway_helper_test.rb +280 -0
- data/test/shway_core/shway_presenter_test.rb +173 -0
- data/test/shway_core/shway_routes_test.rb +31 -0
- data/test/shway_core/views/mock_foos/_list_header.html.erb +1 -0
- data/test/shway_core/views/mock_foos/_list_item.html.erb +5 -0
- data/test/shway_core/views/model_list/list_for_action.html.erb +1 -0
- data/test/shway_core/views/model_list/list_item_for_action.html.erb +1 -0
- data/test/shway_core/views/shway_helper_test.html.erb +24 -0
- 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
|