spud_media 0.9.0 → 0.9.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/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;}
|