spud_media 0.9.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Readme.markdown +10 -10
- data/app/assets/images/spud/admin/media/checkers.jpg +0 -0
- data/app/assets/javascripts/spud/admin/media.js +176 -0
- data/app/assets/libs/jcrop/css/Jcrop.gif +0 -0
- data/app/assets/libs/jcrop/css/jquery.Jcrop.css +86 -0
- data/app/assets/libs/jcrop/css/jquery.Jcrop.min.css +28 -0
- data/app/assets/libs/jcrop/js/jquery.Jcrop.js +1695 -0
- data/app/assets/libs/jcrop/js/jquery.Jcrop.min.js +22 -0
- data/app/assets/libs/jcrop/js/jquery.color.js +123 -0
- data/app/assets/libs/jcrop/js/jquery.min.js +4 -0
- data/app/assets/stylesheets/spud/admin/media.css +98 -0
- data/app/controllers/protected_media_controller.rb +2 -2
- data/app/controllers/spud/admin/media_controller.rb +19 -4
- data/app/models/spud_media.rb +115 -80
- data/app/views/layouts/spud/admin/media/detail.html.erb +3 -2
- data/app/views/spud/admin/media/edit.html.erb +50 -0
- data/app/views/spud/admin/media/index.html.erb +4 -1
- data/config/routes.rb +1 -0
- data/db/migrate/20120508132153_add_cropping_to_spud_media.rb +9 -0
- data/lib/spud_media/version.rb +1 -1
- metadata +34 -24
- data/app/assets/javascripts/spud/admin/media/application.js +0 -0
- data/app/assets/stylesheets/spud/admin/media/application.css +0 -3
data/Readme.markdown
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Spud Media
|
2
2
|
|
3
|
-
Spud Media is an engine for managing documents and other media
|
3
|
+
Spud Media is an engine for managing documents and other miscellaneous media files, designed for use with [Spud][1].
|
4
4
|
|
5
5
|
## Installation/Usage
|
6
6
|
|
@@ -20,17 +20,17 @@ Spud Media is an engine for managing documents and other media miscellaneous fil
|
|
20
20
|
|
21
21
|
Spud Photos accepts the following configuration options:
|
22
22
|
|
23
|
-
|
23
|
+
Spud::Media.configure do |config|
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
# s3 storage requires the 'aws-sdk' gem. defaults to filesystem
|
26
|
+
config.paperclip_storage = :s3
|
27
|
+
config.s3_credentials = "#{Rails.root}/config/s3.yml"
|
28
28
|
|
29
29
|
# see below for notes on 'storage_path_protected'
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
config.storage_path = "public/system/spud_media/:id/:style/:basename.:extension"
|
31
|
+
config.storage_path_protected = "public/system/spud_media_protected/:id/:style/:basename.:extension"
|
32
|
+
config.storage_url = "/system/spud_media/:id/:style/:basename.:extension"
|
33
|
+
end
|
34
34
|
|
35
35
|
## File Protection
|
36
36
|
|
@@ -42,7 +42,7 @@ Unprotected files are stored under `/public/system/spud_media` and are accessed
|
|
42
42
|
|
43
43
|
Protected files are moved to `public/system/spud_media_protected`. Note that the public-facing download URL should __not__ reflect the `protected` storage path. Instead the user will hit the same URL as before, but this time their request will hit the `show` action of the `ProtectedMedia` controller.
|
44
44
|
|
45
|
-
|
45
|
+
__It is up to the individual developer to make sure that the protected storage path is not accessible by the public.__ You may choose to protect this folder via server configurations, or you can move the folder out of the document root using `config.storage_path_protected`.
|
46
46
|
|
47
47
|
### Amazon S3
|
48
48
|
|
Binary file
|
@@ -0,0 +1,176 @@
|
|
1
|
+
//= require jcrop/js/jquery.Jcrop
|
2
|
+
//= require_self
|
3
|
+
|
4
|
+
Spud = (typeof(Spud) == 'undefined') ? {} : Spud;
|
5
|
+
Spud.Admin = (typeof(Spud.Admin) == 'undefined') ? {} : Spud.Admin;
|
6
|
+
|
7
|
+
Spud.Admin.Media = new function(){
|
8
|
+
|
9
|
+
var self = this;
|
10
|
+
var cropimage;
|
11
|
+
var cropcontainer;
|
12
|
+
var croptarget;
|
13
|
+
var cropscale;
|
14
|
+
var maxcropscale;
|
15
|
+
var cropscaleincrement;
|
16
|
+
var originalWidth;
|
17
|
+
var originalHeight;
|
18
|
+
var cropartbox;
|
19
|
+
var jcrop;
|
20
|
+
|
21
|
+
this.edit = function(){
|
22
|
+
cropimage = $('#spud_media_cropper_image');
|
23
|
+
// IE8 isn't handling the image load event properly, so...
|
24
|
+
setTimeout(function(){
|
25
|
+
if(cropimage[0].complete){
|
26
|
+
self.initializeEditor();
|
27
|
+
}
|
28
|
+
else{
|
29
|
+
self.edit();
|
30
|
+
}
|
31
|
+
}, 50);
|
32
|
+
};
|
33
|
+
|
34
|
+
this.initializeEditor = function(){
|
35
|
+
|
36
|
+
// cache some selectors
|
37
|
+
cropcontainer = $('#spud_media_cropper_jcrop_container');
|
38
|
+
cropartbox = $('#spud_media_cropper');
|
39
|
+
|
40
|
+
// get the original dimensions before scaling the image down
|
41
|
+
originalWidth = cropimage.width();
|
42
|
+
originalHeight = cropimage.height();
|
43
|
+
|
44
|
+
// the max width is 900px (at least until the UI can handle more than that)
|
45
|
+
if(originalWidth > 900){
|
46
|
+
maxcropscale = Math.floor(900 / originalWidth * 100);
|
47
|
+
}
|
48
|
+
else{
|
49
|
+
maxcropscale = 100;
|
50
|
+
}
|
51
|
+
cropscaleincrement = Math.ceil(3.0 * (maxcropscale / 100));
|
52
|
+
|
53
|
+
// scale down the original if necessary
|
54
|
+
cropscale = parseInt($('#spud_media_crop_s').val());
|
55
|
+
if(cropscale > maxcropscale){
|
56
|
+
$('#spud_media_crop_s').val(maxcropscale);
|
57
|
+
cropscale = maxcropscale;
|
58
|
+
}
|
59
|
+
|
60
|
+
// if this is a new image, width and hight will be null. set some starter values.
|
61
|
+
if(!$('#spud_media_crop_w').val()){
|
62
|
+
$('#spud_media_crop_w').val(originalWidth * (maxcropscale / 100));
|
63
|
+
$('#spud_media_crop_h').val(originalHeight * (maxcropscale / 100));
|
64
|
+
}
|
65
|
+
|
66
|
+
// update height of artbox to match height of scaled image
|
67
|
+
cropartbox.height(originalHeight * (maxcropscale / 100));
|
68
|
+
|
69
|
+
self.resizeAndCenter(cropscale);
|
70
|
+
|
71
|
+
$('body').on('change', '#spud_media_crop_s', self.changedMediaCropScale);
|
72
|
+
$('body').on('click', '#spud_media_cropper_resize_up, #spud_media_cropper_resize_down', self.incrementMediaCropScale);
|
73
|
+
$('body').on('change', '#spud_media_crop_x, #spud_media_crop_y, #spud_media_crop_w, #spud_media_crop_h', self.changedMediaCropDimensions);
|
74
|
+
$('body').on('keypress', 'form input[type=text]', self.preventSubmitOnEnterKey);
|
75
|
+
};
|
76
|
+
|
77
|
+
this.resizeAndCenter = function(percent){
|
78
|
+
|
79
|
+
// destroy the jcrop object if it exists already
|
80
|
+
if(jcrop){
|
81
|
+
jcrop.destroy();
|
82
|
+
}
|
83
|
+
|
84
|
+
// initialize jcrop. snap to pre-existing selection if one exists.
|
85
|
+
var _width = Math.min(900, (originalWidth * (percent / 100)));
|
86
|
+
var _height = originalHeight * (_width / originalWidth);
|
87
|
+
cropimage.Jcrop({
|
88
|
+
boxWidth:_width,
|
89
|
+
boxHeight:_height,
|
90
|
+
onChange:self.updateCropCoordinates,
|
91
|
+
onSelect:self.updateCropCoordinates,
|
92
|
+
setSelect:self.getSelectFields()
|
93
|
+
},
|
94
|
+
function(){
|
95
|
+
jcrop = this;
|
96
|
+
}
|
97
|
+
);
|
98
|
+
|
99
|
+
// using the outer container, center the jcrop object in the artboard
|
100
|
+
var _left = (900 - _width) / 2;
|
101
|
+
var _top = (cropartbox.height() - _height) / 6;
|
102
|
+
cropcontainer.css({
|
103
|
+
left:_left,
|
104
|
+
top:_top
|
105
|
+
});
|
106
|
+
};
|
107
|
+
|
108
|
+
this.updateCropCoordinates = function(c){
|
109
|
+
$('#spud_media_crop_x').val(Math.floor(c.x * (cropscale / 100)));
|
110
|
+
$('#spud_media_crop_y').val(Math.floor(c.y * (cropscale / 100)));
|
111
|
+
$('#spud_media_crop_w').val(Math.floor(c.w * (cropscale / 100)));
|
112
|
+
$('#spud_media_crop_h').val(Math.floor(c.h * (cropscale / 100)));
|
113
|
+
};
|
114
|
+
|
115
|
+
this.changedMediaCropScale = function(e){
|
116
|
+
var val = $(this).val();
|
117
|
+
var percent = parseInt(val);
|
118
|
+
if(!percent || percent > maxcropscale){
|
119
|
+
$(this).val(maxcropscale);
|
120
|
+
}
|
121
|
+
else{
|
122
|
+
$(this).val(percent);
|
123
|
+
cropscale = percent;
|
124
|
+
self.resizeAndCenter(percent);
|
125
|
+
}
|
126
|
+
};
|
127
|
+
|
128
|
+
this.incrementMediaCropScale = function(e){
|
129
|
+
var id = $(this).attr('id');
|
130
|
+
if(id == 'spud_media_cropper_resize_up'){
|
131
|
+
cropscale = Math.min(maxcropscale, cropscale+cropscaleincrement);
|
132
|
+
}
|
133
|
+
else{
|
134
|
+
cropscale = Math.max(0, cropscale-cropscaleincrement);
|
135
|
+
}
|
136
|
+
$('#spud_media_crop_s').val(cropscale);
|
137
|
+
self.resizeAndCenter(cropscale);
|
138
|
+
return false;
|
139
|
+
}
|
140
|
+
|
141
|
+
this.changedMediaCropDimensions = function(e){
|
142
|
+
var selection = self.getSelectFields();
|
143
|
+
if(selection){
|
144
|
+
jcrop.setSelect(selection);
|
145
|
+
}
|
146
|
+
};
|
147
|
+
|
148
|
+
this.getSelectFields = function(){
|
149
|
+
var x = parseInt($('#spud_media_crop_x').val());
|
150
|
+
var y = parseInt($('#spud_media_crop_y').val());
|
151
|
+
var w = parseInt($('#spud_media_crop_w').val());
|
152
|
+
var h = parseInt($('#spud_media_crop_h').val());
|
153
|
+
var x2 = x + w;
|
154
|
+
var y2 = y + h;
|
155
|
+
if(isNaN(x) || isNaN(w) || isNaN(x2) || isNaN(y2)){
|
156
|
+
return false;
|
157
|
+
}
|
158
|
+
else{
|
159
|
+
return [x * (100 / cropscale), y * (100 / cropscale), x2 * (100 / cropscale), y2 * (100 / cropscale)];
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
this.preventSubmitOnEnterKey = function(e){
|
164
|
+
if(e.keyCode == 13) {
|
165
|
+
e.preventDefault();
|
166
|
+
// need to prevent the form submit, but still fire the value change events
|
167
|
+
if($(this).attr('id') == 'spud_media_crop_s'){
|
168
|
+
self.changedMediaCropScale.apply(this, [e]);
|
169
|
+
}
|
170
|
+
else{
|
171
|
+
self.changedMediaCropDimensions(e);
|
172
|
+
}
|
173
|
+
return false;
|
174
|
+
}
|
175
|
+
};
|
176
|
+
};
|
Binary file
|
@@ -0,0 +1,86 @@
|
|
1
|
+
/* jquery.Jcrop.css v0.9.10 - MIT License */
|
2
|
+
|
3
|
+
/*
|
4
|
+
The outer-most container in a typical Jcrop instance
|
5
|
+
If you are having difficulty with formatting related to styles
|
6
|
+
on a parent element, place any fixes here or in a like selector
|
7
|
+
|
8
|
+
You can also style this element if you want to add a border, etc
|
9
|
+
A better method for styling can be seen below with .jcrop-light
|
10
|
+
(Add a class to the holder and style elements for that extended class)
|
11
|
+
*/
|
12
|
+
.jcrop-holder {
|
13
|
+
direction: ltr;
|
14
|
+
text-align: left;
|
15
|
+
}
|
16
|
+
|
17
|
+
/* These styles define the border lines */
|
18
|
+
.jcrop-vline,.jcrop-hline{background:#FFF url(/assets/jcrop/css/Jcrop.gif) top left repeat;font-size:0;position:absolute;}
|
19
|
+
.jcrop-vline{height:100%;width:1px!important;}
|
20
|
+
.jcrop-hline{height:1px!important;width:100%;}
|
21
|
+
.jcrop-vline.right{right:0;}
|
22
|
+
.jcrop-hline.bottom{bottom:0;}
|
23
|
+
|
24
|
+
/* Handle style - size is set by Jcrop handleSize option (currently) */
|
25
|
+
.jcrop-handle{background-color:#333;border:1px #eee solid;font-size:1px;}
|
26
|
+
|
27
|
+
/* This style is used for invisible click targets */
|
28
|
+
.jcrop-tracker
|
29
|
+
{
|
30
|
+
height: 100%;
|
31
|
+
width: 100%;
|
32
|
+
-webkit-tap-highlight-color: transparent; /* "turn off" link highlight */
|
33
|
+
-webkit-touch-callout: none; /* disable callout, image save panel */
|
34
|
+
-webkit-user-select: none; /* disable cut copy paste */
|
35
|
+
}
|
36
|
+
|
37
|
+
/* Positioning of handles and drag bars */
|
38
|
+
.jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0;}
|
39
|
+
.jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px;}
|
40
|
+
.jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%;}
|
41
|
+
.jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%;}
|
42
|
+
.jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0;}
|
43
|
+
.jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0;}
|
44
|
+
.jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0;}
|
45
|
+
.jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px;}
|
46
|
+
.jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%;}
|
47
|
+
.jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px;}
|
48
|
+
.jcrop-dragbar.ord-n{margin-top:-4px;}
|
49
|
+
.jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px;}
|
50
|
+
.jcrop-dragbar.ord-e{margin-right:-4px;right:0;}
|
51
|
+
.jcrop-dragbar.ord-w{margin-left:-4px;}
|
52
|
+
|
53
|
+
/* The "jcrop-light" class/extension */
|
54
|
+
.jcrop-light .jcrop-vline,.jcrop-light .jcrop-hline
|
55
|
+
{
|
56
|
+
background:#FFF;
|
57
|
+
filter:Alpha(opacity=70)!important;
|
58
|
+
opacity:.70!important;
|
59
|
+
}
|
60
|
+
.jcrop-light .jcrop-handle
|
61
|
+
{
|
62
|
+
-moz-border-radius:3px;
|
63
|
+
-webkit-border-radius:3px;
|
64
|
+
background-color:#000;
|
65
|
+
border-color:#FFF;
|
66
|
+
border-radius:3px;
|
67
|
+
}
|
68
|
+
|
69
|
+
/* The "jcrop-dark" class/extension */
|
70
|
+
.jcrop-dark .jcrop-vline,.jcrop-dark .jcrop-hline
|
71
|
+
{
|
72
|
+
background:#000;
|
73
|
+
filter:Alpha(opacity=70)!important;
|
74
|
+
opacity:.7!important;
|
75
|
+
}
|
76
|
+
.jcrop-dark .jcrop-handle
|
77
|
+
{
|
78
|
+
-moz-border-radius:3px;
|
79
|
+
-webkit-border-radius:3px;
|
80
|
+
background-color:#FFF;
|
81
|
+
border-color:#000;
|
82
|
+
border-radius:3px;
|
83
|
+
}
|
84
|
+
|
85
|
+
/* Fix for twitter bootstrap et al. */
|
86
|
+
.jcrop-holder img,img.jcrop-preview{ max-width: none; }
|
@@ -0,0 +1,28 @@
|
|
1
|
+
/* jquery.Jcrop.min.css v0.9.10 (build:20120429) */
|
2
|
+
.jcrop-holder{direction:ltr;text-align:left;}
|
3
|
+
.jcrop-vline,.jcrop-hline{background:#FFF url(/assets/jcrop/css/Jcrop.gif) top left repeat;font-size:0;position:absolute;}
|
4
|
+
.jcrop-vline{height:100%;width:1px!important;}
|
5
|
+
.jcrop-hline{height:1px!important;width:100%;}
|
6
|
+
.jcrop-vline.right{right:0;}
|
7
|
+
.jcrop-hline.bottom{bottom:0;}
|
8
|
+
.jcrop-handle{background-color:#333;border:1px #eee solid;font-size:1px;}
|
9
|
+
.jcrop-tracker{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-webkit-user-select:none;height:100%;width:100%;}
|
10
|
+
.jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0;}
|
11
|
+
.jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px;}
|
12
|
+
.jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%;}
|
13
|
+
.jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%;}
|
14
|
+
.jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0;}
|
15
|
+
.jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0;}
|
16
|
+
.jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0;}
|
17
|
+
.jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px;}
|
18
|
+
.jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%;}
|
19
|
+
.jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px;}
|
20
|
+
.jcrop-dragbar.ord-n{margin-top:-4px;}
|
21
|
+
.jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px;}
|
22
|
+
.jcrop-dragbar.ord-e{margin-right:-4px;right:0;}
|
23
|
+
.jcrop-dragbar.ord-w{margin-left:-4px;}
|
24
|
+
.jcrop-light .jcrop-vline,.jcrop-light .jcrop-hline{background:#FFF;filter:Alpha(opacity=70)!important;opacity:.70!important;}
|
25
|
+
.jcrop-light .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#000;border-color:#FFF;border-radius:3px;}
|
26
|
+
.jcrop-dark .jcrop-vline,.jcrop-dark .jcrop-hline{background:#000;filter:Alpha(opacity=70)!important;opacity:.7!important;}
|
27
|
+
.jcrop-dark .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#FFF;border-color:#000;border-radius:3px;}
|
28
|
+
.jcrop-holder img,img.jcrop-preview{max-width:none;}
|