tb_media 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +28 -0
- data/Readme.markdown +73 -0
- data/app/assets/images/spud/admin/files_thumbs/dat_thumb.png +0 -0
- data/app/assets/images/spud/admin/files_thumbs/doc_thumb.png +0 -0
- data/app/assets/images/spud/admin/files_thumbs/jpg_thumb.png +0 -0
- data/app/assets/images/spud/admin/files_thumbs/mp3_thumb.png +0 -0
- data/app/assets/images/spud/admin/files_thumbs/pdf_thumb.png +0 -0
- data/app/assets/images/spud/admin/files_thumbs/png_thumb.png +0 -0
- data/app/assets/images/spud/admin/files_thumbs/ppt_thumb.png +0 -0
- data/app/assets/images/spud/admin/files_thumbs/txt_thumb.png +0 -0
- data/app/assets/images/spud/admin/files_thumbs/xls_thumb.png +0 -0
- data/app/assets/images/spud/admin/files_thumbs/zip_thumb.png +0 -0
- data/app/assets/images/spud/admin/media/checkers.jpg +0 -0
- data/app/assets/images/spud/admin/media_thumb.png +0 -0
- data/app/assets/images/spud/admin/media_thumb@2x.png +0 -0
- data/app/assets/images/spud/admin/media_tiny.png +0 -0
- data/app/assets/javascripts/spud/admin/media/application.js +175 -0
- data/app/assets/javascripts/spud/admin/media/picker.js +219 -0
- data/app/assets/javascripts/spud/admin/media/plugin.js +99 -0
- data/app/assets/libs/jcrop/css/Jcrop.gif +0 -0
- data/app/assets/libs/jcrop/css/jquery.Jcrop.css +165 -0
- data/app/assets/libs/jcrop/css/jquery.Jcrop.min.css +29 -0
- data/app/assets/libs/jcrop/js/jquery.Jcrop.js +1694 -0
- data/app/assets/libs/jcrop/js/jquery.Jcrop.min.js +22 -0
- data/app/assets/libs/jcrop/js/jquery.color.js +661 -0
- data/app/assets/libs/jcrop/js/jquery.min.js +4 -0
- data/app/assets/libs/tiny_mce/plugins/spud_media/blank.htm +12 -0
- data/app/assets/libs/tiny_mce/plugins/spud_media/css/template.css +23 -0
- data/app/assets/libs/tiny_mce/plugins/spud_media/editor_plugin.js +1 -0
- data/app/assets/libs/tiny_mce/plugins/spud_media/editor_plugin_src.js +159 -0
- data/app/assets/libs/tiny_mce/plugins/spud_media/js/template.js +106 -0
- data/app/assets/libs/tiny_mce/plugins/spud_media/langs/en_dlg.js +1 -0
- data/app/assets/libs/tiny_mce/plugins/spud_media/template.htm +31 -0
- data/app/assets/stylesheets/spud/admin/media/application.css +103 -0
- data/app/assets/stylesheets/spud/admin/media/plugin.css +154 -0
- data/app/controllers/protected_media_controller.rb +26 -0
- data/app/controllers/spud/admin/media_controller.rb +73 -0
- data/app/controllers/spud/admin/media_picker_controller.rb +28 -0
- data/app/helpers/protected_media_helper.rb +3 -0
- data/app/helpers/spud/admin/users_helper.rb +2 -0
- data/app/helpers/spud/user_sessions_helper.rb +2 -0
- data/app/models/spud_media.rb +154 -0
- data/app/views/spud/admin/media/edit.html.erb +50 -0
- data/app/views/spud/admin/media/index.html.erb +37 -0
- data/app/views/spud/admin/media/new.html.erb +26 -0
- data/app/views/spud/admin/media_picker/_media.html.erb +19 -0
- data/app/views/spud/admin/media_picker/create.html.erb +1 -0
- data/app/views/spud/admin/media_picker/create.js.erb +1 -0
- data/app/views/spud/admin/media_picker/index.html.erb +103 -0
- data/config/routes.rb +13 -0
- data/db/migrate/20120101194256_create_spud_media.rb +11 -0
- data/db/migrate/20120501203325_add_protected_to_spud_media.rb +6 -0
- data/db/migrate/20120508132153_add_cropping_to_spud_media.rb +9 -0
- data/lib/spud_media/configuration.rb +11 -0
- data/lib/spud_media/engine.rb +16 -0
- data/lib/spud_media/version.rb +5 -0
- data/lib/tasks/spud_media_tasks.rake +15 -0
- data/lib/tb_media.rb +6 -0
- metadata +257 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NTZjMTJmNTgwYzNkZWM0OWVmMzAwMGU5NGYwM2IxNjk2ZWIzYTRlOA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
N2Q1NTRmNjhmYTVkN2I3MWQ4M2RhNmEzZGY5MTNjNzM2NmRhYWE3YQ==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
OGNjYTE0MmU1OTU1NzRiZDMwY2IxZWUyZGJhYTliZDk5Y2ZhYmVjMzUwZTdl
|
10
|
+
YmRiNzFhMDhlM2I4MjgxMGVmNDVjMWNhNzEzZmY4ZTE0YmI5YmExMjUzNTZk
|
11
|
+
MTE2ZjcwOGRlOTFlNDVhYTU3ZDBhYmQ1ZjY1ZGEzNDc5ZmIzNjg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
OGNhOTM1ZWNmYzgzM2RhOTNkZjRmOGVjMTVhMjM4MTI1ZmU3YTk2MmNkMWIx
|
14
|
+
YmNmMmRmOTA3YjAzYWIxYjAxYzQwZTQxNzdiODJiODEzMjYxNGNkOGYwMWY3
|
15
|
+
YWJhYjMzMjM4N2I3YWMyOTdiYjc0ZDZiODg0MTU4ZTZjOTU0MDQ=
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 YOURNAME
|
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/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'SpudMedia'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
24
|
+
load 'rails/tasks/engine.rake'
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
28
|
+
require 'rake'
|
data/Readme.markdown
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# Spud Media
|
2
|
+
|
3
|
+
Spud Media is an engine for managing documents and other miscellaneous media files, designed for use with [Spud][1].
|
4
|
+
|
5
|
+
## Installation/Usage
|
6
|
+
|
7
|
+
1. In your Gemfile add the following
|
8
|
+
|
9
|
+
gem 'spud_media'
|
10
|
+
|
11
|
+
2. Run bundle install
|
12
|
+
3. Copy in database migrations to your new rails project
|
13
|
+
|
14
|
+
bundle exec rake railties:install:migrations
|
15
|
+
rake db:migrate
|
16
|
+
|
17
|
+
4. Run a rails server instance and point your browser to /spud/admin
|
18
|
+
|
19
|
+
## Configuration
|
20
|
+
|
21
|
+
Spud Photos accepts the following configuration options:
|
22
|
+
|
23
|
+
Spud::Media.configure do |config|
|
24
|
+
|
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
|
+
|
29
|
+
# see below for notes on 'storage_path_protected'
|
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
|
+
|
35
|
+
## File Protection
|
36
|
+
|
37
|
+
Spud Media allows for individual files to be marked as protected. How this is actually implemented depends on whether you are using the local file system or Amazon S3 for file storage.
|
38
|
+
|
39
|
+
### Filesystem
|
40
|
+
|
41
|
+
Unprotected files are stored under `/public/system/spud_media` and are accessed directly by the web server. No further configuration is required, though you may customize the storage location if desired using `config.storage_path`.
|
42
|
+
|
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
|
+
|
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
|
+
|
47
|
+
### Amazon S3
|
48
|
+
|
49
|
+
Files marked as unprotected will be uploaded to Amazon using the `public_read` ACL. These files are accessed directly - ie, calling `@media.attachment_url` will link directly to Amazon.
|
50
|
+
|
51
|
+
Files marked as protected are uploaded using the `private` ACL. In this case, calling `@media.attachment_url` will return a local URL that hits the show action of our `ProtectedMedia` controller. Once we have verified the user is logged in we generate a secure URL and redirect the user to it. The generated URL is good for 10 minutes.
|
52
|
+
|
53
|
+
[1]:https://github.com/davydotcom/spud_core_admin
|
54
|
+
|
55
|
+
Testing
|
56
|
+
-----------------
|
57
|
+
|
58
|
+
Spud uses RSpec for testing. Get the tests running with a few short commands:
|
59
|
+
|
60
|
+
1. Create and migrate the databases:
|
61
|
+
|
62
|
+
rake db:create
|
63
|
+
rake db:migrate
|
64
|
+
|
65
|
+
2. Load the schema in to the test database:
|
66
|
+
|
67
|
+
rake app:db:test:prepare
|
68
|
+
|
69
|
+
3. Run the tests with RSpec
|
70
|
+
|
71
|
+
rspec spec
|
72
|
+
|
73
|
+
After the tests have completed the current code coverage stats is available by opening ```/coverage/index.html``` in a browser.
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,175 @@
|
|
1
|
+
//= require jcrop/js/jquery.Jcrop
|
2
|
+
//= require spud/admin/media/plugin
|
3
|
+
//= require spud/admin/media/picker
|
4
|
+
//= require_self
|
5
|
+
|
6
|
+
spud.admin.media = new function(){
|
7
|
+
|
8
|
+
var self = this;
|
9
|
+
var cropimage;
|
10
|
+
var cropcontainer;
|
11
|
+
var croptarget;
|
12
|
+
var cropscale;
|
13
|
+
var maxcropscale;
|
14
|
+
var cropscaleincrement;
|
15
|
+
var originalWidth;
|
16
|
+
var originalHeight;
|
17
|
+
var cropartbox;
|
18
|
+
var jcrop;
|
19
|
+
|
20
|
+
this.edit = function(){
|
21
|
+
cropimage = $('#spud_media_cropper_image');
|
22
|
+
// IE8 isn't handling the image load event properly, so...
|
23
|
+
setTimeout(function(){
|
24
|
+
if(cropimage[0].complete){
|
25
|
+
self.initializeEditor();
|
26
|
+
}
|
27
|
+
else{
|
28
|
+
self.edit();
|
29
|
+
}
|
30
|
+
}, 50);
|
31
|
+
};
|
32
|
+
|
33
|
+
this.initializeEditor = function(){
|
34
|
+
|
35
|
+
// cache some selectors
|
36
|
+
cropcontainer = $('#spud_media_cropper_jcrop_container');
|
37
|
+
cropartbox = $('#spud_media_cropper');
|
38
|
+
|
39
|
+
// get the original dimensions before scaling the image down
|
40
|
+
originalWidth = cropimage.width();
|
41
|
+
originalHeight = cropimage.height();
|
42
|
+
|
43
|
+
// the max width is 900px (at least until the UI can handle more than that)
|
44
|
+
if(originalWidth > 900){
|
45
|
+
maxcropscale = Math.floor(900 / originalWidth * 100);
|
46
|
+
}
|
47
|
+
else{
|
48
|
+
maxcropscale = 100;
|
49
|
+
}
|
50
|
+
cropscaleincrement = Math.ceil(3.0 * (maxcropscale / 100));
|
51
|
+
|
52
|
+
// scale down the original if necessary
|
53
|
+
cropscale = parseInt($('#spud_media_crop_s').val(), 10);
|
54
|
+
if(cropscale > maxcropscale){
|
55
|
+
$('#spud_media_crop_s').val(maxcropscale);
|
56
|
+
cropscale = maxcropscale;
|
57
|
+
}
|
58
|
+
|
59
|
+
// if this is a new image, width and hight will be null. set some starter values.
|
60
|
+
if(!$('#spud_media_crop_w').val()){
|
61
|
+
$('#spud_media_crop_w').val(originalWidth * (maxcropscale / 100));
|
62
|
+
$('#spud_media_crop_h').val(originalHeight * (maxcropscale / 100));
|
63
|
+
}
|
64
|
+
|
65
|
+
// update height of artbox to match height of scaled image
|
66
|
+
cropartbox.height(originalHeight * (maxcropscale / 100));
|
67
|
+
|
68
|
+
self.resizeAndCenter(cropscale);
|
69
|
+
|
70
|
+
$('body').on('change', '#spud_media_crop_s', self.changedMediaCropScale);
|
71
|
+
$('body').on('click', '#spud_media_cropper_resize_up, #spud_media_cropper_resize_down', self.incrementMediaCropScale);
|
72
|
+
$('body').on('change', '#spud_media_crop_x, #spud_media_crop_y, #spud_media_crop_w, #spud_media_crop_h', self.changedMediaCropDimensions);
|
73
|
+
$('body').on('keypress', 'form input[type=text]', self.preventSubmitOnEnterKey);
|
74
|
+
};
|
75
|
+
|
76
|
+
this.resizeAndCenter = function(percent){
|
77
|
+
|
78
|
+
// destroy the jcrop object if it exists already
|
79
|
+
if(jcrop){
|
80
|
+
jcrop.destroy();
|
81
|
+
}
|
82
|
+
|
83
|
+
// initialize jcrop. snap to pre-existing selection if one exists.
|
84
|
+
var _width = Math.min(900, (originalWidth * (percent / 100)));
|
85
|
+
var _height = originalHeight * (_width / originalWidth);
|
86
|
+
cropimage.Jcrop({
|
87
|
+
boxWidth:_width,
|
88
|
+
boxHeight:_height,
|
89
|
+
onChange:self.updateCropCoordinates,
|
90
|
+
onSelect:self.updateCropCoordinates,
|
91
|
+
setSelect:self.getSelectFields()
|
92
|
+
},
|
93
|
+
function(){
|
94
|
+
jcrop = this;
|
95
|
+
}
|
96
|
+
);
|
97
|
+
|
98
|
+
// using the outer container, center the jcrop object in the artboard
|
99
|
+
var _left = (900 - _width) / 2;
|
100
|
+
var _top = (cropartbox.height() - _height) / 6;
|
101
|
+
cropcontainer.css({
|
102
|
+
left:_left,
|
103
|
+
top:_top
|
104
|
+
});
|
105
|
+
};
|
106
|
+
|
107
|
+
this.updateCropCoordinates = function(c){
|
108
|
+
$('#spud_media_crop_x').val(Math.floor(c.x * (cropscale / 100)));
|
109
|
+
$('#spud_media_crop_y').val(Math.floor(c.y * (cropscale / 100)));
|
110
|
+
$('#spud_media_crop_w').val(Math.floor(c.w * (cropscale / 100)));
|
111
|
+
$('#spud_media_crop_h').val(Math.floor(c.h * (cropscale / 100)));
|
112
|
+
};
|
113
|
+
|
114
|
+
this.changedMediaCropScale = function(e){
|
115
|
+
var val = $(this).val();
|
116
|
+
var percent = parseInt(val, 10);
|
117
|
+
if(!percent || percent > maxcropscale){
|
118
|
+
$(this).val(maxcropscale);
|
119
|
+
}
|
120
|
+
else{
|
121
|
+
$(this).val(percent);
|
122
|
+
cropscale = percent;
|
123
|
+
self.resizeAndCenter(percent);
|
124
|
+
}
|
125
|
+
};
|
126
|
+
|
127
|
+
this.incrementMediaCropScale = function(e){
|
128
|
+
var id = $(this).attr('id');
|
129
|
+
if(id == 'spud_media_cropper_resize_up'){
|
130
|
+
cropscale = Math.min(maxcropscale, cropscale+cropscaleincrement);
|
131
|
+
}
|
132
|
+
else{
|
133
|
+
cropscale = Math.max(0, cropscale-cropscaleincrement);
|
134
|
+
}
|
135
|
+
$('#spud_media_crop_s').val(cropscale);
|
136
|
+
self.resizeAndCenter(cropscale);
|
137
|
+
return false;
|
138
|
+
};
|
139
|
+
|
140
|
+
this.changedMediaCropDimensions = function(e){
|
141
|
+
var selection = self.getSelectFields();
|
142
|
+
if(selection){
|
143
|
+
jcrop.setSelect(selection);
|
144
|
+
}
|
145
|
+
};
|
146
|
+
|
147
|
+
this.getSelectFields = function(){
|
148
|
+
var x = parseInt($('#spud_media_crop_x').val(), 10);
|
149
|
+
var y = parseInt($('#spud_media_crop_y').val(), 10);
|
150
|
+
var w = parseInt($('#spud_media_crop_w').val(), 10);
|
151
|
+
var h = parseInt($('#spud_media_crop_h').val(), 10);
|
152
|
+
var x2 = x + w;
|
153
|
+
var y2 = y + h;
|
154
|
+
if(isNaN(x) || isNaN(w) || isNaN(x2) || isNaN(y2)){
|
155
|
+
return false;
|
156
|
+
}
|
157
|
+
else{
|
158
|
+
return [x * (100 / cropscale), y * (100 / cropscale), x2 * (100 / cropscale), y2 * (100 / cropscale)];
|
159
|
+
}
|
160
|
+
};
|
161
|
+
|
162
|
+
this.preventSubmitOnEnterKey = function(e){
|
163
|
+
if(e.keyCode == 13) {
|
164
|
+
e.preventDefault();
|
165
|
+
// need to prevent the form submit, but still fire the value change events
|
166
|
+
if($(this).attr('id') == 'spud_media_crop_s'){
|
167
|
+
self.changedMediaCropScale.apply(this, [e]);
|
168
|
+
}
|
169
|
+
else{
|
170
|
+
self.changedMediaCropDimensions(e);
|
171
|
+
}
|
172
|
+
return false;
|
173
|
+
}
|
174
|
+
};
|
175
|
+
};
|
@@ -0,0 +1,219 @@
|
|
1
|
+
spud.admin.mediapicker = new function(){
|
2
|
+
|
3
|
+
var self = this;
|
4
|
+
var supportsHtml5Upload = false;
|
5
|
+
var selectedFile = {};
|
6
|
+
|
7
|
+
self.init = function(){
|
8
|
+
if(typeof(FormData) != 'undefined'){
|
9
|
+
supportsHtml5Upload = true;
|
10
|
+
}
|
11
|
+
$('.spud_media_picker_tab').on('click', self.clickedTab);
|
12
|
+
$('.spud_media_picker_upload_form').on('submit', self.submittedUpload);
|
13
|
+
$('.spud_media_picker_list').on('click', '.spud_media_picker_item', self.clickedListItem);
|
14
|
+
$('.spud_media_picker_button_cancel').on('click', self.clickedCancel);
|
15
|
+
$('.spud_media_picker_button_use_selected').on('click', self.clickedUseSelected);
|
16
|
+
$('.spud_media_picker_button_insert').on('click', self.clickedInsert);
|
17
|
+
$('.spud_media_picker_item').first().click();
|
18
|
+
$('.spud_media_picker_tabs a').first().click();
|
19
|
+
$('.spud_media_picker_tab_advanced').on('spud_media_picker_tab_activated', self.activatedAdvancedTab);
|
20
|
+
$('.spud_media_picker_option_dimensions').on('blur', 'input', self.dimensionsChanged);
|
21
|
+
$('.spud_media_picker_option').on('keyup', 'input[type=text]', self.pickerOptionKeyDown);
|
22
|
+
};
|
23
|
+
|
24
|
+
self.clickedTab = function(e){
|
25
|
+
e.preventDefault();
|
26
|
+
self.goToTab($(this).attr('href'));
|
27
|
+
};
|
28
|
+
|
29
|
+
self.goToTab = function(tabName){
|
30
|
+
$('.spud_media_picker_tab_active').removeClass('spud_media_picker_tab_active');
|
31
|
+
$('a[href="'+tabName+'"]').addClass('spud_media_picker_tab_active');
|
32
|
+
var selector = tabName.replace('#', '.');
|
33
|
+
$('.spud_media_picker_tab_body').hide();
|
34
|
+
$(selector).show();
|
35
|
+
$(selector).trigger('spud_media_picker_tab_activated');
|
36
|
+
};
|
37
|
+
|
38
|
+
self.clickedListItem = function(){
|
39
|
+
$('.spud_media_picker_item_selected').removeClass('spud_media_picker_item_selected');
|
40
|
+
var element = $(this);
|
41
|
+
element.addClass('spud_media_picker_item_selected');
|
42
|
+
$('.spud_media_picker_details_thumb').attr('src', element.find('img').attr('src'));
|
43
|
+
$('.spud_media_picker_details_name').text(element.attr('data-name'));
|
44
|
+
$('.spud_media_picker_details_size').text(element.attr('data-size'));
|
45
|
+
$('.spud_media_picker_details_lastmod').text(element.attr('data-lastmod'));
|
46
|
+
$('.spud_media_picker_details_protected').text(element.attr('data-protected'));
|
47
|
+
$('.spud_media_picker_details').show();
|
48
|
+
};
|
49
|
+
|
50
|
+
self.clickedCancel = function(e){
|
51
|
+
e.preventDefault();
|
52
|
+
tinyMCEPopup.close();
|
53
|
+
};
|
54
|
+
|
55
|
+
self.clickedUseSelected = function(e){
|
56
|
+
e.preventDefault();
|
57
|
+
self.goToTab('#spud_media_picker_tab_advanced');
|
58
|
+
};
|
59
|
+
|
60
|
+
self.submittedUpload = function(e){
|
61
|
+
if(!$('#spud_media_attachment').val()){
|
62
|
+
window.alert("Please select a file.");
|
63
|
+
return false;
|
64
|
+
}
|
65
|
+
|
66
|
+
if(supportsHtml5Upload){
|
67
|
+
e.preventDefault();
|
68
|
+
|
69
|
+
// create html5 form object
|
70
|
+
var fd = new FormData();
|
71
|
+
var form = $(this);
|
72
|
+
var file = form.find('#spud_media_attachment')[0].files[0];
|
73
|
+
fd.append('_method', form.find('[name=_method]').val());
|
74
|
+
fd.append('authenticity_token', form.find('[name=authenticity_token]').val());
|
75
|
+
fd.append('spud_media[attachment]', file);
|
76
|
+
|
77
|
+
// upload via xhr
|
78
|
+
var xhr = new XMLHttpRequest();
|
79
|
+
xhr.upload.addEventListener('progress', self.onFileUploadProgress);
|
80
|
+
xhr.addEventListener('load', self.onFileUploadComplete);
|
81
|
+
xhr.addEventListener('error', self.onFileUploadError);
|
82
|
+
xhr.addEventListener('abort', self.onFileUploadAbort);
|
83
|
+
xhr.open('POST', form.attr('action'));
|
84
|
+
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
85
|
+
xhr.send(fd);
|
86
|
+
|
87
|
+
$('.spud_media_picker_upload_progress').show();
|
88
|
+
}
|
89
|
+
};
|
90
|
+
|
91
|
+
this.onFileUploadProgress = function(e){
|
92
|
+
var percent = Math.round(e.loaded * 100 / e.total);
|
93
|
+
var progress = $('.spud_media_picker_upload_progress');
|
94
|
+
progress.find('.bar').css({width: percent + '%'});
|
95
|
+
if(percent == 100){
|
96
|
+
progress.addClass('progress-success');
|
97
|
+
}
|
98
|
+
};
|
99
|
+
|
100
|
+
this.onFileUploadComplete = function(e){
|
101
|
+
var html = e.target.response;
|
102
|
+
self.onLegacyUploadComplete(html);
|
103
|
+
};
|
104
|
+
|
105
|
+
this.onFileUploadError = function(e){
|
106
|
+
window.alert('Whoops! Something has gone wrong.');
|
107
|
+
self.resetUploadForm();
|
108
|
+
};
|
109
|
+
|
110
|
+
this.onFileUploadAbort = function(e){
|
111
|
+
self.resetUploadForm();
|
112
|
+
};
|
113
|
+
|
114
|
+
// Non-html5 upload
|
115
|
+
this.onLegacyUploadComplete = function(html){
|
116
|
+
$('.spud_media_picker_list').prepend(html);
|
117
|
+
$('.spud_media_picker_item').first().click();
|
118
|
+
self.goToTab('#spud_media_picker_tab_choose');
|
119
|
+
self.resetUplaodForm();
|
120
|
+
};
|
121
|
+
|
122
|
+
this.resetUploadForm = function(){
|
123
|
+
// reset twitter bootstrap "loading" button state
|
124
|
+
$('.spud_media_picker_tab_upload_submit').button('reset');
|
125
|
+
$('#spud_media_attachment').val('');
|
126
|
+
$('.spud_media_picker_upload_progress').hide();
|
127
|
+
$('.spud_media_picker_upload_progress .bar').css({width:0});
|
128
|
+
};
|
129
|
+
|
130
|
+
this.activatedAdvancedTab = function(){
|
131
|
+
var selected = $('.spud_media_picker_item_selected');
|
132
|
+
selectedFile = {
|
133
|
+
id: selected.attr('data-id'),
|
134
|
+
type: selected.attr('data-type'),
|
135
|
+
url: selected.attr('data-url'),
|
136
|
+
name: selected.attr('data-name'),
|
137
|
+
size: selected.attr('data-size'),
|
138
|
+
lastmod: selected.attr('data-lastmod'),
|
139
|
+
isprotected: selected.attr('data-protected')
|
140
|
+
};
|
141
|
+
$('input[name="spud_media_picker_option_selected_file"]').val(selectedFile.name);
|
142
|
+
$('input[name="spud_media_picker_option_type"]').val(selectedFile.type == 'img' ? 'Image' : 'File');
|
143
|
+
if(selectedFile.type == 'img'){
|
144
|
+
$('.spud_media_picker_option_target').hide();
|
145
|
+
$('.spud_media_picker_option_text').hide();
|
146
|
+
$('.spud_media_picker_option_float').show();
|
147
|
+
$('.spud_media_picker_option_title').show();
|
148
|
+
$('.spud_media_picker_option_dimensions').show();
|
149
|
+
self.getOriginalImageDimensions(selectedFile.url);
|
150
|
+
}
|
151
|
+
else{
|
152
|
+
$('.spud_media_picker_option_target').show();
|
153
|
+
$('.spud_media_picker_option_text').show();
|
154
|
+
$('.spud_media_picker_option_text input').val(tinyMCEPopup.editor.selection.getContent());
|
155
|
+
$('.spud_media_picker_option_float').hide();
|
156
|
+
$('.spud_media_picker_option_title').hide();
|
157
|
+
$('.spud_media_picker_option_dimensions').hide();
|
158
|
+
}
|
159
|
+
};
|
160
|
+
|
161
|
+
var _originalWidth, _originalHeight;
|
162
|
+
self.getOriginalImageDimensions = function(url){
|
163
|
+
var img = new Image();
|
164
|
+
img.onload = function(){
|
165
|
+
_originalWidth = img.width;
|
166
|
+
_originalHeight = img.height;
|
167
|
+
};
|
168
|
+
img.src = url;
|
169
|
+
};
|
170
|
+
|
171
|
+
self.dimensionsChanged = function(e){
|
172
|
+
var element = $(this);
|
173
|
+
var val = parseInt(element.val(), 10);
|
174
|
+
if(isNaN(val)){
|
175
|
+
element.val('');
|
176
|
+
return;
|
177
|
+
}
|
178
|
+
var name = element.attr('name');
|
179
|
+
if(name == 'spud_media_picker_option_dimension_w'){
|
180
|
+
var height = Math.floor((_originalHeight/_originalWidth) * val);
|
181
|
+
$('input[name="spud_media_picker_option_dimension_h"]').val(height);
|
182
|
+
}
|
183
|
+
else{
|
184
|
+
var width = Math.ceil((_originalWidth/_originalHeight) * val);
|
185
|
+
$('input[name="spud_media_picker_option_dimension_w"]').val(width);
|
186
|
+
}
|
187
|
+
};
|
188
|
+
|
189
|
+
self.clickedInsert = function(e){
|
190
|
+
e.preventDefault();
|
191
|
+
if(selectedFile.type == 'img'){
|
192
|
+
selectedFile.title = $('input[name="spud_media_picker_option_title"]').val();
|
193
|
+
selectedFile.width = parseInt($('input[name="spud_media_picker_option_dimension_w"]').val(), 10);
|
194
|
+
selectedFile.height = parseInt($('input[name="spud_media_picker_option_dimension_h"]').val(), 10);
|
195
|
+
var float = $('select[name="spud_media_picker_option_float"]').val();
|
196
|
+
var style = "";
|
197
|
+
if(float){
|
198
|
+
style += "float:" + float + ";";
|
199
|
+
}
|
200
|
+
selectedFile.style = style;
|
201
|
+
}
|
202
|
+
else{
|
203
|
+
selectedFile.target = $('select[name="spud_media_picker_option_target"]').val();
|
204
|
+
selectedFile.text = $('input[name="spud_media_picker_option_text"]').val();
|
205
|
+
if(!selectedFile.text){
|
206
|
+
window.alert("Link Text is a required field.");
|
207
|
+
return;
|
208
|
+
}
|
209
|
+
}
|
210
|
+
tinyMCEPopup.editor.execCommand('spudMediaInsertSelected', false, selectedFile);
|
211
|
+
tinyMCEPopup.close();
|
212
|
+
};
|
213
|
+
|
214
|
+
self.pickerOptionKeyDown = function(e){
|
215
|
+
if(e.keyCode == 13){
|
216
|
+
self.clickedInsert(e);
|
217
|
+
}
|
218
|
+
};
|
219
|
+
};
|
@@ -0,0 +1,99 @@
|
|
1
|
+
/**
|
2
|
+
* editor_plugin_src.js
|
3
|
+
*
|
4
|
+
* Copyright 2009, Moxiecode Systems AB
|
5
|
+
* Released under LGPL License.
|
6
|
+
*
|
7
|
+
* License: http://tinymce.moxiecode.com/license
|
8
|
+
* Contributing: http://tinymce.moxiecode.com/contributing
|
9
|
+
*/
|
10
|
+
|
11
|
+
(function() {
|
12
|
+
|
13
|
+
// Tell spud about our plugin and button
|
14
|
+
spud.admin.editor.registerPlugin('spud_media_picker');
|
15
|
+
spud.admin.editor.registerButton('spud_media_picker');
|
16
|
+
|
17
|
+
tinymce.create('tinymce.plugins.SpudMediaPicker', {
|
18
|
+
/**
|
19
|
+
* Initializes the plugin, this will be executed after the plugin has been created.
|
20
|
+
* This call is done before the editor instance has finished it's initialization so use the onInit event
|
21
|
+
* of the editor instance to intercept that event.
|
22
|
+
*
|
23
|
+
* @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
|
24
|
+
* @param {string} url Absolute URL to where the plugin is located.
|
25
|
+
*/
|
26
|
+
init : function(ed, url) {
|
27
|
+
// Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceExample');
|
28
|
+
ed.addCommand('spudMediaShowPicker', function(){
|
29
|
+
ed.windowManager.open({
|
30
|
+
title: 'Spud Media Picker',
|
31
|
+
file: '/spud/admin/media_picker',
|
32
|
+
width: 450 + parseInt(ed.getLang('example.delta_width', 0), 10),
|
33
|
+
height: 300 + parseInt(ed.getLang('example.delta_height', 0), 10),
|
34
|
+
inline: 1,
|
35
|
+
resizable: false,
|
36
|
+
popup_css: false, // prevent tinymce from injecting some default css into our dialog box
|
37
|
+
close_previous: true, // close any previously opened dialogs
|
38
|
+
scrollbars: false
|
39
|
+
});
|
40
|
+
});
|
41
|
+
|
42
|
+
// Register picker button
|
43
|
+
ed.addButton('spud_media_picker', {
|
44
|
+
title: 'Insert Spud Media',
|
45
|
+
cmd: 'spudMediaShowPicker',
|
46
|
+
image: '/assets/spud/admin/media_tiny.png'
|
47
|
+
});
|
48
|
+
|
49
|
+
ed.addCommand('spudMediaInsertSelected', function(ui, data){
|
50
|
+
if(data.type == 'img'){
|
51
|
+
var img = ed.dom.createHTML('img', {
|
52
|
+
src: data.url,
|
53
|
+
title: data.title,
|
54
|
+
style: data.style,
|
55
|
+
width: data.width,
|
56
|
+
height: data.height
|
57
|
+
});
|
58
|
+
ed.execCommand('mceInsertContent', false, img);
|
59
|
+
}
|
60
|
+
else{
|
61
|
+
var link = ed.dom.createHTML('a', {
|
62
|
+
href: data.url,
|
63
|
+
target: data.target
|
64
|
+
}, data.text);
|
65
|
+
ed.execCommand('mceInsertContent', false, link);
|
66
|
+
}
|
67
|
+
});
|
68
|
+
|
69
|
+
/*
|
70
|
+
* Add a node change handler, selects the button in the UI when a image is selected
|
71
|
+
* @param {tinymce.Editor} ed Editor
|
72
|
+
* @param {tinymce.ControlManager} cm
|
73
|
+
* @param {node} n
|
74
|
+
*/
|
75
|
+
// ed.onNodeChange.add(function(ed, cm, n) {
|
76
|
+
// cm.setActive('spud_media_picker', n.nodeName == 'IMG');
|
77
|
+
// });
|
78
|
+
},
|
79
|
+
|
80
|
+
/**
|
81
|
+
* Returns information about the plugin as a name/value array.
|
82
|
+
* The current keys are longname, author, authorurl, infourl and version.
|
83
|
+
*
|
84
|
+
* @return {Object} Name/value array containing information about the plugin.
|
85
|
+
*/
|
86
|
+
getInfo: function(){
|
87
|
+
return {
|
88
|
+
longname : 'Spud Media',
|
89
|
+
author : 'Greg Woods',
|
90
|
+
authorurl : 'https://github.com/davydotcom/spud_media',
|
91
|
+
infourl : 'https://github.com/davydotcom/spud_media',
|
92
|
+
version : "1.0"
|
93
|
+
};
|
94
|
+
}
|
95
|
+
});
|
96
|
+
|
97
|
+
// Register plugin
|
98
|
+
tinymce.PluginManager.add('spud_media_picker', tinymce.plugins.SpudMediaPicker);
|
99
|
+
})();
|
Binary file
|