refinerycms-images 2.1.5 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/refinery/admin/images_controller.rb +62 -49
- data/app/helpers/refinery/admin/images_helper.rb +6 -6
- data/app/models/refinery/image.rb +16 -61
- data/app/models/refinery/thumbnail_dimensions.rb +97 -0
- data/app/views/refinery/admin/images/_actions.html.erb +6 -7
- data/app/views/refinery/admin/images/_form.html.erb +30 -12
- data/app/views/refinery/admin/images/_grid_view.html.erb +9 -16
- data/app/views/refinery/admin/images/_list_view.html.erb +4 -4
- data/app/views/refinery/admin/images/_list_view_image.html.erb +24 -15
- data/app/views/refinery/admin/images/index.html.erb +3 -3
- data/app/views/refinery/admin/images/insert.html.erb +1 -1
- data/config/locales/ca.yml +44 -0
- data/config/locales/cs.yml +5 -0
- data/config/locales/de.yml +5 -0
- data/config/locales/en.yml +4 -0
- data/config/locales/fr.yml +4 -0
- data/config/locales/it.yml +4 -14
- data/config/locales/nl.yml +1 -1
- data/config/routes.rb +1 -1
- data/db/migrate/20140814073957_add_title_and_alt_to_refinery_images.rb +8 -0
- data/db/migrate/20150430171341_translate_refinery_images.rb +22 -0
- data/lib/generators/refinery/images/templates/config/initializers/refinery/images.rb.erb +2 -5
- data/lib/refinery/images.rb +4 -1
- data/lib/refinery/images/configuration.rb +4 -6
- data/lib/refinery/images/dragonfly.rb +38 -27
- data/lib/refinery/images/engine.rb +2 -3
- data/license.md +1 -1
- data/refinerycms-images.gemspec +6 -3
- data/spec/factories/image.rb +6 -2
- data/spec/features/refinery/admin/images_spec.rb +49 -136
- data/spec/lib/generators/refinery/images/images_generator_spec.rb +1 -1
- data/spec/lib/refinery/images/dragonfly_spec.rb +34 -0
- data/spec/models/refinery/image_spec.rb +81 -43
- data/spec/models/refinery/thumbnail_dimensions_spec.rb +18 -0
- data/spec/support/shared contexts/admin_images_tab.rb +17 -0
- data/spec/support/shared contexts/many_images.rb +5 -0
- data/spec/support/shared contexts/no_images.rb +3 -0
- data/spec/support/shared contexts/one_image.rb +3 -0
- data/spec/support/shared contexts/visual_editor_add_image.rb +31 -0
- data/spec/support/shared examples/image_deleter.rb +31 -0
- data/spec/support/shared examples/image_editor.rb +3 -0
- data/spec/support/shared examples/image_indexer.rb +118 -0
- data/spec/support/shared examples/image_inserter.rb +53 -0
- data/spec/support/shared examples/image_previewer.rb +41 -0
- data/spec/support/shared examples/image_translator.rb +31 -0
- data/spec/support/shared examples/image_uploader.rb +37 -0
- data/spec/support/spec_helper.rb +19 -0
- data/test.html +126 -0
- metadata +64 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6520739bb59acf9b68122d223d3df823f96d8d18
|
4
|
+
data.tar.gz: 7845f6b085ab9282114f097f00e477c43a3c6704
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f5983c92699bdec5da908a307ec6797da7ed711197e260b0a7b20024bed246dfbd5b2cb2bf37691ec7b57c143c49ddd4fdfe8e7b6c61e1a07b66b982911b585
|
7
|
+
data.tar.gz: 49e4348699512a24ba728f8affa5bf49d7e1dbcb45573e79f57f77928e5151a67de95b85b6402737d4bc6913a1516dbaa22f9eaca9de9e492b4f0d33b07df151
|
@@ -3,23 +3,23 @@ module Refinery
|
|
3
3
|
class ImagesController < ::Refinery::AdminController
|
4
4
|
|
5
5
|
crudify :'refinery/image',
|
6
|
-
:
|
7
|
-
:
|
8
|
-
:
|
6
|
+
include: [:translations],
|
7
|
+
order: "updated_at DESC",
|
8
|
+
sortable: false
|
9
9
|
|
10
|
-
|
10
|
+
before_action :change_list_mode_if_specified, :init_dialog
|
11
11
|
|
12
12
|
def new
|
13
13
|
@image = ::Refinery::Image.new if @image.nil?
|
14
14
|
|
15
|
-
@url_override = refinery.admin_images_path(:
|
15
|
+
@url_override = refinery.admin_images_path(dialog: from_dialog?)
|
16
16
|
end
|
17
17
|
|
18
18
|
# This renders the image insert dialog
|
19
19
|
def insert
|
20
20
|
self.new if @image.nil?
|
21
21
|
|
22
|
-
@url_override = refinery.admin_images_path(request.query_parameters.merge(:
|
22
|
+
@url_override = refinery.admin_images_path(request.query_parameters.merge(insert: true))
|
23
23
|
|
24
24
|
if params[:conditions].present?
|
25
25
|
extra_condition = params[:conditions].split(',')
|
@@ -34,86 +34,83 @@ module Refinery
|
|
34
34
|
|
35
35
|
paginate_images
|
36
36
|
|
37
|
-
render
|
37
|
+
render 'insert'
|
38
38
|
end
|
39
39
|
|
40
40
|
def create
|
41
41
|
@images = []
|
42
42
|
begin
|
43
|
-
|
44
|
-
@images << (@image = ::Refinery::Image.create(params[:image]))
|
45
|
-
else
|
43
|
+
if params[:image].present? && params[:image][:image].is_a?(Array)
|
46
44
|
params[:image][:image].each do |image|
|
47
|
-
|
45
|
+
params[:image][:image_title] = params[:image][:image_title].presence || auto_title(image.original_filename)
|
46
|
+
@images << (@image = ::Refinery::Image.create({image: image}.merge(image_params.except(:image))))
|
48
47
|
end
|
48
|
+
else
|
49
|
+
@images << (@image = ::Refinery::Image.create(image_params))
|
49
50
|
end
|
50
|
-
rescue
|
51
|
+
rescue NotImplementedError
|
51
52
|
logger.warn($!.message)
|
52
53
|
@image = ::Refinery::Image.new
|
53
54
|
end
|
54
55
|
|
55
|
-
|
56
|
+
if params[:insert]
|
57
|
+
# if all uploaded images are ok redirect page back to dialog, else show current page with error
|
56
58
|
if @images.all?(&:valid?)
|
57
|
-
|
59
|
+
@image_id = @image.id if @image.persisted?
|
60
|
+
@image = nil
|
61
|
+
end
|
62
|
+
|
63
|
+
self.insert
|
64
|
+
else
|
65
|
+
if @images.all?(&:valid?)
|
66
|
+
flash.notice = t('created', scope: 'refinery.crudify', what: "'#{@images.map(&:image_title).join("', '")}'")
|
58
67
|
if from_dialog?
|
59
68
|
@dialog_successful = true
|
60
|
-
render
|
69
|
+
render '/refinery/admin/dialog_success', layout: true
|
61
70
|
else
|
62
71
|
redirect_to refinery.admin_images_path
|
63
72
|
end
|
64
73
|
else
|
65
74
|
self.new # important for dialogs
|
66
|
-
render
|
75
|
+
render 'new'
|
67
76
|
end
|
68
|
-
else
|
69
|
-
# if all uploaded images are ok redirect page back to dialog, else show current page with error
|
70
|
-
if @images.all?(&:valid?)
|
71
|
-
@image_id = @image.id if @image.persisted?
|
72
|
-
@image = nil
|
73
|
-
end
|
74
|
-
|
75
|
-
self.insert
|
76
77
|
end
|
77
78
|
end
|
78
79
|
|
79
80
|
def update
|
80
|
-
|
81
|
-
@image.attributes = params[:image]
|
81
|
+
@image.attributes = image_params
|
82
82
|
if @image.valid? && @image.save
|
83
|
-
flash.notice = t(
|
84
|
-
'refinery.crudify.updated',
|
85
|
-
:what => "'#{@image.title}'"
|
86
|
-
)
|
83
|
+
flash.notice = t('refinery.crudify.updated', what: "'#{@image.title}'")
|
87
84
|
|
88
|
-
|
89
|
-
unless params[:continue_editing] =~ /true|on|1/
|
90
|
-
redirect_back_or_default refinery.admin_images_path
|
91
|
-
else
|
92
|
-
unless request.xhr?
|
93
|
-
redirect_to :back
|
94
|
-
else
|
95
|
-
render :partial => '/refinery/message'
|
96
|
-
end
|
97
|
-
end
|
98
|
-
else
|
85
|
+
if from_dialog?
|
99
86
|
self.index
|
100
87
|
@dialog_successful = true
|
101
88
|
render :index
|
89
|
+
else
|
90
|
+
if params[:continue_editing] =~ /true|on|1/
|
91
|
+
if request.xhr?
|
92
|
+
render partial: '/refinery/message'
|
93
|
+
else
|
94
|
+
redirect_to :back
|
95
|
+
end
|
96
|
+
else
|
97
|
+
redirect_back_or_default refinery.admin_images_path
|
98
|
+
end
|
102
99
|
end
|
103
100
|
else
|
104
101
|
@thumbnail = Image.find params[:id]
|
105
|
-
|
106
|
-
render :
|
107
|
-
|
108
|
-
|
109
|
-
:object => @image,
|
110
|
-
:include_object_name => true
|
102
|
+
if request.xhr?
|
103
|
+
render partial: '/refinery/admin/error_messages', locals: {
|
104
|
+
object: @image,
|
105
|
+
include_object_name: true
|
111
106
|
}
|
107
|
+
else
|
108
|
+
render 'edit'
|
112
109
|
end
|
113
110
|
end
|
114
111
|
end
|
115
112
|
|
116
|
-
|
113
|
+
protected
|
117
114
|
|
118
115
|
def init_dialog
|
119
116
|
@app_dialog = params[:app_dialog].present?
|
@@ -132,13 +129,29 @@ module Refinery
|
|
132
129
|
end
|
133
130
|
|
134
131
|
def paginate_images
|
135
|
-
@images = @images.paginate(:
|
132
|
+
@images = @images.paginate(page: params[:page], per_page: Image.per_page(from_dialog?, !@app_dialog))
|
136
133
|
end
|
137
134
|
|
138
135
|
def restrict_controller
|
139
136
|
super unless action_name == 'insert'
|
140
137
|
end
|
141
138
|
|
139
|
+
def auto_title(filename)
|
140
|
+
CGI::unescape(filename.to_s).gsub(/\.\w+$/, '').titleize
|
141
|
+
end
|
142
|
+
|
143
|
+
def image_params
|
144
|
+
params.require(:image).permit(permitted_image_params)
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def permitted_image_params
|
150
|
+
[
|
151
|
+
:image, :image_size, :image_title, :image_alt
|
152
|
+
]
|
153
|
+
end
|
154
|
+
|
142
155
|
end
|
143
156
|
end
|
144
157
|
end
|
@@ -2,19 +2,19 @@ module Refinery
|
|
2
2
|
module Admin
|
3
3
|
module ImagesHelper
|
4
4
|
def other_image_views
|
5
|
-
Refinery::Images.image_views.reject
|
5
|
+
Refinery::Images.image_views.reject do |image_view|
|
6
6
|
image_view.to_s == Refinery::Images.preferred_image_view.to_s
|
7
|
-
|
7
|
+
end
|
8
8
|
end
|
9
9
|
|
10
10
|
def thumbnail_urls(image)
|
11
11
|
thumbnail_urls = {
|
12
|
-
:"data-original" =>
|
13
|
-
:"data-grid" =>
|
12
|
+
:"data-original" => image_path(image.url),
|
13
|
+
:"data-grid" => image_path(image.thumbnail(:geometry => '135x135#c').url)
|
14
14
|
}
|
15
15
|
|
16
|
-
Refinery::Images.user_image_sizes.sort_by{|key,geometry| geometry}.each do |size, pixels|
|
17
|
-
thumbnail_urls[:"data-#{size.to_s.parameterize}"] =
|
16
|
+
Refinery::Images.user_image_sizes.sort_by{ |key, geometry| geometry}.each do |size, pixels|
|
17
|
+
thumbnail_urls[:"data-#{size.to_s.parameterize}"] = image_path(image.thumbnail(:geometry => pixels).url)
|
18
18
|
end
|
19
19
|
|
20
20
|
thumbnail_urls
|
@@ -2,11 +2,11 @@ require 'dragonfly'
|
|
2
2
|
|
3
3
|
module Refinery
|
4
4
|
class Image < Refinery::Core::BaseModel
|
5
|
-
|
5
|
+
translates :image_title, :image_alt
|
6
6
|
|
7
|
-
|
7
|
+
dragonfly_accessor :image, :app => :refinery_images
|
8
8
|
|
9
|
-
|
9
|
+
include Images::Validators
|
10
10
|
|
11
11
|
validates :image, :presence => true
|
12
12
|
validates_with ImageSizeValidator
|
@@ -16,19 +16,16 @@ module Refinery
|
|
16
16
|
:in => ::Refinery::Images.whitelisted_mime_types,
|
17
17
|
:message => :incorrect_format
|
18
18
|
|
19
|
-
# allows Mass-Assignment
|
20
|
-
attr_accessible :id, :image, :image_size
|
21
|
-
|
22
19
|
delegate :size, :mime_type, :url, :width, :height, :to => :image
|
23
20
|
|
24
21
|
class << self
|
25
22
|
# How many images per page should be displayed?
|
26
23
|
def per_page(dialog = false, has_size_options = false)
|
27
24
|
if dialog
|
28
|
-
|
29
|
-
Images.pages_per_dialog
|
30
|
-
else
|
25
|
+
if has_size_options
|
31
26
|
Images.pages_per_dialog_that_have_size_options
|
27
|
+
else
|
28
|
+
Images.pages_per_dialog
|
32
29
|
end
|
33
30
|
else
|
34
31
|
Images.pages_per_admin_index
|
@@ -38,71 +35,29 @@ module Refinery
|
|
38
35
|
|
39
36
|
# Get a thumbnail job object given a geometry and whether to strip image profiles and comments.
|
40
37
|
def thumbnail(options = {})
|
41
|
-
|
42
|
-
Refinery.deprecate 'Refinery::Image#thumbnail(geometry)',
|
43
|
-
:when => '2.2',
|
44
|
-
:replacement => 'Refinery::Image#thumbnail(:geometry => value)'
|
45
|
-
options = { :geometry => options }
|
46
|
-
end
|
47
|
-
|
48
|
-
options = { :geometry => :no_geometry, :strip => true }.merge(options)
|
38
|
+
options = { :geometry => nil, :strip => false }.merge(options)
|
49
39
|
geometry = convert_to_geometry(options[:geometry])
|
50
40
|
thumbnail = image
|
51
|
-
thumbnail = thumbnail.thumb(geometry)
|
41
|
+
thumbnail = thumbnail.thumb(geometry) if geometry
|
52
42
|
thumbnail = thumbnail.strip if options[:strip]
|
53
43
|
thumbnail
|
54
44
|
end
|
55
45
|
|
56
46
|
# Intelligently works out dimensions for a thumbnail of this image based on the Dragonfly geometry string.
|
57
47
|
def thumbnail_dimensions(geometry)
|
58
|
-
|
59
|
-
|
60
|
-
else
|
61
|
-
geometry.to_s
|
62
|
-
end
|
63
|
-
|
64
|
-
width = original_width = self.image_width.to_f
|
65
|
-
height = original_height = self.image_height.to_f
|
66
|
-
geometry_width, geometry_height = geometry.split(%r{\#{1,2}|\+|>|!|x}im)[0..1].map(&:to_f)
|
67
|
-
if (original_width * original_height > 0) && ::Dragonfly::ImageMagick::Processor::THUMB_GEOMETRY === geometry
|
68
|
-
if ::Dragonfly::ImageMagick::Processor::RESIZE_GEOMETRY === geometry
|
69
|
-
if geometry !~ %r{\d+x\d+>} || (%r{\d+x\d+>} === geometry && (width > geometry_width.to_f || height > geometry_height.to_f))
|
70
|
-
# Try scaling with width factor first. (wf = width factor)
|
71
|
-
wf_width = (original_width * geometry_width / width).round
|
72
|
-
wf_height = (original_height * geometry_width / width).round
|
73
|
-
|
74
|
-
# Scale with height factor (hf = height factor)
|
75
|
-
hf_width = (original_width * geometry_height / height).round
|
76
|
-
hf_height = (original_height * geometry_height / height).round
|
77
|
-
|
78
|
-
# Take the highest value that doesn't exceed either axis limit.
|
79
|
-
use_wf = wf_width <= geometry_width && wf_height <= geometry_height
|
80
|
-
if use_wf && hf_width <= geometry_width && hf_height <= geometry_height
|
81
|
-
use_wf = wf_width * wf_height > hf_width * hf_height
|
82
|
-
end
|
83
|
-
|
84
|
-
if use_wf
|
85
|
-
width = wf_width
|
86
|
-
height = wf_height
|
87
|
-
else
|
88
|
-
width = hf_width
|
89
|
-
height = hf_height
|
90
|
-
end
|
91
|
-
end
|
92
|
-
else
|
93
|
-
# cropping
|
94
|
-
width = geometry_width
|
95
|
-
height = geometry_height
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
{ :width => width.to_i, :height => height.to_i }
|
48
|
+
dimensions = ThumbnailDimensions.new(geometry, image.width, image.height)
|
49
|
+
{ :width => dimensions.width, :height => dimensions.height }
|
100
50
|
end
|
101
51
|
|
102
52
|
# Returns a titleized version of the filename
|
103
53
|
# my_file.jpg returns My File
|
54
|
+
|
104
55
|
def title
|
105
|
-
CGI::unescape(image_name.to_s).gsub(/\.\w+$/, '').titleize
|
56
|
+
image_title.presence || CGI::unescape(image_name.to_s).gsub(/\.\w+$/, '').titleize
|
57
|
+
end
|
58
|
+
|
59
|
+
def alt
|
60
|
+
image_alt.presence || title
|
106
61
|
end
|
107
62
|
|
108
63
|
private
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Refinery
|
2
|
+
class ThumbnailDimensions
|
3
|
+
|
4
|
+
attr_accessor :width, :height, :geometry, :original_width, :original_height
|
5
|
+
|
6
|
+
def initialize(geometry, original_width, original_height)
|
7
|
+
@geometry = Geometry.new(geometry)
|
8
|
+
|
9
|
+
@original_width = original_width.to_f
|
10
|
+
@original_height = original_height.to_f
|
11
|
+
|
12
|
+
process
|
13
|
+
end
|
14
|
+
|
15
|
+
def process
|
16
|
+
if valid_geometry && resize_geometry && resize_necessary
|
17
|
+
scale
|
18
|
+
elsif valid_geometry && !resize_geometry
|
19
|
+
crop
|
20
|
+
else
|
21
|
+
original_dimensions
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid_geometry
|
26
|
+
(original_width * original_height > 0) && thumb_geometry === geometry.geometry
|
27
|
+
end
|
28
|
+
|
29
|
+
def resize_geometry
|
30
|
+
::Dragonfly::ImageMagick::Processors::Thumb::RESIZE_GEOMETRY === geometry.geometry
|
31
|
+
end
|
32
|
+
|
33
|
+
def resize_necessary
|
34
|
+
!geometry.custom? ||
|
35
|
+
(geometry.custom? &&
|
36
|
+
(original_width > geometry.width ||
|
37
|
+
original_height > geometry.height))
|
38
|
+
end
|
39
|
+
|
40
|
+
def original_dimensions
|
41
|
+
@width = original_width
|
42
|
+
@height = original_height
|
43
|
+
end
|
44
|
+
|
45
|
+
def crop
|
46
|
+
@width = geometry.width
|
47
|
+
@height = geometry.height
|
48
|
+
end
|
49
|
+
|
50
|
+
def scale
|
51
|
+
# Try scaling with width factor first. (wf = width factor)
|
52
|
+
wf_width = geometry.width.round
|
53
|
+
wf_height = (original_height * geometry.width / original_width).round
|
54
|
+
|
55
|
+
# Scale with height factor (hf = height factor)
|
56
|
+
hf_width = (original_width * geometry.height / original_height).round
|
57
|
+
hf_height = geometry.height.round
|
58
|
+
|
59
|
+
# Take the highest value that doesn't exceed either axis limit.
|
60
|
+
use_wf = wf_width > 0 && wf_width <= geometry.width && wf_height <= geometry.height
|
61
|
+
if use_wf && hf_width <= geometry.width && hf_height <= geometry.height
|
62
|
+
use_wf = wf_width * wf_height > hf_width * hf_height
|
63
|
+
end
|
64
|
+
|
65
|
+
if use_wf
|
66
|
+
@width = wf_width
|
67
|
+
@height = wf_height
|
68
|
+
else
|
69
|
+
@width = hf_width
|
70
|
+
@height = hf_height
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def thumb_geometry
|
75
|
+
Regexp.union(::Dragonfly::ImageMagick::Processors::Thumb::RESIZE_GEOMETRY,
|
76
|
+
::Dragonfly::ImageMagick::Processors::Thumb::CROPPED_RESIZE_GEOMETRY,
|
77
|
+
::Dragonfly::ImageMagick::Processors::Thumb::CROP_GEOMETRY)
|
78
|
+
end
|
79
|
+
|
80
|
+
class Geometry
|
81
|
+
attr_reader :geometry, :height, :width
|
82
|
+
def initialize(geometry)
|
83
|
+
@geometry = if geometry.is_a?(Symbol) && Refinery::Images.user_image_sizes.keys.include?(geometry)
|
84
|
+
Refinery::Images.user_image_sizes[geometry]
|
85
|
+
else
|
86
|
+
geometry.to_s
|
87
|
+
end
|
88
|
+
|
89
|
+
@width, @height = @geometry.split(%r{\#{1,2}|\+|>|!|x}im)[0..1].map(&:to_f)
|
90
|
+
end
|
91
|
+
|
92
|
+
def custom?
|
93
|
+
%r{\d+x\d+>} === geometry
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -1,15 +1,14 @@
|
|
1
1
|
<ul>
|
2
|
+
<li><%= render '/refinery/admin/search', url: refinery.admin_images_path -%></li>
|
2
3
|
<li>
|
3
|
-
<%=
|
4
|
-
</li>
|
5
|
-
<li>
|
6
|
-
<%= link_to t('.create_new_image'), refinery.new_admin_image_path(:dialog => true), :class => 'add_icon' %>
|
4
|
+
<%= action_label :add, refinery.new_admin_image_path(dialog: true), t('.create_new_image') %>
|
7
5
|
</li>
|
8
6
|
<% other_image_views.each do |image_view| %>
|
9
7
|
<li>
|
10
|
-
<%=
|
11
|
-
|
12
|
-
|
8
|
+
<%= action_label :"switch_view_#{image_view}",
|
9
|
+
refinery.admin_images_path(view: image_view, page: params[:page]),
|
10
|
+
t('switch_to', scope: 'refinery.admin.images.index.view', view_name: t("#{image_view}", scope: 'refinery.admin.images.index.view'))
|
11
|
+
%>
|
13
12
|
</li>
|
14
13
|
<% end %>
|
15
14
|
</ul>
|