storefront 0.3.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/Rakefile +4 -4
  2. data/lib/storefront.rb +22 -35
  3. data/lib/storefront/components/base.rb +99 -0
  4. data/lib/storefront/components/breadcrumb.rb +7 -0
  5. data/lib/storefront/components/button.rb +37 -0
  6. data/lib/storefront/components/definition_list.rb +34 -0
  7. data/lib/storefront/components/definition_list_item.rb +63 -0
  8. data/lib/storefront/components/flash.rb +12 -0
  9. data/lib/storefront/components/footer.rb +19 -0
  10. data/lib/storefront/components/form.rb +82 -0
  11. data/lib/storefront/{form → components/form}/base.rb +3 -3
  12. data/lib/storefront/{form → components/form}/builder.rb +3 -3
  13. data/lib/storefront/{form → components/form}/errors.rb +1 -3
  14. data/lib/storefront/{form → components/form}/field.rb +1 -1
  15. data/lib/storefront/{form → components/form}/fieldset.rb +0 -0
  16. data/lib/storefront/{form → components/form}/hint.rb +0 -0
  17. data/lib/storefront/{form → components/form}/input.rb +7 -5
  18. data/lib/storefront/components/form/inputs.rb +7 -0
  19. data/lib/storefront/{form → components/form}/inputs/checkbox.rb +0 -0
  20. data/lib/storefront/{form → components/form}/inputs/date.rb +0 -0
  21. data/lib/storefront/{form → components/form}/inputs/file.rb +0 -0
  22. data/lib/storefront/{form → components/form}/inputs/hidden.rb +0 -0
  23. data/lib/storefront/{form → components/form}/inputs/radio.rb +0 -0
  24. data/lib/storefront/{form → components/form}/inputs/range.rb +0 -0
  25. data/lib/storefront/{form → components/form}/inputs/select.rb +6 -6
  26. data/lib/storefront/{form → components/form}/inputs/string.rb +0 -0
  27. data/lib/storefront/{form → components/form}/inputs/submit.rb +0 -0
  28. data/lib/storefront/{form → components/form}/inputs/textarea.rb +0 -0
  29. data/lib/storefront/{form → components/form}/inputs/value.rb +0 -0
  30. data/lib/storefront/{form → components/form}/label.rb +1 -1
  31. data/lib/storefront/components/header.rb +73 -0
  32. data/lib/storefront/components/image.rb +12 -0
  33. data/lib/storefront/components/javascript_template.rb +21 -0
  34. data/lib/storefront/components/list.rb +27 -0
  35. data/lib/storefront/components/menu.rb +41 -0
  36. data/lib/storefront/components/nav.rb +78 -0
  37. data/lib/storefront/components/sidebar.rb +23 -0
  38. data/lib/storefront/components/table.rb +232 -0
  39. data/lib/storefront/components/text.rb +29 -0
  40. data/lib/storefront/configuration.rb +53 -5
  41. data/lib/storefront/helpers/cache_helper.rb +37 -19
  42. data/lib/storefront/helpers/component_helper.rb +80 -41
  43. data/lib/storefront/helpers/content_helper.rb +211 -0
  44. data/lib/storefront/helpers/dom_helper.rb +136 -0
  45. data/lib/storefront/helpers/head_helper.rb +277 -205
  46. data/lib/storefront/helpers/model_helper.rb +21 -0
  47. data/lib/storefront/helpers/request_helper.rb +301 -53
  48. data/lib/storefront/helpers/tag_helper.rb +29 -0
  49. data/lib/storefront/{proxies/attribute_proxy.rb → models/attribute.rb} +1 -1
  50. data/lib/storefront/{proxies/model_proxy.rb → models/model.rb} +4 -6
  51. data/lib/storefront/railtie.rb +3 -16
  52. metadata +48 -64
  53. data/lib/storefront/dashboard.rb +0 -185
  54. data/lib/storefront/form.rb +0 -82
  55. data/lib/storefront/helpers/attribute_helper.rb +0 -81
  56. data/lib/storefront/helpers/body_helper.rb +0 -18
  57. data/lib/storefront/helpers/browser_helper.rb +0 -54
  58. data/lib/storefront/helpers/collection_helper.rb +0 -14
  59. data/lib/storefront/helpers/dashboard_helper.rb +0 -29
  60. data/lib/storefront/helpers/debug_helper.rb +0 -11
  61. data/lib/storefront/helpers/definition_list_helper.rb +0 -110
  62. data/lib/storefront/helpers/error_helper.rb +0 -11
  63. data/lib/storefront/helpers/flash_helper.rb +0 -14
  64. data/lib/storefront/helpers/form_helper.rb +0 -13
  65. data/lib/storefront/helpers/format_helper.rb +0 -59
  66. data/lib/storefront/helpers/image_helper.rb +0 -30
  67. data/lib/storefront/helpers/list_helper.rb +0 -135
  68. data/lib/storefront/helpers/locale_helper.rb +0 -245
  69. data/lib/storefront/helpers/open_graph_helper.rb +0 -5
  70. data/lib/storefront/helpers/page_helper.rb +0 -91
  71. data/lib/storefront/helpers/presenter_helper.rb +0 -5
  72. data/lib/storefront/helpers/semantic/location_helper.rb +0 -18
  73. data/lib/storefront/helpers/semantic/time_helper.rb +0 -14
  74. data/lib/storefront/helpers/sidebar_helper.rb +0 -27
  75. data/lib/storefront/helpers/system_helper.rb +0 -18
  76. data/lib/storefront/helpers/table_helper.rb +0 -38
  77. data/lib/storefront/helpers/template_helper.rb +0 -11
  78. data/lib/storefront/helpers/time_helper.rb +0 -21
  79. data/lib/storefront/helpers/url_helper.rb +0 -32
  80. data/lib/storefront/helpers/user_helper.rb +0 -15
  81. data/lib/storefront/helpers/widget_helper.rb +0 -142
  82. data/lib/storefront/helpers/workflow_helper.rb +0 -50
  83. data/lib/storefront/model_helper.rb +0 -17
  84. data/lib/storefront/table.rb +0 -198
  85. data/rails/init.rb +0 -1
  86. data/test/form_helper_test.rb +0 -5
  87. data/test/support/mock_controller.rb +0 -15
  88. data/test/support/mock_response.rb +0 -14
  89. data/test/support/models.rb +0 -0
  90. data/test/test_helper.rb +0 -34
@@ -0,0 +1,211 @@
1
+ module Storefront
2
+ module Helpers
3
+ module ContentHelper
4
+ SCOPES_WITH_NAMESPACE_AND_NESTED_MODEL = [
5
+ '%{namespace}.%{model}.%{nested_model}.%{action}.%{attribute}',
6
+ '%{model}.%{nested_model}.%{action}.%{attribute}',
7
+ '%{namespace}.%{model}.%{action}.%{attribute}',
8
+ '%{model}.%{action}.%{attribute}',
9
+ '%{namespace}.%{model}.%{nested_model}.%{attribute}',
10
+ '%{model}.%{nested_model}.%{attribute}',
11
+ '%{namespace}.%{model}.%{attribute}',
12
+ '%{model}.%{attribute}',
13
+ '%{namespace}.%{nested_model}.%{attribute}',
14
+ '%{nested_model}.%{attribute}',
15
+ '%{namespace}.%{attribute}',
16
+ '%{attribute}'
17
+ ]
18
+
19
+ SCOPES_WITH_NESTED_MODEL = [
20
+ '%{model}.%{nested_model}.%{action}.%{attribute}',
21
+ '%{model}.%{action}.%{attribute}',
22
+ '%{model}.%{nested_model}.%{attribute}',
23
+ '%{model}.%{attribute}',
24
+ '%{nested_model}.%{attribute}',
25
+ '%{attribute}'
26
+ ]
27
+
28
+ SCOPES_WITH_NAMESPACE = [
29
+ '%{namespace}.%{model}.%{action}.%{attribute}',
30
+ '%{namespace}.%{model}.%{attribute}',
31
+ '%{model}.%{action}.%{attribute}',
32
+ '%{model}.%{attribute}',
33
+ '%{namespace}.%{attribute}',
34
+ '%{attribute}'
35
+ ]
36
+
37
+ SCOPES = [
38
+ '%{model}.%{action}.%{attribute}',
39
+ '%{model}.%{attribute}',
40
+ '%{attribute}'
41
+ ]
42
+
43
+ # t?(:"what.summary", :scope => :"reports.titles", :model => deal)
44
+ def t?(key, options = {})
45
+ return key if key.is_a?(::String) || key.blank?
46
+
47
+ models = Storefront::Model.model_names(options[:model] || options[:models] || options[:model_names] || storefront_config.current_scope[:resource] || [])
48
+ models << "" if models.blank?
49
+ namespaces = Array(options[:namespaces] || options[:namespace] || storefront_config.current_scope[:namespace])
50
+ namespaces << "" if namespaces.blank? && !!storefront_config.localize_with_namespace
51
+ action_name = options[:action] || storefront_config.current_scope[:action]
52
+ defaults = []
53
+ allow_blank = options[:allow_blank] == true
54
+ count = options[:count]
55
+ # none, one, many, other
56
+ count_key = count != 1 ? :other : :one
57
+
58
+ keys = [key.to_s]
59
+
60
+ if options.has_key?(:present) || options.has_key?(:past) || options.has_key?(:future)
61
+ if options[:future] == true
62
+ tense_key = :future
63
+ else
64
+ tense_key = (options[:present] == true || options[:past] == false) ? :present : :past
65
+ end
66
+ else
67
+ tense_key = nil
68
+ end
69
+
70
+ if options.has_key?(:nested_model)
71
+ with_nested_model = !!options[:nested_model]
72
+ else
73
+ with_nested_model = !!storefront_config.localize_with_nested_model
74
+ end
75
+
76
+ if options.has_key?(:namespace)
77
+ with_namespace = !!options[:namespace]
78
+ else
79
+ with_namespace = !!storefront_config.localize_with_namespace
80
+ end
81
+
82
+ if with_nested_model && with_namespace
83
+ # TODO, need to performance test before we do this many operations
84
+ SCOPES_WITH_NAMESPACE_AND_NESTED_MODEL
85
+ elsif with_nested_model
86
+ # TODO
87
+ SCOPES_WITH_NESTED_MODEL
88
+ elsif with_namespace
89
+ namespaces.each do |namespace|
90
+ keys.each do |_key|
91
+ SCOPES_WITH_NAMESPACE.each do |_path|
92
+ models.each do |model|
93
+ path = _path.dup
94
+ path.gsub!('%{namespace}', namespace)
95
+ path.gsub!('%{model}', model)
96
+ path.gsub!('%{action}', action_name)
97
+ path.gsub!('%{attribute}', _key)
98
+ path.gsub!('..', '.')
99
+ defaults << path
100
+ end
101
+ end
102
+ end
103
+ end
104
+ else
105
+ keys.each do |_key|
106
+ SCOPES.each do |_path|
107
+ models.each do |model|
108
+ path = _path.dup
109
+ path.gsub!('%{model}', model)
110
+ path.gsub!('%{action}', action_name)
111
+ path.gsub!('%{attribute}', _key)
112
+ path.gsub!('..', '.')
113
+ defaults << path
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ # RESERVED KEYS
120
+ [:past, :present, :future, :allow_blank, :model, :models, :model_names, :action, :nested_model, :namespace, :namespaces].each do |key|
121
+ options.delete(key)
122
+ end
123
+
124
+ defaults.map!(&:to_sym)
125
+ defaults << ''
126
+
127
+ value = I18n.t(defaults.shift, options.merge(:default => defaults))
128
+
129
+ if value.is_a?(::Hash)
130
+ if value.has_key?(count_key)
131
+ value = value[count_key]
132
+ elsif value.has_key?(tense_key)
133
+ value = value[tense_key]
134
+ if value.is_a?(::Hash) && value.has_key?(count_key)
135
+ value = value[count_key]
136
+ end
137
+ elsif value.has_key?(count_key)
138
+ value = value[count_key]
139
+ end
140
+ end
141
+
142
+ if value.is_a?(::Hash)
143
+ if value.has_key?(:one)
144
+ value = value[:one]
145
+ end
146
+ end
147
+
148
+ if value.is_a?(::Hash)
149
+ if value.has_key?(:present)
150
+ value = value[:present]
151
+ elsif value.has_key?(:past)
152
+ value = value[:past]
153
+ elsif value.has_key?(:future)
154
+ value = value[:future]
155
+ end
156
+ end
157
+
158
+ # MORE RESERVED KEYS
159
+ [:scope].each do |key|
160
+ options.delete(key)
161
+ end
162
+
163
+ if value.blank? && !allow_blank
164
+ key.to_s.split(".").last.titleize
165
+ elsif options.present?
166
+ I18n.interpolate(value, options)
167
+ else
168
+ value
169
+ end
170
+ end
171
+
172
+ def rendered_text(string)
173
+ string.to_s.
174
+ gsub(/<\/?[^>]*>/, '').
175
+ gsub(/\n/, " ").
176
+ gsub("\r", " ").
177
+ squeeze(" ").
178
+ gsub(/\"/, "&Prime;"). # convert quotes to inches
179
+ gsub(/\'/, "&prime;"). # single quote to feet
180
+ gsub(/\$0?0*\.(\d+)/, "\\1&cent;").html_safe
181
+ end
182
+
183
+ def sanitize(text)
184
+ text.gsub(/<\/?[^>]*>/, '').gsub(/\n/, " ").gsub("\r", " ").squeeze(" ")
185
+ end
186
+
187
+ def read_binary_file(path)
188
+ File.open(path, 'rb') {|f| f.read }
189
+ end
190
+
191
+ def encoded_contents(path)
192
+ Base64.encode64(read_binary_file(path)).gsub(/\n/, '')
193
+ end
194
+
195
+ def font_face_data_uri(path)
196
+ "url(\"data:font/truetype;base64,#{encoded_contents(path)}\")"
197
+ end
198
+
199
+ # http://snippets.dzone.com/posts/show/805
200
+ def read_image_size(path)
201
+ width, height = IO.read("#{Rails.root}/public/images/#{path}")[0x10..0x18].unpack('NN')
202
+ {:width => width, :height => height}
203
+ end
204
+
205
+ def html5_time(date_or_time)
206
+ return nil if date_or_time.blank?
207
+ date_or_time.acts_like?(:time) ? date_or_time.xmlschema : date_or_time.rfc3339
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,136 @@
1
+ module Storefront
2
+ module Helpers
3
+ # HTML Element Attribute Helper
4
+ module DomHelper
5
+ def clone_attributes(hash)
6
+ result = {}
7
+ return result if hash.blank?
8
+ hash.each do |key, value|
9
+ result[key] = value.is_a?(::Hash) ? clone_attributes(value) : value
10
+ end
11
+ result
12
+ end
13
+
14
+ def merge_class!(attributes, *values)
15
+ return {} if attributes.nil?
16
+ hash = merge_class(attributes, *values)
17
+ attributes[:class] = hash[:class] if hash
18
+ attributes
19
+ end
20
+
21
+ def merge_class(attributes, *values)
22
+ if values.present?
23
+ if attributes[:class].present?
24
+ classes = attributes[:class].split(/\s+/)
25
+ else
26
+ classes = []
27
+ end
28
+ classes += values.compact.map(&:to_s)
29
+ classes.uniq!
30
+ else
31
+ classes = nil
32
+ end
33
+
34
+ if classes.present?
35
+ attributes.merge(:class => classes.join(" "))
36
+ else
37
+ attributes
38
+ end
39
+ end
40
+
41
+ def index_class(index, array_or_length)
42
+ length = array_or_length.is_a?(::Array) ? array_or_length.length : array_or_length
43
+ return nil if length.blank? || (length <= 1)
44
+
45
+ if index == 0
46
+ "first"
47
+ elsif index == length - 1
48
+ "last"
49
+ else
50
+ nil
51
+ end
52
+ end
53
+
54
+ # @example Aria role main.
55
+ #
56
+ # aria(:main) #=> {:role => :main}
57
+ def aria(key)
58
+ {:role => key}
59
+ end
60
+
61
+ # @example Customize <tt><body></tt> tag attributes from inside a partial
62
+ #
63
+ # # app/views/posts/_post.haml
64
+ # - dom :body => {:class => "admin", :id => "admin"}
65
+ #
66
+ # # app/views/layouts/application.haml
67
+ # %body{dom[:body]}
68
+ def dom(attributes = {})
69
+ @dom ||= {}
70
+ @dom.deep_merge!(attributes)
71
+ @dom
72
+ end
73
+
74
+ # calls <tt>model.to_title</tt>
75
+ def page(*args)
76
+ options = args.extract_options!
77
+ title = args.shift
78
+ options[:action] ||= storefront_config.current_scope[:action]
79
+
80
+ title = case title
81
+ when ::String
82
+ title
83
+ when ::Symbol
84
+ t?(title, :scope => :"pages.titles")
85
+ else
86
+ if options[:title].present?
87
+ options[:title]
88
+ else
89
+ parent_name = !!options[:parent] ? resource_to_title(storefront_config.current_scope[:parent], options) : nil
90
+ resource_name = resource_to_title(storefront_config.current_scope[:resource], options)
91
+ [parent_name, resource_name].compact.join(storefront_config.breadcrumb)
92
+ end
93
+ end
94
+
95
+ self.title(options[:browser] || title, options)
96
+
97
+ options = header_widget_options(options.merge(:title => title))
98
+
99
+ options[:header_html].reverse_merge!(:id => storefront_config.page_header_id) if storefront_config.page_header_id.present?
100
+ options[:title_html].reverse_merge!(:id => storefront_config.page_title_id) if storefront_config.page_title_id.present?
101
+ options[:subtitle_html].reverse_merge!(:id => storefront_config.page_subtitle_id) if storefront_config.page_subtitle_id.present?
102
+ options[:level] = 1
103
+ options[:skip_format] = true
104
+
105
+ header_widget options.merge(:title => title)
106
+ end
107
+
108
+ def title_widget(*args, &block)
109
+ options = args.extract_options!
110
+ options[:header_html] ||= {}
111
+ merge_class! options[:header_html], *widget_classes("title-widget")
112
+ header_widget(options, &block)
113
+ end
114
+
115
+ def title_widget_options
116
+
117
+ end
118
+
119
+ def resource_to_title(resource, options = {})
120
+ if resource.present?
121
+
122
+ # handle subdomains as well
123
+ t?(options[:action].to_sym,
124
+ :scope => :"pages.titles",
125
+ :model => Storefront::ModelProxy.model_names(resource),
126
+ :namespaces => storefront_config.current_scope[:namespace],
127
+ :allow_blank => true,
128
+ :action => "",
129
+ :name => resource.is_a?(::Class) ? resource.name.titleize.pluralize : resource.to_title,
130
+ :clazz => resource.is_a?(::Class) ? resource.name.titleize : resource.class.name
131
+ )
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -1,229 +1,301 @@
1
1
  module Storefront
2
- module HeadHelper
3
- def meta_for(post)
4
- result = ""
5
- unless post.title.blank?
6
- result << title(post.title)
7
- result << "\n"
8
- end
9
- unless post.tags.blank?
10
- result << keywords(post.tags.join(", "))
11
- result << "\n"
12
- end
13
- unless post.description.blank?
14
- result << description(post.description)
15
- result << "\n"
16
- end
17
- result
18
- end
19
-
20
- def meta(options = {})
21
- title(options[:title]) if options.has_key?(:title)
22
- description(options[:description]) if options.has_key?(:description)
23
- keywords(options[:keywords]) if options.has_key?(:keywords)
24
- copyright(options[:copyright]) if options.has_key?(:copyright)
25
- end
26
-
27
- def meta_tags(*args)
28
- options = args.extract_options!
29
- site = options[:site] || args.first
30
- result = title_tag(site, options[:title])
31
- result << "\n"
32
- result << content_type_tag
33
- result << "\n"
34
- result << description_tag(options[:description])
35
- result << "\n"
36
- result << keywords_tag(options[:keywords])
37
- result << "\n"
38
- result << copyright_tag(options[:copyright])
39
- result
40
- end
41
-
42
- # country
43
- # classification
44
- # author
45
- # apple-mobile-web-app-capable
46
- # apple-touch-fullscreen
47
- # google-analytics
48
- # Revisit-After
49
- # category
50
- def meta_tag(name, content = '')
51
- tag(:meta, :name => name, :content => content)
52
- end
53
-
54
- def title(string)
55
- @content_for_title = string
56
- end
57
-
58
- def title_tag(*args)
59
- options = args.extract_options!
60
-
61
- site = options[:site] || args.first
62
- # Prefix (leading space)
63
- if options[:prefix]
64
- prefix = options[:prefix]
65
- elsif options[:prefix] === false
66
- prefix = ''
67
- else
68
- prefix = ' '
2
+ module Helpers
3
+ module HeadHelper
4
+ def meta_tags(*args)
5
+ options = args.extract_options!
6
+ options[:site] ||= args.shift
7
+ result = []
8
+ storefront_config.meta_tags.each do |meta_tag_name|
9
+ if options[meta_tag_name].present?
10
+ result << meta_tag(meta_tag_name, options[meta_tag_name])
11
+ end
12
+ end
13
+ result.join("\n")
69
14
  end
70
-
71
- # Separator
72
- unless options[:separator].blank?
73
- separator = options[:separator]
74
- else
75
- separator = '|'
15
+ alias_method :meta, :meta_tags
16
+
17
+ def meta_tag(name, content = '')
18
+ capture_haml { haml_tag :meta, :name => name, :content => content }
76
19
  end
77
-
78
- # Suffix (trailing space)
79
- if options[:suffix]
80
- suffix = options[:suffix]
81
- elsif options[:suffix] === false
82
- suffix = ''
83
- else
84
- suffix = ' '
20
+
21
+ def title(*args)
22
+ @content_for_title = *args
85
23
  end
86
-
87
- # Title
88
- title = @content_for_title
89
- if options[:lowercase] === true
90
- title = title.downcase unless title.blank?
24
+
25
+ def title_tag(*args)
26
+ options = args.extract_options!
27
+ # Title
28
+ title = @content_for_title
29
+
30
+ if title.present?
31
+ options.merge!(title.extract_options!)
32
+ title = @content_for_title.shift || options[:title]
33
+ end
34
+
35
+ if options[:lowercase] === true
36
+ title = title.downcase unless title.blank?
37
+ end
38
+
39
+ site = options.has_key?(:site) ? options[:site] : args.first
40
+
41
+ # Prefix (leading space)
42
+ if options[:prefix]
43
+ prefix = options[:prefix]
44
+ elsif options[:prefix] === false
45
+ prefix = ''
46
+ else
47
+ prefix = ' '
48
+ end
49
+
50
+ # Separator
51
+ unless options[:separator].blank?
52
+ separator = options[:separator]
53
+ else
54
+ separator = '|'
55
+ end
56
+
57
+ # Suffix (trailing space)
58
+ if options[:suffix]
59
+ suffix = options[:suffix]
60
+ elsif options[:suffix] === false
61
+ suffix = ''
62
+ else
63
+ suffix = ' '
64
+ end
65
+
66
+ # title
67
+ if title.blank?
68
+ result = content_tag :title, site
69
+ else
70
+ title = normalize_title(title)
71
+ title = [site] + title if site
72
+ title.reverse! unless options[:reverse] === false
73
+ sep = prefix + separator + suffix
74
+ result = content_tag(:title, title.join(sep))
75
+ end
76
+ result
77
+ end
78
+
79
+ def description(string)
80
+ @content_for_description = string
81
+ end
82
+
83
+ def description_tag(default='')
84
+ content = normalize_description(@content_for_description || default)
85
+ meta_tag(:description, content) unless content.blank?
91
86
  end
92
-
93
- # title
94
- if title.blank?
95
- result = content_tag :title, site
96
- else
97
- title = normalize_title(title)
98
- title = [site] + title
99
- title.reverse! unless options[:reverse] === false
100
- sep = prefix + separator + suffix
101
- result = content_tag(:title, title.join(sep))
102
- end
103
- result
104
- end
105
-
106
- def description(string)
107
- @content_for_description = string
108
- end
109
-
110
- def description_tag(default='')
111
- content = normalize_description(@content_for_description || default)
112
- tag(:meta, :name => :description, :content => content) unless content.blank?
113
- end
114
87
 
115
- def keywords(string)
116
- @content_for_keywords = string
117
- end
88
+ def keywords(string)
89
+ @content_for_keywords = string
90
+ end
118
91
 
119
- def keywords_tag(default = '')
120
- content = normalize_keywords(@content_for_keywords || default)
121
- tag(:meta, :name => :keywords, :content => content) unless content.blank?
122
- end
92
+ def keywords_tag(default = '')
93
+ content = normalize_keywords(@content_for_keywords || default)
94
+ meta_tag(:keywords, content) unless content.blank?
95
+ end
123
96
 
124
- def copyright(string)
125
- @content_for_copyright = string
126
- end
97
+ def copyright(string)
98
+ @content_for_copyright = string
99
+ end
127
100
 
128
- def copyright_tag(default='')
129
- content = @content_for_copyright || default
130
- tag(:meta, :name => :copyright, :content => content) unless content.blank?
131
- end
101
+ def copyright_tag(default='')
102
+ content = @content_for_copyright || default
103
+ meta_tag(:copyright, content) unless content.blank?
104
+ end
132
105
 
133
- def robots(*args)
134
- content_for(:robots, args.join(", "))
135
- end
106
+ def robots(*args)
107
+ content_for(:robots, args.join(", "))
108
+ end
136
109
 
137
- def robots_tag(*args)
138
- options = args.extract_options!
110
+ def robots_tag(*args)
111
+ options = args.extract_options!
139
112
 
140
- noindex_name = tags[:noindex].is_a?(String) ? tags[:noindex] : 'robots'
141
- nofollow_name = tags[:nofollow].is_a?(String) ? tags[:nofollow] : 'robots'
142
-
143
- if noindex_name == nofollow_name
144
- content = [(tags[:noindex] ? 'noindex' : nil), (tags[:nofollow] ? 'nofollow' : nil)].compact.join(', ')
145
- unless content.blank?
146
- result << "\n"
147
- result << tag(:meta, :name => noindex_name, :content => content)
148
- end
149
- else
150
- if tags[:noindex]
151
- result << "\n"
152
- result << tag(:meta, :name => noindex_name, :content => 'noindex')
153
- end
154
- if tags[:nofollow]
155
- result << "\n"
156
- result << tag(:meta, :name => nofollow_name, :content => 'nofollow')
113
+ noindex_name = tags[:noindex].is_a?(String) ? tags[:noindex] : 'robots'
114
+ nofollow_name = tags[:nofollow].is_a?(String) ? tags[:nofollow] : 'robots'
115
+
116
+ if noindex_name == nofollow_name
117
+ content = [(tags[:noindex] ? 'noindex' : nil), (tags[:nofollow] ? 'nofollow' : nil)].compact.join(', ')
118
+ unless content.blank?
119
+ result << "\n"
120
+ result << meta_tag(noindex_name, content)
121
+ end
122
+ else
123
+ if tags[:noindex]
124
+ result << "\n"
125
+ result << meta_tag(noindex_name, "noindex")
126
+ end
127
+ if tags[:nofollow]
128
+ result << "\n"
129
+ result << meta_tag(nofollow_name, "nofollow")
130
+ end
157
131
  end
132
+
133
+ return result
158
134
  end
159
- # canonical
160
- unless tags[:canonical].blank?
161
- result << "\n"
162
- result << tag(:link, :rel => :canonical, :href => tags[:canonical])
135
+
136
+ def canonical_link_tag(path)
137
+ link_tag(:rel => :canonical, :href => path)
163
138
  end
164
-
165
- return result
166
- end
167
-
168
- def copyright(from)
169
- now = Time.now.year
170
- now.eql?(from) ? now : "#{from} - #{now}"
171
- end
172
-
173
- # Apple
174
- # http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html
175
-
176
- # Facebook (and opengraph)
177
- # http://developers.facebook.com/docs/opengraph#types
178
-
179
- # http://wiki.developers.facebook.com/index.php/Facebook_Share/Specifying_Meta_Tags
180
- def snapshot_tag(href)
181
- tag(:link, :rel => "image_src", :href => href)
182
- end
183
-
184
- # http://wiki.developers.facebook.com/index.php/Facebook_Share/Specifying_Meta_Tags
185
- def medium(type)
186
- tag(:meta, :name => :medium, :content => type)
187
- end
188
-
189
- def classification(type)
190
- tag(:meta, :name => "og:type", :content => type)
191
- end
192
-
193
- def content_type_tag(type = "text/html", charset = "UTF-8")
194
- meta_tag("Content-Type", "#{type}; charset=#{charset}")
195
- end
139
+
140
+ def http_meta_tag(name, content)
141
+ capture_haml { haml_tag :meta, :"http-equiv" => name, :content => content }
142
+ end
143
+
144
+ # @example Redirect to the site home page in 20 seconds.
145
+ #
146
+ # refresh_meta_tag root_url, :in => 20.seconds
147
+ def refresh_meta_tag(path, options = {})
148
+ http_meta_tag("refresh", "#{options[:in].to_i};url=#{path}")
149
+ end
150
+
151
+ def copyright(from)
152
+ now = Time.now.year
153
+ now.eql?(from) ? now : "#{from} - #{now}"
154
+ end
155
+
156
+ # Apple
157
+ # http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html
196
158
 
197
- def search_link_tag(href, title)
198
- link_tag({:rel => "search", :type => "application/opensearchdescription+xml", :href => href, :title => title})
199
- end
159
+ # Facebook (and opengraph)
160
+ # http://developers.facebook.com/docs/opengraph#types
200
161
 
201
- def favicon_link_tag(favicon = "/favicon.ico")
202
- link_tag({:rel => "shortcut icon", :href => favicon, :type => "image/x-icon"})
203
- end
162
+ # http://wiki.developers.facebook.com/index.php/Facebook_Share/Specifying_Meta_Tags
163
+ def snapshot_link_tag(href)
164
+ link_tag(:rel => "image_src", :href => href)
165
+ end
204
166
 
205
- def link_tag(options = {})
206
- tag(:link, options)
207
- end
208
-
209
- private
210
-
211
- def normalize_title(title)
212
- if title.is_a? String
213
- title = [title]
167
+ def html4_content_type_tag(charset = "UTF-8", type = "text/html")
168
+ http_meta_tag("Content-Type", "#{type}; charset=#{charset}")
169
+ end
170
+
171
+ def html5_content_type_tag(charset = "UTF-8")
172
+ capture_haml { haml_tag :meta, "charset" => charset }
173
+ end
174
+ alias_method :content_type_tag, :html5_content_type_tag
175
+
176
+ def search_link_tag(href, title)
177
+ link_tag(:rel => "search", :type => "application/opensearchdescription+xml", :href => href, :title => title)
178
+ end
179
+
180
+ def favicon_link_tag(favicon = "/favicon.ico")
181
+ link_tag(:rel => "shortcut icon", :href => favicon, :type => "image/x-icon")
182
+ end
183
+
184
+ def link_tag(options = {})
185
+ capture_haml { haml_tag :link, options }
186
+ end
187
+
188
+ def ie_application_meta_tags(title, options = {})
189
+ result = []
190
+ result << meta_tag("application-name", title)
191
+ result << meta_tag("msapplication-tooltip", options[:tooltip]) if options[:tooltip].present?
192
+ result << meta_tag("msapplication-starturl", options[:url]) if options[:url].present?
193
+ if options[:width].present? && options[:height].present?
194
+ result << meta_tag("msapplication-window", "width=#{options[:width]};height=#{options[:height]}")
214
195
  end
215
- title.map { |t| h(strip_tags(t)) }
196
+ result << meta_tag("msapplication-navbutton-color", options[:color]) if options[:color].present?
197
+ result.join("\n")
216
198
  end
217
-
218
- def normalize_description(description)
219
- return '' unless description
220
- truncate(strip_tags(description).gsub(/\s+/, ' '), :length => 200)
199
+
200
+ def ie_task_meta_tag(name, path, icon = nil)
201
+ content = []
202
+ content << "name=#{name}"
203
+ content << "uri=#{path}"
204
+ content << "icon-uri=#{icon}" if icon
205
+ meta_tag("msapplication-task", content.join(";"))
221
206
  end
222
-
223
- def normalize_keywords(keywords)
224
- return '' unless keywords
225
- keywords = keywords.flatten.join(', ') if keywords.is_a?(Array)
226
- strip_tags(keywords).mb_chars.downcase
207
+
208
+ def apple_meta_tags(options = {})
209
+ result = []
210
+ result << apple_viewport_meta_tag(options)
211
+ result << apple_full_screen_meta_tag(options[:full_screen]) if options.has_key?(:full_screen)
212
+ result << apple_mobile_compatible_meta_tag(options[:mobile]) if options.has_key?(:mobile)
213
+ result.join
214
+ end
215
+
216
+ # http://www.html5rocks.com/en/mobile/mobifying.html
217
+ def apple_viewport_meta_tag(options = {})
218
+ viewport = []
219
+ viewport << "width=#{options[:width]}" if options[:width].present?
220
+ viewport << "height=#{options[:height]}" if options[:height].present?
221
+ viewport << "initial-scale=#{options[:scale] || 1.0}"
222
+ viewport << "minimum-scale=#{options[:min]}" if options[:min].present?
223
+ viewport << "maximum-scale=#{options[:max]}" if options[:max].present?
224
+ viewport << "user-scalable=#{options[:scalable] == true ? "yes" : "no"}" if options.has_key?(:scalable)
225
+
226
+ meta_tag("viewport", viewport.join(", "))
227
+ end
228
+
229
+ def apple_full_screen_meta_tag(value)
230
+ meta_tag("apple-touch-fullscreen", value == true ? "yes" : "no")
231
+ end
232
+
233
+ def apple_mobile_compatible_meta_tag(value)
234
+ meta_tag("apple-mobile-web-app-capable", value == true ? "yes" : "no")
235
+ end
236
+
237
+ def apple_touch_icon_link_tag(path, options = {})
238
+ rel = ["apple-touch-icon"]
239
+ rel << "#{options[:size]}x#{options[:size]}" if options[:size].present?
240
+ rel << "precomposed" if options[:precomposed]
241
+ link_tag(:rel => rel.join("-"), :href => path)
227
242
  end
243
+
244
+ def apple_touch_icon_link_tags(path, *sizes)
245
+ options = sizes.extract_options!
246
+ sizes.map { |size| apple_touch_icon_link_tag(path, options.merge(:size => size)) }.join
247
+ end
248
+
249
+ def open_graph_meta_tags(options = {})
250
+ result = []
251
+
252
+ result << open_graph_meta_tag("og:title", options[:title]) if options[:title]
253
+ result << open_graph_meta_tag("og:type", options[:type]) if options[:type]
254
+ result << open_graph_meta_tag("og:image", options[:image]) if options[:image]
255
+ result << open_graph_meta_tag("og:site_name", options[:site]) if options[:site]
256
+ result << open_graph_meta_tag("og:description", options[:description]) if options[:description]
257
+ result << open_graph_meta_tag("og:email", options[:email]) if options[:email]
258
+ result << open_graph_meta_tag("og:phone_number", options[:phone]) if options[:phone]
259
+ result << open_graph_meta_tag("og:fax_number", options[:fax]) if options[:fax]
260
+ result << open_graph_meta_tag("og:latitude", options[:lat]) if options[:lat]
261
+ result << open_graph_meta_tag("og:longitude", options[:lng]) if options[:lng]
262
+ result << open_graph_meta_tag("og:street-address", options[:street]) if options[:street]
263
+ result << open_graph_meta_tag("og:locality", options[:city]) if options[:city]
264
+ result << open_graph_meta_tag("og:region", options[:state]) if options[:state]
265
+ result << open_graph_meta_tag("og:postal-code", options[:zip]) if options[:zip]
266
+ result << open_graph_meta_tag("og:country-name", options[:country]) if options[:country]
267
+
268
+ result.join("\n")
269
+ end
270
+
271
+ def open_graph_meta_tag(property, content)
272
+ capture_haml { haml_tag :meta, :property => property, :content => content }
273
+ end
274
+
275
+ # first, last, next, prev
276
+ def pagination_meta_tags(options = {})
277
+
278
+ end
279
+
280
+ private
281
+
282
+ def normalize_title(title)
283
+ if title.is_a? String
284
+ title = [title]
285
+ end
286
+ title.map { |t| h(strip_tags(t)) }
287
+ end
288
+
289
+ def normalize_description(description)
290
+ return '' unless description
291
+ truncate(strip_tags(description).gsub(/\s+/, ' '), :length => 200)
292
+ end
293
+
294
+ def normalize_keywords(keywords)
295
+ return '' unless keywords
296
+ keywords = keywords.flatten.join(', ') if keywords.is_a?(Array)
297
+ strip_tags(keywords).mb_chars.downcase
298
+ end
299
+ end
228
300
  end
229
301
  end