jcropper 0.1.0
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/MIT-LICENSE +20 -0
- data/README.rdoc +35 -0
- data/Rakefile +38 -0
- data/TODO +20 -0
- data/VERSION +1 -0
- data/generators/jcropper/USAGE +6 -0
- data/generators/jcropper/jcropper_generator.rb +22 -0
- data/generators/jcropper/templates/jcropper_migration.rb.erb +15 -0
- data/install.rb +1 -0
- data/lib/jcropper.rb +3 -0
- data/lib/jcropper/helpers.rb +137 -0
- data/lib/jcropper/jcropper.rb +55 -0
- data/lib/paperclip_processors/jcropper.rb +28 -0
- data/public/images/Jcrop.gif +0 -0
- data/public/javascripts/jquery.Jcrop.min.js +163 -0
- data/public/stylesheets/jquery.Jcrop.css +35 -0
- data/rails/init.rb +1 -0
- data/tasks/js_cropper.rake +9 -0
- data/test/jcropper_test.rb +8 -0
- data/test/test_helper.rb +3 -0
- data/uninstall.rb +1 -0
- metadata +84 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 [name of plugin creator]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
= Overview
|
2
|
+
|
3
|
+
jcropper wraps jcrop 0.98, http://deepliquid.com/content/Jcrop.html, a javascript cropping tool.
|
4
|
+
|
5
|
+
jcropper currently only works with paperclip.
|
6
|
+
|
7
|
+
= Installation
|
8
|
+
|
9
|
+
Include the jcropper processor in the paperclip style.
|
10
|
+
|
11
|
+
class User < ActiveRecord::Base
|
12
|
+
has_attached_file :avatar, :styles => { :thumb => "100x100>", :processors => "jcropper" }
|
13
|
+
...
|
14
|
+
end
|
15
|
+
|
16
|
+
Tell jcropper to crop the paperclip attachment
|
17
|
+
|
18
|
+
jcrop :avatar, :thumb
|
19
|
+
|
20
|
+
Generate and install your migration
|
21
|
+
|
22
|
+
script/generate jcropper user avatar thumb
|
23
|
+
rake db:migrate
|
24
|
+
|
25
|
+
Install js/css/images for jcropper
|
26
|
+
|
27
|
+
rake js_cropper:install
|
28
|
+
|
29
|
+
Add the helpers to your view:
|
30
|
+
|
31
|
+
<%= croppable_image @user, :avatar, :thumb -%>
|
32
|
+
<%= croppable_image_preview @user, :avatar, :thumb -%>
|
33
|
+
|
34
|
+
|
35
|
+
Copyright (c) 2010 Symbolforce, LLC., released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'jeweler'
|
7
|
+
Jeweler::Tasks.new do |gemspec|
|
8
|
+
gemspec.name = "jcropper"
|
9
|
+
gemspec.summary = "gem plugin wrapping jquery "
|
10
|
+
gemspec.description = ""
|
11
|
+
gemspec.email = "ryan@symbolforce.com"
|
12
|
+
gemspec.homepage = "http://github.com/syfo/jcropper"
|
13
|
+
gemspec.authors = ["Ryan Ziegler"]
|
14
|
+
end
|
15
|
+
Jeweler::GemcutterTasks.new
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Default: run unit tests.'
|
21
|
+
task :default => :test
|
22
|
+
|
23
|
+
desc 'Test the jcropper plugin.'
|
24
|
+
Rake::TestTask.new(:test) do |t|
|
25
|
+
t.libs << 'lib'
|
26
|
+
t.libs << 'test'
|
27
|
+
t.pattern = 'test/**/*_test.rb'
|
28
|
+
t.verbose = true
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Generate documentation for the jcropper plugin.'
|
32
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
33
|
+
rdoc.rdoc_dir = 'rdoc'
|
34
|
+
rdoc.title = 'JCropper'
|
35
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
36
|
+
rdoc.rdoc_files.include('README')
|
37
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
38
|
+
end
|
data/TODO
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
- make helper a FormHelper
|
2
|
+
- support for multiple crops per model
|
3
|
+
- support for more than just paperclip
|
4
|
+
- decouple to paperclip
|
5
|
+
- what others to support?
|
6
|
+
- test with latest jquery as well as 1.3.1
|
7
|
+
- write tests, of course
|
8
|
+
- what should the syntax be for including in a model?
|
9
|
+
a) simply be adding a style with :processor => 'jcropper', its added to the model
|
10
|
+
b) js_crop :icon, :style => { ... } mirrors paperclip options, and ADDS that style to the preexisting paperclip options
|
11
|
+
c) maybe you add a style with whatever processor, then js_crop :ikon, :style_name overrides that style
|
12
|
+
|
13
|
+
- syntax for view helpers?
|
14
|
+
- editable image
|
15
|
+
- previewable image?
|
16
|
+
- need to be able to turn on/off aspect ratio lock and resize lock
|
17
|
+
- is it really necc to have a paperclip processor?
|
18
|
+
- use inline css or separate css
|
19
|
+
- reset cropping when uploading new image
|
20
|
+
- make options[:view_size] work
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class JcropperGenerator < Rails::Generator::NamedBase
|
2
|
+
attr_accessor :attachment, :migration_name
|
3
|
+
|
4
|
+
def initialize(args, options = {})
|
5
|
+
super
|
6
|
+
@class_name, @attachment, @style = args[0], args[1], args[2]
|
7
|
+
end
|
8
|
+
|
9
|
+
def manifest
|
10
|
+
file_name = generate_file_name
|
11
|
+
@migration_name = file_name.camelize
|
12
|
+
record do |m|
|
13
|
+
m.migration_template "jcropper_migration.rb.erb", File.join('db', 'migrate'), :migration_file_name => file_name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def generate_file_name
|
20
|
+
"add_crop_variables_for_#{@attachment}_style_#{@style}_to_#{@class_name.underscore}"
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class <%= migration_name %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_<%= style %>_crop_x, :integer, :default => 0
|
4
|
+
add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_<%= style %>_crop_y, :integer, :default => 0
|
5
|
+
add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_<%= style %>_crop_w, :integer, :default => 0
|
6
|
+
add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_<%= style %>_crop_h, :integer, :default => 0
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.down
|
10
|
+
remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_<%= style %>_crop_x
|
11
|
+
remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_<%= style %>_crop_y
|
12
|
+
remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_<%= style %>_crop_w
|
13
|
+
remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_<%= style %>_crop_h
|
14
|
+
end
|
15
|
+
end
|
data/install.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Install hook code here
|
data/lib/jcropper.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
module JCropper
|
2
|
+
module Helpers
|
3
|
+
def croppable_image(object_name, attachment, style, options = {})
|
4
|
+
object = eval("@#{object_name.to_s}") unless object_name.is_a? ActiveRecord::Base
|
5
|
+
paperclip_options = object.send(attachment).styles[style.to_sym]
|
6
|
+
options = options.merge(default_options)
|
7
|
+
|
8
|
+
x, y, w, h = ['x', 'y', 'w', 'h'].map{|v| "#{attachment}_crop_#{v}"}
|
9
|
+
|
10
|
+
target_geometry = Paperclip::Geometry.parse(paperclip_options[:geometry])
|
11
|
+
file_geometry = Paperclip::Geometry.from_file(object.send(attachment).path(:original))
|
12
|
+
options[:view_size] ||= {:width => file_geometry.width, :height => file_geometry.height}
|
13
|
+
|
14
|
+
resized_ratio = options[:view_size][:width] / file_geometry.width
|
15
|
+
|
16
|
+
s = "<div class='#{options[:css_prefix]}'>#{image_tag(object.send(attachment).url, options[:view_size])}</div>" + "\n"
|
17
|
+
s += hidden_field_tag("#{object_name}[#{x}]", object.send(x), :id => x) + "\n"
|
18
|
+
s += hidden_field_tag("#{object_name}[#{y}]", object.send(y), :id => y) + "\n"
|
19
|
+
s += hidden_field_tag("#{object_name}[#{w}]", object.send(w), :id => w) + "\n"
|
20
|
+
s += hidden_field_tag("#{object_name}[#{h}]", object.send(h), :id => h) + "\n"
|
21
|
+
s += <<-CSS
|
22
|
+
<style type="text/css">
|
23
|
+
/* Fixes issue here http://code.google.com/p/jcrop/issues/detail?id=1 */
|
24
|
+
.jcrop-holder { text-align: left; }
|
25
|
+
|
26
|
+
.jcrop-vline, .jcrop-hline
|
27
|
+
{
|
28
|
+
font-size: 0;
|
29
|
+
position: absolute;
|
30
|
+
background: white url('Jcrop.gif') top left repeat;
|
31
|
+
}
|
32
|
+
.jcrop-vline { height: 100%; width: 1px !important; }
|
33
|
+
.jcrop-hline { width: 100%; height: 1px !important; }
|
34
|
+
.jcrop-handle {
|
35
|
+
font-size: 1px;
|
36
|
+
width: 7px !important;
|
37
|
+
height: 7px !important;
|
38
|
+
border: 1px #eee solid;
|
39
|
+
background-color: #333;
|
40
|
+
*width: 9px;
|
41
|
+
*height: 9px;
|
42
|
+
}
|
43
|
+
|
44
|
+
.jcrop-tracker { width: 100%; height: 100%; }
|
45
|
+
|
46
|
+
.custom .jcrop-vline,
|
47
|
+
.custom .jcrop-hline
|
48
|
+
{
|
49
|
+
background: yellow;
|
50
|
+
}
|
51
|
+
.custom .jcrop-handle
|
52
|
+
{
|
53
|
+
border-color: black;
|
54
|
+
background-color: #C7BB00;
|
55
|
+
-moz-border-radius: 3px;
|
56
|
+
-webkit-border-radius: 3px;
|
57
|
+
}
|
58
|
+
</style>
|
59
|
+
CSS
|
60
|
+
|
61
|
+
s += <<-HTML
|
62
|
+
<script type='text/javascript'>
|
63
|
+
function findBoundingScale(img, container) {
|
64
|
+
imgAspect = img[0] / img[1]
|
65
|
+
containerAspect = container[0] / container[1]
|
66
|
+
|
67
|
+
if(imgAspect < containerAspect) {
|
68
|
+
return (container[0] / img[0]);
|
69
|
+
}
|
70
|
+
else {
|
71
|
+
return (container[1] / img[1]);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
$('.#{options[:css_prefix]} img').load(function() {
|
76
|
+
var trueWidth = #{file_geometry.width};
|
77
|
+
var trueHeight = #{file_geometry.height};
|
78
|
+
|
79
|
+
var targetWidth = #{target_geometry.width};
|
80
|
+
var targetHeight = #{target_geometry.height};
|
81
|
+
|
82
|
+
function cropOnChange(coords) {
|
83
|
+
var rx = $('##{options[:css_prefix]}-preview').parent().width() / coords.w;
|
84
|
+
var ry = $('##{options[:css_prefix]}-preview').parent().height() / coords.h;
|
85
|
+
|
86
|
+
$('##{options[:css_prefix]}-preview').css({
|
87
|
+
width: Math.round(rx * trueWidth) + 'px',
|
88
|
+
height: Math.round(ry * trueHeight) + 'px',
|
89
|
+
marginLeft: '-' + Math.round(rx * coords.x) + 'px',
|
90
|
+
marginTop: '-' + Math.round(ry * coords.y) + 'px'
|
91
|
+
});
|
92
|
+
|
93
|
+
$('##{x}').val(coords.x);
|
94
|
+
$('##{y}').val(coords.y);
|
95
|
+
$('##{w}').val(coords.w);
|
96
|
+
$('##{h}').val(coords.h);
|
97
|
+
console.log(coords);
|
98
|
+
}
|
99
|
+
|
100
|
+
api = $('.#{options[:css_prefix]} img').Jcrop({
|
101
|
+
#{options[:jcrop_options].map{|k,v| "#{k.to_s}: #{v.to_s},\n"}}
|
102
|
+
setSelect: #{[object.send(x), object.send(y),
|
103
|
+
object.send(x) + object.send(w), object.send(y) + object.send(h)].map {|v| v*resized_ratio}.to_json},
|
104
|
+
onChange: cropOnChange,
|
105
|
+
onSelect: cropOnChange,
|
106
|
+
// aspectRatio: targetWidth / targetHeight,
|
107
|
+
trueSize: [trueWidth, trueHeight]
|
108
|
+
});
|
109
|
+
});
|
110
|
+
</script>
|
111
|
+
HTML
|
112
|
+
end
|
113
|
+
|
114
|
+
def croppable_image_preview(object_name, attachment, style, options = {})
|
115
|
+
object = eval("@#{object_name.to_s}") unless object_name.is_a? ActiveRecord::Base
|
116
|
+
options = options.merge(default_options)
|
117
|
+
|
118
|
+
<<-HTML
|
119
|
+
<div style="overflow:hidden;height:100px;width:100px;border:1px solid black;">
|
120
|
+
#{image_tag(object.send(attachment).url(:original), :id => "#{options[:css_prefix]}-preview")}
|
121
|
+
</div>
|
122
|
+
HTML
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
def default_options
|
127
|
+
{
|
128
|
+
:css_prefix => 'js_crop',
|
129
|
+
:jcrop_options => {}
|
130
|
+
}
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class ActionView::Base
|
136
|
+
include JCropper::Helpers
|
137
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module JCropper
|
2
|
+
module ClassMethods
|
3
|
+
def jcrop(attachment, style, options = {})
|
4
|
+
raise "jcropper requires attachment to be of type Paperclip::Attachment" if self.attachment_definitions[attachment.to_sym].nil?
|
5
|
+
require File.join(ROOT, '../paperclip_processors/jcropper.rb')
|
6
|
+
|
7
|
+
options[:attachment] = attachment = attachment.to_s
|
8
|
+
options[:lock_aspect] ||= true
|
9
|
+
|
10
|
+
x, y, w, h = [:x, :y, :w, :h].map{|coord| jattr(attachment, style, coord) }
|
11
|
+
|
12
|
+
class_exec(options) do |options|
|
13
|
+
write_inheritable_attribute :jcropper_options, options.dup
|
14
|
+
class_inheritable_reader :jcropper_options
|
15
|
+
|
16
|
+
attr_accessor :jcropper_should_reprocess
|
17
|
+
before_save :jcropper_check_for_reprocess
|
18
|
+
after_save :jcropper_reprocess
|
19
|
+
|
20
|
+
def jcropper_reprocess
|
21
|
+
send(self.class.jcropper_options[:attachment]).reprocess! if @jcropper_should_reprocess
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
to_eval = <<-TO_EVAL
|
26
|
+
def jcropper_check_for_reprocess
|
27
|
+
@jcropper_should_reprocess ||= !(changed & %w(#{x} #{y} #{w} #{h})).empty?
|
28
|
+
return true
|
29
|
+
end
|
30
|
+
|
31
|
+
def jcropper_crop_string
|
32
|
+
if not [#{x}, #{y}, #{w}, #{h}].all?{|v| v.nil? or v.zero?}
|
33
|
+
"-crop \#{#{w}}x\#{#{h}}+\#{#{x}}+\#{#{y}}"
|
34
|
+
else
|
35
|
+
""
|
36
|
+
end
|
37
|
+
end
|
38
|
+
TO_EVAL
|
39
|
+
class_eval to_eval
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def self.jattr(attachment, style, coord)
|
45
|
+
"#{attachment}_#{style}_crop_#{coord}"
|
46
|
+
end
|
47
|
+
|
48
|
+
module InstanceMethods
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class ActiveRecord::Base
|
53
|
+
include JCropper::InstanceMethods
|
54
|
+
extend JCropper::ClassMethods
|
55
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Paperclip
|
2
|
+
class JCropper < Thumbnail
|
3
|
+
def transformation_command
|
4
|
+
scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
|
5
|
+
trans = ''
|
6
|
+
if crop_string?
|
7
|
+
trans << " #{crop_string}"
|
8
|
+
trans << " -resize \"#{scale}\""
|
9
|
+
else
|
10
|
+
trans << " -resize \"#{scale}\""
|
11
|
+
trans << " -crop \"#{crop}\" +repage" if crop
|
12
|
+
trans.sub!('-crop', '-gravity North -crop') # add north gravity
|
13
|
+
trans.sub!(/\d+\+\d+"/, '0+0"') # remove calculated offset
|
14
|
+
end
|
15
|
+
trans << " #{convert_options}" if convert_options?
|
16
|
+
puts trans
|
17
|
+
trans
|
18
|
+
end
|
19
|
+
|
20
|
+
def crop_string
|
21
|
+
@attachment.instance.jcropper_crop_string
|
22
|
+
end
|
23
|
+
|
24
|
+
def crop_string?
|
25
|
+
not crop_string.blank?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
Binary file
|
@@ -0,0 +1,163 @@
|
|
1
|
+
/**
|
2
|
+
* Jcrop v.0.9.8 (minimized)
|
3
|
+
* (c) 2008 Kelly Hallman and DeepLiquid.com
|
4
|
+
* More information: http://deepliquid.com/content/Jcrop.html
|
5
|
+
* Released under MIT License - this header must remain with code
|
6
|
+
*/
|
7
|
+
|
8
|
+
|
9
|
+
(function($){$.Jcrop=function(obj,opt)
|
10
|
+
{var obj=obj,opt=opt;if(typeof(obj)!=='object')obj=$(obj)[0];if(typeof(opt)!=='object')opt={};if(!('trackDocument'in opt))
|
11
|
+
{opt.trackDocument=$.browser.msie?false:true;if($.browser.msie&&$.browser.version.split('.')[0]=='8')
|
12
|
+
opt.trackDocument=true;}
|
13
|
+
if(!('keySupport'in opt))
|
14
|
+
opt.keySupport=$.browser.msie?false:true;var defaults={trackDocument:false,baseClass:'jcrop',addClass:null,bgColor:'black',bgOpacity:.6,borderOpacity:.4,handleOpacity:.5,handlePad:5,handleSize:9,handleOffset:5,edgeMargin:14,aspectRatio:0,keySupport:true,cornerHandles:true,sideHandles:true,drawBorders:true,dragEdges:true,boxWidth:0,boxHeight:0,boundary:8,animationDelay:20,swingSpeed:3,allowSelect:true,allowMove:true,allowResize:true,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){}};var options=defaults;setOptions(opt);var $origimg=$(obj);var $img=$origimg.clone().removeAttr('id').css({position:'absolute'});$img.width($origimg.width());$img.height($origimg.height());$origimg.after($img).hide();presize($img,options.boxWidth,options.boxHeight);var boundx=$img.width(),boundy=$img.height(),$div=$('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({position:'relative',backgroundColor:options.bgColor}).insertAfter($origimg).append($img);;if(options.addClass)$div.addClass(options.addClass);var $img2=$('<img />').attr('src',$img.attr('src')).css('position','absolute').width(boundx).height(boundy);var $img_holder=$('<div />').width(pct(100)).height(pct(100)).css({zIndex:310,position:'absolute',overflow:'hidden'}).append($img2);var $hdl_holder=$('<div />').width(pct(100)).height(pct(100)).css('zIndex',320);var $sel=$('<div />').css({position:'absolute',zIndex:300}).insertBefore($img).append($img_holder,$hdl_holder);var bound=options.boundary;var $trk=newTracker().width(boundx+(bound*2)).height(boundy+(bound*2)).css({position:'absolute',top:px(-bound),left:px(-bound),zIndex:290}).mousedown(newSelection);var xlimit,ylimit,xmin,ymin;var xscale,yscale,enabled=true;var docOffset=getPos($img),btndown,lastcurs,dimmed,animating,shift_down;var Coords=function()
|
15
|
+
{var x1=0,y1=0,x2=0,y2=0,ox,oy;function setPressed(pos)
|
16
|
+
{var pos=rebound(pos);x2=x1=pos[0];y2=y1=pos[1];};function setCurrent(pos)
|
17
|
+
{var pos=rebound(pos);ox=pos[0]-x2;oy=pos[1]-y2;x2=pos[0];y2=pos[1];};function getOffset()
|
18
|
+
{return[ox,oy];};function moveOffset(offset)
|
19
|
+
{var ox=offset[0],oy=offset[1];if(0>x1+ox)ox-=ox+x1;if(0>y1+oy)oy-=oy+y1;if(boundy<y2+oy)oy+=boundy-(y2+oy);if(boundx<x2+ox)ox+=boundx-(x2+ox);x1+=ox;x2+=ox;y1+=oy;y2+=oy;};function getCorner(ord)
|
20
|
+
{var c=getFixed();switch(ord)
|
21
|
+
{case'ne':return[c.x2,c.y];case'nw':return[c.x,c.y];case'se':return[c.x2,c.y2];case'sw':return[c.x,c.y2];}};function getFixed()
|
22
|
+
{if(!options.aspectRatio)return getRect();var aspect=options.aspectRatio,min_x=options.minSize[0]/xscale,min_y=options.minSize[1]/yscale,max_x=options.maxSize[0]/xscale,max_y=options.maxSize[1]/yscale,rw=x2-x1,rh=y2-y1,rwa=Math.abs(rw),rha=Math.abs(rh),real_ratio=rwa/rha,xx,yy;if(max_x==0){max_x=boundx*10}
|
23
|
+
if(max_y==0){max_y=boundy*10}
|
24
|
+
if(real_ratio<aspect)
|
25
|
+
{yy=y2;w=rha*aspect;xx=rw<0?x1-w:w+x1;if(xx<0)
|
26
|
+
{xx=0;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}
|
27
|
+
else if(xx>boundx)
|
28
|
+
{xx=boundx;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}}
|
29
|
+
else
|
30
|
+
{xx=x2;h=rwa/aspect;yy=rh<0?y1-h:y1+h;if(yy<0)
|
31
|
+
{yy=0;w=Math.abs((yy-y1)*aspect);xx=rw<0?x1-w:w+x1;}
|
32
|
+
else if(yy>boundy)
|
33
|
+
{yy=boundy;w=Math.abs(yy-y1)*aspect;xx=rw<0?x1-w:w+x1;}}
|
34
|
+
if(xx>x1){if(xx-x1<min_x){xx=x1+min_x;}else if(xx-x1>max_x){xx=x1+max_x;}
|
35
|
+
if(yy>y1){yy=y1+(xx-x1)/aspect;}else{yy=y1-(xx-x1)/aspect;}}else if(xx<x1){if(x1-xx<min_x){xx=x1-min_x}else if(x1-xx>max_x){xx=x1-max_x;}
|
36
|
+
if(yy>y1){yy=y1+(x1-xx)/aspect;}else{yy=y1-(x1-xx)/aspect;}}
|
37
|
+
if(xx<0){x1-=xx;xx=0;}else if(xx>boundx){x1-=xx-boundx;xx=boundx;}
|
38
|
+
if(yy<0){y1-=yy;yy=0;}else if(yy>boundy){y1-=yy-boundy;yy=boundy;}
|
39
|
+
return last=makeObj(flipCoords(x1,y1,xx,yy));};function rebound(p)
|
40
|
+
{if(p[0]<0)p[0]=0;if(p[1]<0)p[1]=0;if(p[0]>boundx)p[0]=boundx;if(p[1]>boundy)p[1]=boundy;return[p[0],p[1]];};function flipCoords(x1,y1,x2,y2)
|
41
|
+
{var xa=x1,xb=x2,ya=y1,yb=y2;if(x2<x1)
|
42
|
+
{xa=x2;xb=x1;}
|
43
|
+
if(y2<y1)
|
44
|
+
{ya=y2;yb=y1;}
|
45
|
+
return[Math.round(xa),Math.round(ya),Math.round(xb),Math.round(yb)];};function getRect()
|
46
|
+
{var xsize=x2-x1;var ysize=y2-y1;if(xlimit&&(Math.abs(xsize)>xlimit))
|
47
|
+
x2=(xsize>0)?(x1+xlimit):(x1-xlimit);if(ylimit&&(Math.abs(ysize)>ylimit))
|
48
|
+
y2=(ysize>0)?(y1+ylimit):(y1-ylimit);if(ymin&&(Math.abs(ysize)<ymin))
|
49
|
+
y2=(ysize>0)?(y1+ymin):(y1-ymin);if(xmin&&(Math.abs(xsize)<xmin))
|
50
|
+
x2=(xsize>0)?(x1+xmin):(x1-xmin);if(x1<0){x2-=x1;x1-=x1;}
|
51
|
+
if(y1<0){y2-=y1;y1-=y1;}
|
52
|
+
if(x2<0){x1-=x2;x2-=x2;}
|
53
|
+
if(y2<0){y1-=y2;y2-=y2;}
|
54
|
+
if(x2>boundx){var delta=x2-boundx;x1-=delta;x2-=delta;}
|
55
|
+
if(y2>boundy){var delta=y2-boundy;y1-=delta;y2-=delta;}
|
56
|
+
if(x1>boundx){var delta=x1-boundy;y2-=delta;y1-=delta;}
|
57
|
+
if(y1>boundy){var delta=y1-boundy;y2-=delta;y1-=delta;}
|
58
|
+
return makeObj(flipCoords(x1,y1,x2,y2));};function makeObj(a)
|
59
|
+
{return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]};};return{flipCoords:flipCoords,setPressed:setPressed,setCurrent:setCurrent,getOffset:getOffset,moveOffset:moveOffset,getCorner:getCorner,getFixed:getFixed};}();var Selection=function()
|
60
|
+
{var start,end,dragmode,awake,hdep=370;var borders={};var handle={};var seehandles=false;var hhs=options.handleOffset;if(options.drawBorders){borders={top:insertBorder('hline').css('top',$.browser.msie?px(-1):px(0)),bottom:insertBorder('hline'),left:insertBorder('vline'),right:insertBorder('vline')};}
|
61
|
+
if(options.dragEdges){handle.t=insertDragbar('n');handle.b=insertDragbar('s');handle.r=insertDragbar('e');handle.l=insertDragbar('w');}
|
62
|
+
options.sideHandles&&createHandles(['n','s','e','w']);options.cornerHandles&&createHandles(['sw','nw','ne','se']);function insertBorder(type)
|
63
|
+
{var jq=$('<div />').css({position:'absolute',opacity:options.borderOpacity}).addClass(cssClass(type));$img_holder.append(jq);return jq;};function dragDiv(ord,zi)
|
64
|
+
{var jq=$('<div />').mousedown(createDragger(ord)).css({cursor:ord+'-resize',position:'absolute',zIndex:zi});$hdl_holder.append(jq);return jq;};function insertHandle(ord)
|
65
|
+
{return dragDiv(ord,hdep++).css({top:px(-hhs+1),left:px(-hhs+1),opacity:options.handleOpacity}).addClass(cssClass('handle'));};function insertDragbar(ord)
|
66
|
+
{var s=options.handleSize,o=hhs,h=s,w=s,t=o,l=o;switch(ord)
|
67
|
+
{case'n':case's':w=pct(100);break;case'e':case'w':h=pct(100);break;}
|
68
|
+
return dragDiv(ord,hdep++).width(w).height(h).css({top:px(-t+1),left:px(-l+1)});};function createHandles(li)
|
69
|
+
{for(i in li)handle[li[i]]=insertHandle(li[i]);};function moveHandles(c)
|
70
|
+
{var midvert=Math.round((c.h/2)-hhs),midhoriz=Math.round((c.w/2)-hhs),north=west=-hhs+1,east=c.w-hhs,south=c.h-hhs,x,y;'e'in handle&&handle.e.css({top:px(midvert),left:px(east)})&&handle.w.css({top:px(midvert)})&&handle.s.css({top:px(south),left:px(midhoriz)})&&handle.n.css({left:px(midhoriz)});'ne'in handle&&handle.ne.css({left:px(east)})&&handle.se.css({top:px(south),left:px(east)})&&handle.sw.css({top:px(south)});'b'in handle&&handle.b.css({top:px(south)})&&handle.r.css({left:px(east)});};function moveto(x,y)
|
71
|
+
{$img2.css({top:px(-y),left:px(-x)});$sel.css({top:px(y),left:px(x)});};function resize(w,h)
|
72
|
+
{$sel.width(w).height(h);};function refresh()
|
73
|
+
{var c=Coords.getFixed();Coords.setPressed([c.x,c.y]);Coords.setCurrent([c.x2,c.y2]);updateVisible();};function updateVisible()
|
74
|
+
{if(awake)return update();};function update()
|
75
|
+
{var c=Coords.getFixed();resize(c.w,c.h);moveto(c.x,c.y);options.drawBorders&&borders['right'].css({left:px(c.w-1)})&&borders['bottom'].css({top:px(c.h-1)});seehandles&&moveHandles(c);awake||show();options.onChange(unscale(c));};function show()
|
76
|
+
{$sel.show();$img.css('opacity',options.bgOpacity);awake=true;};function release()
|
77
|
+
{disableHandles();$sel.hide();$img.css('opacity',1);awake=false;};function showHandles()
|
78
|
+
{if(seehandles)
|
79
|
+
{moveHandles(Coords.getFixed());$hdl_holder.show();}};function enableHandles()
|
80
|
+
{seehandles=true;if(options.allowResize)
|
81
|
+
{moveHandles(Coords.getFixed());$hdl_holder.show();return true;}};function disableHandles()
|
82
|
+
{seehandles=false;$hdl_holder.hide();};function animMode(v)
|
83
|
+
{(animating=v)?disableHandles():enableHandles();};function done()
|
84
|
+
{animMode(false);refresh();};var $track=newTracker().mousedown(createDragger('move')).css({cursor:'move',position:'absolute',zIndex:360})
|
85
|
+
$img_holder.append($track);disableHandles();return{updateVisible:updateVisible,update:update,release:release,refresh:refresh,setCursor:function(cursor){$track.css('cursor',cursor);},enableHandles:enableHandles,enableOnly:function(){seehandles=true;},showHandles:showHandles,disableHandles:disableHandles,animMode:animMode,done:done};}();var Tracker=function()
|
86
|
+
{var onMove=function(){},onDone=function(){},trackDoc=options.trackDocument;if(!trackDoc)
|
87
|
+
{$trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);}
|
88
|
+
function toFront()
|
89
|
+
{$trk.css({zIndex:450});if(trackDoc)
|
90
|
+
{$(document).mousemove(trackMove).mouseup(trackUp);}}
|
91
|
+
function toBack()
|
92
|
+
{$trk.css({zIndex:290});if(trackDoc)
|
93
|
+
{$(document).unbind('mousemove',trackMove).unbind('mouseup',trackUp);}}
|
94
|
+
function trackMove(e)
|
95
|
+
{onMove(mouseAbs(e));};function trackUp(e)
|
96
|
+
{e.preventDefault();e.stopPropagation();if(btndown)
|
97
|
+
{btndown=false;onDone(mouseAbs(e));options.onSelect(unscale(Coords.getFixed()));toBack();onMove=function(){};onDone=function(){};}
|
98
|
+
return false;};function activateHandlers(move,done)
|
99
|
+
{btndown=true;onMove=move;onDone=done;toFront();return false;};function setCursor(t){$trk.css('cursor',t);};$img.before($trk);return{activateHandlers:activateHandlers,setCursor:setCursor};}();var KeyManager=function()
|
100
|
+
{var $keymgr=$('<input type="radio" />').css({position:'absolute',left:'-30px'}).keypress(parseKey).blur(onBlur),$keywrap=$('<div />').css({position:'absolute',overflow:'hidden'}).append($keymgr);function watchKeys()
|
101
|
+
{if(options.keySupport)
|
102
|
+
{$keymgr.show();$keymgr.focus();}};function onBlur(e)
|
103
|
+
{$keymgr.hide();};function doNudge(e,x,y)
|
104
|
+
{if(options.allowMove){Coords.moveOffset([x,y]);Selection.updateVisible();};e.preventDefault();e.stopPropagation();};function parseKey(e)
|
105
|
+
{if(e.ctrlKey)return true;shift_down=e.shiftKey?true:false;var nudge=shift_down?10:1;switch(e.keyCode)
|
106
|
+
{case 37:doNudge(e,-nudge,0);break;case 39:doNudge(e,nudge,0);break;case 38:doNudge(e,0,-nudge);break;case 40:doNudge(e,0,nudge);break;case 27:Selection.release();break;case 9:return true;}
|
107
|
+
return nothing(e);};if(options.keySupport)$keywrap.insertBefore($img);return{watchKeys:watchKeys};}();function px(n){return''+parseInt(n)+'px';};function pct(n){return''+parseInt(n)+'%';};function cssClass(cl){return options.baseClass+'-'+cl;};function getPos(obj)
|
108
|
+
{var pos=$(obj).offset();return[pos.left,pos.top];};function mouseAbs(e)
|
109
|
+
{return[(e.pageX-docOffset[0]),(e.pageY-docOffset[1])];};function myCursor(type)
|
110
|
+
{if(type!=lastcurs)
|
111
|
+
{Tracker.setCursor(type);lastcurs=type;}};function startDragMode(mode,pos)
|
112
|
+
{docOffset=getPos($img);Tracker.setCursor(mode=='move'?mode:mode+'-resize');if(mode=='move')
|
113
|
+
return Tracker.activateHandlers(createMover(pos),doneSelect);var fc=Coords.getFixed();var opp=oppLockCorner(mode);var opc=Coords.getCorner(oppLockCorner(opp));Coords.setPressed(Coords.getCorner(opp));Coords.setCurrent(opc);Tracker.activateHandlers(dragmodeHandler(mode,fc),doneSelect);};function dragmodeHandler(mode,f)
|
114
|
+
{return function(pos){if(!options.aspectRatio)switch(mode)
|
115
|
+
{case'e':pos[1]=f.y2;break;case'w':pos[1]=f.y2;break;case'n':pos[0]=f.x2;break;case's':pos[0]=f.x2;break;}
|
116
|
+
else switch(mode)
|
117
|
+
{case'e':pos[1]=f.y+1;break;case'w':pos[1]=f.y+1;break;case'n':pos[0]=f.x+1;break;case's':pos[0]=f.x+1;break;}
|
118
|
+
Coords.setCurrent(pos);Selection.update();};};function createMover(pos)
|
119
|
+
{var lloc=pos;KeyManager.watchKeys();return function(pos)
|
120
|
+
{Coords.moveOffset([pos[0]-lloc[0],pos[1]-lloc[1]]);lloc=pos;Selection.update();};};function oppLockCorner(ord)
|
121
|
+
{switch(ord)
|
122
|
+
{case'n':return'sw';case's':return'nw';case'e':return'nw';case'w':return'ne';case'ne':return'sw';case'nw':return'se';case'se':return'nw';case'sw':return'ne';};};function createDragger(ord)
|
123
|
+
{return function(e){if(options.disabled)return false;if((ord=='move')&&!options.allowMove)return false;btndown=true;startDragMode(ord,mouseAbs(e));e.stopPropagation();e.preventDefault();return false;};};function presize($obj,w,h)
|
124
|
+
{var nw=$obj.width(),nh=$obj.height();if((nw>w)&&w>0)
|
125
|
+
{nw=w;nh=(w/$obj.width())*$obj.height();}
|
126
|
+
if((nh>h)&&h>0)
|
127
|
+
{nh=h;nw=(h/$obj.height())*$obj.width();}
|
128
|
+
xscale=$obj.width()/nw;yscale=$obj.height()/nh;$obj.width(nw).height(nh);};function unscale(c)
|
129
|
+
{return{x:parseInt(c.x*xscale),y:parseInt(c.y*yscale),x2:parseInt(c.x2*xscale),y2:parseInt(c.y2*yscale),w:parseInt(c.w*xscale),h:parseInt(c.h*yscale)};};function doneSelect(pos)
|
130
|
+
{var c=Coords.getFixed();if(c.w>options.minSelect[0]&&c.h>options.minSelect[1])
|
131
|
+
{Selection.enableHandles();Selection.done();}
|
132
|
+
else
|
133
|
+
{Selection.release();}
|
134
|
+
Tracker.setCursor(options.allowSelect?'crosshair':'default');};function newSelection(e)
|
135
|
+
{if(options.disabled)return false;if(!options.allowSelect)return false;btndown=true;docOffset=getPos($img);Selection.disableHandles();myCursor('crosshair');var pos=mouseAbs(e);Coords.setPressed(pos);Tracker.activateHandlers(selectDrag,doneSelect);KeyManager.watchKeys();Selection.update();e.stopPropagation();e.preventDefault();return false;};function selectDrag(pos)
|
136
|
+
{Coords.setCurrent(pos);Selection.update();};function newTracker()
|
137
|
+
{var trk=$('<div></div>').addClass(cssClass('tracker'));$.browser.msie&&trk.css({opacity:0,backgroundColor:'white'});return trk;};function animateTo(a)
|
138
|
+
{var x1=a[0]/xscale,y1=a[1]/yscale,x2=a[2]/xscale,y2=a[3]/yscale;if(animating)return;var animto=Coords.flipCoords(x1,y1,x2,y2);var c=Coords.getFixed();var animat=initcr=[c.x,c.y,c.x2,c.y2];var interv=options.animationDelay;var x=animat[0];var y=animat[1];var x2=animat[2];var y2=animat[3];var ix1=animto[0]-initcr[0];var iy1=animto[1]-initcr[1];var ix2=animto[2]-initcr[2];var iy2=animto[3]-initcr[3];var pcent=0;var velocity=options.swingSpeed;Selection.animMode(true);var animator=function()
|
139
|
+
{return function()
|
140
|
+
{pcent+=(100-pcent)/velocity;animat[0]=x+((pcent/100)*ix1);animat[1]=y+((pcent/100)*iy1);animat[2]=x2+((pcent/100)*ix2);animat[3]=y2+((pcent/100)*iy2);if(pcent<100)animateStart();else Selection.done();if(pcent>=99.8)pcent=100;setSelectRaw(animat);};}();function animateStart()
|
141
|
+
{window.setTimeout(animator,interv);};animateStart();};function setSelect(rect)
|
142
|
+
{setSelectRaw([rect[0]/xscale,rect[1]/yscale,rect[2]/xscale,rect[3]/yscale]);};function setSelectRaw(l)
|
143
|
+
{Coords.setPressed([l[0],l[1]]);Coords.setCurrent([l[2],l[3]]);Selection.update();};function setOptions(opt)
|
144
|
+
{if(typeof(opt)!='object')opt={};options=$.extend(options,opt);if(typeof(options.onChange)!=='function')
|
145
|
+
options.onChange=function(){};if(typeof(options.onSelect)!=='function')
|
146
|
+
options.onSelect=function(){};};function tellSelect()
|
147
|
+
{return unscale(Coords.getFixed());};function tellScaled()
|
148
|
+
{return Coords.getFixed();};function setOptionsNew(opt)
|
149
|
+
{setOptions(opt);interfaceUpdate();};function disableCrop()
|
150
|
+
{options.disabled=true;Selection.disableHandles();Selection.setCursor('default');Tracker.setCursor('default');};function enableCrop()
|
151
|
+
{options.disabled=false;interfaceUpdate();};function cancelCrop()
|
152
|
+
{Selection.done();Tracker.activateHandlers(null,null);};function destroy()
|
153
|
+
{$div.remove();$origimg.show();};function interfaceUpdate(alt)
|
154
|
+
{options.allowResize?alt?Selection.enableOnly():Selection.enableHandles():Selection.disableHandles();Tracker.setCursor(options.allowSelect?'crosshair':'default');Selection.setCursor(options.allowMove?'move':'default');$div.css('backgroundColor',options.bgColor);if('setSelect'in options){setSelect(opt.setSelect);Selection.done();delete(options.setSelect);}
|
155
|
+
if('trueSize'in options){xscale=options.trueSize[0]/boundx;yscale=options.trueSize[1]/boundy;}
|
156
|
+
xlimit=options.maxSize[0]||0;ylimit=options.maxSize[1]||0;xmin=options.minSize[0]||0;ymin=options.minSize[1]||0;if('outerImage'in options)
|
157
|
+
{$img.attr('src',options.outerImage);delete(options.outerImage);}
|
158
|
+
Selection.refresh();};$hdl_holder.hide();interfaceUpdate(true);var api={animateTo:animateTo,setSelect:setSelect,setOptions:setOptionsNew,tellSelect:tellSelect,tellScaled:tellScaled,disable:disableCrop,enable:enableCrop,cancel:cancelCrop,focus:KeyManager.watchKeys,getBounds:function(){return[boundx*xscale,boundy*yscale];},getWidgetSize:function(){return[boundx,boundy];},release:Selection.release,destroy:destroy};$origimg.data('Jcrop',api);return api;};$.fn.Jcrop=function(options)
|
159
|
+
{function attachWhenDone(from)
|
160
|
+
{var loadsrc=options.useImg||from.src;var img=new Image();img.onload=function(){$.Jcrop(from,options);};img.src=loadsrc;};if(typeof(options)!=='object')options={};this.each(function()
|
161
|
+
{if($(this).data('Jcrop'))
|
162
|
+
{if(options=='api')return $(this).data('Jcrop');else $(this).data('Jcrop').setOptions(options);}
|
163
|
+
else attachWhenDone(this);});return this;};})(jQuery);
|
@@ -0,0 +1,35 @@
|
|
1
|
+
/* Fixes issue here http://code.google.com/p/jcrop/issues/detail?id=1 */
|
2
|
+
.jcrop-holder { text-align: left; }
|
3
|
+
|
4
|
+
.jcrop-vline, .jcrop-hline
|
5
|
+
{
|
6
|
+
font-size: 0;
|
7
|
+
position: absolute;
|
8
|
+
background: white url('Jcrop.gif') top left repeat;
|
9
|
+
}
|
10
|
+
.jcrop-vline { height: 100%; width: 1px !important; }
|
11
|
+
.jcrop-hline { width: 100%; height: 1px !important; }
|
12
|
+
.jcrop-handle {
|
13
|
+
font-size: 1px;
|
14
|
+
width: 7px !important;
|
15
|
+
height: 7px !important;
|
16
|
+
border: 1px #eee solid;
|
17
|
+
background-color: #333;
|
18
|
+
*width: 9px;
|
19
|
+
*height: 9px;
|
20
|
+
}
|
21
|
+
|
22
|
+
.jcrop-tracker { width: 100%; height: 100%; }
|
23
|
+
|
24
|
+
.custom .jcrop-vline,
|
25
|
+
.custom .jcrop-hline
|
26
|
+
{
|
27
|
+
background: yellow;
|
28
|
+
}
|
29
|
+
.custom .jcrop-handle
|
30
|
+
{
|
31
|
+
border-color: black;
|
32
|
+
background-color: #C7BB00;
|
33
|
+
-moz-border-radius: 3px;
|
34
|
+
-webkit-border-radius: 3px;
|
35
|
+
}
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'jcropper'
|
@@ -0,0 +1,9 @@
|
|
1
|
+
namespace :jcropper do
|
2
|
+
desc "install files"
|
3
|
+
task :install => :environment do
|
4
|
+
root = File.join(File.dirname(__FILE__), '..')
|
5
|
+
FileUtils.cp(File.join(root, 'public/images/Jcrop.gif'), File.join(Rails.root, 'public/images/Jcrop.gif'))
|
6
|
+
FileUtils.cp(File.join(root, 'public/javascripts/jquery.Jcrop.min.js'), File.join(Rails.root, 'public/javascripts/jquery.Jcrop.min.js'))
|
7
|
+
FileUtils.cp(File.join(root, 'public/stylesheets/jquery.Jcrop.css'), File.join(Rails.root, 'public/stylesheets/jquery.Jcrop.css'))
|
8
|
+
end
|
9
|
+
end
|
data/test/test_helper.rb
ADDED
data/uninstall.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Uninstall hook code here
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jcropper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Ryan Ziegler
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-05-13 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: ""
|
22
|
+
email: ryan@symbolforce.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- README.rdoc
|
29
|
+
- TODO
|
30
|
+
files:
|
31
|
+
- MIT-LICENSE
|
32
|
+
- README.rdoc
|
33
|
+
- Rakefile
|
34
|
+
- TODO
|
35
|
+
- VERSION
|
36
|
+
- generators/jcropper/USAGE
|
37
|
+
- generators/jcropper/jcropper_generator.rb
|
38
|
+
- generators/jcropper/templates/jcropper_migration.rb.erb
|
39
|
+
- install.rb
|
40
|
+
- lib/jcropper.rb
|
41
|
+
- lib/jcropper/helpers.rb
|
42
|
+
- lib/jcropper/jcropper.rb
|
43
|
+
- lib/paperclip_processors/jcropper.rb
|
44
|
+
- public/images/Jcrop.gif
|
45
|
+
- public/javascripts/jquery.Jcrop.min.js
|
46
|
+
- public/stylesheets/jquery.Jcrop.css
|
47
|
+
- rails/init.rb
|
48
|
+
- tasks/js_cropper.rake
|
49
|
+
- test/jcropper_test.rb
|
50
|
+
- test/test_helper.rb
|
51
|
+
- uninstall.rb
|
52
|
+
has_rdoc: true
|
53
|
+
homepage: http://github.com/syfo/jcropper
|
54
|
+
licenses: []
|
55
|
+
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options:
|
58
|
+
- --charset=UTF-8
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
requirements: []
|
76
|
+
|
77
|
+
rubyforge_project:
|
78
|
+
rubygems_version: 1.3.6
|
79
|
+
signing_key:
|
80
|
+
specification_version: 3
|
81
|
+
summary: gem plugin wrapping jquery
|
82
|
+
test_files:
|
83
|
+
- test/jcropper_test.rb
|
84
|
+
- test/test_helper.rb
|