locomotive_cms 2.5.4 → 2.5.5
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.
- checksums.yaml +4 -4
- data/app/assets/images/locomotive/icons/flags/bf.png +0 -0
- data/app/assets/images/locomotive/icons/flags/mg.png +0 -0
- data/app/assets/javascripts/locomotive/views/sites/memberships_view.js.coffee +4 -0
- data/app/controllers/locomotive/api/content_entries_controller.rb +1 -1
- data/app/controllers/locomotive/content_entries_controller.rb +1 -1
- data/app/controllers/locomotive/public/sitemaps_controller.rb +9 -0
- data/app/helpers/locomotive/base_helper.rb +13 -0
- data/app/helpers/locomotive/content_types_helper.rb +2 -1
- data/app/models/locomotive/content_entry.rb +46 -10
- data/app/models/locomotive/content_type.rb +3 -0
- data/app/models/locomotive/extensions/content_entry/csv.rb +2 -2
- data/app/models/locomotive/theme_asset.rb +2 -1
- data/app/views/locomotive/content_entries/_list.html.haml +1 -1
- data/app/views/locomotive/public/sitemaps/show.xml.builder +6 -4
- data/config/locales/admin_ui.es.yml +7 -0
- data/features/public/content_entries.feature +1 -1
- data/lib/generators/locomotive/install/templates/locomotive.rb +4 -0
- data/lib/locomotive/configuration.rb +2 -1
- data/lib/locomotive/liquid/asset_host.rb +51 -0
- data/lib/locomotive/liquid/drops/uploader.rb +7 -1
- data/lib/locomotive/liquid/filters/base.rb +8 -4
- data/lib/locomotive/liquid/tags/editable/file.rb +9 -5
- data/lib/locomotive/mongoid/patches.rb +44 -0
- data/lib/locomotive/render.rb +2 -1
- data/lib/locomotive/version.rb +1 -1
- data/spec/lib/locomotive/liquid/asset_host_spec.rb +79 -0
- data/spec/lib/locomotive/liquid/drops/content_entry_spec.rb +55 -19
- data/spec/lib/locomotive/liquid/filters/html_spec.rb +3 -1
- data/spec/lib/locomotive/liquid/tags/editable/file_spec.rb +72 -0
- data/spec/models/locomotive/content_type_spec.rb +31 -0
- data/spec/models/locomotive/theme_asset_spec.rb +4 -4
- data/spec/support/asset_host_stubs.rb +17 -0
- metadata +11 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 934e34a25d00b8c0c55c81d20e17346b7a75f105
|
|
4
|
+
data.tar.gz: dd086d5f1ef9307fd1b6f4deb59c0581840b45c7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3dd291b6d7e877f9187ec006a9d66300b176d7cecba047cf94a842f9d29f72d614f13e67a41006f0a1ac97537eac170134f8d31f468b99a1c2a3ca00b47c1c7a
|
|
7
|
+
data.tar.gz: 249b2e6f9b65fc55e13ff4aa31e40853d7f163a8c9e846fedeba3619ca456dd81e6610f5858b719fd8f8966f0e558e924772ab985bb5e840056120fe006d7df7
|
|
Binary file
|
|
Binary file
|
|
@@ -4,6 +4,8 @@ class Locomotive.Views.Sites.MembershipsView extends Backbone.View
|
|
|
4
4
|
|
|
5
5
|
tagName: 'div'
|
|
6
6
|
|
|
7
|
+
id: 'site_memberships'
|
|
8
|
+
|
|
7
9
|
className: 'list'
|
|
8
10
|
|
|
9
11
|
_entry_views = []
|
|
@@ -13,6 +15,8 @@ class Locomotive.Views.Sites.MembershipsView extends Backbone.View
|
|
|
13
15
|
|
|
14
16
|
@enable_ui_effects()
|
|
15
17
|
|
|
18
|
+
$(@el).append('<span class="error-anchor"></span>')
|
|
19
|
+
|
|
16
20
|
return @
|
|
17
21
|
|
|
18
22
|
change_entry: (membership, value) ->
|
|
@@ -2,6 +2,8 @@ module Locomotive
|
|
|
2
2
|
module Public
|
|
3
3
|
class SitemapsController < Public::BaseController
|
|
4
4
|
|
|
5
|
+
before_filter :set_locale
|
|
6
|
+
|
|
5
7
|
respond_to :xml
|
|
6
8
|
|
|
7
9
|
def show
|
|
@@ -9,6 +11,13 @@ module Locomotive
|
|
|
9
11
|
respond_with @pages
|
|
10
12
|
end
|
|
11
13
|
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
def set_locale
|
|
17
|
+
::Mongoid::Fields::I18n.locale = params[:locale] || current_site.default_locale
|
|
18
|
+
::I18n.locale = ::Mongoid::Fields::I18n.locale
|
|
19
|
+
end
|
|
20
|
+
|
|
12
21
|
end
|
|
13
22
|
end
|
|
14
23
|
end
|
|
@@ -200,5 +200,18 @@ module Locomotive
|
|
|
200
200
|
end
|
|
201
201
|
alias :l :localize
|
|
202
202
|
|
|
203
|
+
# other helpers
|
|
204
|
+
|
|
205
|
+
# MongoDB crashes when performing a query on a big collection
|
|
206
|
+
# where there is a sort without an index on the fields to sort.
|
|
207
|
+
def empty_collection?(collection)
|
|
208
|
+
# criteria ?
|
|
209
|
+
if collection.respond_to?(:without_sorting)
|
|
210
|
+
collection.without_sorting.empty?
|
|
211
|
+
else
|
|
212
|
+
collection.empty?
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
203
216
|
end
|
|
204
217
|
end
|
|
@@ -61,7 +61,8 @@ module Locomotive
|
|
|
61
61
|
registers = {
|
|
62
62
|
controller: self,
|
|
63
63
|
site: current_site,
|
|
64
|
-
current_locomotive_account: current_locomotive_account
|
|
64
|
+
current_locomotive_account: current_locomotive_account,
|
|
65
|
+
asset_host: Locomotive::Liquid::AssetHost.new(request, current_site, Locomotive.config.asset_host)
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
preserve(content_type.item_template.render(::Liquid::Context.new({}, assigns, registers)))
|
|
@@ -36,6 +36,19 @@ module Locomotive
|
|
|
36
36
|
scope :latest_updated, order_by(updated_at: :desc).limit(Locomotive.config.ui[:latest_entries_nb])
|
|
37
37
|
scope :next_or_previous, ->(condition, order_by) { where({ _visible: true }.merge(condition)).limit(1).order_by(order_by) }
|
|
38
38
|
|
|
39
|
+
## indexes ##
|
|
40
|
+
index site_id: 1
|
|
41
|
+
index _type: 1
|
|
42
|
+
index content_type_id: 1
|
|
43
|
+
Locomotive.config.site_locales.each do |locale|
|
|
44
|
+
index _type: 1, "_slug.#{locale}" => 1
|
|
45
|
+
index content_type_id: 1, "_slug.#{locale}" => 1
|
|
46
|
+
end
|
|
47
|
+
index content_type_id: 1, created_at: 1
|
|
48
|
+
index content_type_id: 1, _type: 1, created_at: 1
|
|
49
|
+
index _type: 1, _position: 1
|
|
50
|
+
index content_type_id: 1, _position: 1
|
|
51
|
+
|
|
39
52
|
## methods ##
|
|
40
53
|
|
|
41
54
|
alias :visible? :_visible?
|
|
@@ -153,7 +166,7 @@ module Locomotive
|
|
|
153
166
|
if self._slug.present?
|
|
154
167
|
self._slug.permalink!
|
|
155
168
|
|
|
156
|
-
self.
|
|
169
|
+
self.find_next_unique_slug if self.slug_already_taken?
|
|
157
170
|
end
|
|
158
171
|
|
|
159
172
|
# all the site locales share the same slug ONLY IF the entry is not localized.
|
|
@@ -174,12 +187,36 @@ module Locomotive
|
|
|
174
187
|
end
|
|
175
188
|
end
|
|
176
189
|
|
|
177
|
-
#
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
190
|
+
# Find the next available unique slug as a string
|
|
191
|
+
# and replace the current _slug.
|
|
192
|
+
def find_next_unique_slug
|
|
193
|
+
_index = 0
|
|
194
|
+
_base = self._slug.gsub(/-\d+$/, '')
|
|
195
|
+
|
|
196
|
+
if _similar = similar_slug(_base)
|
|
197
|
+
_index = _similar.scan(/-(\d+)$/).flatten.last.to_i
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
loop do
|
|
201
|
+
_index += 1
|
|
202
|
+
self._slug = [_base, _index].join('-')
|
|
203
|
+
break unless self.slug_already_taken?
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def similar_slug(slug)
|
|
208
|
+
_last = self.class.where(:_id.ne => self._id, _slug: /^#{slug}-?\d*$/i)
|
|
209
|
+
.only(:_slug)
|
|
210
|
+
.order_by(:_id.desc)
|
|
211
|
+
.context
|
|
212
|
+
.query
|
|
213
|
+
.first
|
|
214
|
+
|
|
215
|
+
if _last
|
|
216
|
+
_last['_slug'][::Mongoid::Fields::I18n.locale.to_s]
|
|
217
|
+
else
|
|
218
|
+
nil
|
|
219
|
+
end
|
|
183
220
|
end
|
|
184
221
|
|
|
185
222
|
def slug_already_taken?
|
|
@@ -203,9 +240,8 @@ module Locomotive
|
|
|
203
240
|
end
|
|
204
241
|
|
|
205
242
|
def add_to_list_bottom
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
end
|
|
243
|
+
max = self.class.indexed_max(:_position)
|
|
244
|
+
self._position = max + 1 if max
|
|
209
245
|
end
|
|
210
246
|
|
|
211
247
|
def send_notifications
|
|
@@ -37,7 +37,7 @@ module Locomotive
|
|
|
37
37
|
when :file
|
|
38
38
|
value.blank? ? '' : value.guess_url(options[:host])
|
|
39
39
|
when :belongs_to
|
|
40
|
-
value.try(:_label)
|
|
40
|
+
value.try(:_label) || ''
|
|
41
41
|
when :has_many, :many_to_many
|
|
42
42
|
value.map(&:_label).join(', ')
|
|
43
43
|
when :tags
|
|
@@ -68,7 +68,7 @@ module Locomotive
|
|
|
68
68
|
# header
|
|
69
69
|
csv << labels
|
|
70
70
|
# body
|
|
71
|
-
all.
|
|
71
|
+
all.each_by(100) do |entry|
|
|
72
72
|
csv << entry.to_values(options)
|
|
73
73
|
end
|
|
74
74
|
end
|
|
@@ -155,7 +155,8 @@ module Locomotive
|
|
|
155
155
|
sanitized_path = path.gsub(/[("')]/, '').gsub(/^\//, '').gsub(/\?[0-9]+$/, '')
|
|
156
156
|
|
|
157
157
|
if asset = self.site.theme_assets.where(local_path: sanitized_path).first
|
|
158
|
-
|
|
158
|
+
timestamp = self.updated_at.to_i
|
|
159
|
+
"#{path.first}#{asset.source.url}?#{timestamp}#{path.last}"
|
|
159
160
|
else
|
|
160
161
|
path
|
|
161
162
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
- if entries
|
|
1
|
+
- if empty_collection?(entries)
|
|
2
2
|
%p.no-items!= t('.no_items', url: new_content_entry_path(content_type.slug))
|
|
3
3
|
- else
|
|
4
4
|
%ul{ id: 'entries-list', class: "#{content_type.groupable? ? 'grouped' : 'list'} #{'sortable' if content_type.order_manually?}", :'data-url' => sort_content_entries_path(content_type.slug, :json) }
|
|
@@ -10,10 +10,12 @@ xml.urlset "xmlns" => "http://www.sitemaps.org/schemas/sitemap/0.9" do
|
|
|
10
10
|
if not page.index_or_not_found?
|
|
11
11
|
if page.templatized?
|
|
12
12
|
page.fetch_target_entries(_visible: true).each do |c|
|
|
13
|
-
|
|
14
|
-
xml.
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
if c._slug.present?
|
|
14
|
+
xml.url do
|
|
15
|
+
xml.loc public_page_url(page, { content: c })
|
|
16
|
+
xml.lastmod c.updated_at.to_date.to_s('%Y-%m-%d')
|
|
17
|
+
xml.priority 0.9
|
|
18
|
+
end
|
|
17
19
|
end
|
|
18
20
|
end
|
|
19
21
|
else
|
|
@@ -60,11 +60,16 @@ es:
|
|
|
60
60
|
disable_with: "locomotive.disable_with.form_actions"
|
|
61
61
|
footer:
|
|
62
62
|
who_is_behind: "Servicio desarrollado por %{development} y diseñado por <a href=\"http://www.sachagreif.com\">Sacha Greif</a>"
|
|
63
|
+
form:
|
|
64
|
+
change_file: cambiar
|
|
65
|
+
delete_file: eliminar
|
|
66
|
+
cancel: cancelar
|
|
63
67
|
form_actions:
|
|
64
68
|
back: Volver sin guardar
|
|
65
69
|
create: Crear
|
|
66
70
|
update: Actualizar
|
|
67
71
|
send: Enviar
|
|
72
|
+
disable_with: Pendiente...
|
|
68
73
|
|
|
69
74
|
notifications:
|
|
70
75
|
new_content_entry:
|
|
@@ -86,6 +91,8 @@ es:
|
|
|
86
91
|
index:
|
|
87
92
|
is_required: requerido
|
|
88
93
|
default_label: Nombre del campo
|
|
94
|
+
form:
|
|
95
|
+
default_label: Nombre del campo
|
|
89
96
|
|
|
90
97
|
sessions:
|
|
91
98
|
new:
|
|
@@ -65,6 +65,10 @@ Locomotive.configure do |config|
|
|
|
65
65
|
#
|
|
66
66
|
# config.theme_assets_checksum = true
|
|
67
67
|
|
|
68
|
+
# Enable serving of images, stylesheets, and JavaScripts from an asset server
|
|
69
|
+
# config.asset_host = 'http://assets.example.com'
|
|
70
|
+
# config.asset_host = -> (request, site) { ... }
|
|
71
|
+
|
|
68
72
|
# Rack-cache settings, mainly used for the inline resizing image module. Default options:
|
|
69
73
|
# config.rack_cache = {
|
|
70
74
|
# verbose: true,
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Locomotive
|
|
2
|
+
module Liquid
|
|
3
|
+
|
|
4
|
+
class AssetHost
|
|
5
|
+
|
|
6
|
+
IsHTTP = /^https?\/\//o
|
|
7
|
+
|
|
8
|
+
attr_reader :request, :site, :host
|
|
9
|
+
|
|
10
|
+
def initialize(request, site, host)
|
|
11
|
+
@request, @site = request, site
|
|
12
|
+
|
|
13
|
+
@host = build_host(host, request, site)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def compute(source, timestamp = nil)
|
|
17
|
+
return source if source.nil?
|
|
18
|
+
|
|
19
|
+
return add_timestamp_suffix(source, timestamp) if source =~ IsHTTP
|
|
20
|
+
|
|
21
|
+
url = self.host ? URI.join(host, source).to_s : source
|
|
22
|
+
|
|
23
|
+
add_timestamp_suffix(url, timestamp)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def build_host(host, request, site)
|
|
29
|
+
if host
|
|
30
|
+
if host.respond_to?(:call)
|
|
31
|
+
host.call(request, site)
|
|
32
|
+
else
|
|
33
|
+
host
|
|
34
|
+
end
|
|
35
|
+
else
|
|
36
|
+
nil
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add_timestamp_suffix(source, timestamp)
|
|
41
|
+
if timestamp.nil? || timestamp == 0 || source.include?('?')
|
|
42
|
+
source
|
|
43
|
+
else
|
|
44
|
+
"#{source}?#{timestamp}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -3,7 +3,13 @@ module Locomotive
|
|
|
3
3
|
module Drops
|
|
4
4
|
class Uploader < Base
|
|
5
5
|
|
|
6
|
-
delegate :
|
|
6
|
+
delegate :size, to: :@_source
|
|
7
|
+
|
|
8
|
+
def url
|
|
9
|
+
url, timestamp = @_source.url, @_source.model.updated_at.to_i
|
|
10
|
+
|
|
11
|
+
@context.registers[:asset_host].compute(url, timestamp)
|
|
12
|
+
end
|
|
7
13
|
|
|
8
14
|
def filename
|
|
9
15
|
File.basename(@_source.url)
|
|
@@ -35,11 +35,15 @@ module Locomotive
|
|
|
35
35
|
path.gsub!(/(\?+.+)$/, '')
|
|
36
36
|
query_string = $1
|
|
37
37
|
|
|
38
|
-
url
|
|
38
|
+
# build the url of the theme asset based on the site and without loading
|
|
39
|
+
# the whole theme asset from database
|
|
40
|
+
_url = ThemeAssetUploader.url_for(@context.registers[:site], path)
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
# get a timestamp only the source url does not include a query string
|
|
43
|
+
timestamp = query_string.blank? ? @context.registers[:theme_assets_checksum][path] : nil
|
|
44
|
+
|
|
45
|
+
# prefix by a asset host if given
|
|
46
|
+
url = @context.registers[:asset_host].compute(_url, timestamp)
|
|
43
47
|
|
|
44
48
|
query_string ? "#{url}#{query_string}" : url
|
|
45
49
|
end
|
|
@@ -15,15 +15,19 @@ module Locomotive
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def render_element(context, element)
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
default_timestamp = context.registers[:page].updated_at.to_i
|
|
19
|
+
|
|
20
|
+
url, timestamp = (if element.source?
|
|
21
|
+
[element.source.url, default_timestamp]
|
|
20
22
|
else
|
|
21
23
|
if element.default_source_url.present?
|
|
22
|
-
element.default_source_url
|
|
24
|
+
[element.default_source_url, default_timestamp]
|
|
23
25
|
else
|
|
24
|
-
render_default_content(context)
|
|
26
|
+
[render_default_content(context), nil]
|
|
25
27
|
end
|
|
26
|
-
end
|
|
28
|
+
end)
|
|
29
|
+
|
|
30
|
+
context.registers[:asset_host].compute(url, timestamp)
|
|
27
31
|
end
|
|
28
32
|
|
|
29
33
|
def document_type
|
|
@@ -22,9 +22,53 @@ module Mongoid#:nodoc:
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
class Criteria
|
|
25
|
+
def without_sorting
|
|
26
|
+
clone.tap { |crit| crit.options.delete(:sort) }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# http://code.dblock.org/paging-and-iterating-over-large-mongo-collections
|
|
30
|
+
def each_by(by, &block)
|
|
31
|
+
idx = total = 0
|
|
32
|
+
set_limit = options[:limit]
|
|
33
|
+
while ((results = ordered_clone.limit(by).skip(idx)) && results.any?)
|
|
34
|
+
results.each do |result|
|
|
35
|
+
return self if set_limit and set_limit >= total
|
|
36
|
+
total += 1
|
|
37
|
+
yield result
|
|
38
|
+
end
|
|
39
|
+
idx += by
|
|
40
|
+
end
|
|
41
|
+
self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Optimized version of the max aggregate method.
|
|
45
|
+
# It works efficiently only if the field is part of a MongoDB index.
|
|
46
|
+
# more here: http://stackoverflow.com/questions/4762980/getting-the-highest-value-of-a-column-in-mongodb
|
|
47
|
+
def indexed_max(field)
|
|
48
|
+
_criteria = criteria.order_by(field.to_sym.desc).only(field.to_sym)
|
|
49
|
+
selector = _criteria.send(:selector_with_type_selection)
|
|
50
|
+
fields = _criteria.options[:fields]
|
|
51
|
+
sort = _criteria.options[:sort]
|
|
52
|
+
|
|
53
|
+
document = collection.find(selector).select(fields).sort(sort).limit(1).first
|
|
54
|
+
document ? document[field.to_s].to_i : nil
|
|
55
|
+
end
|
|
56
|
+
|
|
25
57
|
def to_liquid
|
|
26
58
|
Locomotive::Liquid::Drops::ProxyCollection.new(self)
|
|
27
59
|
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def ordered_clone
|
|
64
|
+
options[:sort] ? clone : clone.asc(:_id)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
module Finders
|
|
69
|
+
def indexed_max(field)
|
|
70
|
+
with_default_scope.indexed_max(field)
|
|
71
|
+
end
|
|
28
72
|
end
|
|
29
73
|
|
|
30
74
|
module Criterion
|
data/lib/locomotive/render.rb
CHANGED
|
@@ -222,7 +222,8 @@ module Locomotive
|
|
|
222
222
|
inline_editor: self.editing_page?,
|
|
223
223
|
logger: Rails.logger,
|
|
224
224
|
current_locomotive_account: current_locomotive_account,
|
|
225
|
-
theme_assets_checksum: Locomotive.config.theme_assets_checksum ? current_site.theme_assets.checksums : {}
|
|
225
|
+
theme_assets_checksum: Locomotive.config.theme_assets_checksum ? current_site.theme_assets.checksums : {},
|
|
226
|
+
asset_host: Locomotive::Liquid::AssetHost.new(request, current_site, Locomotive.config.asset_host)
|
|
226
227
|
}
|
|
227
228
|
end
|
|
228
229
|
|
data/lib/locomotive/version.rb
CHANGED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Locomotive::Liquid::AssetHost do
|
|
4
|
+
|
|
5
|
+
let(:request) { nil }
|
|
6
|
+
let(:site) { nil }
|
|
7
|
+
let(:host) { nil }
|
|
8
|
+
let(:timestamp) { nil }
|
|
9
|
+
let(:asset_host) { Locomotive::Liquid::AssetHost.new(request, site, host) }
|
|
10
|
+
let(:source) { '/sites/42/assets/1/banner.png' }
|
|
11
|
+
|
|
12
|
+
subject { asset_host.compute(source, timestamp) }
|
|
13
|
+
|
|
14
|
+
describe 'no host provided' do
|
|
15
|
+
|
|
16
|
+
it { should eq '/sites/42/assets/1/banner.png' }
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe 'with a timestamp' do
|
|
21
|
+
|
|
22
|
+
let(:timestamp) { '42' }
|
|
23
|
+
it { should eq '/sites/42/assets/1/banner.png?42' }
|
|
24
|
+
|
|
25
|
+
context 'the source already includes a query string' do
|
|
26
|
+
|
|
27
|
+
let(:source) { '/sites/42/assets/1/banner.png?foo' }
|
|
28
|
+
it { should eq '/sites/42/assets/1/banner.png?foo' }
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe 'the source is already a full url' do
|
|
35
|
+
|
|
36
|
+
let(:source) { 'http://somewhere.net/sites/42/assets/1/banner.png' }
|
|
37
|
+
it { should eq 'http://somewhere.net/sites/42/assets/1/banner.png' }
|
|
38
|
+
|
|
39
|
+
describe 'also with https' do
|
|
40
|
+
|
|
41
|
+
let(:source) { 'https://somewhere.net/sites/42/assets/1/banner.png' }
|
|
42
|
+
it { should eq 'https://somewhere.net/sites/42/assets/1/banner.png' }
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe 'the host is a string' do
|
|
49
|
+
|
|
50
|
+
let(:host) { 'http://assets.locomotivecms.com' }
|
|
51
|
+
it { should eq 'http://assets.locomotivecms.com/sites/42/assets/1/banner.png' }
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe 'the host is a block' do
|
|
56
|
+
|
|
57
|
+
let(:request) { stub(ssl: true) }
|
|
58
|
+
let(:site) { stub(cdn: true) }
|
|
59
|
+
let(:host) { ->(request, site) { site.cdn ? "http#{request.ssl ? 's' : ''}://assets.locomotivecms.com" : nil } }
|
|
60
|
+
|
|
61
|
+
it { should eq 'https://assets.locomotivecms.com/sites/42/assets/1/banner.png' }
|
|
62
|
+
|
|
63
|
+
context 'with a different request var' do
|
|
64
|
+
|
|
65
|
+
let(:request) { stub(ssl: false) }
|
|
66
|
+
it { should eq 'http://assets.locomotivecms.com/sites/42/assets/1/banner.png' }
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
context 'with a different site var' do
|
|
71
|
+
|
|
72
|
+
let(:site) { stub(cdn: false) }
|
|
73
|
+
it { should eq '/sites/42/assets/1/banner.png' }
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
@@ -2,45 +2,81 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
describe Locomotive::Liquid::Drops::ContentEntry do
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@category = Locomotive::Liquid::Drops::ContentEntry.new(mock('category', projects: @list))
|
|
9
|
-
end
|
|
5
|
+
describe 'with a file' do
|
|
6
|
+
|
|
7
|
+
before { Locomotive::Site.any_instance.stubs(:create_default_pages!).returns(true) }
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
let(:content_type) { build_content_type }
|
|
10
|
+
let(:content_entry) { content_type.entries.build(title: 'Locomotive', description: 'Lorem ipsum....', _label_field_name: 'title', created_at: Time.zone.parse('2013-07-05 00:00:00'), file: FixturedAsset.open('5k.png'), updated_at: DateTime.parse('2007-06-29 21:00:00')) }
|
|
11
|
+
let(:content_entry_drop) { Locomotive::Liquid::Drops::ContentEntry.new(content_entry) }
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
template = %({% for project in category.projects %}{{ project }},{% endfor %})
|
|
13
|
+
describe 'displaying the timestamp' do
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
subject { render('{{ article.file.url }}', { 'article' => content_entry_drop }) }
|
|
16
|
+
|
|
17
|
+
it { should include '5k.png?1183150800' }
|
|
17
18
|
|
|
18
|
-
render(template, { 'category' => @category }).should == 'a,b,'
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
template = %({% with_scope order_by: 'name ASC', active: true %}{% for project in category.projects %}{{ project }},{% endfor %}{% endwith_scope %})
|
|
21
|
+
end
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
describe 'a list of entries' do
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
before(:each) do
|
|
26
|
+
@list = mock('list')
|
|
27
|
+
@list.stubs(:all).returns(true)
|
|
28
|
+
@category = Locomotive::Liquid::Drops::ContentEntry.new(mock('category', projects: @list))
|
|
27
29
|
end
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
context '#accessing a has_many relationship' do
|
|
32
|
+
|
|
33
|
+
it 'loops through the list' do
|
|
34
|
+
template = %({% for project in category.projects %}{{ project }},{% endfor %})
|
|
35
|
+
|
|
36
|
+
@list.expects(:ordered).returns(%w(a b))
|
|
37
|
+
|
|
38
|
+
render(template, { 'category' => @category }).should == 'a,b,'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'filters the list' do
|
|
42
|
+
template = %({% with_scope order_by: 'name ASC', active: true %}{% for project in category.projects %}{{ project }},{% endfor %}{% endwith_scope %})
|
|
31
43
|
|
|
32
|
-
|
|
44
|
+
@list.expects(:filtered).with({ 'active' => true }, ['name', 'ASC']).returns(%w(a b))
|
|
45
|
+
|
|
46
|
+
render(template, { 'category' => @category }).should == 'a,b,'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'filters the list and uses the default order' do
|
|
50
|
+
template = %({% with_scope active: true %}{% for project in category.projects %}{{ project }},{% endfor %}{% endwith_scope %})
|
|
51
|
+
|
|
52
|
+
@list.expects(:filtered).with({ 'active' => true }, nil).returns(%w(a b))
|
|
53
|
+
|
|
54
|
+
render(template, { 'category' => @category }).should == 'a,b,'
|
|
55
|
+
end
|
|
33
56
|
|
|
34
|
-
render(template, { 'category' => @category }).should == 'a,b,'
|
|
35
57
|
end
|
|
36
58
|
|
|
37
59
|
end
|
|
38
60
|
|
|
39
61
|
def render(template, assigns = {})
|
|
40
|
-
liquid_context = ::Liquid::Context.new(assigns, {}, {
|
|
62
|
+
liquid_context = ::Liquid::Context.new(assigns, {}, {
|
|
63
|
+
asset_host: TimestampAssetHost.new
|
|
64
|
+
})
|
|
41
65
|
|
|
42
66
|
output = ::Liquid::Template.parse(template).render(liquid_context)
|
|
43
67
|
output.gsub(/\n\s{0,}/, '')
|
|
44
68
|
end
|
|
45
69
|
|
|
70
|
+
def build_content_type
|
|
71
|
+
FactoryGirl.build(:content_type).tap do |content_type|
|
|
72
|
+
content_type.entries_custom_fields.build label: 'Title', type: 'string'
|
|
73
|
+
content_type.entries_custom_fields.build label: 'Description', type: 'text'
|
|
74
|
+
content_type.entries_custom_fields.build label: 'Visible ?', type: 'boolean', name: 'visible'
|
|
75
|
+
content_type.entries_custom_fields.build label: 'File', type: 'file'
|
|
76
|
+
content_type.entries_custom_fields.build label: 'Published at', type: 'date'
|
|
77
|
+
content_type.valid?
|
|
78
|
+
content_type.send(:set_label_field)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
46
82
|
end
|
|
@@ -236,12 +236,14 @@ describe Locomotive::Liquid::Filters::Html do
|
|
|
236
236
|
end
|
|
237
237
|
|
|
238
238
|
def build_context
|
|
239
|
+
|
|
239
240
|
klass = Class.new
|
|
240
241
|
klass.class_eval do
|
|
241
242
|
def registers
|
|
242
243
|
@registers ||= {
|
|
243
244
|
site: FactoryGirl.build(:site, id: fake_bson_id(42)),
|
|
244
|
-
theme_assets_checksum: {}
|
|
245
|
+
theme_assets_checksum: {},
|
|
246
|
+
asset_host: TimestampAssetHost.new
|
|
245
247
|
}
|
|
246
248
|
end
|
|
247
249
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Locomotive::Liquid::Tags::Editable::File do
|
|
4
|
+
|
|
5
|
+
before { Locomotive::Site.any_instance.stubs(:create_default_pages!).returns(true) }
|
|
6
|
+
|
|
7
|
+
let(:asset_host) { CdnAssetHost.new }
|
|
8
|
+
let(:page) { Locomotive::Page.new(updated_at: DateTime.parse('2007-06-29 21:00:00')) }
|
|
9
|
+
|
|
10
|
+
subject { render("{% editable_file banner %}http://www.placehold.it/500x500{% endeditable_file %}") }
|
|
11
|
+
|
|
12
|
+
describe 'no uploaded file' do
|
|
13
|
+
|
|
14
|
+
let(:asset_host) { IsoAssetHost.new }
|
|
15
|
+
before { add_editable_file({}) }
|
|
16
|
+
it { should eq 'http://www.placehold.it/500x500' }
|
|
17
|
+
|
|
18
|
+
context 'a timestamp is not applicable' do
|
|
19
|
+
|
|
20
|
+
let(:asset_host) { TimestampAssetHost.new }
|
|
21
|
+
it { should eq 'http://www.placehold.it/500x500' }
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe 'with a default source url' do
|
|
28
|
+
|
|
29
|
+
before { add_editable_file(default_source_url: '/assets/42/assets/1/foo.png') }
|
|
30
|
+
it { should eq 'http://cdn.locomotivecms.com/assets/42/assets/1/foo.png' }
|
|
31
|
+
|
|
32
|
+
context 'has a timestamp' do
|
|
33
|
+
|
|
34
|
+
let(:asset_host) { TimestampAssetHost.new }
|
|
35
|
+
it { should eq '/assets/42/assets/1/foo.png?1183150800' }
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe 'with an uploaded file' do
|
|
42
|
+
|
|
43
|
+
before { add_editable_file }
|
|
44
|
+
it { should match /^http:\/\/cdn\.locomotivecms\.com\/spec\/(.*)\/5k.png$/ }
|
|
45
|
+
|
|
46
|
+
context 'has a timestamp' do
|
|
47
|
+
|
|
48
|
+
let(:asset_host) { TimestampAssetHost.new }
|
|
49
|
+
it { should match /^\/spec\/(.*)\/5k.png\?1183150800$/ }
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def render(template, assigns = {})
|
|
56
|
+
liquid_context = ::Liquid::Context.new(assigns, {}, {
|
|
57
|
+
asset_host: asset_host,
|
|
58
|
+
page: page
|
|
59
|
+
}, true)
|
|
60
|
+
|
|
61
|
+
output = ::Liquid::Template.parse(template).render(liquid_context)
|
|
62
|
+
output.gsub(/\n\s{0,}/, '')
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def add_editable_file(attributes = nil)
|
|
66
|
+
attributes ||= { source: FixturedAsset.open('5k.png') }
|
|
67
|
+
|
|
68
|
+
editable_file = Locomotive::EditableFile.new({ slug: 'banner' }.merge(attributes))
|
|
69
|
+
page.editable_elements << editable_file
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
@@ -348,6 +348,37 @@ describe Locomotive::ContentType do
|
|
|
348
348
|
|
|
349
349
|
end
|
|
350
350
|
|
|
351
|
+
describe 'finding by id or slug' do
|
|
352
|
+
|
|
353
|
+
let(:content_type) { build_content_type }
|
|
354
|
+
let(:id_or_slug) { 'unknown' }
|
|
355
|
+
|
|
356
|
+
subject { Locomotive::ContentType.by_id_or_slug(id_or_slug).first }
|
|
357
|
+
|
|
358
|
+
before { content_type.save }
|
|
359
|
+
|
|
360
|
+
describe 'unknown id' do
|
|
361
|
+
|
|
362
|
+
it { should eq nil }
|
|
363
|
+
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
describe 'existing id' do
|
|
367
|
+
|
|
368
|
+
let(:id_or_slug) { content_type._id.to_s }
|
|
369
|
+
its(:name) { should eq 'My project' }
|
|
370
|
+
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
describe 'existing slug' do
|
|
374
|
+
|
|
375
|
+
let(:id_or_slug) { 'my_project' }
|
|
376
|
+
its(:name) { should eq 'My project' }
|
|
377
|
+
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
end
|
|
381
|
+
|
|
351
382
|
def build_content_type(options = {}, &block)
|
|
352
383
|
FactoryGirl.build(:content_type, options).tap do |content_type|
|
|
353
384
|
content_type.entries_custom_fields.build label: 'Name', type: 'string'
|
|
@@ -6,7 +6,7 @@ describe Locomotive::ThemeAsset do
|
|
|
6
6
|
|
|
7
7
|
let(:site) { FactoryGirl.build(:site, domains: %w{www.acme.com}) }
|
|
8
8
|
|
|
9
|
-
let(:asset) { FactoryGirl.build(:theme_asset, site: site) }
|
|
9
|
+
let(:asset) { FactoryGirl.build(:theme_asset, site: site, updated_at: DateTime.parse('2007/06/29 21:10:00')) }
|
|
10
10
|
|
|
11
11
|
describe 'attaching a file' do
|
|
12
12
|
|
|
@@ -145,21 +145,21 @@ describe Locomotive::ThemeAsset do
|
|
|
145
145
|
context 'simple url' do
|
|
146
146
|
|
|
147
147
|
let(:text) { "background: url(/images/banner.png) no-repeat 0 0" }
|
|
148
|
-
it { should == "background: url(http://engine.dev/images/banner.png) no-repeat 0 0" }
|
|
148
|
+
it { should == "background: url(http://engine.dev/images/banner.png?1183151400) no-repeat 0 0" }
|
|
149
149
|
|
|
150
150
|
end
|
|
151
151
|
|
|
152
152
|
context 'url with quotes' do
|
|
153
153
|
|
|
154
154
|
let(:text) { "background: url(\"/images/banner.png\") no-repeat 0 0" }
|
|
155
|
-
it { should == "background: url(\"http://engine.dev/images/banner.png\") no-repeat 0 0" }
|
|
155
|
+
it { should == "background: url(\"http://engine.dev/images/banner.png?1183151400\") no-repeat 0 0" }
|
|
156
156
|
|
|
157
157
|
end
|
|
158
158
|
|
|
159
159
|
context 'url with quotes and timestamps' do
|
|
160
160
|
|
|
161
161
|
let(:text) { "background: url(\"/images/banner.png?123456\") no-repeat 0 0" }
|
|
162
|
-
it { should == "background: url(\"http://engine.dev/images/banner.png\") no-repeat 0 0" }
|
|
162
|
+
it { should == "background: url(\"http://engine.dev/images/banner.png?1183151400\") no-repeat 0 0" }
|
|
163
163
|
|
|
164
164
|
end
|
|
165
165
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class IsoAssetHost
|
|
2
|
+
def compute(source, timestamp = nil)
|
|
3
|
+
source
|
|
4
|
+
end
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class CdnAssetHost
|
|
8
|
+
def compute(source, timestamp = nil)
|
|
9
|
+
"http://cdn.locomotivecms.com#{source}"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class TimestampAssetHost
|
|
14
|
+
def compute(source, timestamp = nil)
|
|
15
|
+
timestamp ? "#{source}?#{timestamp}" : source
|
|
16
|
+
end
|
|
17
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: locomotive_cms
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.5.
|
|
4
|
+
version: 2.5.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Didier Lafforgue
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-
|
|
11
|
+
date: 2014-08-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -545,6 +545,7 @@ files:
|
|
|
545
545
|
- app/assets/images/locomotive/datepicker/ui-widget-content-top.png
|
|
546
546
|
- app/assets/images/locomotive/form/error-arrow.png
|
|
547
547
|
- app/assets/images/locomotive/form/input-sep.png
|
|
548
|
+
- app/assets/images/locomotive/icons/flags/bf.png
|
|
548
549
|
- app/assets/images/locomotive/icons/flags/bg.png
|
|
549
550
|
- app/assets/images/locomotive/icons/flags/cs.png
|
|
550
551
|
- app/assets/images/locomotive/icons/flags/de.png
|
|
@@ -554,6 +555,7 @@ files:
|
|
|
554
555
|
- app/assets/images/locomotive/icons/flags/fr.png
|
|
555
556
|
- app/assets/images/locomotive/icons/flags/it.png
|
|
556
557
|
- app/assets/images/locomotive/icons/flags/ja.png
|
|
558
|
+
- app/assets/images/locomotive/icons/flags/mg.png
|
|
557
559
|
- app/assets/images/locomotive/icons/flags/nb.png
|
|
558
560
|
- app/assets/images/locomotive/icons/flags/nl.png
|
|
559
561
|
- app/assets/images/locomotive/icons/flags/pl.png
|
|
@@ -1172,6 +1174,7 @@ files:
|
|
|
1172
1174
|
- lib/locomotive/httparty/webservice.rb
|
|
1173
1175
|
- lib/locomotive/kaminari.rb
|
|
1174
1176
|
- lib/locomotive/liquid.rb
|
|
1177
|
+
- lib/locomotive/liquid/asset_host.rb
|
|
1175
1178
|
- lib/locomotive/liquid/drops/base.rb
|
|
1176
1179
|
- lib/locomotive/liquid/drops/content_entry.rb
|
|
1177
1180
|
- lib/locomotive/liquid/drops/content_types.rb
|
|
@@ -1299,6 +1302,7 @@ files:
|
|
|
1299
1302
|
- spec/lib/core_ext_spec.rb
|
|
1300
1303
|
- spec/lib/locomotive/configuration_spec.rb
|
|
1301
1304
|
- spec/lib/locomotive/httparty/webservice_spec.rb
|
|
1305
|
+
- spec/lib/locomotive/liquid/asset_host_spec.rb
|
|
1302
1306
|
- spec/lib/locomotive/liquid/drops/content_entry_spec.rb
|
|
1303
1307
|
- spec/lib/locomotive/liquid/drops/current_user.rb
|
|
1304
1308
|
- spec/lib/locomotive/liquid/drops/page_spec.rb
|
|
@@ -1311,6 +1315,7 @@ files:
|
|
|
1311
1315
|
- spec/lib/locomotive/liquid/filters/translate_spec.rb
|
|
1312
1316
|
- spec/lib/locomotive/liquid/tags/consume_spec.rb
|
|
1313
1317
|
- spec/lib/locomotive/liquid/tags/csrf_spec.rb
|
|
1318
|
+
- spec/lib/locomotive/liquid/tags/editable/file_spec.rb
|
|
1314
1319
|
- spec/lib/locomotive/liquid/tags/editable/text_spec.rb
|
|
1315
1320
|
- spec/lib/locomotive/liquid/tags/extends_spec.rb
|
|
1316
1321
|
- spec/lib/locomotive/liquid/tags/javascript_spec.rb
|
|
@@ -1346,6 +1351,7 @@ files:
|
|
|
1346
1351
|
- spec/models/locomotive/theme_asset_spec.rb
|
|
1347
1352
|
- spec/requests/admin_ssl_spec.rb
|
|
1348
1353
|
- spec/requests/seo_trailing_slash_spec.rb
|
|
1354
|
+
- spec/support/asset_host_stubs.rb
|
|
1349
1355
|
- spec/support/carrierwave.rb
|
|
1350
1356
|
- spec/support/cells.rb
|
|
1351
1357
|
- spec/support/controller.rb
|
|
@@ -1532,6 +1538,7 @@ test_files:
|
|
|
1532
1538
|
- spec/lib/core_ext_spec.rb
|
|
1533
1539
|
- spec/lib/locomotive/configuration_spec.rb
|
|
1534
1540
|
- spec/lib/locomotive/httparty/webservice_spec.rb
|
|
1541
|
+
- spec/lib/locomotive/liquid/asset_host_spec.rb
|
|
1535
1542
|
- spec/lib/locomotive/liquid/drops/content_entry_spec.rb
|
|
1536
1543
|
- spec/lib/locomotive/liquid/drops/current_user.rb
|
|
1537
1544
|
- spec/lib/locomotive/liquid/drops/page_spec.rb
|
|
@@ -1544,6 +1551,7 @@ test_files:
|
|
|
1544
1551
|
- spec/lib/locomotive/liquid/filters/translate_spec.rb
|
|
1545
1552
|
- spec/lib/locomotive/liquid/tags/consume_spec.rb
|
|
1546
1553
|
- spec/lib/locomotive/liquid/tags/csrf_spec.rb
|
|
1554
|
+
- spec/lib/locomotive/liquid/tags/editable/file_spec.rb
|
|
1547
1555
|
- spec/lib/locomotive/liquid/tags/editable/text_spec.rb
|
|
1548
1556
|
- spec/lib/locomotive/liquid/tags/extends_spec.rb
|
|
1549
1557
|
- spec/lib/locomotive/liquid/tags/javascript_spec.rb
|
|
@@ -1579,6 +1587,7 @@ test_files:
|
|
|
1579
1587
|
- spec/models/locomotive/theme_asset_spec.rb
|
|
1580
1588
|
- spec/requests/admin_ssl_spec.rb
|
|
1581
1589
|
- spec/requests/seo_trailing_slash_spec.rb
|
|
1590
|
+
- spec/support/asset_host_stubs.rb
|
|
1582
1591
|
- spec/support/carrierwave.rb
|
|
1583
1592
|
- spec/support/cells.rb
|
|
1584
1593
|
- spec/support/controller.rb
|