storefront 0.2.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/Rakefile +76 -0
- data/init.rb +1 -0
- data/lib/storefront.rb +21 -0
- data/lib/storefront/dashboard.rb +184 -0
- data/lib/storefront/form.rb +65 -0
- data/lib/storefront/form/elements.rb +101 -0
- data/lib/storefront/form/errors.rb +57 -0
- data/lib/storefront/form/fields.rb +420 -0
- data/lib/storefront/form/hints.rb +18 -0
- data/lib/storefront/form/inputs.rb +254 -0
- data/lib/storefront/form/labels.rb +81 -0
- data/lib/storefront/form/model.rb +84 -0
- data/lib/storefront/helpers/attribute_helper.rb +60 -0
- data/lib/storefront/helpers/body_helper.rb +18 -0
- data/lib/storefront/helpers/browser_helper.rb +54 -0
- data/lib/storefront/helpers/cache_helper.rb +25 -0
- data/lib/storefront/helpers/collection_helper.rb +14 -0
- data/lib/storefront/helpers/component_helper.rb +35 -0
- data/lib/storefront/helpers/dashboard_helper.rb +37 -0
- data/lib/storefront/helpers/debug_helper.rb +11 -0
- data/lib/storefront/helpers/definition_list_helper.rb +29 -0
- data/lib/storefront/helpers/error_helper.rb +11 -0
- data/lib/storefront/helpers/flash_helper.rb +14 -0
- data/lib/storefront/helpers/form_helper.rb +8 -0
- data/lib/storefront/helpers/format_helper.rb +59 -0
- data/lib/storefront/helpers/head_helper.rb +229 -0
- data/lib/storefront/helpers/image_helper.rb +54 -0
- data/lib/storefront/helpers/list_helper.rb +47 -0
- data/lib/storefront/helpers/locale_helper.rb +175 -0
- data/lib/storefront/helpers/open_graph_helper.rb +5 -0
- data/lib/storefront/helpers/page_helper.rb +73 -0
- data/lib/storefront/helpers/presenter_helper.rb +5 -0
- data/lib/storefront/helpers/request_helper.rb +66 -0
- data/lib/storefront/helpers/semantic/location_helper.rb +18 -0
- data/lib/storefront/helpers/semantic/time_helper.rb +14 -0
- data/lib/storefront/helpers/sidebar_helper.rb +27 -0
- data/lib/storefront/helpers/system_helper.rb +18 -0
- data/lib/storefront/helpers/table_helper.rb +38 -0
- data/lib/storefront/helpers/time_helper.rb +20 -0
- data/lib/storefront/helpers/url_helper.rb +32 -0
- data/lib/storefront/helpers/user_helper.rb +15 -0
- data/lib/storefront/helpers/widget_helper.rb +10 -0
- data/lib/storefront/helpers/workflow_helper.rb +50 -0
- data/lib/storefront/microdata/address.rb +7 -0
- data/lib/storefront/microdata/event.rb +13 -0
- data/lib/storefront/microdata/geo.rb +7 -0
- data/lib/storefront/microdata/organization.rb +7 -0
- data/lib/storefront/microdata/person.rb +7 -0
- data/lib/storefront/microformat/event.rb +7 -0
- data/lib/storefront/microformat/person.rb +7 -0
- data/lib/storefront/railtie.rb +28 -0
- data/lib/storefront/table.rb +191 -0
- data/rails/init.rb +1 -0
- data/test/form_helper_test.rb +5 -0
- data/test/support/mock_controller.rb +15 -0
- data/test/support/mock_response.rb +14 -0
- data/test/support/models.rb +0 -0
- data/test/test_helper.rb +34 -0
- metadata +111 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
module Storefront
|
2
|
+
module BodyHelper
|
3
|
+
def body_id(string)
|
4
|
+
@body_id = string
|
5
|
+
end
|
6
|
+
|
7
|
+
def body_class(string)
|
8
|
+
@body_class = string
|
9
|
+
end
|
10
|
+
|
11
|
+
def body_attributes(options = {})
|
12
|
+
options[:class] = @body_class if @body_class
|
13
|
+
options[:id] = @body_id if @body_id
|
14
|
+
|
15
|
+
options
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Storefront
|
2
|
+
module BrowserHelper
|
3
|
+
# check the current browser (via user agent) for the following:
|
4
|
+
# :mozilla / :firefox
|
5
|
+
# :ie6
|
6
|
+
# :ie7
|
7
|
+
# :ie
|
8
|
+
# :iphone
|
9
|
+
# :safari
|
10
|
+
def browser_is? name
|
11
|
+
name = name.to_s.strip
|
12
|
+
|
13
|
+
return true if browser_name == name
|
14
|
+
return true if (name == 'mozilla' or name == "firefox") && browser_name == 'gecko'
|
15
|
+
return true if name == 'ie6' && browser_name.index('ie6')
|
16
|
+
return true if name == 'ie7' && browser_name.index('ie7')
|
17
|
+
return true if name == 'ie' && browser_name.index('ie')
|
18
|
+
return true if name == 'iphone' && browser_name == 'iphone'
|
19
|
+
return true if name == 'webkit' && browser_name == 'safari'
|
20
|
+
end
|
21
|
+
|
22
|
+
# find the current browser name
|
23
|
+
def browser_name
|
24
|
+
@browser_name ||= begin
|
25
|
+
ua = request.user_agent.to_s.downcase
|
26
|
+
if ua.index('msie') && !ua.index('opera') && !ua.index('webtv')
|
27
|
+
'ie'+ua[ua.index('msie')+5].chr
|
28
|
+
elsif ua.index('gecko/')
|
29
|
+
'gecko'
|
30
|
+
elsif ua.index('opera')
|
31
|
+
'opera'
|
32
|
+
elsif ua.index('konqueror')
|
33
|
+
'konqueror'
|
34
|
+
elsif ua.index('iphone')
|
35
|
+
'iphone'
|
36
|
+
elsif ua.index('applewebkit/')
|
37
|
+
'safari'
|
38
|
+
elsif ua.index('mozilla/')
|
39
|
+
'gecko'
|
40
|
+
else
|
41
|
+
""
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def ip_address
|
47
|
+
request.env['REMOTE_ADDR']
|
48
|
+
end
|
49
|
+
|
50
|
+
def user_agent
|
51
|
+
request.user_agent
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Storefront
|
2
|
+
module CacheHelper
|
3
|
+
def optional_cache(key, &block)
|
4
|
+
cache(key, &block) unless session[:disable_caching]
|
5
|
+
end
|
6
|
+
|
7
|
+
def conditional_cache(key, options = {}, &block)
|
8
|
+
condition = true
|
9
|
+
condition = false if options.has_key?(:if) && options[:if] != true
|
10
|
+
if condition
|
11
|
+
cache(key, &block)
|
12
|
+
else
|
13
|
+
haml_concat capture_haml(&block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_cache_buster
|
18
|
+
if request.xhr?
|
19
|
+
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
|
20
|
+
response.headers["Pragma"] = "no-cache"
|
21
|
+
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Storefront
|
2
|
+
# Encapsulates common browser hacks
|
3
|
+
module ComponentHelper
|
4
|
+
def component_image_tag
|
5
|
+
capture_haml do
|
6
|
+
haml_tag :span
|
7
|
+
haml_concat image_tag()
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def popup_button(label, path, message, subtitle, submit = nil, kind = :group)
|
12
|
+
link_to "<span>#{label}</span>", path, :class => "delete", "data-message" => message, "data-subtitle" => subtitle, "data-model" => kind.to_s, "data-submit" => submit.to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def component_button(*args, &block)
|
16
|
+
options = args.extract_options!
|
17
|
+
button_options = options.delete(:button_options) || {}
|
18
|
+
|
19
|
+
if block_given?
|
20
|
+
content = capture(&block)
|
21
|
+
else
|
22
|
+
label = args.shift
|
23
|
+
path = args.shift
|
24
|
+
content = link_to(label, path, button_options)
|
25
|
+
end
|
26
|
+
|
27
|
+
capture_haml do
|
28
|
+
haml_tag :button, options.merge(:class => ["button", options[:class]].compact.uniq.join(" ")) do
|
29
|
+
haml_concat content
|
30
|
+
haml_tag :span
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Storefront
|
2
|
+
module DashboardHelper
|
3
|
+
def dashboard_for(*args, &block)
|
4
|
+
record = args.shift
|
5
|
+
options = args.extract_options!
|
6
|
+
condition = extract_condition!(options)
|
7
|
+
@dashboard_record = record
|
8
|
+
concat(capture(&block)) if record && condition != false
|
9
|
+
@dashboard_record = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def dashboard(key, locals = {})
|
13
|
+
render :partial => key, :locals => locals.reverse_merge(:figures => [])
|
14
|
+
end
|
15
|
+
|
16
|
+
def figure(*names, &block)
|
17
|
+
locals = names.extract_options!
|
18
|
+
condition = extract_condition!(locals)
|
19
|
+
|
20
|
+
if condition != false
|
21
|
+
locals.reverse_merge(:locale => nil)
|
22
|
+
locals.merge!(:yielded_content => capture(&block)) if block_given?
|
23
|
+
result = capture_haml do
|
24
|
+
names.each do |name|
|
25
|
+
haml_concat render(:partial => "shared/dashboard/#{name}", :locals => locals)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
result
|
31
|
+
end
|
32
|
+
|
33
|
+
def report_for(record_or_key, hash, options = {}, &block)
|
34
|
+
Semantic::Dashboard.new(self, record_or_key, hash, options, &block).content
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Storefront
|
2
|
+
module DefinitionListHelper
|
3
|
+
def term(key, value, options = {})
|
4
|
+
return if value.blank?
|
5
|
+
condition = extract_condition!(options)
|
6
|
+
|
7
|
+
if condition != false
|
8
|
+
result = capture_haml do
|
9
|
+
haml_tag :tr, :class => "term" do
|
10
|
+
text = key.is_a?(String) ? key : t("widgets.details.#{key}")
|
11
|
+
haml_tag :td, text.gsub(/:?$/, ":"), :class => "key first"
|
12
|
+
haml_tag :td, value, :class => "value"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
result
|
18
|
+
end
|
19
|
+
|
20
|
+
def terms(&block)
|
21
|
+
capture_haml do
|
22
|
+
haml_tag :dl do
|
23
|
+
yield
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
alias definition_list terms
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Storefront
|
2
|
+
module ErrorHelper
|
3
|
+
def render_not_found(exception)
|
4
|
+
Exceptional::Catcher.handle_with_controller(exception, self, request) if defined?(::Exceptional)
|
5
|
+
logger.error(exception)
|
6
|
+
puts exception.inspect
|
7
|
+
puts exception.backtrace.join("\n")
|
8
|
+
render :template => "/error/404.html", :status => 404, :layout => false
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Storefront
|
2
|
+
module FlashHelper
|
3
|
+
def render_flash
|
4
|
+
flash_to_render = [:success, :failure, :notice, :error]
|
5
|
+
flash.select { |type, _| flash_to_render.include?(type) }.map do |type, content|
|
6
|
+
content_tag(:output, content, :class => "flash-#{type}")
|
7
|
+
end.join
|
8
|
+
end
|
9
|
+
|
10
|
+
def flash?
|
11
|
+
flash.present?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Storefront
|
2
|
+
module FormatHelper
|
3
|
+
def rendered_text(string)
|
4
|
+
string.to_s.
|
5
|
+
gsub(/<\/?[^>]*>/, '').
|
6
|
+
gsub(/\n/, " ").
|
7
|
+
gsub("\r", " ").
|
8
|
+
squeeze(" ").
|
9
|
+
gsub(/\"/, "″"). # convert quotes to inches
|
10
|
+
gsub(/\'/, "′"). # single quote to feet
|
11
|
+
gsub(/\$0?0*\.(\d+)/, "\\1¢").html_safe
|
12
|
+
end
|
13
|
+
|
14
|
+
def format_money(value)
|
15
|
+
value.present? ? ("$" + number_with_precision(value.to_s.gsub("$", ""), :precision => 2)) : nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def format_percent(value)
|
19
|
+
value.present? ? (number_with_precision(value.to_s.gsub("%", ""), :precision => 0) + "%") : nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def sanitize(text)
|
23
|
+
text.gsub(/<\/?[^>]*>/, '').gsub(/\n/, " ").gsub("\r", " ").squeeze(" ")
|
24
|
+
end
|
25
|
+
|
26
|
+
def n(value)
|
27
|
+
if value.respond_to?(:nan?) && value.nan?
|
28
|
+
0
|
29
|
+
else
|
30
|
+
value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def s(string, default = "N/A")
|
35
|
+
string.present? ? string : default
|
36
|
+
end
|
37
|
+
|
38
|
+
def num(num, default = "N/A")
|
39
|
+
result = number_with_precision(num, :precision => 1)
|
40
|
+
result.blank? ? default : result
|
41
|
+
end
|
42
|
+
|
43
|
+
def money(value)
|
44
|
+
value ? value.to_s.gsub(/^\$?/, "$") : "$0"
|
45
|
+
end
|
46
|
+
|
47
|
+
def read_binary_file(path)
|
48
|
+
File.open(path, 'rb') {|f| f.read }
|
49
|
+
end
|
50
|
+
|
51
|
+
def encoded_contents(path)
|
52
|
+
Base64.encode64(read_binary_file(path)).gsub(/\n/, '')
|
53
|
+
end
|
54
|
+
|
55
|
+
def font_face_data_uri(path)
|
56
|
+
"url(\"data:font/truetype;base64,#{encoded_contents(path)}\")"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,229 @@
|
|
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 = ' '
|
69
|
+
end
|
70
|
+
|
71
|
+
# Separator
|
72
|
+
unless options[:separator].blank?
|
73
|
+
separator = options[:separator]
|
74
|
+
else
|
75
|
+
separator = '|'
|
76
|
+
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 = ' '
|
85
|
+
end
|
86
|
+
|
87
|
+
# Title
|
88
|
+
title = @content_for_title
|
89
|
+
if options[:lowercase] === true
|
90
|
+
title = title.downcase unless title.blank?
|
91
|
+
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
|
+
|
115
|
+
def keywords(string)
|
116
|
+
@content_for_keywords = string
|
117
|
+
end
|
118
|
+
|
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
|
123
|
+
|
124
|
+
def copyright(string)
|
125
|
+
@content_for_copyright = string
|
126
|
+
end
|
127
|
+
|
128
|
+
def copyright_tag(default='')
|
129
|
+
content = @content_for_copyright || default
|
130
|
+
tag(:meta, :name => :copyright, :content => content) unless content.blank?
|
131
|
+
end
|
132
|
+
|
133
|
+
def robots(*args)
|
134
|
+
content_for(:robots, args.join(", "))
|
135
|
+
end
|
136
|
+
|
137
|
+
def robots_tag(*args)
|
138
|
+
options = args.extract_options!
|
139
|
+
|
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')
|
157
|
+
end
|
158
|
+
end
|
159
|
+
# canonical
|
160
|
+
unless tags[:canonical].blank?
|
161
|
+
result << "\n"
|
162
|
+
result << tag(:link, :rel => :canonical, :href => tags[:canonical])
|
163
|
+
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
|
196
|
+
|
197
|
+
def search_link_tag(href, title)
|
198
|
+
link_tag({:rel => "search", :type => "application/opensearchdescription+xml", :href => href, :title => title})
|
199
|
+
end
|
200
|
+
|
201
|
+
def favicon_link_tag(favicon = "/favicon.ico")
|
202
|
+
link_tag({:rel => "shortcut icon", :href => favicon, :type => "image/x-icon"})
|
203
|
+
end
|
204
|
+
|
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]
|
214
|
+
end
|
215
|
+
title.map { |t| h(strip_tags(t)) }
|
216
|
+
end
|
217
|
+
|
218
|
+
def normalize_description(description)
|
219
|
+
return '' unless description
|
220
|
+
truncate(strip_tags(description).gsub(/\s+/, ' '), :length => 200)
|
221
|
+
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
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|