cropper 0.2.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.
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.rvmrc +48 -0
- data/Gemfile +7 -0
- data/README.md +17 -0
- data/Rakefile +31 -0
- data/app/assets/images/cropper/progress_stripes.png +0 -0
- data/app/assets/images/cropper/scale.png +0 -0
- data/app/assets/images/cropper/scale_large.png +0 -0
- data/app/assets/images/cropper/scale_small.png +0 -0
- data/app/assets/images/cropper/upload_spinner.gif +0 -0
- data/app/assets/javascripts/cropper.js.coffee +9 -0
- data/app/assets/javascripts/cropper/filedrop.js.coffee +255 -0
- data/app/assets/javascripts/cropper/upload_crop_scale.js.coffee +360 -0
- data/app/assets/javascripts/lib/es5-shim.js +1105 -0
- data/app/assets/javascripts/lib/modernizr.js +4 -0
- data/app/assets/stylesheets/cropper/uploads.css.sass +203 -0
- data/app/controllers/cropper/application_controller.rb +4 -0
- data/app/controllers/cropper/uploads_controller.rb +74 -0
- data/app/helpers/cropper/application_helper.rb +4 -0
- data/app/models/cropper/upload.rb +231 -0
- data/app/views/cropper/uploads/_crop.html.haml +34 -0
- data/app/views/cropper/uploads/_error.html.haml +1 -0
- data/app/views/cropper/uploads/_pick.html.haml +42 -0
- data/app/views/cropper/uploads/edit.html.haml +6 -0
- data/app/views/cropper/uploads/new.html.haml +5 -0
- data/app/views/cropper/uploads/show.html.haml +1 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +3 -0
- data/cropper.gemspec +32 -0
- data/db/migrate/20120510103921_uploads.rb +11 -0
- data/db/migrate/20130226190434_uploads_hold_crop_data.rb +8 -0
- data/db/migrate/20130402074802_upload_holder.rb +20 -0
- data/init.rb +4 -0
- data/lib/cropper.rb +159 -0
- data/lib/cropper/engine.rb +8 -0
- data/lib/cropper/glue.rb +20 -0
- data/lib/cropper/routing.rb +23 -0
- data/lib/cropper/schema.rb +63 -0
- data/lib/cropper/version.rb +3 -0
- data/lib/paperclip/geometry_transformation.rb +80 -0
- data/lib/paperclip/validators/attachment_height_validator.rb +89 -0
- data/lib/paperclip/validators/attachment_width_validator.rb +89 -0
- data/lib/paperclip_processors/offset_thumbnail.rb +93 -0
- data/lib/tasks/cropper_tasks.rake +4 -0
- data/script/rails +8 -0
- data/spec/acceptance/acceptance_helper.rb +2 -0
- data/spec/controllers/uploads_controller_spec.rb +5 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/thing.rb +4 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +56 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +6 -0
- data/spec/dummy/db/migrate/20120510104910_things.rb +8 -0
- data/spec/dummy/db/schema.rb +51 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/fixtures/images/icon.png +0 -0
- data/spec/fixtures/images/test.jpg +0 -0
- data/spec/models/thing_spec.rb +6 -0
- data/spec/models/upload_spec.rb +7 -0
- data/spec/spec_helper.rb +18 -0
- metadata +326 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
- upload ||= @upload
|
|
2
|
+
- prefix = upload.holder_column
|
|
3
|
+
- multiplier ||= (params[:multiplier] || 1).to_i
|
|
4
|
+
|
|
5
|
+
- target_w = upload.crop_width / multiplier
|
|
6
|
+
- target_h = upload.crop_height / multiplier
|
|
7
|
+
|
|
8
|
+
- max_w = upload.precrop_width / multiplier
|
|
9
|
+
- max_h = upload.precrop_height / multiplier
|
|
10
|
+
|
|
11
|
+
- initial_w = upload.scale_width? ? upload.scale_width / multiplier : max_w * 3 / 4
|
|
12
|
+
- initial_h = upload.scale_height? ? upload.scale_height / multiplier : max_h * 3 / 4
|
|
13
|
+
|
|
14
|
+
- offset_l = upload.offset_left? ? upload.offset_left / multiplier : (target_w - initial_w)/2
|
|
15
|
+
- offset_t = upload.offset_top? ? upload.offset_top / multiplier : (target_h - initial_h)/2
|
|
16
|
+
|
|
17
|
+
.cropper
|
|
18
|
+
.preview{:style => "width: #{initial_w}px; height: #{initial_h}px; top: #{offset_t}px; left: #{offset_l}px"}
|
|
19
|
+
%img{:src => upload.file.url(:precrop)}
|
|
20
|
+
|
|
21
|
+
%p.drag_instructions
|
|
22
|
+
= t :drag_instructions
|
|
23
|
+
|
|
24
|
+
= fields_for upload.holder do |hf|
|
|
25
|
+
= hf.fields_for :"#{upload.holder_column}_upload", upload do |uf|
|
|
26
|
+
%fieldset.crop
|
|
27
|
+
= uf.hidden_field :id, :data => {:"clear-on-detach" => true}
|
|
28
|
+
= uf.hidden_field :offset_left, :value => offset_l, :class => 'ol'
|
|
29
|
+
= uf.hidden_field :offset_top, :value => offset_t, :class => 'ot'
|
|
30
|
+
= uf.hidden_field :multiplier, :value => multiplier
|
|
31
|
+
.scaler
|
|
32
|
+
%p.range
|
|
33
|
+
= uf.range_field :scale_width, :min => target_w, :max => max_w, :value => initial_w, :class => 'sw'
|
|
34
|
+
= uf.hidden_field :scale_height, :value => initial_h, :class => 'sh'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
= @upload.errors[:file].first
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
- upload ||= @upload
|
|
2
|
+
- holder ||= @holder || upload.holder
|
|
3
|
+
- extra_controls ||= false
|
|
4
|
+
|
|
5
|
+
- multiplier ||= params[:multiplier] || 1
|
|
6
|
+
|
|
7
|
+
= fields_for holder do |hf|
|
|
8
|
+
= hf.fields_for :"#{upload.holder_column}_upload", upload do |uf|
|
|
9
|
+
.uploadbox{:data => {:action => "upload", :url => cropper.uploads_path(:holder_id => holder.id, :holder_type => holder.class.to_s.underscore, :holder_column => upload.holder_column, :multiplier => multiplier, :format => :js)}}
|
|
10
|
+
.prompt
|
|
11
|
+
= link_to t(:click_to_upload), '#', :data => {:action => "pick"}
|
|
12
|
+
.droppable
|
|
13
|
+
.note
|
|
14
|
+
= t :drop_to_upload
|
|
15
|
+
.img<
|
|
16
|
+
- if upload.persisted?
|
|
17
|
+
- width = upload.crop_width / multiplier
|
|
18
|
+
- height = upload.crop_height / multiplier
|
|
19
|
+
= link_to image_tag(upload.file.url(:cropped), :style => "width: #{width}px; height: #{height}px"), cropper.edit_upload_url(upload, :multiplier => multiplier), :data => {:action => "recrop"}
|
|
20
|
+
= link_to t(:detach_upload), '#', :class => 'detach', :data => {:action => 'detach'}
|
|
21
|
+
|
|
22
|
+
%p.file
|
|
23
|
+
= uf.file_field :file, :class => 'file_upload', :accept => "image"
|
|
24
|
+
|
|
25
|
+
%p.instructions
|
|
26
|
+
- unless upload.persisted?
|
|
27
|
+
= link_to t(:click_to_upload), '#', :data => {:action => "pick"}
|
|
28
|
+
%span.droppable
|
|
29
|
+
= t :drop_to_upload
|
|
30
|
+
|
|
31
|
+
- if extra_controls
|
|
32
|
+
.controls
|
|
33
|
+
#uploader.upload.button
|
|
34
|
+
= link_to t(:upload), '#', :data => {:action => "pick"}
|
|
35
|
+
.edit.button
|
|
36
|
+
- if upload && upload.persisted?
|
|
37
|
+
= link_to t(:edit_crop), cropper.edit_upload_url(upload, :multiplier => multiplier), :data => {:action => "recrop"}
|
|
38
|
+
- else
|
|
39
|
+
= link_to t(:edit_crop), '#', :data => {:action => "recrop"}, :class => 'unavailable'
|
|
40
|
+
.cancel.button
|
|
41
|
+
= link_to t(:cancel), '#'
|
|
42
|
+
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/ This we show when setting the crop parameters of an upload.
|
|
2
|
+
/ It is usually either summoned by a click or returned on a
|
|
3
|
+
/ redirect from uploads#create. For more direct editing you could
|
|
4
|
+
/ also nest cropper/uploads/crop in the recipient's edit form.
|
|
5
|
+
.edit_upload
|
|
6
|
+
= render :partial => "cropper/uploads/crop"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
= image_tag @upload.file.url(:cropped)
|
data/config/routes.rb
ADDED
data/cropper.gemspec
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "cropper/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "cropper"
|
|
7
|
+
s.version = Cropper::VERSION
|
|
8
|
+
s.authors = ["William Ross"]
|
|
9
|
+
s.email = ["will@spanner.org"]
|
|
10
|
+
s.homepage = ""
|
|
11
|
+
s.summary = %q{A simple but specific way to attach (re)croppable uploads to any model}
|
|
12
|
+
s.description = %q{Provides a mechanism for uploading, cropping and reusing images in any of your models.}
|
|
13
|
+
|
|
14
|
+
s.rubyforge_project = "cropper"
|
|
15
|
+
|
|
16
|
+
s.files = `git ls-files`.split("\n")
|
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
19
|
+
s.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
s.add_dependency "rails", "~> 3.2.0"
|
|
22
|
+
s.add_dependency('paperclip', '~> 3.3')
|
|
23
|
+
s.add_dependency('delayed_job_active_record')
|
|
24
|
+
|
|
25
|
+
s.add_development_dependency "rake"
|
|
26
|
+
s.add_development_dependency "rspec-rails"
|
|
27
|
+
s.add_development_dependency "shoulda-matchers"
|
|
28
|
+
s.add_development_dependency "capybara"
|
|
29
|
+
s.add_development_dependency "acts_as_fu"
|
|
30
|
+
s.add_development_dependency "sqlite3"
|
|
31
|
+
|
|
32
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
class UploadsHoldCropData < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
add_column :cropper_uploads, :scale_width, :integer
|
|
4
|
+
add_column :cropper_uploads, :scale_height, :integer
|
|
5
|
+
add_column :cropper_uploads, :offset_left, :integer
|
|
6
|
+
add_column :cropper_uploads, :offset_top, :integer
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class UploadHolder < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
add_column :cropper_uploads, :holder_id, :integer
|
|
4
|
+
add_column :cropper_uploads, :holder_type, :string
|
|
5
|
+
add_column :cropper_uploads, :holder_column, :string
|
|
6
|
+
|
|
7
|
+
Cropper::Upload.reset_column_information
|
|
8
|
+
Cropper::Upload.all.each do |u|
|
|
9
|
+
puts "finding match for upload #{u.id}"
|
|
10
|
+
if person = Droom::Person.where(:image_upload_id => u.id).first
|
|
11
|
+
puts "-> #{person.formal_name}"
|
|
12
|
+
%w{offset_left offset_top scale_width scale_height}.each do |col|
|
|
13
|
+
u.update_column(col.to_sym, person.send(:"image_#{col}"))
|
|
14
|
+
end
|
|
15
|
+
u.update_column(:holder_type, "Droom::Person")
|
|
16
|
+
u.update_column(:holder_column, 'image')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/init.rb
ADDED
data/lib/cropper.rb
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
require "paperclip"
|
|
2
|
+
require "paperclip/validators/attachment_height_validator"
|
|
3
|
+
require "paperclip/validators/attachment_width_validator"
|
|
4
|
+
require "paperclip/geometry_transformation"
|
|
5
|
+
require "paperclip_processors/offset_thumbnail"
|
|
6
|
+
require "cropper/engine"
|
|
7
|
+
require "cropper/routing"
|
|
8
|
+
require 'cropper/glue'
|
|
9
|
+
require 'open-uri'
|
|
10
|
+
|
|
11
|
+
module Cropper
|
|
12
|
+
# Module configuration is handled in a simple way by accessors on the Cropper module. At the moment
|
|
13
|
+
# there aren't many. Any, in fact, but we do hold some structural information about the uploading classes.
|
|
14
|
+
#
|
|
15
|
+
mattr_accessor :uploadable_classes, :upload_options
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
def uploadable_classes
|
|
19
|
+
@@uploadable_classes ||= {}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def upload_options
|
|
23
|
+
@@upload_options ||= {}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def declare_uploadable(klass, column, options)
|
|
27
|
+
k = klass.to_s.underscore.to_sym
|
|
28
|
+
uploadable_classes[k] ||= []
|
|
29
|
+
uploadable_classes[k].push(column.to_sym)
|
|
30
|
+
upload_options[k] ||= {}
|
|
31
|
+
upload_options[k][column.to_sym] = {
|
|
32
|
+
:precrop_geometry => options[:styles][:precrop],
|
|
33
|
+
:crop_geometry => options[:geometry]
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def crop_geometry(klass, column)
|
|
38
|
+
k = klass.to_s.underscore.to_sym
|
|
39
|
+
upload_options[k][column.to_sym][:crop_geometry]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def precrop_geometry(klass, column)
|
|
43
|
+
k = klass.to_s.underscore.to_sym
|
|
44
|
+
Rails.logger.warn "precrop_geometry(#{k.inspect}, #{column.inspect})"
|
|
45
|
+
upload_options[k][column.to_sym][:precrop_geometry]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Cropper::ClassMethods is included into ActiveRecord::Base in the same way as the Paperclip module.
|
|
50
|
+
# It adds a `has_upload` class method that defines an attachment and adds several instance methods
|
|
51
|
+
# that will return the values that determine its cropping. Those values are usually but not
|
|
52
|
+
# necessarily given by the user.
|
|
53
|
+
#
|
|
54
|
+
module ClassMethods
|
|
55
|
+
## Defining upload columns
|
|
56
|
+
#
|
|
57
|
+
# *has_upload* brings in the whole machinery of receiving and cropping an uploaded file. The options given are exactly the same
|
|
58
|
+
# as paperclip's `has_attached_file` call, with the addition of a 'crop' parameter that gives the target dimensions. The crop
|
|
59
|
+
# value is applied in the upload object, then any other styles you specify here are applied to that cropped image when it is
|
|
60
|
+
# passed to this model.
|
|
61
|
+
#
|
|
62
|
+
# The practical effect of this is that your :original file always has your :crop dimensions.
|
|
63
|
+
#
|
|
64
|
+
# You can also set an optional :precrop option to set the dimensions of the file that is presented in the cropping interface.
|
|
65
|
+
# The default is 1600x1600<, which is often going to be too big and may cause unwanted scaling-up of your source image.
|
|
66
|
+
# The precrop geometry is also applied in the upload object, when a file is first uploaded.
|
|
67
|
+
#
|
|
68
|
+
# The call usually looks like this:
|
|
69
|
+
#
|
|
70
|
+
# class User < ActiveRecord::Base
|
|
71
|
+
# has_upload :avatar,
|
|
72
|
+
# :precrop => '1440x960<
|
|
73
|
+
# :crop => '720x480#'
|
|
74
|
+
# :styles => {
|
|
75
|
+
# :thumbnail => "60x60#"
|
|
76
|
+
# }
|
|
77
|
+
#
|
|
78
|
+
# The crop geometry will always be treated as a fixed target shape: that is, as though it ended in '#'. Any other suffix will be
|
|
79
|
+
# removed. The other styles that you define can be in any form that paperclip understands.
|
|
80
|
+
#
|
|
81
|
+
# A model can make more than one has_upload call. The methods we define here are all prefixed with the association name, so you
|
|
82
|
+
# usually end up calling methods like `person.icon_upload`.
|
|
83
|
+
#
|
|
84
|
+
def has_upload(attachment_name=:image, options={})
|
|
85
|
+
# unless !table_exists? || column_names.include?("#{attachment_name}_upload_id")
|
|
86
|
+
# raise RuntimeError, "has_upload(#{attachment_name}) called on class #{self.to_s} but we have no #{attachment_name}_upload_id column" unless
|
|
87
|
+
# end
|
|
88
|
+
|
|
89
|
+
# allow uploads to be assigned to this class and column in the UploadsController.
|
|
90
|
+
options.reverse_merge!(:geometry => "960x640#", :whiny => true, :styles => {})
|
|
91
|
+
options[:styles].reverse_merge!({:precrop => "1600x1600<"})
|
|
92
|
+
Cropper.declare_uploadable(self, attachment_name, options)
|
|
93
|
+
|
|
94
|
+
### Upload association
|
|
95
|
+
#
|
|
96
|
+
# [uploads](/app/models/upload.html) are the original image files uploaded and cropped by this person.
|
|
97
|
+
#
|
|
98
|
+
has_many :uploads, :class_name => "Cropper::Upload", :as => :holder # so what happens when we call this twice?
|
|
99
|
+
|
|
100
|
+
# Ok, I give in. We have to require an image_upload_id column. It's silly trying to fake the whole association machine.
|
|
101
|
+
belongs_to :"#{attachment_name}_upload", :class_name => "Cropper::Upload", :autosave => true
|
|
102
|
+
|
|
103
|
+
# accepts_nested_attributes_for :"#{attachment_name}_upload"
|
|
104
|
+
attr_accessible :"#{attachment_name}_upload_attributes"
|
|
105
|
+
after_save :"connect_to_#{attachment_name}_upload"
|
|
106
|
+
|
|
107
|
+
#...but we still need to intervene to set the holder_column column of the upload when it is assigned
|
|
108
|
+
define_method :"#{attachment_name}_upload_with_holder_column=" do |upload|
|
|
109
|
+
upload.holder_column = attachment_name
|
|
110
|
+
send :"#{attachment_name}_upload_without_holder_column=", upload
|
|
111
|
+
end
|
|
112
|
+
alias_method_chain :"#{attachment_name}_upload=", :holder_column
|
|
113
|
+
|
|
114
|
+
#...or built.
|
|
115
|
+
define_method :"build_#{attachment_name}_upload_with_holder_column" do |attributes={}, options={}|
|
|
116
|
+
attributes[:holder_column] = attachment_name
|
|
117
|
+
attributes[:holder_type] ||= self.class.to_s unless attributes[:holder]
|
|
118
|
+
send :"build_#{attachment_name}_upload_without_holder_column", attributes, options
|
|
119
|
+
end
|
|
120
|
+
alias_method_chain :"build_#{attachment_name}_upload", :holder_column
|
|
121
|
+
|
|
122
|
+
# when a new holder is created, the interface means that the upload will have preceded it. In that
|
|
123
|
+
# case we will have forced the setting of holder_type to allow crop-dimension lookups. When eventually
|
|
124
|
+
# saving, we have to make sure that holder_id is also present.
|
|
125
|
+
define_method :"connect_to_#{attachment_name}_upload" do
|
|
126
|
+
if upload = send(:"#{attachment_name}_upload")
|
|
127
|
+
upload.update_column(:holder_type, self.class.to_s)
|
|
128
|
+
upload.update_column(:holder_id, self.id)
|
|
129
|
+
upload.update_column(:holder_column, attachment_name)
|
|
130
|
+
end
|
|
131
|
+
Rails.logger.warn "connect_to_#{attachment_name}_upload: upload is #{upload.inspect}. Self is #{self.inspect}"
|
|
132
|
+
true
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
define_method :"#{attachment_name}_upload_attributes=" do |attributes|
|
|
136
|
+
# assign_nested_attributes_for_image_upload_association(:image_upload, attributes, mass_assignment_options)
|
|
137
|
+
if upload_id = attributes.delete('id')
|
|
138
|
+
self.send :"#{attachment_name}_upload=", Cropper::Upload.find(upload_id)
|
|
139
|
+
end
|
|
140
|
+
if upload = self.send(:"#{attachment_name}_upload")
|
|
141
|
+
Rails.logger.warn "setting upload attributes for #{upload.inspect} -> #{attributes.inspect}"
|
|
142
|
+
upload.assign_attributes(attributes)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
### Attachment
|
|
147
|
+
#
|
|
148
|
+
# Eventually we get to the point. Image attachments work in the usual Paperclip way except that they are always received from
|
|
149
|
+
# an upload object, presumably in an already-cropped form.
|
|
150
|
+
# If this class then generates other styles, they are built from that cropped image rather than the file originally uploaded.
|
|
151
|
+
#
|
|
152
|
+
has_attached_file attachment_name, options
|
|
153
|
+
|
|
154
|
+
# Note: updates to the attached file are pushed to the holder from the upload after processing is complete, so we won't always
|
|
155
|
+
# have them immediately. Best course is to display the upload cropped rather than the holder original.
|
|
156
|
+
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
data/lib/cropper/glue.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'cropper/schema'
|
|
2
|
+
|
|
3
|
+
module Cropper
|
|
4
|
+
module Glue
|
|
5
|
+
def self.included base #:nodoc:
|
|
6
|
+
|
|
7
|
+
# Extend ActiveRecord::Base with Cropper::ClassMethods, as defined in cropper.rb.
|
|
8
|
+
#
|
|
9
|
+
base.extend ClassMethods
|
|
10
|
+
|
|
11
|
+
# Load migration helpers into all the right places.
|
|
12
|
+
#
|
|
13
|
+
if defined?(ActiveRecord)
|
|
14
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, Cropper::Schema)
|
|
15
|
+
ActiveRecord::ConnectionAdapters::Table.send(:include, Cropper::Schema)
|
|
16
|
+
ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, Cropper::Schema)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module ActionDispatch::Routing
|
|
2
|
+
|
|
3
|
+
class Mapper
|
|
4
|
+
def cropper_for(*res)
|
|
5
|
+
options = res.extract_options!
|
|
6
|
+
res.map!(&:to_sym)
|
|
7
|
+
|
|
8
|
+
# options[:path] ||= "cropper"
|
|
9
|
+
# options[:as] ||= :cropper
|
|
10
|
+
# options[:path] = "#{options[:path]}/" unless options[:path].last == '/'
|
|
11
|
+
# mount Cropper::Engine => options[:path], :as => options[:as]
|
|
12
|
+
|
|
13
|
+
Rails.application.routes.draw do
|
|
14
|
+
resources :uploads, :module => :cropper
|
|
15
|
+
res.each do |resource|
|
|
16
|
+
resources resource do
|
|
17
|
+
resources :uploads, :module => :cropper
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module Cropper
|
|
2
|
+
# Provides helpers that can be used in migrations.
|
|
3
|
+
# Copied from, and often makes calls on, the equivalent file in Paperclip.
|
|
4
|
+
#
|
|
5
|
+
module Schema
|
|
6
|
+
UPLOAD_COLUMNS = {
|
|
7
|
+
:file_name => :string,
|
|
8
|
+
:content_type => :string,
|
|
9
|
+
:file_size => :integer,
|
|
10
|
+
:updated_at => :datetime,
|
|
11
|
+
:upload_id => :integer,
|
|
12
|
+
:scale_width => :integer,
|
|
13
|
+
:scale_height => :integer,
|
|
14
|
+
:offset_left => :integer,
|
|
15
|
+
:offset_top => :integer
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
def self.included(base)
|
|
19
|
+
ActiveRecord::ConnectionAdapters::Table.send :include, TableDefinition
|
|
20
|
+
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, TableDefinition
|
|
21
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.send :include, Statements
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
module Statements
|
|
25
|
+
def add_upload(table_name, *attachment_names)
|
|
26
|
+
raise ArgumentError, "Please specify attachment name in your add_upload call in your migration." if attachment_names.empty?
|
|
27
|
+
|
|
28
|
+
attachment_names.each do |attachment_name|
|
|
29
|
+
UPLOAD_COLUMNS.each_pair do |column_name, column_type|
|
|
30
|
+
unless column_exists? table_name, "#{attachment_name}_#{column_name}"
|
|
31
|
+
add_column(table_name, "#{attachment_name}_#{column_name}", column_type)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def remove_upload(table_name, *attachment_names)
|
|
39
|
+
raise ArgumentError, "Please specify attachment name in your remove_upload call in your migration." if attachment_names.empty?
|
|
40
|
+
|
|
41
|
+
attachment_names.each do |attachment_name|
|
|
42
|
+
COLUMNS.each_pair do |column_name, column_type|
|
|
43
|
+
if column_exists? table_name, "#{attachment_name}_#{column_name}"
|
|
44
|
+
remove_column(table_name, "#{attachment_name}_#{column_name}")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
module TableDefinition
|
|
52
|
+
def cropped_attachment(*attachment_names)
|
|
53
|
+
attachment_names.each do |attachment_name|
|
|
54
|
+
UPLOAD_COLUMNS.each_pair do |column_name, column_type|
|
|
55
|
+
column("#{attachment_name}_#{column_name}", column_type)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|