locomotivecms_wagon 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/generators/bootstrap/app/views/pages/index.liquid +10 -1
- data/generators/bootstrap/app/views/pages/index.liquid.haml +9 -1
- data/generators/bootstrap/public/stylesheets/fonts/awesome.css.scss +3 -0
- data/generators/bootstrap/public/{fonts → stylesheets/fonts}/font-awesome-ie7.min.css +0 -0
- data/generators/bootstrap/public/{fonts → stylesheets/fonts}/font-awesome.css +0 -9
- data/generators/foundation/app/views/pages/index.liquid +1 -0
- data/generators/foundation/app/views/pages/index.liquid.haml +3 -1
- data/lib/locomotive/wagon/liquid.rb +2 -0
- data/lib/locomotive/wagon/liquid/drops/content_types.rb +6 -3
- data/lib/locomotive/wagon/liquid/drops/page.rb +2 -2
- data/lib/locomotive/wagon/liquid/drops/site.rb +0 -2
- data/lib/locomotive/wagon/liquid/filters/misc.rb +4 -0
- data/lib/locomotive/wagon/liquid/filters/text.rb +0 -1
- data/lib/locomotive/wagon/liquid/scopeable.rb +32 -0
- data/lib/locomotive/wagon/liquid/tags/editable.rb +1 -0
- data/lib/locomotive/wagon/liquid/tags/editable/base.rb +5 -1
- data/lib/locomotive/wagon/liquid/tags/editable/short_text.rb +5 -0
- data/lib/locomotive/wagon/liquid/tags/editable/text.rb +15 -0
- data/lib/locomotive/wagon/liquid/tags/hybrid.rb +27 -0
- data/lib/locomotive/wagon/liquid/tags/link_to.rb +112 -0
- data/lib/locomotive/wagon/liquid/tags/nav.rb +192 -73
- data/lib/locomotive/wagon/misc/core_ext.rb +18 -0
- data/lib/locomotive/wagon/server.rb +3 -1
- data/lib/locomotive/wagon/server/dynamic_assets.rb +19 -12
- data/lib/locomotive/wagon/server/logging.rb +1 -1
- data/lib/locomotive/wagon/server/page.rb +1 -1
- data/lib/locomotive/wagon/version.rb +1 -1
- data/locomotivecms_wagon.gemspec +3 -1
- data/spec/fixtures/default/app/views/pages/about_us.liquid.haml +1 -0
- data/spec/fixtures/default/app/views/pages/about_us/john_doe.liquid.haml +2 -0
- data/spec/fixtures/default/app/views/pages/archives/news.liquid.haml +3 -0
- data/spec/fixtures/default/app/views/pages/events.liquid.haml +13 -0
- data/spec/fixtures/default/app/views/pages/music.liquid.haml +13 -1
- data/spec/fixtures/default/app/views/pages/songs/template.liquid.haml +1 -0
- data/spec/fixtures/default/app/views/pages/tags/nav_in_deep.liquid.haml +6 -0
- data/spec/fixtures/default/app/views/snippets/A_Complicated-one.liquid.haml +1 -0
- data/spec/integration/server/basic_spec.rb +16 -9
- data/spec/integration/server/liquid_spec.rb +48 -4
- metadata +96 -11
- checksums.yaml +0 -15
- data/generators/bootstrap/public/fonts/font-awesome.min.css +0 -34
- data/lib/locomotive/wagon/scopeable.rb +0 -28
@@ -2,6 +2,7 @@ module Locomotive
|
|
2
2
|
module Wagon
|
3
3
|
module Liquid
|
4
4
|
module Tags
|
5
|
+
|
5
6
|
# Display the children pages of the site, current page or the parent page. If not precised, nav is applied on the current page.
|
6
7
|
# The html output is based on the ul/li tags.
|
7
8
|
#
|
@@ -20,16 +21,8 @@ module Locomotive
|
|
20
21
|
def initialize(tag_name, markup, tokens, context)
|
21
22
|
if markup =~ Syntax
|
22
23
|
@source = ($1 || 'page').gsub(/"|'/, '')
|
23
|
-
@options = { id: 'nav', class: '', active_class: 'on', bootstrap: false }
|
24
|
-
markup.scan(::Liquid::TagAttributes) { |key, value| @options[key.to_sym] = value.gsub(/"|'/, '') }
|
25
|
-
|
26
|
-
@options[:exclude] = Regexp.new(@options[:exclude]) if @options[:exclude]
|
27
24
|
|
28
|
-
|
29
|
-
if template = self.parse_snippet_template(context, @options[:snippet])
|
30
|
-
@options[:liquid_render] = template
|
31
|
-
end
|
32
|
-
end
|
25
|
+
self.set_options(markup, context)
|
33
26
|
else
|
34
27
|
raise ::Liquid::SyntaxError.new("Syntax Error in 'nav' - Valid syntax: nav <site|parent|page|<path to a page>> <options>")
|
35
28
|
end
|
@@ -40,45 +33,44 @@ module Locomotive
|
|
40
33
|
def render(context)
|
41
34
|
self.set_accessors_from_context(context)
|
42
35
|
|
43
|
-
children_output = []
|
44
|
-
|
45
36
|
entries = self.fetch_entries
|
37
|
+
output = self.build_entries_output(entries)
|
46
38
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
output = children_output.join("\n")
|
56
|
-
|
57
|
-
if @options[:no_wrapper] != 'true'
|
58
|
-
list_class = !@options[:class].blank? ? %( class="#{@options[:class]}") : ''
|
59
|
-
output = %{<nav id="#{@options[:id]}"#{list_class}><ul>\n#{output}</ul></nav>}
|
39
|
+
if self.no_wrapper?
|
40
|
+
output
|
41
|
+
else
|
42
|
+
self.render_tag(:nav, id: @options[:id], css: @options[:class]) do
|
43
|
+
self.render_tag(:ul) { output }
|
44
|
+
end
|
60
45
|
end
|
61
|
-
|
62
|
-
output
|
63
46
|
end
|
64
47
|
|
65
48
|
protected
|
66
49
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
50
|
+
# Build recursively the links of all the pages.
|
51
|
+
#
|
52
|
+
# @param [ Array ] entries List of pages
|
53
|
+
#
|
54
|
+
# @return [ String ] The final HTML output
|
55
|
+
#
|
56
|
+
def build_entries_output(entries, depth = 1)
|
57
|
+
output = []
|
71
58
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
59
|
+
entries.each_with_index do |page, index|
|
60
|
+
css = []
|
61
|
+
css << 'first' if index == 0
|
62
|
+
css << 'last' if index == entries.size - 1
|
63
|
+
|
64
|
+
output << self.render_entry_link(page, css.join(' '), depth)
|
77
65
|
end
|
78
66
|
|
79
|
-
|
67
|
+
output.join("\n")
|
80
68
|
end
|
81
69
|
|
70
|
+
# Get all the children of a source: site (index page), parent or page.
|
71
|
+
#
|
72
|
+
# @return [ Array ] List of pages
|
73
|
+
#
|
82
74
|
def fetch_entries
|
83
75
|
children = (case @source
|
84
76
|
when 'site' then self.mounting_point.pages['index']
|
@@ -91,7 +83,12 @@ module Locomotive
|
|
91
83
|
children.delete_if { |p| !include_page?(p) }
|
92
84
|
end
|
93
85
|
|
94
|
-
#
|
86
|
+
# Determine whether or not a page should be a part of the menu.
|
87
|
+
#
|
88
|
+
# @param [ Object ] page The page
|
89
|
+
#
|
90
|
+
# @return [ Boolean ] True if the page can be included or not
|
91
|
+
#
|
95
92
|
def include_page?(page)
|
96
93
|
if !page.listed? || page.templatized? || !page.published?
|
97
94
|
false
|
@@ -102,62 +99,184 @@ module Locomotive
|
|
102
99
|
end
|
103
100
|
end
|
104
101
|
|
105
|
-
#
|
106
|
-
|
107
|
-
|
102
|
+
# Determine wether or not a page is currently the displayed one.
|
103
|
+
#
|
104
|
+
# @param [ Object ] page The page
|
105
|
+
#
|
106
|
+
# @return [ Boolean ]
|
107
|
+
#
|
108
|
+
def page_selected?(page)
|
109
|
+
self.current_page.fullpath =~ /^#{page.fullpath}/
|
110
|
+
end
|
108
111
|
|
109
|
-
|
112
|
+
# Determine if the children of a page have to be rendered or not.
|
113
|
+
# It depends on the depth passed in the option.
|
114
|
+
#
|
115
|
+
# @param [ Object ] page The page
|
116
|
+
# @param [ Integer ] depth The current depth
|
117
|
+
#
|
118
|
+
# @return [ Boolean ] True if the children have to be rendered.
|
119
|
+
#
|
120
|
+
def render_children_for_page?(page, depth)
|
121
|
+
depth.succ <= @options[:depth].to_i &&
|
122
|
+
(page.children || []).select { |child| self.include_page?(child) }.any?
|
123
|
+
end
|
110
124
|
|
125
|
+
# Return the label of an entry. It may use or not the template
|
126
|
+
# given by the snippet option.
|
127
|
+
#
|
128
|
+
# @param [ Object ] page The page
|
129
|
+
#
|
130
|
+
# @return [ String ] The label in HTML
|
131
|
+
#
|
132
|
+
def entry_label(page)
|
133
|
+
icon = @options[:icon] ? '<span></span>' : ''
|
111
134
|
title = @options[:liquid_render] ? @options[:liquid_render].render('page' => page) : page.title
|
112
135
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
if render_children_for_page?(page, depth) && bootstrap?
|
121
|
-
dropdow = "dropdown"
|
122
|
-
link_options = %{class="dropdown-toggle" data-toggle="dropdown"}
|
123
|
-
href = "#"
|
124
|
-
caret = %{<b class="caret"></b>}
|
136
|
+
if icon.blank?
|
137
|
+
title
|
138
|
+
elsif @options[:icon] == 'after'
|
139
|
+
"#{title} #{icon}"
|
140
|
+
else
|
141
|
+
"#{icon} #{title}"
|
125
142
|
end
|
143
|
+
end
|
126
144
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
145
|
+
# Return the localized url of an entry (page).
|
146
|
+
#
|
147
|
+
# @param [ Object ] page The page
|
148
|
+
#
|
149
|
+
# @return [ String ] The localized url
|
150
|
+
#
|
151
|
+
def entry_url(page)
|
152
|
+
if ::I18n.locale.to_s == self.mounting_point.default_locale.to_s
|
153
|
+
"/#{page.fullpath}"
|
154
|
+
else
|
155
|
+
"/#{::I18n.locale}/#{page.fullpath}"
|
156
|
+
end
|
157
|
+
end
|
131
158
|
|
132
|
-
|
159
|
+
# Return the css of an entry (page).
|
160
|
+
#
|
161
|
+
# @param [ Object ] page The page
|
162
|
+
# @param [ String ] css The extra css
|
163
|
+
#
|
164
|
+
# @return [ String ] The css
|
165
|
+
#
|
166
|
+
def entry_css(page, css = '')
|
167
|
+
_css = 'link'
|
168
|
+
_css = "#{page}#{@options[:active_class]}" if self.page_selected?(page)
|
169
|
+
|
170
|
+
(_css + " #{css}").strip
|
133
171
|
end
|
134
172
|
|
135
|
-
|
136
|
-
|
173
|
+
# Return the HTML output of a page and its children if requested.
|
174
|
+
#
|
175
|
+
# @param [ Object ] page The page
|
176
|
+
# @param [ String ] css The current css to apply to the entry
|
177
|
+
# @param [ Integer] depth Used to know if the children has to be added or not.
|
178
|
+
#
|
179
|
+
# @return [ String ] The HTML output
|
180
|
+
#
|
181
|
+
def render_entry_link(page, css, depth)
|
182
|
+
url = self.entry_url(page)
|
183
|
+
label = self.entry_label(page)
|
184
|
+
css = self.entry_css(page, css)
|
185
|
+
options = ''
|
186
|
+
|
187
|
+
if self.render_children_for_page?(page, depth) && self.bootstrap?
|
188
|
+
url = '#'
|
189
|
+
label += %{ <b class="caret"></b>}
|
190
|
+
css += ' dropdown'
|
191
|
+
options = %{ class="dropdown-toggle" data-toggle="dropdown"}
|
192
|
+
end
|
193
|
+
|
194
|
+
self.render_tag(:li, id: "#{page.slug.to_s.dasherize}-link", css: css) do
|
195
|
+
children_output = depth.succ <= @options[:depth].to_i ? self.render_entry_children(page, depth.succ) : ''
|
196
|
+
%{<a href="#{url}"#{options}>#{label}</a>} + children_output
|
197
|
+
end
|
137
198
|
end
|
138
199
|
|
139
|
-
# Recursively
|
200
|
+
# Recursively create a nested unordered list for the depth specified.
|
201
|
+
#
|
202
|
+
# @param [ Array ] entries The children of the page
|
203
|
+
# @param [ Integer ] depth The current depth
|
204
|
+
#
|
205
|
+
# @return [ String ] The HTML code
|
206
|
+
#
|
140
207
|
def render_entry_children(page, depth)
|
141
|
-
|
208
|
+
entries = (page.children || []).select { |child| self.include_page?(child) }
|
209
|
+
css = self.bootstrap? ? 'dropdown-menu' : ''
|
210
|
+
|
211
|
+
unless entries.empty?
|
212
|
+
self.render_tag(:ul, id: "#{@options[:id]}-#{page.slug.to_s.dasherize}", css: css) do
|
213
|
+
self.build_entries_output(entries, depth)
|
214
|
+
end
|
215
|
+
else
|
216
|
+
''
|
217
|
+
end
|
218
|
+
end
|
142
219
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
css = []
|
148
|
-
css << 'first' if children.first == c
|
149
|
-
css << 'last' if children.last == c
|
220
|
+
# Set the value (default or assigned by the tag) of the options.
|
221
|
+
#
|
222
|
+
def set_options(markup, context)
|
223
|
+
@options = { id: 'nav', class: '', active_class: 'on', bootstrap: false, no_wrapper: false }
|
150
224
|
|
151
|
-
|
225
|
+
markup.scan(::Liquid::TagAttributes) { |key, value| @options[key.to_sym] = value.gsub(/"|'/, '') }
|
226
|
+
|
227
|
+
@options[:exclude] = Regexp.new(@options[:exclude]) if @options[:exclude]
|
228
|
+
|
229
|
+
if @options[:snippet]
|
230
|
+
if template = self.parse_snippet_template(context, @options[:snippet])
|
231
|
+
@options[:liquid_render] = template
|
152
232
|
end
|
153
|
-
output << %{</ul>}
|
154
233
|
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# Avoid to call context.registers to get the current page
|
237
|
+
# and the mounting point.
|
238
|
+
#
|
239
|
+
def set_accessors_from_context(context)
|
240
|
+
self.current_page = context.registers[:page]
|
241
|
+
self.mounting_point = context.registers[:mounting_point]
|
242
|
+
end
|
243
|
+
|
244
|
+
# Parse the template of the snippet give in option of the tag.
|
245
|
+
# If the template_name contains a liquid tag or drop, it will
|
246
|
+
# be used an inline template.
|
247
|
+
#
|
248
|
+
def parse_snippet_template(context, template_name)
|
249
|
+
source = if template_name.include?('{')
|
250
|
+
template_name
|
251
|
+
else
|
252
|
+
context[:mounting_point].snippets[template_name].try(:source)
|
253
|
+
end
|
254
|
+
|
255
|
+
source ? ::Liquid::Template.parse(source) : nil
|
256
|
+
end
|
155
257
|
|
156
|
-
|
258
|
+
# Render any kind HTML tags. The content of the tag comes from
|
259
|
+
# the block.
|
260
|
+
#
|
261
|
+
# @param [ String ] tag_name Name of the HTML tag (li, ul, div, ...etc).
|
262
|
+
# @param [ String ] html_options Id, class, ..etc
|
263
|
+
#
|
264
|
+
# @return [ String ] The HTML
|
265
|
+
#
|
266
|
+
def render_tag(tag_name, html_options = {}, &block)
|
267
|
+
options = ['']
|
268
|
+
options << %{id="#{html_options[:id]}"} if html_options[:id].present?
|
269
|
+
options << %{class="#{html_options[:css]}"} if html_options[:css].present?
|
270
|
+
|
271
|
+
%{<#{tag_name}#{options.join(' ')}>#{yield}</#{tag_name}>}
|
157
272
|
end
|
158
273
|
|
159
274
|
def bootstrap?
|
160
|
-
@options[:bootstrap]
|
275
|
+
@options[:bootstrap].to_bool
|
276
|
+
end
|
277
|
+
|
278
|
+
def no_wrapper?
|
279
|
+
@options[:no_wrapper].to_bool
|
161
280
|
end
|
162
281
|
|
163
282
|
::Liquid::Template.register_tag('nav', Nav)
|
@@ -26,4 +26,22 @@ unless Hash.instance_methods.include?(:underscore_keys)
|
|
26
26
|
end
|
27
27
|
|
28
28
|
end
|
29
|
+
end
|
30
|
+
|
31
|
+
unless String.instance_methods.include?(:to_bool)
|
32
|
+
class String
|
33
|
+
def to_bool
|
34
|
+
return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
|
35
|
+
return false if self == false || self.blank? || self =~ (/(false|f|no|n|0)$/i)
|
36
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class TrueClass
|
41
|
+
def to_bool; self; end
|
42
|
+
end
|
43
|
+
|
44
|
+
class FalseClass
|
45
|
+
def to_bool; self; end
|
46
|
+
end
|
29
47
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'better_errors'
|
2
2
|
require 'coffee_script'
|
3
|
+
require 'sprockets'
|
4
|
+
require "sprockets-sass"
|
3
5
|
|
4
6
|
require 'locomotive/wagon/listen'
|
5
7
|
require 'locomotive/wagon/server/middleware'
|
@@ -58,7 +60,7 @@ module Locomotive::Wagon
|
|
58
60
|
}
|
59
61
|
|
60
62
|
use Favicon
|
61
|
-
use DynamicAssets
|
63
|
+
use DynamicAssets, reader.mounting_point.path
|
62
64
|
|
63
65
|
use Logging
|
64
66
|
|
@@ -3,22 +3,29 @@ module Locomotive::Wagon
|
|
3
3
|
|
4
4
|
class DynamicAssets < Middleware
|
5
5
|
|
6
|
-
|
7
|
-
self.set_accessors(env)
|
6
|
+
attr_reader :app, :sprockets, :regexp
|
8
7
|
|
9
|
-
|
8
|
+
def initialize(app, root)
|
9
|
+
super(app)
|
10
10
|
|
11
|
-
|
11
|
+
@regexp = /^\/(javascripts|stylesheets)\/(.*)$/
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
# make sure Compass is correctly configured
|
14
|
+
Locomotive::Mounter::Extensions::Compass.configure(root)
|
15
|
+
|
16
|
+
@sprockets = Sprockets::Environment.new
|
17
|
+
@sprockets.append_path File.join(root, 'public/stylesheets')
|
18
|
+
@sprockets.append_path File.join(root, 'public/javascripts')
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(env)
|
22
|
+
if env['PATH_INFO'] =~ self.regexp
|
23
|
+
env['PATH_INFO'] = $2
|
17
24
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
25
|
+
begin
|
26
|
+
self.sprockets.call(env)
|
27
|
+
rescue Exception => e
|
28
|
+
raise Locomotive::Wagon::DefaultException.new "Unable to serve a dynamic asset. Please check the logs.", e
|
22
29
|
end
|
23
30
|
else
|
24
31
|
app.call(env)
|
@@ -11,7 +11,7 @@ module Locomotive::Wagon
|
|
11
11
|
log "Started #{env['REQUEST_METHOD'].upcase} \"#{env['PATH_INFO']}\" at #{now}"
|
12
12
|
|
13
13
|
app.call(env).tap do |response|
|
14
|
-
done_in_ms = (Time.now - now) *
|
14
|
+
done_in_ms = ((Time.now - now) * 10000).truncate / 10.0
|
15
15
|
log "Completed #{code_to_human(response.first)} in #{done_in_ms}ms\n\n"
|
16
16
|
end
|
17
17
|
end
|
data/locomotivecms_wagon.gemspec
CHANGED
@@ -24,6 +24,8 @@ Gem::Specification.new do |gem|
|
|
24
24
|
gem.add_dependency 'locomotive_liquid', '~> 2.4.1'
|
25
25
|
gem.add_dependency 'RedCloth', '~> 4.2.9'
|
26
26
|
gem.add_dependency 'dragonfly', '~> 0.9.12'
|
27
|
+
gem.add_dependency 'sprockets', '~> 2.0'
|
28
|
+
gem.add_dependency 'sprockets-sass', '~> 1.0.1'
|
27
29
|
gem.add_dependency 'rack-cache', '~> 1.1'
|
28
30
|
gem.add_dependency 'better_errors', '~> 0.7.2'
|
29
31
|
|
@@ -31,7 +33,7 @@ Gem::Specification.new do |gem|
|
|
31
33
|
|
32
34
|
gem.add_dependency 'httmultiparty', '0.3.8'
|
33
35
|
gem.add_dependency 'will_paginate', '~> 3.0.3'
|
34
|
-
gem.add_dependency 'locomotivecms_mounter', '~> 1.
|
36
|
+
gem.add_dependency 'locomotivecms_mounter', '~> 1.2.0'
|
35
37
|
|
36
38
|
gem.add_dependency 'faker', '~> 0.9.5'
|
37
39
|
|