locomotivecms_steam 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +19 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +188 -0
- data/LICENSE +20 -0
- data/README.md +36 -0
- data/Rakefile +17 -0
- data/bin/publish +28 -0
- data/config/locales/de.yml +157 -0
- data/config/locales/en.yml +189 -0
- data/config/locales/es.yml +133 -0
- data/config/locales/et.yml +154 -0
- data/config/locales/fr.yml +148 -0
- data/config/locales/it.yml +155 -0
- data/config/locales/nb.yml +191 -0
- data/config/locales/nl.yml +160 -0
- data/config/locales/pl.yml +203 -0
- data/config/locales/pt-BR.yml +139 -0
- data/config/locales/ru.yml +224 -0
- data/lib/locomotive/steam/core_ext.rb +5 -0
- data/lib/locomotive/steam/core_ext/array.rb +3 -0
- data/lib/locomotive/steam/core_ext/boolean/false.rb +3 -0
- data/lib/locomotive/steam/core_ext/boolean/true.rb +3 -0
- data/lib/locomotive/steam/core_ext/hash.rb +27 -0
- data/lib/locomotive/steam/core_ext/string.rb +8 -0
- data/lib/locomotive/steam/exceptions.rb +62 -0
- data/lib/locomotive/steam/initializers.rb +5 -0
- data/lib/locomotive/steam/initializers/i18n.rb +3 -0
- data/lib/locomotive/steam/initializers/markdown.rb +27 -0
- data/lib/locomotive/steam/initializers/will_paginate.rb +16 -0
- data/lib/locomotive/steam/liquid.rb +22 -0
- data/lib/locomotive/steam/liquid/drops/base.rb +46 -0
- data/lib/locomotive/steam/liquid/drops/content_entry.rb +48 -0
- data/lib/locomotive/steam/liquid/drops/content_types.rb +117 -0
- data/lib/locomotive/steam/liquid/drops/page.rb +28 -0
- data/lib/locomotive/steam/liquid/drops/session_proxy.rb +18 -0
- data/lib/locomotive/steam/liquid/drops/site.rb +26 -0
- data/lib/locomotive/steam/liquid/errors.rb +17 -0
- data/lib/locomotive/steam/liquid/filters/date.rb +136 -0
- data/lib/locomotive/steam/liquid/filters/html.rb +188 -0
- data/lib/locomotive/steam/liquid/filters/misc.rb +49 -0
- data/lib/locomotive/steam/liquid/filters/resize.rb +18 -0
- data/lib/locomotive/steam/liquid/filters/text.rb +55 -0
- data/lib/locomotive/steam/liquid/filters/translate.rb +28 -0
- data/lib/locomotive/steam/liquid/patches.rb +47 -0
- data/lib/locomotive/steam/liquid/scopeable.rb +149 -0
- data/lib/locomotive/steam/liquid/tags/consume.rb +97 -0
- data/lib/locomotive/steam/liquid/tags/csrf.rb +34 -0
- data/lib/locomotive/steam/liquid/tags/editable.rb +6 -0
- data/lib/locomotive/steam/liquid/tags/editable/base.rb +50 -0
- data/lib/locomotive/steam/liquid/tags/editable/control.rb +19 -0
- data/lib/locomotive/steam/liquid/tags/editable/file.rb +15 -0
- data/lib/locomotive/steam/liquid/tags/editable/long_text.rb +15 -0
- data/lib/locomotive/steam/liquid/tags/editable/short_text.rb +20 -0
- data/lib/locomotive/steam/liquid/tags/editable/text.rb +15 -0
- data/lib/locomotive/steam/liquid/tags/extends.rb +25 -0
- data/lib/locomotive/steam/liquid/tags/google_analytics.rb +28 -0
- data/lib/locomotive/steam/liquid/tags/hybrid.rb +27 -0
- data/lib/locomotive/steam/liquid/tags/inline_editor.rb +16 -0
- data/lib/locomotive/steam/liquid/tags/link_to.rb +56 -0
- data/lib/locomotive/steam/liquid/tags/locale_switcher.rb +106 -0
- data/lib/locomotive/steam/liquid/tags/nav.rb +287 -0
- data/lib/locomotive/steam/liquid/tags/paginate.rb +105 -0
- data/lib/locomotive/steam/liquid/tags/path_helper.rb +98 -0
- data/lib/locomotive/steam/liquid/tags/path_to.rb +36 -0
- data/lib/locomotive/steam/liquid/tags/seo.rb +74 -0
- data/lib/locomotive/steam/liquid/tags/session_assign.rb +41 -0
- data/lib/locomotive/steam/liquid/tags/snippet.rb +63 -0
- data/lib/locomotive/steam/liquid/tags/with_scope.rb +44 -0
- data/lib/locomotive/steam/listen.rb +64 -0
- data/lib/locomotive/steam/logger.rb +54 -0
- data/lib/locomotive/steam/monkey_patches.rb +5 -0
- data/lib/locomotive/steam/monkey_patches/better_errors.rb +70 -0
- data/lib/locomotive/steam/monkey_patches/dragonfly.rb +79 -0
- data/lib/locomotive/steam/monkey_patches/haml.rb +15 -0
- data/lib/locomotive/steam/monkey_patches/httparty.rb +46 -0
- data/lib/locomotive/steam/monkey_patches/mounter.rb +32 -0
- data/lib/locomotive/steam/server.rb +81 -0
- data/lib/locomotive/steam/server/dynamic_assets.rb +33 -0
- data/lib/locomotive/steam/server/entry_submission.rb +120 -0
- data/lib/locomotive/steam/server/favicon.rb +18 -0
- data/lib/locomotive/steam/server/locale.rb +42 -0
- data/lib/locomotive/steam/server/logging.rb +32 -0
- data/lib/locomotive/steam/server/middleware.rb +61 -0
- data/lib/locomotive/steam/server/page.rb +69 -0
- data/lib/locomotive/steam/server/path.rb +34 -0
- data/lib/locomotive/steam/server/renderer.rb +118 -0
- data/lib/locomotive/steam/server/templatized_page.rb +32 -0
- data/lib/locomotive/steam/server/timezone.rb +18 -0
- data/lib/locomotive/steam/standalone_server.rb +33 -0
- data/lib/locomotive/steam/version.rb +5 -0
- data/lib/steam.rb +4 -0
- data/locomotivecms_steam.gemspec +42 -0
- data/spec/fixtures/default/README +0 -0
- data/spec/fixtures/default/app/content_types/bands.yml +19 -0
- data/spec/fixtures/default/app/content_types/events.yml +25 -0
- data/spec/fixtures/default/app/content_types/messages.yml +17 -0
- data/spec/fixtures/default/app/content_types/songs.yml +25 -0
- data/spec/fixtures/default/app/content_types/updates.yml +33 -0
- data/spec/fixtures/default/app/views/pages/404.liquid.haml +10 -0
- data/spec/fixtures/default/app/views/pages/about_us.fr.liquid.haml +7 -0
- data/spec/fixtures/default/app/views/pages/about_us.liquid.haml +21 -0
- data/spec/fixtures/default/app/views/pages/about_us.nb.liquid.haml +4 -0
- data/spec/fixtures/default/app/views/pages/about_us/jane_doe.liquid.haml +4 -0
- data/spec/fixtures/default/app/views/pages/about_us/john_doe.fr.liquid.haml +5 -0
- data/spec/fixtures/default/app/views/pages/about_us/john_doe.liquid.haml +6 -0
- data/spec/fixtures/default/app/views/pages/all.liquid.haml +13 -0
- data/spec/fixtures/default/app/views/pages/archives/news.liquid.haml +10 -0
- data/spec/fixtures/default/app/views/pages/contact.liquid.haml +54 -0
- data/spec/fixtures/default/app/views/pages/contest.liquid.haml +18 -0
- data/spec/fixtures/default/app/views/pages/events.liquid.haml +42 -0
- data/spec/fixtures/default/app/views/pages/filtered.liquid.haml +10 -0
- data/spec/fixtures/default/app/views/pages/grunge_bands.liquid.haml +8 -0
- data/spec/fixtures/default/app/views/pages/index.fr.liquid.haml +3 -0
- data/spec/fixtures/default/app/views/pages/index.liquid.haml +100 -0
- data/spec/fixtures/default/app/views/pages/music.fr.liquid.haml +4 -0
- data/spec/fixtures/default/app/views/pages/music.liquid.haml +42 -0
- data/spec/fixtures/default/app/views/pages/songs/template.fr.liquid.haml +16 -0
- data/spec/fixtures/default/app/views/pages/songs/template.liquid.haml +18 -0
- data/spec/fixtures/default/app/views/pages/songs/template/band.liquid.haml +16 -0
- data/spec/fixtures/default/app/views/pages/store.fr.liquid.haml +5 -0
- data/spec/fixtures/default/app/views/pages/store.liquid +5 -0
- data/spec/fixtures/default/app/views/pages/tags/nav.liquid.haml +6 -0
- data/spec/fixtures/default/app/views/pages/tags/nav_in_deep.liquid.haml +6 -0
- data/spec/fixtures/default/app/views/pages/unlisted_pages.liquid.haml +9 -0
- data/spec/fixtures/default/app/views/snippets/A_Complicated-one.liquid.haml +1 -0
- data/spec/fixtures/default/app/views/snippets/footer.liquid.haml +6 -0
- data/spec/fixtures/default/app/views/snippets/header.liquid.haml +1 -0
- data/spec/fixtures/default/app/views/snippets/song.fr.liquid.haml +8 -0
- data/spec/fixtures/default/app/views/snippets/song.liquid +12 -0
- data/spec/fixtures/default/config/deploy.yml +12 -0
- data/spec/fixtures/default/config/deploy_example.yml +12 -0
- data/spec/fixtures/default/config/site.yml +15 -0
- data/spec/fixtures/default/config/translations.yml +3 -0
- data/spec/fixtures/default/data/bands.yml +10 -0
- data/spec/fixtures/default/data/events.yml +53 -0
- data/spec/fixtures/default/data/songs.yml +46 -0
- data/spec/fixtures/default/data/updates.yml +48 -0
- data/spec/fixtures/default/public/fonts/chunkfive-webfont.eot +0 -0
- data/spec/fixtures/default/public/fonts/chunkfive-webfont.svg +213 -0
- data/spec/fixtures/default/public/fonts/chunkfive-webfont.ttf +0 -0
- data/spec/fixtures/default/public/fonts/chunkfive-webfont.woff +0 -0
- data/spec/fixtures/default/public/fonts/chunkfive.css +8 -0
- data/spec/fixtures/default/public/fonts/chunkfive.otf +0 -0
- data/spec/fixtures/default/public/images/nav_on.png +0 -0
- data/spec/fixtures/default/public/images/photo_frame.png +0 -0
- data/spec/fixtures/default/public/images/sep.png +0 -0
- data/spec/fixtures/default/public/images/top.jpg +0 -0
- data/spec/fixtures/default/public/javascripts/application.js.coffee +2 -0
- data/spec/fixtures/default/public/javascripts/common.js +1 -0
- data/spec/fixtures/default/public/samples/asset_collections/cover.jpg +0 -0
- data/spec/fixtures/default/public/samples/photo.jpg +0 -0
- data/spec/fixtures/default/public/samples/photo_2.jpg +0 -0
- data/spec/fixtures/default/public/stylesheets/application.css +64 -0
- data/spec/fixtures/default/public/stylesheets/other/extra.css.less +8 -0
- data/spec/fixtures/default/public/stylesheets/other/style.css.scss +13 -0
- data/spec/fixtures/default/public/stylesheets/reboot.css +82 -0
- data/spec/integration/integration_helper.rb +15 -0
- data/spec/integration/server/basic_spec.rb +170 -0
- data/spec/integration/server/contact_form_spec.rb +111 -0
- data/spec/integration/server/liquid_spec.rb +91 -0
- data/spec/integration/server/with_scope_spec.rb +20 -0
- data/spec/locales/locales_spec.rb +22 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/support.rb +4 -0
- data/spec/support/examples/locale_file.rb +14 -0
- data/spec/support/examples/matching_locale.rb +8 -0
- data/spec/support/helpers.rb +22 -0
- data/spec/support/matchers/hash.rb +5 -0
- metadata +564 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Steam
|
3
|
+
module Liquid
|
4
|
+
module Drops
|
5
|
+
class ContentEntry < Base
|
6
|
+
|
7
|
+
delegate :seo_title, :meta_keywords, :meta_description, to: :@_source
|
8
|
+
|
9
|
+
def _label
|
10
|
+
@_label ||= @_source._label
|
11
|
+
end
|
12
|
+
|
13
|
+
def _permalink
|
14
|
+
@_source._permalink.try(:parameterize)
|
15
|
+
end
|
16
|
+
|
17
|
+
alias :_slug :_permalink
|
18
|
+
|
19
|
+
def next
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def previous
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def errors
|
28
|
+
(@_source.errors || []).inject({}) do |memo, name|
|
29
|
+
memo[name] = ::I18n.t('errors.messages.blank')
|
30
|
+
memo
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def before_method(meth)
|
35
|
+
return '' if @_source.nil?
|
36
|
+
|
37
|
+
if not @@forbidden_attributes.include?(meth.to_s)
|
38
|
+
@_source.send(meth)
|
39
|
+
else
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Steam
|
3
|
+
module Liquid
|
4
|
+
module Drops
|
5
|
+
class ContentTypes < ::Liquid::Drop
|
6
|
+
|
7
|
+
def before_method(meth)
|
8
|
+
type = self.mounting_point.content_types[meth.to_s]
|
9
|
+
ProxyCollection.new(type)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
class ProxyCollection < ::Liquid::Drop
|
15
|
+
|
16
|
+
include Scopeable
|
17
|
+
|
18
|
+
def initialize(content_type)
|
19
|
+
@content_type = content_type
|
20
|
+
@collection = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def all
|
24
|
+
self.collection
|
25
|
+
end
|
26
|
+
|
27
|
+
def any
|
28
|
+
self.collection.any?
|
29
|
+
end
|
30
|
+
|
31
|
+
def first
|
32
|
+
self.collection.first
|
33
|
+
end
|
34
|
+
|
35
|
+
def last
|
36
|
+
self.collection.last
|
37
|
+
end
|
38
|
+
|
39
|
+
def size
|
40
|
+
self.collection.size
|
41
|
+
end
|
42
|
+
|
43
|
+
alias :length :size
|
44
|
+
alias :count :size
|
45
|
+
|
46
|
+
def each(&block)
|
47
|
+
self.collection.each(&block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def public_submission_url
|
51
|
+
"/entry_submissions/#{@content_type.slug}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def api
|
55
|
+
{ 'create' => "/entry_submissions/#{@content_type.slug}" }
|
56
|
+
end
|
57
|
+
|
58
|
+
def before_method(meth)
|
59
|
+
if (meth.to_s =~ /^group_by_(.+)$/) == 0
|
60
|
+
self.group_entries_by(@content_type, $1)
|
61
|
+
elsif (meth.to_s =~ /^(.+)_options$/) == 0
|
62
|
+
self.select_options_for(@content_type, $1)
|
63
|
+
else
|
64
|
+
@content_type.send(meth)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
def group_entries_by(content_type, name)
|
71
|
+
field = @content_type.find_field(name)
|
72
|
+
|
73
|
+
return {} if field.nil? || !%w(belongs_to select).include?(field.type.to_s)
|
74
|
+
|
75
|
+
(@content_type.entries || []).group_by do |entry|
|
76
|
+
entry.send(name.to_sym)
|
77
|
+
end.to_a.collect do |group|
|
78
|
+
{ name: group.first, entries: group.last }.with_indifferent_access
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def select_options_for(content_type, name)
|
83
|
+
field = @content_type.find_field(name)
|
84
|
+
|
85
|
+
return {} if field.nil? || field.type.to_s != 'select'
|
86
|
+
|
87
|
+
field.select_options.map(&:name)
|
88
|
+
end
|
89
|
+
|
90
|
+
def paginate(options = {})
|
91
|
+
@collection ||= self.collection.paginate(options)
|
92
|
+
{
|
93
|
+
collection: @collection,
|
94
|
+
current_page: @collection.current_page,
|
95
|
+
previous_page: @collection.previous_page,
|
96
|
+
next_page: @collection.next_page,
|
97
|
+
total_entries: @collection.total_entries,
|
98
|
+
total_pages: @collection.total_pages,
|
99
|
+
per_page: @collection.per_page
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
def collection
|
104
|
+
return unless @collection.blank?
|
105
|
+
|
106
|
+
# define the default order_by if not set
|
107
|
+
if @context['with_scope'] && !@context['with_scope']['order_by'].blank? && !%w(manually position).include?(@content_type.order_by)
|
108
|
+
@context['with_scope']['order_by'] = @content_type.order_by + '.' + @content_type.order_direction
|
109
|
+
end
|
110
|
+
|
111
|
+
@collection = apply_scope(@content_type.entries)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Steam
|
3
|
+
module Liquid
|
4
|
+
module Drops
|
5
|
+
class Page < Base
|
6
|
+
|
7
|
+
delegate :title, :slug, :fullpath, :parent, :depth, :seo_title, :redirect_url, :meta_description, :meta_keywords,
|
8
|
+
:templatized?, :published?, :redirect?, :listed?, :handle, to: :@_source
|
9
|
+
|
10
|
+
def children
|
11
|
+
_children = @_source.children || []
|
12
|
+
_children = _children.sort { |a, b| a.position.to_i <=> b.position.to_i }
|
13
|
+
@children ||= liquify(*_children)
|
14
|
+
end
|
15
|
+
|
16
|
+
def content_type
|
17
|
+
ProxyCollection.new(@_source.content_type) if @_source.content_type
|
18
|
+
end
|
19
|
+
|
20
|
+
def breadcrumbs
|
21
|
+
# TODO
|
22
|
+
''
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Steam
|
3
|
+
module Liquid
|
4
|
+
module Drops
|
5
|
+
|
6
|
+
class SessionProxy < ::Liquid::Drop
|
7
|
+
|
8
|
+
def before_method(meth)
|
9
|
+
request = @context.registers[:request]
|
10
|
+
request.session[meth.to_sym]
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Steam
|
3
|
+
module Liquid
|
4
|
+
module Drops
|
5
|
+
class Site < Base
|
6
|
+
include Scopeable
|
7
|
+
|
8
|
+
delegate :name, :seo_title, :meta_description, :meta_keywords, to: :@_source
|
9
|
+
|
10
|
+
def index
|
11
|
+
@index ||= self.mounting_point.pages['index']
|
12
|
+
end
|
13
|
+
|
14
|
+
def pages
|
15
|
+
liquify(*apply_scope(self.mounting_point.pages.values))
|
16
|
+
end
|
17
|
+
|
18
|
+
def domains
|
19
|
+
@_source.domains
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Steam
|
3
|
+
module Liquid
|
4
|
+
class PageNotFound < ::Liquid::Error; end
|
5
|
+
|
6
|
+
class PageNotTranslated < ::Liquid::Error; end
|
7
|
+
|
8
|
+
class ContentEntryNotTranslated < ::Liquid::Error; end
|
9
|
+
|
10
|
+
class UnknownConditionInScope < ::Liquid::Error; end
|
11
|
+
|
12
|
+
class UnknownConditionInScope < ::Liquid::Error; end
|
13
|
+
|
14
|
+
class ConnectionRefused < ::Liquid::Error; end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Steam
|
3
|
+
module Liquid
|
4
|
+
module Filters
|
5
|
+
module Date
|
6
|
+
|
7
|
+
def parse_date_time(input, format = nil)
|
8
|
+
return '' if input.blank?
|
9
|
+
|
10
|
+
format ||= I18n.t('time.formats.default')
|
11
|
+
date_time = ::DateTime._strptime(input, format)
|
12
|
+
|
13
|
+
if date_time
|
14
|
+
::Time.zone.local(date_time[:year], date_time[:mon], date_time[:mday], date_time[:hour], date_time[:min], date_time[:sec] || 0)
|
15
|
+
else
|
16
|
+
::Time.zone.parse(input) rescue ''
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse_date(input, format)
|
21
|
+
return '' if input.blank?
|
22
|
+
|
23
|
+
format ||= I18n.t('date.formats.default')
|
24
|
+
date = ::Date._strptime(input, format)
|
25
|
+
|
26
|
+
if date
|
27
|
+
::Date.new(date[:year], date[:mon], date[:mday])
|
28
|
+
else
|
29
|
+
::Date.parse(value) rescue ''
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def localized_date(input, *args)
|
34
|
+
return '' if input.blank?
|
35
|
+
|
36
|
+
format, locale = args
|
37
|
+
|
38
|
+
locale ||= I18n.locale
|
39
|
+
format ||= I18n.t('date.formats.default', locale: locale)
|
40
|
+
|
41
|
+
if input.is_a?(String)
|
42
|
+
begin
|
43
|
+
fragments = ::Date._strptime(input, format)
|
44
|
+
input = ::Date.new(fragments[:year], fragments[:mon], fragments[:mday])
|
45
|
+
rescue
|
46
|
+
input = Time.zone.parse(input)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
return input.to_s unless input.respond_to?(:strftime)
|
51
|
+
|
52
|
+
I18n.l input, format: format, locale: locale
|
53
|
+
end
|
54
|
+
|
55
|
+
alias :format_date :localized_date
|
56
|
+
|
57
|
+
def distance_of_time_in_words(input, from_time = Time.zone.now, include_seconds = false)
|
58
|
+
return '' if input.blank?
|
59
|
+
|
60
|
+
# make sure we deals with instances of Time
|
61
|
+
to_time = to_time(input)
|
62
|
+
from_time = to_time(from_time)
|
63
|
+
|
64
|
+
from_time = from_time.to_time if from_time.respond_to?(:to_time)
|
65
|
+
to_time = to_time.to_time if to_time.respond_to?(:to_time)
|
66
|
+
distance_in_minutes = (((to_time - from_time).abs)/60).round
|
67
|
+
distance_in_seconds = ((to_time - from_time).abs).round
|
68
|
+
|
69
|
+
::I18n.with_options({ scope: :'datetime.distance_in_words' }) do |locale|
|
70
|
+
|
71
|
+
case distance_in_minutes
|
72
|
+
when 0..1
|
73
|
+
return distance_in_minutes == 0 ?
|
74
|
+
locale.t(:less_than_x_minutes, count: 1) :
|
75
|
+
locale.t(:x_minutes, count: distance_in_minutes) unless include_seconds
|
76
|
+
|
77
|
+
case distance_in_seconds
|
78
|
+
when 0..4 then locale.t :less_than_x_seconds, count: 5
|
79
|
+
when 5..9 then locale.t :less_than_x_seconds, count: 10
|
80
|
+
when 10..19 then locale.t :less_than_x_seconds, count: 20
|
81
|
+
when 20..39 then locale.t :half_a_minute
|
82
|
+
when 40..59 then locale.t :less_than_x_minutes, count: 1
|
83
|
+
else locale.t :x_minutes, count: 1
|
84
|
+
end
|
85
|
+
|
86
|
+
when 2..44 then locale.t :x_minutes, count: distance_in_minutes
|
87
|
+
when 45..89 then locale.t :about_x_hours, count: 1
|
88
|
+
when 90..1439 then locale.t :about_x_hours, count: (distance_in_minutes.to_f / 60.0).round
|
89
|
+
when 1440..2519 then locale.t :x_days, count: 1
|
90
|
+
when 2520..43199 then locale.t :x_days, count: (distance_in_minutes.to_f / 1440.0).round
|
91
|
+
when 43200..86399 then locale.t :about_x_months, count: 1
|
92
|
+
when 86400..525599 then locale.t :x_months, count: (distance_in_minutes.to_f / 43200.0).round
|
93
|
+
else
|
94
|
+
fyear = from_time.year
|
95
|
+
fyear += 1 if from_time.month >= 3
|
96
|
+
tyear = to_time.year
|
97
|
+
tyear -= 1 if to_time.month < 3
|
98
|
+
leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count{|x| ::Date.leap?(x)}
|
99
|
+
minute_offset_for_leap_year = leap_years * 1440
|
100
|
+
# Discount the leap year days when calculating year distance.
|
101
|
+
# e.g. if there are 20 leap year days between 2 dates having the same day
|
102
|
+
# and month then the based on 365 days calculation
|
103
|
+
# the distance in years will come out to over 80 years when in written
|
104
|
+
# english it would read better as about 80 years.
|
105
|
+
minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
|
106
|
+
remainder = (minutes_with_offset % 525600)
|
107
|
+
distance_in_years = (minutes_with_offset / 525600)
|
108
|
+
if remainder < 131400
|
109
|
+
locale.t(:about_x_years, count: distance_in_years)
|
110
|
+
elsif remainder < 394200
|
111
|
+
locale.t(:over_x_years, count: distance_in_years)
|
112
|
+
else
|
113
|
+
locale.t(:almost_x_years, count: distance_in_years + 1)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def to_time(input)
|
122
|
+
case input
|
123
|
+
when Date then input.to_time
|
124
|
+
when String then Time.zone.parse(input)
|
125
|
+
else
|
126
|
+
input
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
::Liquid::Template.register_filter(Date)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Steam
|
3
|
+
module Liquid
|
4
|
+
module Filters
|
5
|
+
module Html
|
6
|
+
|
7
|
+
# Returns a link tag that browsers and news readers can use to auto-detect an RSS or ATOM feed.
|
8
|
+
# input: url of the feed
|
9
|
+
# example:
|
10
|
+
# {{ '/foo/bar' | auto_discovery_link_tag: 'rel:alternate', 'type:application/atom+xml', 'title:A title' }}
|
11
|
+
def auto_discovery_link_tag(input, *args)
|
12
|
+
options = args_to_options(args)
|
13
|
+
|
14
|
+
rel = options[:rel] || 'alternate'
|
15
|
+
type = options[:type] || MIME::Types.type_for('rss').first
|
16
|
+
title = options[:title] || 'RSS'
|
17
|
+
|
18
|
+
%{<link rel="#{rel}" type="#{type}" title="#{title}" href="#{input}" />}
|
19
|
+
end
|
20
|
+
|
21
|
+
# Write the url of a theme stylesheet
|
22
|
+
# input: name of the css file
|
23
|
+
def stylesheet_url(input)
|
24
|
+
return '' if input.nil?
|
25
|
+
|
26
|
+
if input =~ /^https?:/
|
27
|
+
input
|
28
|
+
else
|
29
|
+
input = "/stylesheets/#{input}" unless input =~ /^\//
|
30
|
+
input = "#{input}.css" unless input.ends_with?('.css')
|
31
|
+
input
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Write the link to a stylesheet resource
|
36
|
+
# input: url of the css file
|
37
|
+
def stylesheet_tag(input, media = 'screen')
|
38
|
+
return '' if input.nil?
|
39
|
+
|
40
|
+
input = stylesheet_url(input)
|
41
|
+
|
42
|
+
%{<link href="#{input}" media="#{media}" rel="stylesheet" type="text/css" />}
|
43
|
+
end
|
44
|
+
|
45
|
+
# Write the url to javascript resource
|
46
|
+
# input: name of the javascript file
|
47
|
+
def javascript_url(input)
|
48
|
+
return '' if input.nil?
|
49
|
+
|
50
|
+
input = "/javascripts/#{input}" unless input =~ /^(\/|https?:)/
|
51
|
+
|
52
|
+
input = "#{input}.js" unless input.ends_with?('.js')
|
53
|
+
|
54
|
+
input
|
55
|
+
end
|
56
|
+
|
57
|
+
# Write the link to javascript resource
|
58
|
+
# input: url of the javascript file
|
59
|
+
def javascript_tag(input)
|
60
|
+
return '' if input.nil?
|
61
|
+
|
62
|
+
input = javascript_url(input)
|
63
|
+
|
64
|
+
%{<script src="#{input}" type="text/javascript"></script>}
|
65
|
+
end
|
66
|
+
|
67
|
+
# Write an image tag
|
68
|
+
# input: url of the image OR asset drop
|
69
|
+
def image_tag(input, *args)
|
70
|
+
image_options = inline_options(args_to_options(args))
|
71
|
+
|
72
|
+
"<img src=\"#{get_url_from_asset(input)}\" #{image_options}>"
|
73
|
+
end
|
74
|
+
|
75
|
+
# Write a theme image tag
|
76
|
+
# input: name of file including folder
|
77
|
+
# example: 'about/myphoto.jpg' | theme_image # <img src="images/about/myphoto.jpg" />
|
78
|
+
def theme_image_tag(input, *args)
|
79
|
+
image_options = inline_options(args_to_options(args))
|
80
|
+
"<img src=\"#{theme_image_url(input)}\" #{image_options}/>"
|
81
|
+
end
|
82
|
+
|
83
|
+
def theme_image_url(input)
|
84
|
+
return '' if input.nil?
|
85
|
+
|
86
|
+
input = "images/#{input}" unless input.starts_with?('/')
|
87
|
+
|
88
|
+
File.join('/', input)
|
89
|
+
end
|
90
|
+
|
91
|
+
def image_format(input, *args)
|
92
|
+
format = args_to_options(args).first
|
93
|
+
"#{input}.#{format}"
|
94
|
+
end
|
95
|
+
|
96
|
+
# Embed a flash movie into a page
|
97
|
+
# input: url of the flash movie OR asset drop
|
98
|
+
# width: width (in pixel or in %) of the embedded movie
|
99
|
+
# height: height (in pixel or in %) of the embedded movie
|
100
|
+
def flash_tag(input, *args)
|
101
|
+
path = get_url_from_asset(input)
|
102
|
+
embed_options = inline_options(args_to_options(args))
|
103
|
+
%{
|
104
|
+
<object #{embed_options}>
|
105
|
+
<param name="movie" value="#{path}" />
|
106
|
+
<embed src="#{path}" #{embed_options}/>
|
107
|
+
</embed>
|
108
|
+
</object>
|
109
|
+
}.gsub(/ >/, '>').strip
|
110
|
+
end
|
111
|
+
|
112
|
+
# Steam the navigation for a paginated collection
|
113
|
+
def default_pagination(paginate, *args)
|
114
|
+
return '' if paginate['parts'].empty?
|
115
|
+
|
116
|
+
options = args_to_options(args)
|
117
|
+
|
118
|
+
previous_label = options[:previous_label] || I18n.t('pagination.previous')
|
119
|
+
next_label = options[:next_label] || I18n.t('pagination.next')
|
120
|
+
|
121
|
+
previous_link = (if paginate['previous'].blank?
|
122
|
+
"<span class=\"disabled prev_page\">#{previous_label}</span>"
|
123
|
+
else
|
124
|
+
"<a href=\"#{absolute_url(paginate['previous']['url'])}\" class=\"prev_page\">#{previous_label}</a>"
|
125
|
+
end)
|
126
|
+
|
127
|
+
links = ""
|
128
|
+
paginate['parts'].each do |part|
|
129
|
+
links << (if part['is_link']
|
130
|
+
"<a href=\"#{absolute_url(part['url'])}\">#{part['title']}</a>"
|
131
|
+
elsif part['hellip_break']
|
132
|
+
"<span class=\"gap\">#{part['title']}</span>"
|
133
|
+
else
|
134
|
+
"<span class=\"current\">#{part['title']}</span>"
|
135
|
+
end)
|
136
|
+
end
|
137
|
+
|
138
|
+
next_link = (if paginate['next'].blank?
|
139
|
+
"<span class=\"disabled next_page\">#{next_label}</span>"
|
140
|
+
else
|
141
|
+
"<a href=\"#{absolute_url(paginate['next']['url'])}\" class=\"next_page\">#{next_label}</a>"
|
142
|
+
end)
|
143
|
+
|
144
|
+
%{<div class="pagination #{options[:css]}">
|
145
|
+
#{previous_link}
|
146
|
+
#{links}
|
147
|
+
#{next_link}
|
148
|
+
</div>}
|
149
|
+
end
|
150
|
+
|
151
|
+
protected
|
152
|
+
|
153
|
+
# Convert an array of properties ('key:value') into a hash
|
154
|
+
# Ex: ['width:50', 'height:100'] => { :width => '50', :height => '100' }
|
155
|
+
def args_to_options(*args)
|
156
|
+
options = {}
|
157
|
+
args.flatten.each do |a|
|
158
|
+
if (a =~ /^(.*):(.*)$/)
|
159
|
+
options[$1.to_sym] = $2
|
160
|
+
end
|
161
|
+
end
|
162
|
+
options
|
163
|
+
end
|
164
|
+
|
165
|
+
# Write options (Hash) into a string according to the following pattern:
|
166
|
+
# <key1>="<value1>", <key2>="<value2", ...etc
|
167
|
+
def inline_options(options = {})
|
168
|
+
return '' if options.empty?
|
169
|
+
(options.stringify_keys.to_a.collect { |a, b| "#{a}=\"#{b}\"" }).join(' ') << ' '
|
170
|
+
end
|
171
|
+
|
172
|
+
# Get the path to be used in html tags such as image_tag, flash_tag, ...etc
|
173
|
+
# input: url (String) OR asset drop
|
174
|
+
def get_url_from_asset(input)
|
175
|
+
input.respond_to?(:url) ? input.url : input
|
176
|
+
end
|
177
|
+
|
178
|
+
def absolute_url(url)
|
179
|
+
url =~ /^\// ? url : "/#{url}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
::Liquid::Template.register_filter(Html)
|
184
|
+
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|