storefront 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,14 @@
|
|
1
|
+
module Storefront
|
2
|
+
module Semantic
|
3
|
+
module TimeHelper
|
4
|
+
def semantic_time_tag(value, time, options = {})
|
5
|
+
capture_haml do
|
6
|
+
haml_tag :time, :class => "dtstart", :itemprop => "startDate", :title => time.xmlschema, :datetime => time.xmlschema do
|
7
|
+
haml_tag :span, :class => "value-title", :title => time.xmlschema
|
8
|
+
haml_concat value
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Storefront
|
2
|
+
module SidebarHelper
|
3
|
+
def sidebar_for(record, options = {}, &block)
|
4
|
+
@sidebar_record = record
|
5
|
+
concat(capture(&block))
|
6
|
+
@sidebar_record = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def sidebar(*args)
|
10
|
+
locals = args.extract_options!
|
11
|
+
path = args.shift
|
12
|
+
if path.blank?
|
13
|
+
path = resource.class.name.underscore.pluralize.to_sym rescue nil
|
14
|
+
end
|
15
|
+
if path.is_a?(Symbol)
|
16
|
+
path = [path_namespace, path.to_s, "sidebar"].compact.join("/")
|
17
|
+
end
|
18
|
+
content_for :sidebar do
|
19
|
+
render :partial => path, :locals => locals
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def sidebar_record
|
24
|
+
@sidebar_record
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Storefront
|
2
|
+
module SystemHelper
|
3
|
+
def windows?
|
4
|
+
# Can't match for just 'win' cause it will match darwin as well.
|
5
|
+
(/win32|mswin|mingw/).match(RUBY_PLATFORM) ? true : false
|
6
|
+
end
|
7
|
+
|
8
|
+
# Works on Debian and Ubuntu, don't have anything else to test on.
|
9
|
+
def linux?
|
10
|
+
(/linux/).match(RUBY_PLATFORM) ? true : false
|
11
|
+
end
|
12
|
+
|
13
|
+
# Works on my MacBook Pro, don't have anything else to test on,
|
14
|
+
def mac?
|
15
|
+
(/darwin/).match(RUBY_PLATFORM) ? true : false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Storefront
|
2
|
+
module TableHelper
|
3
|
+
def table_for(*args, &block)
|
4
|
+
Storefront::Table.new(self, *args, &block).content
|
5
|
+
end
|
6
|
+
|
7
|
+
def table_query_row_class
|
8
|
+
["search-row", query_params.except("page", "sort").blank? ? nil : "search-results"].compact.join(" ")
|
9
|
+
end
|
10
|
+
|
11
|
+
def link_to_sort(title, attribute, options = {})
|
12
|
+
sort_param = sort_value(attribute, opposite_sort_direction(attribute))
|
13
|
+
link_to title, with_params(request.path, :sort => sort_param), options
|
14
|
+
end
|
15
|
+
|
16
|
+
def next_page_path(collection)
|
17
|
+
with_params(request.path, :page => collection.next_page)
|
18
|
+
end
|
19
|
+
|
20
|
+
def prev_page_path(collection)
|
21
|
+
with_params(request.path, :page => collection.prev_page)
|
22
|
+
end
|
23
|
+
|
24
|
+
def first_page_path(collection)
|
25
|
+
with_params(request.path, :page => 1)
|
26
|
+
end
|
27
|
+
|
28
|
+
def last_page_path(collection)
|
29
|
+
with_params(request.path, :page => collection.last_page)
|
30
|
+
end
|
31
|
+
|
32
|
+
def current_page_num
|
33
|
+
page = params[:page] ? params[:page].to_i : 1
|
34
|
+
page = 1 if page < 1
|
35
|
+
page
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Storefront
|
2
|
+
module TimeHelper
|
3
|
+
# (new Date()).getTimezoneOffset() in JavaScript returns (UTC - localtime) in
|
4
|
+
# minutes, while ActiveSupport::TimeZone expects (localtime - UTC) in seconds.
|
5
|
+
def set_time_zone
|
6
|
+
offset = (cookies[:timezone] || 0).to_i * -60
|
7
|
+
# User.time_zone = ActiveSupport::TimeZone[-min.minutes]
|
8
|
+
User.time_zone = ActiveSupport::TimeZone.us_zones.find { |z| z.utc_offset == offset.to_i }
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def record_post_time
|
13
|
+
cookies[:last_post_at] = Time.zone.now.to_i
|
14
|
+
end
|
15
|
+
|
16
|
+
def html5_time(date_or_time)
|
17
|
+
date_or_time.acts_like?(:time) ? date_or_time.xmlschema : date_or_time.rfc3339
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Storefront
|
2
|
+
module UrlHelper
|
3
|
+
def current_subdomain
|
4
|
+
subdomain = request.subdomain.to_s.split(".").first
|
5
|
+
subdomain = nil if subdomain == App.name
|
6
|
+
(subdomain.blank? || subdomain == "www") ? nil : subdomain
|
7
|
+
end
|
8
|
+
|
9
|
+
def path_namespace?(*args)
|
10
|
+
args.present? ? args.any? { |is| path_namespace == is.to_s } : path_namespace.present?
|
11
|
+
end
|
12
|
+
|
13
|
+
def path_namespace
|
14
|
+
if @path_namespace.nil?
|
15
|
+
if current_subdomain.present?
|
16
|
+
@path_namespace = current_subdomain
|
17
|
+
elsif params[:path_namespace]
|
18
|
+
@path_namespace = params[:path_namespace]
|
19
|
+
else
|
20
|
+
parts = params[:controller].split("/")
|
21
|
+
@path_namespace = parts.length > 1 ? parts.first : ""
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
@path_namespace
|
26
|
+
end
|
27
|
+
|
28
|
+
def with_current_params(path_method, *args)
|
29
|
+
send path_method, *(args << Rack::Utils.parse_query(request.query_string).merge(args.extract_options!))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Storefront
|
2
|
+
module UserHelper
|
3
|
+
def globalize_current_user
|
4
|
+
current_user.request = request if current_user
|
5
|
+
User.current = current_user
|
6
|
+
Rails.logger.info "Current User: [#{ip_address}] #{current_user.present? ? current_user.email : 'Unknown'} (#{user_agent})"
|
7
|
+
true
|
8
|
+
end
|
9
|
+
|
10
|
+
def deglobalize_current_user
|
11
|
+
User.current = nil
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Storefront
|
2
|
+
module WidgetHelper
|
3
|
+
def widget(*args, &block)
|
4
|
+
options = args.extract_options!
|
5
|
+
options.reverse_merge(:locale => nil)
|
6
|
+
options.merge!(:yielded_content => block_given? ? capture(&block) : nil)
|
7
|
+
render(:partial => "shared/widgets/#{name}", :locals => options)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Storefront
|
2
|
+
module WorkflowHelper
|
3
|
+
def current_workflow
|
4
|
+
params[:flow]
|
5
|
+
end
|
6
|
+
|
7
|
+
def flow?(*args)
|
8
|
+
args.present? ? args.any? { |flow| current_workflow == flow.to_s } : current_workflow.present?
|
9
|
+
end
|
10
|
+
|
11
|
+
def workflow_steps(current, *labels)
|
12
|
+
steps = labels.flatten.map do |label|
|
13
|
+
if label.is_a?(Hash)
|
14
|
+
label.symbolize_keys
|
15
|
+
else
|
16
|
+
{:title => label, :description => ""}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
steps.each_with_index do |step, index|
|
20
|
+
step[:active] = index == (current - 1)
|
21
|
+
end
|
22
|
+
steps
|
23
|
+
end
|
24
|
+
|
25
|
+
def workflow_step(label, current, desired)
|
26
|
+
image_name = "step_#{desired}"
|
27
|
+
image_name << "_active" if current == desired
|
28
|
+
image_name << ".png"
|
29
|
+
td_class = current == desired ? "step_active" : "step"
|
30
|
+
result = capture_haml do
|
31
|
+
haml_tag :td, :class => :number do
|
32
|
+
haml_tag :img, :class => :step_number, :src => "/images/#{image_name}"
|
33
|
+
end
|
34
|
+
haml_tag :td, :class => td_class do
|
35
|
+
haml_concat label
|
36
|
+
end
|
37
|
+
end
|
38
|
+
result
|
39
|
+
end
|
40
|
+
|
41
|
+
def next_step_tag(resource = self.resource)
|
42
|
+
result = capture_haml do
|
43
|
+
haml_concat hidden_field_tag(:event, current_step)
|
44
|
+
if resource && resource.id
|
45
|
+
haml_concat hidden_field_tag(:id, resource.id)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# https://gist.github.com/af7e572c2dc973add221
|
2
|
+
module Storefront
|
3
|
+
class Railtie < Rails::Railtie
|
4
|
+
initializer "storefront.insert_into_action_view" do
|
5
|
+
ActiveSupport.on_load :action_view do
|
6
|
+
base = "#{File.expand_path(File.dirname(__FILE__))}/helpers"
|
7
|
+
Dir["#{base}/*"].each do |path|
|
8
|
+
next if File.directory?(path)
|
9
|
+
constant_name = File.basename(path, File.extname(path)).gsub("/", "::").camelize
|
10
|
+
ActionView::Base.send :include, "Storefront::#{constant_name}".constantize
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
ActiveSupport.on_load :active_record do
|
15
|
+
#
|
16
|
+
end
|
17
|
+
|
18
|
+
ActiveSupport.on_load :action_controller do
|
19
|
+
base = "#{File.expand_path(File.dirname(__FILE__))}/helpers"
|
20
|
+
Dir["#{base}/*"].each do |path|
|
21
|
+
next if File.directory?(path) || File.basename(path) =~ /(form|table|dashboard)/
|
22
|
+
constant_name = File.basename(path, File.extname(path)).gsub("/", "::").camelize
|
23
|
+
ActionController::Base.send :include, "Storefront::#{constant_name}".constantize
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
module Storefront
|
2
|
+
class Table
|
3
|
+
attr_reader :content, :template, :key
|
4
|
+
|
5
|
+
def initialize(template, *args, &block)
|
6
|
+
@template = template
|
7
|
+
options = args.extract_options!
|
8
|
+
record_or_key = args.shift
|
9
|
+
@key = record_key(record_or_key)
|
10
|
+
@row_index = 0
|
11
|
+
@cell_index = 0
|
12
|
+
@scope = :table
|
13
|
+
@headers = []
|
14
|
+
options[:summary] ||= "Table for #{key.titleize}"
|
15
|
+
options[:class] = ["data-table", options[:class]].compact.uniq.join(" ")
|
16
|
+
options[:role] = :grid
|
17
|
+
data = options.delete(:data) || {}
|
18
|
+
data[:url] = options[:url] || @template.controller.request.path
|
19
|
+
data[:for] = options[:for] || options[:model] || @key
|
20
|
+
data[:total] = options[:total] if options[:total]
|
21
|
+
data[:page] = options[:page] if options[:page]
|
22
|
+
data[:count] = options[:count] if options[:count]
|
23
|
+
aria = options.delete(:aria) || {}
|
24
|
+
aria[:"aria-multiselectable"] = false unless aria.has_key?(:"aria-multiselectable") || options[:multiselect] == true
|
25
|
+
options[:data] = data
|
26
|
+
options[:id] ||= "#{record_or_key.to_s}-table"
|
27
|
+
|
28
|
+
@content = template.capture_haml do
|
29
|
+
template.haml_tag :table, options do
|
30
|
+
yield(self)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def caption
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
# scope='col'
|
40
|
+
def head(attributes = {}, &block)
|
41
|
+
@hide_header = attributes.delete(:visible) == false
|
42
|
+
template.capture_haml do
|
43
|
+
@row_index = 0
|
44
|
+
@scope = :head
|
45
|
+
template.haml_tag :thead, attributes, &block
|
46
|
+
@row_index = 0
|
47
|
+
@scope = :table
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# scope='row'
|
52
|
+
# <td headers='x'/>
|
53
|
+
def body(attributes = {}, &block)
|
54
|
+
template.capture_haml do
|
55
|
+
@row_index = 0
|
56
|
+
@scope = :body
|
57
|
+
template.haml_tag :tbody, attributes, &block
|
58
|
+
@row_index = 0
|
59
|
+
@scope = :table
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def foot(attributes = {}, &block)
|
64
|
+
template.capture_haml do
|
65
|
+
@row_index = 0
|
66
|
+
@scope = :foot
|
67
|
+
template.haml_tag :tfoot, attributes, &block
|
68
|
+
@row_index = 0
|
69
|
+
@scope = :table
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def row(*args, &block)
|
74
|
+
attributes = args.extract_options!
|
75
|
+
if @scope == :body
|
76
|
+
attributes[:class] = [template.cycle("odd", "even"), attributes[:class]].compact.uniq.join(" ")
|
77
|
+
end
|
78
|
+
attributes[:role] = :row
|
79
|
+
attributes[:scope] = :row
|
80
|
+
template.capture_haml do
|
81
|
+
@row_index += 1
|
82
|
+
@cell_index = 0
|
83
|
+
template.haml_tag :tr, attributes, &block
|
84
|
+
@cell_index = 0
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def column(*args, &block)
|
89
|
+
attributes = args.extract_options!
|
90
|
+
value = args.shift
|
91
|
+
attributes[:id] ||= id_for(:header, key, value, @row_index, @cell_index)
|
92
|
+
[:width, :height].each do |size|
|
93
|
+
attributes[size] = pixelate(attributes[size]) unless attributes[size].nil?
|
94
|
+
end
|
95
|
+
@headers.push(attributes[:id])
|
96
|
+
|
97
|
+
template.capture_haml do
|
98
|
+
template.haml_tag :col, attributes
|
99
|
+
@cell_index += 1
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# direction => "ascending"
|
104
|
+
# valid directions: ascending, descending, none, other
|
105
|
+
# abbr is what the header controls (for sorting)
|
106
|
+
def header(*args, &block)
|
107
|
+
attributes = args.extract_options!
|
108
|
+
value = args.shift
|
109
|
+
if value.is_a?(::Symbol)
|
110
|
+
attributes[:abbr] ||= value.to_s
|
111
|
+
end
|
112
|
+
# aria-selected if sorted
|
113
|
+
attributes[:role] = :columnheader
|
114
|
+
attributes[:id] ||= id_for(:header, key, value, @row_index, @cell_index)
|
115
|
+
attributes[:scope] = :col
|
116
|
+
attributes[:abbr] ||= attributes.delete(:for) if attributes.has_key?(:for)
|
117
|
+
[:width, :height].each do |size|
|
118
|
+
attributes[size] = pixelate(attributes[size]) unless attributes[size].nil?
|
119
|
+
end
|
120
|
+
sort = attributes.delete(:sort) == true
|
121
|
+
label = attributes.delete(:label) || (value.is_a?(::String) ? value.strip : value.to_s.titleize)
|
122
|
+
|
123
|
+
if sort
|
124
|
+
attributes[:class] = [attributes[:class], attributes.delete(:sort_class) || "sortable"].compact.uniq.join(" ")
|
125
|
+
attributes[:direction] ||= template.sort_class(value)
|
126
|
+
end
|
127
|
+
|
128
|
+
direction = attributes.delete(:direction)
|
129
|
+
if direction.present?
|
130
|
+
attributes[:"aria-sort"] = direction
|
131
|
+
attributes[:class] = [attributes[:class], direction].join(" ")
|
132
|
+
attributes[:"aria-selected"] = true
|
133
|
+
else
|
134
|
+
attributes[:"aria-sort"] = "none"
|
135
|
+
attributes[:"aria-selected"] = false
|
136
|
+
end
|
137
|
+
|
138
|
+
@headers.push(attributes[:id])
|
139
|
+
template.capture_haml do
|
140
|
+
if block_given?
|
141
|
+
template.haml_tag :th, attributes, &block
|
142
|
+
else
|
143
|
+
if sort
|
144
|
+
template.haml_tag :th, attributes do
|
145
|
+
template.haml_concat template.link_to_sort(label, value)
|
146
|
+
end
|
147
|
+
else
|
148
|
+
template.haml_tag :th, label, attributes
|
149
|
+
end
|
150
|
+
end
|
151
|
+
@cell_index += 1
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def cell(*args, &block)
|
156
|
+
attributes = args.extract_options!
|
157
|
+
value = args.shift
|
158
|
+
attributes[:role] = :gridcell
|
159
|
+
attributes[:id] ||= id_for(:cell, key, value, @row_index, @cell_index)
|
160
|
+
#attributes[:"aria-describedby"] = @headers[@cell_index]
|
161
|
+
attributes[:headers] = @headers[@cell_index]
|
162
|
+
template.capture_haml do
|
163
|
+
if block_given?
|
164
|
+
template.haml_tag :td, attributes, &block
|
165
|
+
else
|
166
|
+
template.haml_tag :td, value.to_s.strip, attributes
|
167
|
+
end
|
168
|
+
@cell_index += 1
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def record_key(record_or_key)
|
173
|
+
if record_or_key.is_a?(String) || record_or_key.is_a?(Symbol)
|
174
|
+
record_or_key.to_s
|
175
|
+
else
|
176
|
+
record_or_key.class.name
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def id_for(type, key, value, row_index = @row_index, column_index = @column_index)
|
181
|
+
[key, type, row_index, column_index].compact.map do |node|
|
182
|
+
node.to_s.gsub(/[\s_]/, "-")
|
183
|
+
end.join("-")
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
def pixelate(value)
|
188
|
+
value.is_a?(::String) ? value : "#{value}px"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|