alchemy_cms 5.0.3 → 5.1.1
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/.github/PULL_REQUEST_TEMPLATE.md +1 -1
- data/.github/workflows/stale.yml +1 -1
- data/.gitignore +1 -0
- data/CHANGELOG.md +66 -2
- data/CONTRIBUTING.md +2 -2
- data/Gemfile +1 -1
- data/README.md +1 -1
- data/alchemy_cms.gemspec +3 -3
- data/app/assets/images/alchemy/missing-image.svg +1 -0
- data/app/assets/javascripts/alchemy/admin.js +0 -1
- data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +1 -4
- data/app/assets/javascripts/alchemy/alchemy.preview.js.coffee +0 -3
- data/app/assets/javascripts/alchemy/alchemy.preview_window.js.coffee +29 -4
- data/app/assets/stylesheets/alchemy/_variables.scss +8 -0
- data/app/assets/stylesheets/alchemy/admin.scss +0 -1
- data/app/assets/stylesheets/alchemy/archive.scss +23 -17
- data/app/assets/stylesheets/alchemy/buttons.scss +26 -15
- data/app/assets/stylesheets/alchemy/elements.scss +58 -19
- data/app/assets/stylesheets/alchemy/errors.scss +1 -1
- data/app/assets/stylesheets/alchemy/frame.scss +0 -1
- data/app/assets/stylesheets/alchemy/hints.scss +2 -1
- data/app/assets/stylesheets/alchemy/navigation.scss +7 -10
- data/app/assets/stylesheets/alchemy/pagination.scss +1 -1
- data/app/assets/stylesheets/alchemy/search.scss +13 -3
- data/app/assets/stylesheets/alchemy/selects.scss +26 -20
- data/app/assets/stylesheets/alchemy/tables.scss +38 -9
- data/app/assets/stylesheets/alchemy/tags.scss +19 -31
- data/app/controllers/alchemy/admin/pages_controller.rb +58 -8
- data/app/controllers/alchemy/admin/pictures_controller.rb +13 -6
- data/app/controllers/alchemy/admin/resources_controller.rb +3 -3
- data/app/controllers/alchemy/pages_controller.rb +49 -14
- data/app/decorators/alchemy/element_editor.rb +1 -0
- data/app/helpers/alchemy/admin/base_helper.rb +0 -44
- data/app/helpers/alchemy/admin/navigation_helper.rb +2 -1
- data/app/models/alchemy/attachment.rb +20 -3
- data/app/models/alchemy/attachment/url.rb +40 -0
- data/app/models/alchemy/essence_picture.rb +3 -3
- data/app/models/alchemy/essence_picture_view.rb +5 -3
- data/app/models/alchemy/legacy_page_url.rb +1 -1
- data/app/models/alchemy/page.rb +24 -1
- data/app/models/alchemy/page/page_natures.rb +2 -0
- data/app/models/alchemy/page/url_path.rb +8 -6
- data/app/models/alchemy/picture.rb +58 -2
- data/app/models/alchemy/picture/calculations.rb +55 -0
- data/app/models/alchemy/picture/transformations.rb +5 -49
- data/app/models/alchemy/picture/url.rb +28 -77
- data/app/models/alchemy/picture_thumb.rb +57 -0
- data/app/models/alchemy/picture_thumb/create.rb +39 -0
- data/app/models/alchemy/picture_thumb/signature.rb +23 -0
- data/app/models/alchemy/picture_thumb/uid.rb +22 -0
- data/app/models/alchemy/picture_variant.rb +114 -0
- data/app/models/alchemy/site/layout.rb +30 -2
- data/app/views/alchemy/admin/attachments/show.html.erb +8 -8
- data/app/views/alchemy/admin/dashboard/index.html.erb +13 -16
- data/app/views/alchemy/admin/elements/_element_footer.html.erb +1 -1
- data/app/views/alchemy/admin/elements/publish.js.erb +1 -0
- data/app/views/alchemy/admin/essence_pictures/crop.html.erb +1 -1
- data/app/views/alchemy/admin/essence_pictures/edit.html.erb +2 -2
- data/app/views/alchemy/admin/layoutpages/edit.html.erb +4 -6
- data/app/views/alchemy/admin/pages/_create_language_form.html.erb +19 -29
- data/app/views/alchemy/admin/pages/_form.html.erb +4 -6
- data/app/views/alchemy/admin/pages/_new_page_form.html.erb +12 -2
- data/app/views/alchemy/admin/pages/_page_layout_filter.html.erb +29 -0
- data/app/views/alchemy/admin/pages/_table.html.erb +27 -0
- data/app/views/alchemy/admin/pages/_table_row.html.erb +107 -0
- data/app/views/alchemy/admin/pages/_toolbar.html.erb +77 -0
- data/app/views/alchemy/admin/pages/edit.html.erb +9 -1
- data/app/views/alchemy/admin/pages/index.html.erb +41 -74
- data/app/views/alchemy/admin/pages/list/_table.html.erb +31 -0
- data/app/views/alchemy/admin/pages/unlock.js.erb +2 -2
- data/app/views/alchemy/admin/pages/update.js.erb +19 -10
- data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +14 -13
- data/app/views/alchemy/admin/partials/_search_form.html.erb +8 -8
- data/app/views/alchemy/admin/pictures/_archive.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/_form.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/_picture.html.erb +3 -3
- data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/edit_multiple.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/index.html.erb +1 -1
- data/app/views/alchemy/admin/pictures/show.html.erb +3 -3
- data/app/views/alchemy/admin/resources/_filter_bar.html.erb +13 -11
- data/app/views/alchemy/admin/resources/_per_page_select.html.erb +3 -3
- data/app/views/alchemy/admin/resources/index.html.erb +4 -1
- data/app/views/alchemy/admin/tags/index.html.erb +14 -15
- data/app/views/alchemy/base/500.html.erb +11 -13
- data/app/views/alchemy/essences/_essence_file_view.html.erb +3 -3
- data/config/alchemy/config.yml +15 -11
- data/config/alchemy/modules.yml +12 -12
- data/config/locales/alchemy.en.yml +6 -4
- data/config/routes.rb +1 -1
- data/db/migrate/20200617110713_create_alchemy_picture_thumbs.rb +22 -0
- data/db/migrate/20200907111332_remove_tri_state_booleans.rb +33 -0
- data/lib/alchemy.rb +66 -0
- data/lib/alchemy/admin/preview_url.rb +2 -0
- data/lib/alchemy/auth_accessors.rb +12 -5
- data/lib/alchemy/config.rb +1 -3
- data/lib/alchemy/engine.rb +7 -6
- data/lib/alchemy/modules.rb +11 -1
- data/lib/alchemy/permissions.rb +1 -0
- data/lib/alchemy/test_support/factories/picture_factory.rb +0 -1
- data/lib/alchemy/test_support/factories/picture_thumb_factory.rb +12 -0
- data/lib/alchemy/test_support/integration_helpers.rb +0 -7
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy_cms.rb +2 -4
- data/lib/generators/alchemy/install/files/alchemy.en.yml +2 -2
- data/lib/generators/alchemy/install/templates/dragonfly.rb.tt +5 -5
- data/lib/tasks/alchemy/thumbnails.rake +37 -0
- data/vendor/assets/javascripts/jquery_plugins/select2.js +3729 -0
- data/vendor/assets/stylesheets/alchemy_admin/select2.scss +740 -0
- metadata +41 -31
- data/.github/workflows/greetings.yml +0 -13
- data/app/controllers/concerns/alchemy/locale_redirects.rb +0 -40
- data/app/controllers/concerns/alchemy/page_redirects.rb +0 -68
- data/lib/alchemy/userstamp.rb +0 -12
|
@@ -175,7 +175,8 @@ module Alchemy
|
|
|
175
175
|
# Returns true if the given entry's controller is current controller
|
|
176
176
|
#
|
|
177
177
|
def is_entry_controller_active?(entry)
|
|
178
|
-
entry["controller"].gsub(/\A\//, "") == params[:controller]
|
|
178
|
+
entry["controller"].gsub(/\A\//, "") == params[:controller] ||
|
|
179
|
+
entry.fetch("nested_controllers", []).include?(params[:controller])
|
|
179
180
|
end
|
|
180
181
|
|
|
181
182
|
# Returns true if the given entry's action is current controllers action
|
|
@@ -37,6 +37,20 @@ module Alchemy
|
|
|
37
37
|
|
|
38
38
|
# We need to define this method here to have it available in the validations below.
|
|
39
39
|
class << self
|
|
40
|
+
# The class used to generate URLs for attachments
|
|
41
|
+
#
|
|
42
|
+
# @see Alchemy::Attachment::Url
|
|
43
|
+
def url_class
|
|
44
|
+
@_url_class ||= Alchemy::Attachment::Url
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Set a different attachment url class
|
|
48
|
+
#
|
|
49
|
+
# @see Alchemy::Attachment::Url
|
|
50
|
+
def url_class=(klass)
|
|
51
|
+
@_url_class = klass
|
|
52
|
+
end
|
|
53
|
+
|
|
40
54
|
def searchable_alchemy_resource_attributes
|
|
41
55
|
%w(name file_name)
|
|
42
56
|
end
|
|
@@ -76,14 +90,17 @@ module Alchemy
|
|
|
76
90
|
}
|
|
77
91
|
end
|
|
78
92
|
|
|
93
|
+
def url(options = {})
|
|
94
|
+
if file
|
|
95
|
+
self.class.url_class.new(self).call(options)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
79
99
|
# An url save filename without format suffix
|
|
80
100
|
def slug
|
|
81
101
|
CGI.escape(file_name.gsub(/\.#{extension}$/, "").tr(".", " "))
|
|
82
102
|
end
|
|
83
103
|
|
|
84
|
-
alias_method :urlname, :slug
|
|
85
|
-
deprecate urlname: :slug, deprecator: Alchemy::Deprecation
|
|
86
|
-
|
|
87
104
|
# Checks if the attachment is restricted, because it is attached on restricted pages only
|
|
88
105
|
def restricted?
|
|
89
106
|
pages.any? && pages.not_restricted.blank?
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Alchemy
|
|
4
|
+
class Attachment < BaseRecord
|
|
5
|
+
# The class representing an URL to an attachment
|
|
6
|
+
#
|
|
7
|
+
# Set a different one
|
|
8
|
+
#
|
|
9
|
+
# Alchemy::Attachment.url_class = MyRemoteUrlClass
|
|
10
|
+
#
|
|
11
|
+
class Url
|
|
12
|
+
def initialize(attachment)
|
|
13
|
+
@attachment = attachment
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# The attachment url
|
|
17
|
+
#
|
|
18
|
+
# @param [Hash] options
|
|
19
|
+
# @option options [Symbol] :download return a URL for downloading the attachment
|
|
20
|
+
# @option options [Symbol] :name The filename
|
|
21
|
+
# @option options [Symbol] :format The file extension
|
|
22
|
+
#
|
|
23
|
+
# @return [String]
|
|
24
|
+
#
|
|
25
|
+
def call(options = {})
|
|
26
|
+
if options.delete(:download)
|
|
27
|
+
routes.download_attachment_path(@attachment, options)
|
|
28
|
+
else
|
|
29
|
+
routes.show_attachment_path(@attachment, options)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def routes
|
|
36
|
+
Alchemy::Engine.routes.url_helpers
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -62,7 +62,7 @@ module Alchemy
|
|
|
62
62
|
def picture_url(options = {})
|
|
63
63
|
return if picture.nil?
|
|
64
64
|
|
|
65
|
-
picture.url
|
|
65
|
+
picture.url(picture_url_options.merge(options)) || "missing-image.png"
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
# Picture rendering options
|
|
@@ -103,7 +103,7 @@ module Alchemy
|
|
|
103
103
|
format: picture.image_file_format,
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
picture.url(options)
|
|
106
|
+
picture.url(options) || "alchemy/missing-image.svg"
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
# The name of the picture used as preview text in element editor views.
|
|
@@ -140,7 +140,7 @@ module Alchemy
|
|
|
140
140
|
# Show image cropping link for content
|
|
141
141
|
def allow_image_cropping?
|
|
142
142
|
content && content.settings[:crop] && picture &&
|
|
143
|
-
picture.can_be_cropped_to(
|
|
143
|
+
picture.can_be_cropped_to?(
|
|
144
144
|
content.settings[:size],
|
|
145
145
|
content.settings[:upsample],
|
|
146
146
|
) && !!picture.image_file
|
|
@@ -44,17 +44,19 @@ module Alchemy
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
private
|
|
48
|
-
|
|
49
47
|
def caption
|
|
50
48
|
return unless show_caption?
|
|
51
49
|
|
|
52
50
|
@_caption ||= content_tag(:figcaption, essence.caption)
|
|
53
51
|
end
|
|
54
52
|
|
|
53
|
+
def src
|
|
54
|
+
essence.picture_url(options.except(*DEFAULT_OPTIONS.keys))
|
|
55
|
+
end
|
|
56
|
+
|
|
55
57
|
def img_tag
|
|
56
58
|
@_img_tag ||= image_tag(
|
|
57
|
-
|
|
59
|
+
src, {
|
|
58
60
|
alt: alt_text,
|
|
59
61
|
title: essence.title.presence,
|
|
60
62
|
class: caption ? nil : essence.css_class.presence,
|
data/app/models/alchemy/page.rb
CHANGED
|
@@ -149,6 +149,29 @@ module Alchemy
|
|
|
149
149
|
# Class methods
|
|
150
150
|
#
|
|
151
151
|
class << self
|
|
152
|
+
# The url_path class
|
|
153
|
+
# @see Alchemy::Page::UrlPath
|
|
154
|
+
def url_path_class
|
|
155
|
+
@_url_path_class ||= Alchemy::Page::UrlPath
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Set a custom url path class
|
|
159
|
+
#
|
|
160
|
+
# # config/initializers/alchemy.rb
|
|
161
|
+
# Alchemy::Page.url_path_class = MyPageUrlPathClass
|
|
162
|
+
#
|
|
163
|
+
def url_path_class=(klass)
|
|
164
|
+
@_url_path_class = klass
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def alchemy_resource_filters
|
|
168
|
+
%w[published not_public restricted]
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def searchable_alchemy_resource_attributes
|
|
172
|
+
%w[name urlname title]
|
|
173
|
+
end
|
|
174
|
+
|
|
152
175
|
# Used to store the current page previewed in the edit page template.
|
|
153
176
|
#
|
|
154
177
|
def current_preview=(page)
|
|
@@ -298,7 +321,7 @@ module Alchemy
|
|
|
298
321
|
#
|
|
299
322
|
# @see Alchemy::Page::UrlPath#call
|
|
300
323
|
def url_path
|
|
301
|
-
|
|
324
|
+
self.class.url_path_class.new(self).call
|
|
302
325
|
end
|
|
303
326
|
|
|
304
327
|
# The page's view partial is dependent from its page layout
|
|
@@ -20,8 +20,6 @@ module Alchemy
|
|
|
20
20
|
# link_to page.url
|
|
21
21
|
#
|
|
22
22
|
class UrlPath
|
|
23
|
-
ROOT_PATH = "/"
|
|
24
|
-
|
|
25
23
|
def initialize(page)
|
|
26
24
|
@page = page
|
|
27
25
|
@language = @page.language
|
|
@@ -41,7 +39,7 @@ module Alchemy
|
|
|
41
39
|
private
|
|
42
40
|
|
|
43
41
|
def language_root_path
|
|
44
|
-
@language.default? ?
|
|
42
|
+
@language.default? ? root_path : language_path
|
|
45
43
|
end
|
|
46
44
|
|
|
47
45
|
def page_path_with_language_prefix
|
|
@@ -49,15 +47,19 @@ module Alchemy
|
|
|
49
47
|
end
|
|
50
48
|
|
|
51
49
|
def page_path_with_leading_slash
|
|
52
|
-
@page.language_root? ?
|
|
50
|
+
@page.language_root? ? root_path : page_path
|
|
53
51
|
end
|
|
54
52
|
|
|
55
53
|
def language_path
|
|
56
|
-
"
|
|
54
|
+
"#{root_path}#{@page.language_code}"
|
|
57
55
|
end
|
|
58
56
|
|
|
59
57
|
def page_path
|
|
60
|
-
"
|
|
58
|
+
"#{root_path}#{@page.urlname}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def root_path
|
|
62
|
+
Engine.routes.url_helpers.root_path
|
|
61
63
|
end
|
|
62
64
|
end
|
|
63
65
|
end
|
|
@@ -30,11 +30,22 @@ module Alchemy
|
|
|
30
30
|
|
|
31
31
|
CONVERTIBLE_FILE_FORMATS = %w(gif jpg jpeg png).freeze
|
|
32
32
|
|
|
33
|
+
TRANSFORMATION_OPTIONS = [
|
|
34
|
+
:crop,
|
|
35
|
+
:crop_from,
|
|
36
|
+
:crop_size,
|
|
37
|
+
:flatten,
|
|
38
|
+
:format,
|
|
39
|
+
:quality,
|
|
40
|
+
:size,
|
|
41
|
+
:upsample,
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
include Alchemy::Logger
|
|
33
45
|
include Alchemy::NameConversions
|
|
34
46
|
include Alchemy::Taggable
|
|
35
47
|
include Alchemy::TouchElements
|
|
36
|
-
include
|
|
37
|
-
include Alchemy::Picture::Url
|
|
48
|
+
include Calculations
|
|
38
49
|
|
|
39
50
|
has_many :essence_pictures,
|
|
40
51
|
class_name: "Alchemy::EssencePicture",
|
|
@@ -44,6 +55,7 @@ module Alchemy
|
|
|
44
55
|
has_many :contents, through: :essence_pictures
|
|
45
56
|
has_many :elements, through: :contents
|
|
46
57
|
has_many :pages, through: :elements
|
|
58
|
+
has_many :thumbs, class_name: "Alchemy::PictureThumb", dependent: :destroy
|
|
47
59
|
|
|
48
60
|
# Raise error, if picture is in use (aka. assigned to an EssencePicture)
|
|
49
61
|
#
|
|
@@ -78,6 +90,9 @@ module Alchemy
|
|
|
78
90
|
end
|
|
79
91
|
end
|
|
80
92
|
|
|
93
|
+
# Create important thumbnails upfront
|
|
94
|
+
after_create -> { PictureThumb.generate_thumbs!(self) }
|
|
95
|
+
|
|
81
96
|
# We need to define this method here to have it available in the validations below.
|
|
82
97
|
class << self
|
|
83
98
|
def allowed_filetypes
|
|
@@ -103,6 +118,20 @@ module Alchemy
|
|
|
103
118
|
# Class methods
|
|
104
119
|
|
|
105
120
|
class << self
|
|
121
|
+
# The class used to generate URLs for pictures
|
|
122
|
+
#
|
|
123
|
+
# @see Alchemy::Picture::Url
|
|
124
|
+
def url_class
|
|
125
|
+
@_url_class ||= Alchemy::Picture::Url
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Set a different picture url class
|
|
129
|
+
#
|
|
130
|
+
# @see Alchemy::Picture::Url
|
|
131
|
+
def url_class=(klass)
|
|
132
|
+
@_url_class = klass
|
|
133
|
+
end
|
|
134
|
+
|
|
106
135
|
def searchable_alchemy_resource_attributes
|
|
107
136
|
%w(name image_file_name)
|
|
108
137
|
end
|
|
@@ -145,6 +174,33 @@ module Alchemy
|
|
|
145
174
|
|
|
146
175
|
# Instance methods
|
|
147
176
|
|
|
177
|
+
# Returns an url (or relative path) to a processed image for use inside an image_tag helper.
|
|
178
|
+
#
|
|
179
|
+
# Any additional options are passed to the url method, so you can add params to your url.
|
|
180
|
+
#
|
|
181
|
+
# Example:
|
|
182
|
+
#
|
|
183
|
+
# <%= image_tag picture.url(size: '320x200', format: 'png') %>
|
|
184
|
+
#
|
|
185
|
+
# @see Alchemy::PictureVariant#call for transformation options
|
|
186
|
+
# @see Alchemy::Picture::Url#call for url options
|
|
187
|
+
# @return [String|Nil]
|
|
188
|
+
def url(options = {})
|
|
189
|
+
return unless image_file
|
|
190
|
+
|
|
191
|
+
variant = PictureVariant.new(self, options.slice(*TRANSFORMATION_OPTIONS))
|
|
192
|
+
self.class.url_class.new(variant).call(
|
|
193
|
+
options.except(*TRANSFORMATION_OPTIONS).merge(
|
|
194
|
+
basename: name,
|
|
195
|
+
ext: variant.render_format,
|
|
196
|
+
name: name,
|
|
197
|
+
)
|
|
198
|
+
)
|
|
199
|
+
rescue ::Dragonfly::Job::Fetch::NotFound => e
|
|
200
|
+
log_warning(e.message)
|
|
201
|
+
nil
|
|
202
|
+
end
|
|
203
|
+
|
|
148
204
|
def previous(params = {})
|
|
149
205
|
query = Picture.ransack(params[:q])
|
|
150
206
|
Picture.search_by(params, query).where("name < ?", name).last
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Alchemy
|
|
4
|
+
class Picture < BaseRecord
|
|
5
|
+
module Calculations
|
|
6
|
+
# An Image smaller than dimensions
|
|
7
|
+
# can not be cropped to given size - unless upsample is true.
|
|
8
|
+
#
|
|
9
|
+
def can_be_cropped_to?(string, upsample = false)
|
|
10
|
+
return true if upsample
|
|
11
|
+
|
|
12
|
+
is_bigger_than? sizes_from_string(string)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Returns true if both dimensions of the base image are bigger than the dimensions hash.
|
|
16
|
+
#
|
|
17
|
+
def is_bigger_than?(dimensions)
|
|
18
|
+
image_file_width > dimensions[:width] && image_file_height > dimensions[:height]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Returns true is one dimension of the base image is smaller than the dimensions hash.
|
|
22
|
+
#
|
|
23
|
+
def is_smaller_than?(dimensions)
|
|
24
|
+
!is_bigger_than?(dimensions)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Given a string with an x, this function returns a Hash with point
|
|
28
|
+
# :width and :height.
|
|
29
|
+
#
|
|
30
|
+
def sizes_from_string(string = "0x0")
|
|
31
|
+
string = "0x0" if string.nil? || string.empty?
|
|
32
|
+
|
|
33
|
+
raise ArgumentError unless string =~ /(\d*x\d*)/
|
|
34
|
+
|
|
35
|
+
width, height = string.scan(/(\d*)x(\d*)/)[0].map(&:to_i)
|
|
36
|
+
|
|
37
|
+
width = 0 if width.nil?
|
|
38
|
+
height = 0 if height.nil?
|
|
39
|
+
{
|
|
40
|
+
width: width,
|
|
41
|
+
height: height,
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# This function returns the :width and :height of the image file
|
|
46
|
+
# as a Hash
|
|
47
|
+
def image_size
|
|
48
|
+
{
|
|
49
|
+
width: image_file_width,
|
|
50
|
+
height: image_file_height,
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -7,6 +7,10 @@ module Alchemy
|
|
|
7
7
|
module Picture::Transformations
|
|
8
8
|
extend ActiveSupport::Concern
|
|
9
9
|
|
|
10
|
+
included do
|
|
11
|
+
include Alchemy::Picture::Calculations
|
|
12
|
+
end
|
|
13
|
+
|
|
10
14
|
THUMBNAIL_WIDTH = 160
|
|
11
15
|
THUMBNAIL_HEIGHT = 120
|
|
12
16
|
|
|
@@ -66,24 +70,6 @@ module Alchemy
|
|
|
66
70
|
image_file.thumb(upsample ? size : "#{size}>")
|
|
67
71
|
end
|
|
68
72
|
|
|
69
|
-
# Given a string with an x, this function returns a Hash with point
|
|
70
|
-
# :width and :height.
|
|
71
|
-
#
|
|
72
|
-
def sizes_from_string(string = "0x0")
|
|
73
|
-
string = "0x0" if string.nil? || string.empty?
|
|
74
|
-
|
|
75
|
-
raise ArgumentError unless string =~ /(\d*x\d*)/
|
|
76
|
-
|
|
77
|
-
width, height = string.scan(/(\d*)x(\d*)/)[0].map(&:to_i)
|
|
78
|
-
|
|
79
|
-
width = 0 if width.nil?
|
|
80
|
-
height = 0 if height.nil?
|
|
81
|
-
{
|
|
82
|
-
width: width,
|
|
83
|
-
height: height,
|
|
84
|
-
}
|
|
85
|
-
end
|
|
86
|
-
|
|
87
73
|
# Returns true if picture's width is greater than it's height
|
|
88
74
|
#
|
|
89
75
|
def landscape_format?
|
|
@@ -105,24 +91,6 @@ module Alchemy
|
|
|
105
91
|
end
|
|
106
92
|
alias_method :square?, :square_format?
|
|
107
93
|
|
|
108
|
-
# This function returns the :width and :height of the image file
|
|
109
|
-
# as a Hash
|
|
110
|
-
def image_size
|
|
111
|
-
{
|
|
112
|
-
width: image_file_width,
|
|
113
|
-
height: image_file_height,
|
|
114
|
-
}
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
# An Image smaller than dimensions
|
|
118
|
-
# can not be cropped to given size - unless upsample is true.
|
|
119
|
-
#
|
|
120
|
-
def can_be_cropped_to(string, upsample = false)
|
|
121
|
-
return true if upsample
|
|
122
|
-
|
|
123
|
-
is_bigger_than sizes_from_string(string)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
94
|
# Returns true if the class we're included in has a meaningful render_size attribute
|
|
127
95
|
#
|
|
128
96
|
def render_size?
|
|
@@ -217,22 +185,10 @@ module Alchemy
|
|
|
217
185
|
"#{dimensions[:width]}x#{dimensions[:height]}"
|
|
218
186
|
end
|
|
219
187
|
|
|
220
|
-
# Returns true if both dimensions of the base image are bigger than the dimensions hash.
|
|
221
|
-
#
|
|
222
|
-
def is_bigger_than(dimensions)
|
|
223
|
-
image_file_width > dimensions[:width] && image_file_height > dimensions[:height]
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
# Returns true is one dimension of the base image is smaller than the dimensions hash.
|
|
227
|
-
#
|
|
228
|
-
def is_smaller_than(dimensions)
|
|
229
|
-
!is_bigger_than(dimensions)
|
|
230
|
-
end
|
|
231
|
-
|
|
232
188
|
# Uses imagemagick to make a centercropped thumbnail. Does not scale the image up.
|
|
233
189
|
#
|
|
234
190
|
def center_crop(dimensions, upsample)
|
|
235
|
-
if is_smaller_than(dimensions) && upsample == false
|
|
191
|
+
if is_smaller_than?(dimensions) && upsample == false
|
|
236
192
|
dimensions = reduce_to_image(dimensions)
|
|
237
193
|
end
|
|
238
194
|
image_file.thumb("#{dimensions_to_string(dimensions)}#")
|