locomotivecms_builder 1.0.0.alpha1
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/.gitignore +31 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +68 -0
- data/Rakefile +47 -0
- data/TODO +57 -0
- data/bin/builder +9 -0
- data/generators/blank/Gemfile.tt +20 -0
- data/generators/blank/app/content_types/.empty_directory +1 -0
- data/generators/blank/app/views/pages/404.liquid +11 -0
- data/generators/blank/app/views/pages/index.liquid +19 -0
- data/generators/blank/app/views/snippets/.empty_directory +1 -0
- data/generators/blank/config/deploy.yml +12 -0
- data/generators/blank/config/site.yml.tt +16 -0
- data/generators/blank/config/translations.yml +8 -0
- data/generators/blank/config.ru +3 -0
- data/generators/blank/data/.empty_directory +1 -0
- data/generators/blank/public/fonts/.empty_directory +1 -0
- data/generators/blank/public/images/.empty_directory +1 -0
- data/generators/blank/public/javascripts/.empty_directory +1 -0
- data/generators/blank/public/samples/.empty_directory +1 -0
- data/generators/blank/public/stylesheets/.empty_directory +1 -0
- data/generators/bootstrap/Gemfile.tt +20 -0
- data/generators/bootstrap/app/content_types/.empty_directory +1 -0
- data/generators/bootstrap/app/views/pages/404.liquid +13 -0
- data/generators/bootstrap/app/views/pages/404.liquid.haml +10 -0
- data/generators/bootstrap/app/views/pages/index.liquid +85 -0
- data/generators/bootstrap/app/views/pages/index.liquid.haml +72 -0
- data/generators/bootstrap/app/views/snippets/footer.liquid +3 -0
- data/generators/bootstrap/app/views/snippets/footer.liquid.haml +2 -0
- data/generators/bootstrap/config/deploy.yml +12 -0
- data/generators/bootstrap/config/site.yml.tt +16 -0
- data/generators/bootstrap/config/translations.yml +8 -0
- data/generators/bootstrap/config.ru +3 -0
- data/generators/bootstrap/data/.empty_directory +1 -0
- data/generators/bootstrap/public/fonts/FontAwesome.otf +0 -0
- data/generators/bootstrap/public/fonts/font-awesome-ie7.min.css +23 -0
- data/generators/bootstrap/public/fonts/font-awesome.css +469 -0
- data/generators/bootstrap/public/fonts/font-awesome.min.css +34 -0
- data/generators/bootstrap/public/fonts/fontawesome-webfont.eot +0 -0
- data/generators/bootstrap/public/fonts/fontawesome-webfont.ttf +0 -0
- data/generators/bootstrap/public/fonts/fontawesome-webfont.woff +0 -0
- data/generators/bootstrap/public/javascripts/bootstrap.js +2159 -0
- data/generators/bootstrap/public/javascripts/bootstrap.min.js +6 -0
- data/generators/bootstrap/public/samples/.empty_directory +1 -0
- data/generators/bootstrap/public/stylesheets/application.css.scss +39 -0
- data/generators/bootstrap/public/stylesheets/bootstrap-responsive.css +1092 -0
- data/generators/bootstrap/public/stylesheets/bootstrap-responsive.min.css +9 -0
- data/generators/bootstrap/public/stylesheets/bootstrap.css +5652 -0
- data/generators/bootstrap/public/stylesheets/bootstrap.min.css +726 -0
- data/generators/content_type/app/content_types/%name%.yml.tt +58 -0
- data/generators/content_type/data/%name%.yml.tt +24 -0
- data/generators/page/template.liquid.haml.tt +35 -0
- data/generators/page/template.liquid.tt +1 -0
- data/generators/snippet/template.liquid.haml.tt +4 -0
- data/generators/snippet/template.liquid.tt +4 -0
- data/lib/locomotive/builder/cli.rb +225 -0
- data/lib/locomotive/builder/exceptions.rb +17 -0
- data/lib/locomotive/builder/generators/content_type.rb +47 -0
- data/lib/locomotive/builder/generators/page.rb +57 -0
- data/lib/locomotive/builder/generators/site/base.rb +30 -0
- data/lib/locomotive/builder/generators/site/blank.rb +23 -0
- data/lib/locomotive/builder/generators/site/bootstrap.rb +35 -0
- data/lib/locomotive/builder/generators/site.rb +97 -0
- data/lib/locomotive/builder/generators/snippet.rb +54 -0
- data/lib/locomotive/builder/liquid/drops/base.rb +44 -0
- data/lib/locomotive/builder/liquid/drops/content_entry.rb +48 -0
- data/lib/locomotive/builder/liquid/drops/content_types.rb +121 -0
- data/lib/locomotive/builder/liquid/drops/page.rb +36 -0
- data/lib/locomotive/builder/liquid/drops/site.rb +21 -0
- data/lib/locomotive/builder/liquid/errors.rb +7 -0
- data/lib/locomotive/builder/liquid/filters/date.rb +98 -0
- data/lib/locomotive/builder/liquid/filters/html.rb +154 -0
- data/lib/locomotive/builder/liquid/filters/misc.rb +28 -0
- data/lib/locomotive/builder/liquid/filters/resize.rb +18 -0
- data/lib/locomotive/builder/liquid/filters/text.rb +50 -0
- data/lib/locomotive/builder/liquid/filters/translate.rb +24 -0
- data/lib/locomotive/builder/liquid/patches.rb +47 -0
- data/lib/locomotive/builder/liquid/tags/consume.rb +58 -0
- data/lib/locomotive/builder/liquid/tags/csrf.rb +34 -0
- data/lib/locomotive/builder/liquid/tags/editable/base.rb +46 -0
- data/lib/locomotive/builder/liquid/tags/editable/control.rb +19 -0
- data/lib/locomotive/builder/liquid/tags/editable/file.rb +15 -0
- data/lib/locomotive/builder/liquid/tags/editable/long_text.rb +15 -0
- data/lib/locomotive/builder/liquid/tags/editable/short_text.rb +15 -0
- data/lib/locomotive/builder/liquid/tags/editable.rb +5 -0
- data/lib/locomotive/builder/liquid/tags/extends.rb +25 -0
- data/lib/locomotive/builder/liquid/tags/google_analytics.rb +28 -0
- data/lib/locomotive/builder/liquid/tags/inline_editor.rb +16 -0
- data/lib/locomotive/builder/liquid/tags/locale_switcher.rb +180 -0
- data/lib/locomotive/builder/liquid/tags/nav.rb +167 -0
- data/lib/locomotive/builder/liquid/tags/paginate.rb +105 -0
- data/lib/locomotive/builder/liquid/tags/seo.rb +74 -0
- data/lib/locomotive/builder/liquid/tags/snippet.rb +42 -0
- data/lib/locomotive/builder/liquid/tags/with_scope.rb +43 -0
- data/lib/locomotive/builder/liquid.rb +19 -0
- data/lib/locomotive/builder/listen.rb +48 -0
- data/lib/locomotive/builder/misc/core_ext.rb +29 -0
- data/lib/locomotive/builder/misc/dragonfly.rb +82 -0
- data/lib/locomotive/builder/misc/httparty.rb +47 -0
- data/lib/locomotive/builder/misc/i18n.rb +2 -0
- data/lib/locomotive/builder/misc/will_paginate.rb +16 -0
- data/lib/locomotive/builder/misc.rb +5 -0
- data/lib/locomotive/builder/server/dynamic_assets.rb +31 -0
- data/lib/locomotive/builder/server/entry_submission.rb +116 -0
- data/lib/locomotive/builder/server/favicon.rb +17 -0
- data/lib/locomotive/builder/server/locale.rb +42 -0
- data/lib/locomotive/builder/server/middleware.rb +54 -0
- data/lib/locomotive/builder/server/not_found.rb +18 -0
- data/lib/locomotive/builder/server/page.rb +59 -0
- data/lib/locomotive/builder/server/path.rb +34 -0
- data/lib/locomotive/builder/server/renderer.rb +105 -0
- data/lib/locomotive/builder/server/templatized_page.rb +32 -0
- data/lib/locomotive/builder/server.rb +78 -0
- data/lib/locomotive/builder/standalone_server.rb +33 -0
- data/lib/locomotive/builder/version.rb +5 -0
- data/lib/locomotive/builder.rb +167 -0
- data/locales/de.yml +143 -0
- data/locales/en.yml +164 -0
- data/locales/es.yml +119 -0
- data/locales/et.yml +140 -0
- data/locales/fr.yml +133 -0
- data/locales/it.yml +141 -0
- data/locales/nb.yml +177 -0
- data/locales/nl.yml +148 -0
- data/locales/pl.yml +189 -0
- data/locales/pt-BR.yml +125 -0
- data/locales/ru.yml +210 -0
- data/locomotivecms_builder.gemspec +42 -0
- data/spec/integration/cassettes/pull.yml +590 -0
- data/spec/integration/cassettes/push.yml +775 -0
- data/spec/integration/integration_helper.rb +15 -0
- data/spec/integration/server_spec.rb +37 -0
- data/spec/integration/sites_spec.rb +27 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/helpers.rb +13 -0
- metadata +468 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
module Locomotive
|
|
2
|
+
module Builder
|
|
3
|
+
module Liquid
|
|
4
|
+
module Tags
|
|
5
|
+
# Display the children pages of the site, current page or the parent page. If not precised, nav is applied on the current page.
|
|
6
|
+
# The html output is based on the ul/li tags.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
#
|
|
10
|
+
# {% nav site %} => <ul class="nav"><li class="on"><a href="/features">Features</a></li></ul>
|
|
11
|
+
#
|
|
12
|
+
# {% nav site, no_wrapper: true, exclude: 'contact|about', id: 'main-nav', class: 'nav', active_class: 'on' }
|
|
13
|
+
#
|
|
14
|
+
class Nav < ::Liquid::Tag
|
|
15
|
+
|
|
16
|
+
Syntax = /(#{::Liquid::Expression}+)?/
|
|
17
|
+
|
|
18
|
+
attr_accessor :current_page, :mounting_point
|
|
19
|
+
|
|
20
|
+
def initialize(tag_name, markup, tokens, context)
|
|
21
|
+
if markup =~ Syntax
|
|
22
|
+
@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
|
+
|
|
28
|
+
if @options[:snippet]
|
|
29
|
+
if template = self.parse_snippet_template(context, @options[:snippet])
|
|
30
|
+
@options[:liquid_render] = template
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
else
|
|
34
|
+
raise ::Liquid::SyntaxError.new("Syntax Error in 'nav' - Valid syntax: nav <site|parent|page|<path to a page>> <options>")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
super
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def render(context)
|
|
41
|
+
self.set_accessors_from_context(context)
|
|
42
|
+
|
|
43
|
+
children_output = []
|
|
44
|
+
|
|
45
|
+
entries = self.fetch_entries
|
|
46
|
+
|
|
47
|
+
entries.each_with_index do |p, index|
|
|
48
|
+
css = []
|
|
49
|
+
css << 'first' if index == 0
|
|
50
|
+
css << 'last' if index == entries.size - 1
|
|
51
|
+
|
|
52
|
+
children_output << render_entry_link(p, css.join(' '), 1)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
output = children_output.join("\n")
|
|
56
|
+
|
|
57
|
+
if @options[:no_wrapper] != 'true'
|
|
58
|
+
output = %{<ul id="#{@options[:id]}" class="#{@options[:class]}">\n#{output}</ul>}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
output
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
protected
|
|
65
|
+
|
|
66
|
+
def set_accessors_from_context(context)
|
|
67
|
+
self.current_page = context.registers[:page]
|
|
68
|
+
self.mounting_point = context.registers[:mounting_point]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def parse_snippet_template(context, template_name)
|
|
72
|
+
source = if template_name.include?('{')
|
|
73
|
+
template_name
|
|
74
|
+
else
|
|
75
|
+
context[:mounting_point].snippets[template_name].try(:source)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
source ? ::Liquid::Template.parse(source) : nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def fetch_entries
|
|
82
|
+
children = (case @source
|
|
83
|
+
when 'site' then self.mounting_point.pages['index']
|
|
84
|
+
when 'parent' then self.current_page.parent || self.current_page
|
|
85
|
+
when 'page' then self.current_page
|
|
86
|
+
else
|
|
87
|
+
self.mounting_point.pages[@source]
|
|
88
|
+
end).children.clone
|
|
89
|
+
|
|
90
|
+
children.delete_if { |p| !include_page?(p) }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Determines whether or not a page should be a part of the menu
|
|
94
|
+
def include_page?(page)
|
|
95
|
+
if !page.listed? || page.templatized? || !page.published?
|
|
96
|
+
false
|
|
97
|
+
elsif @options[:exclude]
|
|
98
|
+
(page.fullpath =~ @options[:exclude]).nil?
|
|
99
|
+
else
|
|
100
|
+
true
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Returns a list element, a link to the page and its children
|
|
105
|
+
def render_entry_link(page, css, depth)
|
|
106
|
+
selected = self.current_page.fullpath =~ /^#{page.fullpath}/ ? " #{@options[:active_class]}" : ''
|
|
107
|
+
|
|
108
|
+
icon = @options[:icon] ? '<span></span>' : ''
|
|
109
|
+
|
|
110
|
+
title = @options[:liquid_render] ? @options[:liquid_render].render('page' => page) : page.title
|
|
111
|
+
|
|
112
|
+
label = %{#{icon if @options[:icon] != 'after' }#{title}#{icon if @options[:icon] == 'after' }}
|
|
113
|
+
|
|
114
|
+
dropdow = ""
|
|
115
|
+
link_options = ""
|
|
116
|
+
href = ::I18n.locale.to_s == self.mounting_point.default_locale.to_s ? "/#{page.fullpath}" : "/#{::I18n.locale}/#{page.fullpath}"
|
|
117
|
+
caret = ""
|
|
118
|
+
|
|
119
|
+
if render_children_for_page?(page, depth) && bootstrap?
|
|
120
|
+
dropdow = "dropdown"
|
|
121
|
+
link_options = %{class="dropdown-toggle" data-toggle="dropdown"}
|
|
122
|
+
href = "#"
|
|
123
|
+
caret = %{<b class="caret"></b>}
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
output = %{<li id="#{page.slug.to_s.dasherize}-link" class="link#{selected} #{css} #{dropdow}">}
|
|
127
|
+
output << %{<a href="#{href}" #{link_options}>#{label} #{caret}</a>}
|
|
128
|
+
output << render_entry_children(page, depth.succ) if (depth.succ <= @options[:depth].to_i)
|
|
129
|
+
output << %{</li>}
|
|
130
|
+
|
|
131
|
+
output.strip
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def render_children_for_page?(page, depth)
|
|
135
|
+
depth.succ <= @options[:depth].to_i && page.children.reject { |c| !include_page?(c) }.any?
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Recursively creates a nested unordered list for the depth specified
|
|
139
|
+
def render_entry_children(page, depth)
|
|
140
|
+
output = %{}
|
|
141
|
+
|
|
142
|
+
children = page.children.reject { |c| !include_page?(c) }
|
|
143
|
+
if children.present?
|
|
144
|
+
output = %{<ul id="#{@options[:id]}-#{page.slug.to_s.dasherize}" class="#{bootstrap? ? "dropdown-menu" : ""}">}
|
|
145
|
+
children.each do |c, page|
|
|
146
|
+
css = []
|
|
147
|
+
css << 'first' if children.first == c
|
|
148
|
+
css << 'last' if children.last == c
|
|
149
|
+
|
|
150
|
+
output << render_entry_link(c, css.join(' '),depth)
|
|
151
|
+
end
|
|
152
|
+
output << %{</ul>}
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
output
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def bootstrap?
|
|
159
|
+
@options[:bootstrap] == 'true' || @options[:bootstrap] == true
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
::Liquid::Template.register_tag('nav', Nav)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module Locomotive
|
|
2
|
+
module Builder
|
|
3
|
+
module Liquid
|
|
4
|
+
module Tags
|
|
5
|
+
|
|
6
|
+
# Paginate a collection
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
#
|
|
10
|
+
# {% paginate contents.projects by 5 %}
|
|
11
|
+
# {% for project in paginate.collection %}
|
|
12
|
+
# {{ project.name }}
|
|
13
|
+
# {% endfor %}
|
|
14
|
+
# {% endpaginate %}
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
class Paginate < ::Liquid::Block
|
|
18
|
+
|
|
19
|
+
Syntax = /(#{::Liquid::Expression}+)\s+by\s+([0-9]+)/
|
|
20
|
+
|
|
21
|
+
def initialize(tag_name, markup, tokens, context)
|
|
22
|
+
if markup =~ Syntax
|
|
23
|
+
@collection_name = $1
|
|
24
|
+
@per_page = $2.to_i
|
|
25
|
+
else
|
|
26
|
+
raise ::Liquid::SyntaxError.new("Syntax Error in 'paginate' - Valid syntax: paginate <collection> by <number>")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
super
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def render(context)
|
|
33
|
+
context.stack do
|
|
34
|
+
collection = context[@collection_name]
|
|
35
|
+
|
|
36
|
+
raise ::Liquid::ArgumentError.new("Cannot paginate array '#{@collection_name}'. Not found.") if collection.nil?
|
|
37
|
+
|
|
38
|
+
pagination = collection.send(:paginate, {
|
|
39
|
+
:page => context['current_page'],
|
|
40
|
+
:per_page => @per_page }).stringify_keys!
|
|
41
|
+
|
|
42
|
+
page_count, current_page = pagination['total_pages'], pagination['current_page']
|
|
43
|
+
|
|
44
|
+
path = sanitize_path(context['fullpath'])
|
|
45
|
+
|
|
46
|
+
pagination['previous'] = link(I18n.t('pagination.previous'), current_page - 1, path) if pagination['previous_page']
|
|
47
|
+
pagination['next'] = link(I18n.t('pagination.next'), current_page + 1, path) if pagination['next_page']
|
|
48
|
+
pagination['parts'] = []
|
|
49
|
+
|
|
50
|
+
hellip_break = false
|
|
51
|
+
|
|
52
|
+
if page_count > 1
|
|
53
|
+
1.upto(page_count) do |page|
|
|
54
|
+
if current_page == page
|
|
55
|
+
pagination['parts'] << no_link(page)
|
|
56
|
+
elsif page == 1
|
|
57
|
+
pagination['parts'] << link(page, page, path)
|
|
58
|
+
elsif page == page_count - 1
|
|
59
|
+
pagination['parts'] << link(page, page, path)
|
|
60
|
+
elsif page <= current_page - window_size or page >= current_page + window_size
|
|
61
|
+
next if hellip_break
|
|
62
|
+
pagination['parts'] << no_link('…')
|
|
63
|
+
hellip_break = true
|
|
64
|
+
next
|
|
65
|
+
else
|
|
66
|
+
pagination['parts'] << link(page, page, path)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
hellip_break = false
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context['paginate'] = pagination
|
|
74
|
+
|
|
75
|
+
render_all(@nodelist, context)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def sanitize_path(path)
|
|
82
|
+
_path = path.gsub(/page=[0-9]+&?/, '').gsub(/_pjax=true&?/, '')
|
|
83
|
+
_path = _path.slice(0..-2) if _path.last == '?' || _path.last == '&'
|
|
84
|
+
_path
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def window_size
|
|
88
|
+
3
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def no_link(title)
|
|
92
|
+
{ 'title' => title, 'is_link' => false, 'hellip_break' => title == '…' }
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def link(title, page, path)
|
|
96
|
+
_path = %(#{path}#{path.include?('?') ? '&' : '?'}page=#{page})
|
|
97
|
+
{ 'title' => title, 'url' => _path, 'is_link' => true }
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
::Liquid::Template.register_tag('paginate', Paginate)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module Locomotive
|
|
2
|
+
module Builder
|
|
3
|
+
module Liquid
|
|
4
|
+
module Tags
|
|
5
|
+
module SEO
|
|
6
|
+
|
|
7
|
+
class Base < ::Liquid::Tag
|
|
8
|
+
|
|
9
|
+
def render(context)
|
|
10
|
+
%{
|
|
11
|
+
#{self.render_title(context)}
|
|
12
|
+
#{self.render_metadata(context)}
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
protected
|
|
17
|
+
|
|
18
|
+
def render_title(context)
|
|
19
|
+
title = self.value_for(:seo_title, context)
|
|
20
|
+
title = context.registers[:site].name if title.blank?
|
|
21
|
+
|
|
22
|
+
%{
|
|
23
|
+
<title>#{title}</title>
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def render_metadata(context)
|
|
28
|
+
%{
|
|
29
|
+
<meta name="description" content="#{self.value_for(:meta_description, context)}" />
|
|
30
|
+
<meta name="keywords" content="#{self.value_for(:meta_keywords, context)}" />
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Removes whitespace and quote characters from the input
|
|
35
|
+
def sanitized_string(string)
|
|
36
|
+
string ? string.strip.gsub(/"/, '') : ''
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def value_for(attribute, context)
|
|
40
|
+
object = self.metadata_object(context)
|
|
41
|
+
value = object.try(attribute.to_sym).blank? ? context.registers[:site].send(attribute.to_sym) : object.send(attribute.to_sym)
|
|
42
|
+
self.sanitized_string(value)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def metadata_object(context)
|
|
46
|
+
context['content_instance'] || context['page']
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class Title < Base
|
|
51
|
+
|
|
52
|
+
def render(context)
|
|
53
|
+
self.render_title(context)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
class Metadata < Base
|
|
59
|
+
|
|
60
|
+
def render(context)
|
|
61
|
+
self.render_metadata(context)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
::Liquid::Template.register_tag('seo', SEO::Base)
|
|
69
|
+
::Liquid::Template.register_tag('seo_title', SEO::Title)
|
|
70
|
+
::Liquid::Template.register_tag('seo_metadata', SEO::Metadata)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Locomotive
|
|
2
|
+
module Builder
|
|
3
|
+
module Liquid
|
|
4
|
+
module Tags
|
|
5
|
+
|
|
6
|
+
class Snippet < ::Liquid::Include
|
|
7
|
+
|
|
8
|
+
def render(context)
|
|
9
|
+
name = @template_name.gsub(/[\"\']/, '')
|
|
10
|
+
|
|
11
|
+
source = context.registers[:mounting_point].snippets[name].try(:source)
|
|
12
|
+
|
|
13
|
+
partial = ::Liquid::Template.parse(source)
|
|
14
|
+
|
|
15
|
+
variable = context[@variable_name || @template_name[1..-2]]
|
|
16
|
+
|
|
17
|
+
context.stack do
|
|
18
|
+
@attributes.each do |key, value|
|
|
19
|
+
context[key] = context[value]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
output = (if variable.is_a?(Array)
|
|
23
|
+
variable.collect do |variable|
|
|
24
|
+
context[@template_name[1..-2]] = variable
|
|
25
|
+
partial.render(context)
|
|
26
|
+
end
|
|
27
|
+
else
|
|
28
|
+
context[@template_name[1..-2]] = variable
|
|
29
|
+
partial.render(context)
|
|
30
|
+
end)
|
|
31
|
+
|
|
32
|
+
output
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
::Liquid::Template.register_tag('include', Snippet)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Locomotive
|
|
2
|
+
module Builder
|
|
3
|
+
module Liquid
|
|
4
|
+
module Tags
|
|
5
|
+
class WithScope < ::Liquid::Block
|
|
6
|
+
|
|
7
|
+
def initialize(tag_name, markup, tokens, context)
|
|
8
|
+
@options = {}
|
|
9
|
+
|
|
10
|
+
markup.scan(::Liquid::TagAttributes) do |key, value|
|
|
11
|
+
@options[key] = value
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def render(context)
|
|
18
|
+
context.stack do
|
|
19
|
+
context['with_scope'] = decode(@options, context)
|
|
20
|
+
render_all(@nodelist, context)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def decode(attributes, context)
|
|
27
|
+
attributes.each_pair do |key, value|
|
|
28
|
+
attributes[key] = (case value
|
|
29
|
+
when /^true|false$/i then value == 'true'
|
|
30
|
+
when /^[0-9]+$/ then value.to_i
|
|
31
|
+
when /^["|'](.+)["|']$/ then $1.gsub(/^["|']/, '').gsub(/["|']$/, '')
|
|
32
|
+
else
|
|
33
|
+
context[value] || value
|
|
34
|
+
end)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
::Liquid::Template.register_tag('with_scope', WithScope)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require "locomotive/mounter"
|
|
2
|
+
require 'liquid'
|
|
3
|
+
require 'locomotive/builder/liquid/drops/base'
|
|
4
|
+
|
|
5
|
+
%w{. drops tags filters}.each do |dir|
|
|
6
|
+
Dir[File.join(File.dirname(__FILE__), 'liquid', dir, '*.rb')].each { |lib| require lib }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# add to_liquid methods to main models from the mounter
|
|
11
|
+
%w{site page content_entry}.each do |name|
|
|
12
|
+
klass = "Locomotive::Mounter::Models::#{name.classify}".constantize
|
|
13
|
+
|
|
14
|
+
klass.class_eval <<-EOV
|
|
15
|
+
def to_liquid
|
|
16
|
+
::Locomotive::Builder::Liquid::Drops::#{name.classify}.new(self)
|
|
17
|
+
end
|
|
18
|
+
EOV
|
|
19
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'listen'
|
|
2
|
+
|
|
3
|
+
module Locomotive::Builder
|
|
4
|
+
class Listen
|
|
5
|
+
|
|
6
|
+
attr_accessor :reader
|
|
7
|
+
|
|
8
|
+
def self.instance
|
|
9
|
+
@@instance = new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def start(reader)
|
|
13
|
+
self.reader = reader
|
|
14
|
+
|
|
15
|
+
self.definitions.each do |definition|
|
|
16
|
+
self.apply(definition)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def definitions
|
|
21
|
+
[
|
|
22
|
+
['config', /\.yml/, [:site, :content_types, :pages, :snippets, :content_entries, :translations]],
|
|
23
|
+
['app/views', /\.liquid/, [:pages, :snippets]],
|
|
24
|
+
['app/content_types', /\.yml/, [:content_types, :content_entries]],
|
|
25
|
+
['data', /\.yml/, :content_entries]
|
|
26
|
+
]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
protected
|
|
30
|
+
|
|
31
|
+
def apply(definition)
|
|
32
|
+
reloader = Proc.new do |modified, added, removed|
|
|
33
|
+
reader.reload(definition.last)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
filter = definition[1]
|
|
37
|
+
path = File.join(self.reader.mounting_point.path, definition.first)
|
|
38
|
+
path = File.expand_path(path)
|
|
39
|
+
|
|
40
|
+
listener = ::Listen.to(path).filter(filter).change(&reloader)
|
|
41
|
+
|
|
42
|
+
# non blocking listener
|
|
43
|
+
listener.start(false)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
unless Hash.instance_methods.include?(:underscore_keys)
|
|
2
|
+
class Hash
|
|
3
|
+
|
|
4
|
+
def underscore_keys
|
|
5
|
+
new_hash = {}
|
|
6
|
+
|
|
7
|
+
self.each_pair do |key, value|
|
|
8
|
+
if value.respond_to?(:collect!) # Array
|
|
9
|
+
value.collect do |item|
|
|
10
|
+
if item.respond_to?(:each_pair) # Hash item within
|
|
11
|
+
item.underscore_keys
|
|
12
|
+
else
|
|
13
|
+
item
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
elsif value.respond_to?(:each_pair) # Hash
|
|
17
|
+
value = value.underscore_keys
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
new_key = key.is_a?(String) ? key.underscore : key # only String keys
|
|
21
|
+
|
|
22
|
+
new_hash[new_key] = value
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
self.replace(new_hash)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module Locomotive
|
|
2
|
+
module Builder
|
|
3
|
+
class Dragonfly
|
|
4
|
+
|
|
5
|
+
attr_accessor :path, :enabled
|
|
6
|
+
|
|
7
|
+
def enabled?
|
|
8
|
+
!!self.enabled
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def resize_url(source, resize_string)
|
|
12
|
+
_source = (case source
|
|
13
|
+
when String then source
|
|
14
|
+
when Hash then source['url'] || source[:url]
|
|
15
|
+
else
|
|
16
|
+
source.try(:url)
|
|
17
|
+
end)
|
|
18
|
+
|
|
19
|
+
if _source.blank?
|
|
20
|
+
LocomotiveEditor::Logger.error "Unable to resize on the fly: #{source.inspect}"
|
|
21
|
+
return
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
return _source unless self.enabled?
|
|
25
|
+
|
|
26
|
+
if _source =~ /^http/
|
|
27
|
+
file = self.class.app.fetch_url(_source)
|
|
28
|
+
else
|
|
29
|
+
file = self.class.app.fetch_file(File.join(self.path, 'public', _source))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
file.process(:thumb, resize_string).url
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.app
|
|
36
|
+
::Dragonfly[:images]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def self.instance
|
|
41
|
+
@@instance ||= new
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.setup!(path)
|
|
45
|
+
self.instance.path = path
|
|
46
|
+
self.instance.enabled = false
|
|
47
|
+
|
|
48
|
+
begin
|
|
49
|
+
require 'rack/cache'
|
|
50
|
+
require 'RMagick'
|
|
51
|
+
require 'dragonfly'
|
|
52
|
+
|
|
53
|
+
## initialize Dragonfly ##
|
|
54
|
+
app = ::Dragonfly[:images].configure_with(:imagemagick)
|
|
55
|
+
|
|
56
|
+
## configure it ##
|
|
57
|
+
::Dragonfly[:images].configure do |c|
|
|
58
|
+
convert = `which convert`.strip.presence || '/usr/local/bin/convert'
|
|
59
|
+
c.convert_command = convert
|
|
60
|
+
c.identify_command = convert
|
|
61
|
+
|
|
62
|
+
c.allow_fetch_url = true
|
|
63
|
+
c.allow_fetch_file = true
|
|
64
|
+
|
|
65
|
+
c.url_format = '/images/dynamic/:job/:basename.:format'
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
puts 'Dragonfly enabled'
|
|
69
|
+
|
|
70
|
+
self.instance.enabled = true
|
|
71
|
+
rescue Exception => e
|
|
72
|
+
puts %{
|
|
73
|
+
\tIf you want to take full benefits of all the features in the LocomotiveEditor, we recommend you to install ImageMagick and RMagick.
|
|
74
|
+
\tCheck out the documentation here: http://doc.locomotivecms.com/editor/installation.}
|
|
75
|
+
|
|
76
|
+
puts 'Dragonfly disabled'
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
|
|
3
|
+
module Locomotive
|
|
4
|
+
module Builder
|
|
5
|
+
module Httparty
|
|
6
|
+
class Webservice
|
|
7
|
+
|
|
8
|
+
include ::HTTParty
|
|
9
|
+
|
|
10
|
+
def self.consume(url, options = {})
|
|
11
|
+
url = ::HTTParty.normalize_base_uri(url)
|
|
12
|
+
|
|
13
|
+
uri = URI.parse(url)
|
|
14
|
+
options[:base_uri] = "#{uri.scheme}://#{uri.host}"
|
|
15
|
+
options[:base_uri] += ":#{uri.port}" if uri.port != 80
|
|
16
|
+
path = uri.request_uri
|
|
17
|
+
|
|
18
|
+
options.delete(:format) if options[:format] == 'default'
|
|
19
|
+
|
|
20
|
+
username, password = options.delete(:username), options.delete(:password)
|
|
21
|
+
options[:basic_auth] = { username: username, password: password } if username
|
|
22
|
+
|
|
23
|
+
path ||= '/'
|
|
24
|
+
|
|
25
|
+
# puts "[WebService] consuming #{path}, #{options.inspect}"
|
|
26
|
+
|
|
27
|
+
response = self.get(path, options)
|
|
28
|
+
|
|
29
|
+
if response.code == 200
|
|
30
|
+
_response = response.parsed_response
|
|
31
|
+
if _response.respond_to?(:underscore_keys)
|
|
32
|
+
_response.underscore_keys
|
|
33
|
+
else
|
|
34
|
+
_response.collect(&:underscore_keys)
|
|
35
|
+
end
|
|
36
|
+
else
|
|
37
|
+
# TODO: handle errors
|
|
38
|
+
puts "[Locomotive][Builder][Error] consuming #{path}, #{options.inspect}, response = #{response.inspect}"
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'will_paginate'
|
|
2
|
+
require 'will_paginate/collection'
|
|
3
|
+
|
|
4
|
+
Array.class_eval do
|
|
5
|
+
def paginate(options = {})
|
|
6
|
+
raise ArgumentError, "parameter hash expected (got #{options.inspect})" unless Hash === options
|
|
7
|
+
|
|
8
|
+
WillPaginate::Collection.create(
|
|
9
|
+
options[:page] || 1,
|
|
10
|
+
options[:per_page] || 30,
|
|
11
|
+
options[:total_entries] || self.length
|
|
12
|
+
) { |pager|
|
|
13
|
+
pager.replace self[pager.offset, pager.per_page].to_a
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
end
|