BBenezech-papermill 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +62 -0
- data/Rakefile +37 -0
- data/VERSION +1 -0
- data/app/controllers/papermill_controller.rb +80 -0
- data/app/views/papermill/_asset.html.erb +11 -0
- data/app/views/papermill/_raw_asset.html.erb +1 -0
- data/app/views/papermill/_thumbnail_asset.html.erb +6 -0
- data/config/locale/papermill.yml +30 -0
- data/config/routes.rb +4 -0
- data/generators/papermill/USAGE +3 -0
- data/generators/papermill/papermill_generator.rb +16 -0
- data/generators/papermill/templates/migrate/papermill_migration.rb.erb +22 -0
- data/init.rb +10 -0
- data/install.rb +7 -0
- data/lib/core_extensions.rb +25 -0
- data/lib/papermill.rb +4 -0
- data/lib/papermill/form_builder.rb +91 -0
- data/lib/papermill/papermill_asset.rb +67 -0
- data/lib/papermill/papermill_helper.rb +35 -0
- data/lib/papermill/papermill_module.rb +182 -0
- data/papermill.gemspec +77 -0
- data/public/flashs/swfupload.swf +0 -0
- data/public/images/papermill/background.png +0 -0
- data/public/images/papermill/container-background.jpg +0 -0
- data/public/images/papermill/delete.png +0 -0
- data/public/images/papermill/upload-blank.png +0 -0
- data/public/images/papermill/upload.png +0 -0
- data/public/javascripts/papermill.js +89 -0
- data/public/stylesheets/papermill.css +33 -0
- data/tasks/papermill_tasks.rake +1 -0
- data/test/papermill_test.rb +8 -0
- data/test/test_helper.rb +3 -0
- data/uninstall.rb +1 -0
- metadata +92 -0
data/.gitignore
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 [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,62 @@
|
|
1
|
+
= Papermill
|
2
|
+
|
3
|
+
Asset management made easy.. Painfully easy.
|
4
|
+
Try the demo to see for yourself.
|
5
|
+
|
6
|
+
See papermill_module.rb for a complete list of available options.
|
7
|
+
These options can be application wide, for a class, or set at the last moment for the helper.
|
8
|
+
|
9
|
+
In your model:
|
10
|
+
|
11
|
+
papermill :assets
|
12
|
+
|
13
|
+
In your layout:
|
14
|
+
|
15
|
+
<%= papermill_stylesheet_tag %>
|
16
|
+
<%= papermill_javascript_tag :with_jquery => true %>
|
17
|
+
|
18
|
+
In your edit form:
|
19
|
+
|
20
|
+
f.images_upload(:my_image_gallery)
|
21
|
+
f.image_upload(:header_image)
|
22
|
+
|
23
|
+
Finally, in your views:
|
24
|
+
|
25
|
+
# Some template image :
|
26
|
+
<%= image_tag @article.assets(:header_image).first.url("800x>") %>
|
27
|
+
|
28
|
+
# Some image gallery:
|
29
|
+
<ul>
|
30
|
+
<% @article.assets(:my_image_gallery).each do |image| %>
|
31
|
+
<li><%= link_to(image_tag(image.url("100x100>")), image.url) %></li>
|
32
|
+
<% end %>
|
33
|
+
</ul>
|
34
|
+
|
35
|
+
Also see http://gist.github.com/177714.txt to get up-to-date installation steps.
|
36
|
+
See the API here http://rdoc.info/projects/BBenezech/papermill
|
37
|
+
|
38
|
+
== Word of caution:
|
39
|
+
|
40
|
+
Beta.
|
41
|
+
|
42
|
+
This is xNIX only (system("rm ...")).
|
43
|
+
|
44
|
+
You'll need rails 2.3, since this is an engine. Anyway, copying the controller/view/routes to your project will make it work on an older version of rails.
|
45
|
+
|
46
|
+
You'll need rails 2.2, since their are calls to I18n.t. But it shouldn't be too hard to work-around either.
|
47
|
+
|
48
|
+
== Usage :
|
49
|
+
|
50
|
+
=== Demo :
|
51
|
+
|
52
|
+
You can use the custom template generator to get an example application up and running in no time.
|
53
|
+
|
54
|
+
rails -m http://gist.github.com/177714.txt papermill-example
|
55
|
+
|
56
|
+
=== Translation:
|
57
|
+
|
58
|
+
Papermill is fully Rails 2.2 I18n-able.
|
59
|
+
|
60
|
+
Copy config/locale/papermill.yml to your root config/locale folder to modify any wording in a any locale.
|
61
|
+
|
62
|
+
Copyright (c) 2009 Benoit Bénézech, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the papermill plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.libs << 'test'
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate documentation for the papermill plugin.'
|
17
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
18
|
+
rdoc.rdoc_dir = 'rdoc'
|
19
|
+
rdoc.title = 'Papermill'
|
20
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
21
|
+
rdoc.rdoc_files.include('README')
|
22
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
require 'jeweler'
|
27
|
+
Jeweler::Tasks.new do |gemspec|
|
28
|
+
gemspec.name = "papermill"
|
29
|
+
gemspec.summary = "Paperclip wrapper"
|
30
|
+
gemspec.description = "Paperclip wrapper"
|
31
|
+
gemspec.email = "benoit.benezech@gmail.com"
|
32
|
+
gemspec.homepage = "http://github.com/BBenezech/papermill"
|
33
|
+
gemspec.authors = ["Benoit Bénézech"]
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
37
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,80 @@
|
|
1
|
+
class PapermillController < ApplicationController
|
2
|
+
|
3
|
+
skip_before_filter :verify_authenticity_token
|
4
|
+
|
5
|
+
def show
|
6
|
+
begin
|
7
|
+
if Papermill::PAPERMILL_DEFAULTS[:alias_only]
|
8
|
+
style = Papermill::PAPERMILL_DEFAULTS[:aliases][params[:style]]
|
9
|
+
else
|
10
|
+
style = Papermill::PAPERMILL_DEFAULTS[:aliases][params[:style]] || params[:style]
|
11
|
+
end
|
12
|
+
raise unless style
|
13
|
+
asset = PapermillAsset.find(params[:id])
|
14
|
+
temp_thumbnail = Paperclip::Thumbnail.make(asset_file = asset.file, style)
|
15
|
+
new_parent_folder_path = File.dirname(new_image_path = asset_file.path(params[:style]))
|
16
|
+
FileUtils.mkdir_p new_parent_folder_path unless File.exists? new_parent_folder_path
|
17
|
+
FileUtils.cp temp_thumbnail.path, new_image_path
|
18
|
+
redirect_to asset.url(params[:style])
|
19
|
+
rescue
|
20
|
+
render :text => t("not-processed", :scope => "papermill"), :status => "500"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def destroy
|
25
|
+
begin
|
26
|
+
@asset = PapermillAsset.find(params[:id])
|
27
|
+
render :update do |page|
|
28
|
+
if @asset.destroy
|
29
|
+
page << "jQuery('#papermill_asset_#{params[:id]}').remove()"
|
30
|
+
else
|
31
|
+
page << "jQuery('#papermill_asset_#{params[:id]}').show()"
|
32
|
+
message = t("not-deleted", :ressource => @asset.name, :scope => "papermill")
|
33
|
+
page << %{ notify("#{message}", error) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
rescue ActiveRecord::RecordNotFound
|
37
|
+
render :update do |page|
|
38
|
+
page << "jQuery('#papermill_asset_#{params[:id]}').remove()"
|
39
|
+
message = t("not-found", :ressource => params[:id].to_s, :scope => "papermill")
|
40
|
+
page << %{ notify("#{message}", "warning") }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def update
|
46
|
+
@asset = PapermillAsset.find params[:id]
|
47
|
+
@asset.update(params)
|
48
|
+
render :update do |page|
|
49
|
+
message = t("updated", :ressource => @asset.name, :scope => "papermill")
|
50
|
+
page << %{ notify("#{message}", "notice") }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def edit
|
55
|
+
@asset = PapermillAsset.find params[:id]
|
56
|
+
end
|
57
|
+
|
58
|
+
def create
|
59
|
+
params[:assetable_type] = params[:assetable_type].camelize
|
60
|
+
asset_class = params[:assetable_type].constantize.papermill_associations[params[:association].to_sym][:class]
|
61
|
+
params[:swfupload_file] = params.delete(:Filedata)
|
62
|
+
@old_asset = asset_class.find(:first, :conditions => {:assetable_key => params[:assetable_key].to_s, :assetable_type => params[:assetable_type], :assetable_id => params[:assetable_id]}) unless params[:gallery]
|
63
|
+
@asset = asset_class.new(params.reject{|key, value| !(PapermillAsset.columns.map(&:name)+["swfupload_file"]).include?(key.to_s)})
|
64
|
+
|
65
|
+
if @asset.save
|
66
|
+
@old_asset.destroy if @old_asset
|
67
|
+
render :partial => "papermill/asset", :object => @asset, :locals => {:thumbnail => params[:thumbnail], :gallery => params[:gallery], :thumbnail_style => params[:thumbnail_style]}
|
68
|
+
else
|
69
|
+
message = t("not-created", :scope => "papermill")
|
70
|
+
render :text => message, :status => "500"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def sort
|
75
|
+
params[:papermill_asset].each_with_index do |id, index|
|
76
|
+
PapermillAsset.find(id).update_attribute(:position, index + 1)
|
77
|
+
end
|
78
|
+
render :nothing => true
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<%- dom_id = dom_id(asset) -%>
|
2
|
+
<%- delete_link = %{<a onclick="if(confirm('#{escape_javascript I18n.t("delete-confirmation", :scope => :papermill, :resource => asset.name)}')){ $.ajax({async:true, beforeSend:function(request){$('##{dom_id}').hide();}, dataType:'script', error:function(request){$('##{dom_id}').show();}, type:'delete', url:'#{papermill_url(asset)}'})}; return false;" href="#" class="delete"><img title="#{escape_javascript t("delete", :scope => "papermill", :ressource => asset.name)}" src="/images/papermill/delete.png" alt="delete"/></a>} %>
|
3
|
+
|
4
|
+
<li id="<%= dom_id %>" rel="<%= edit_papermill_url(asset) %>" title="<%= t("#{thumbnail_style ? "thumbnail-" : ""}edit-title", :scope => "papermill", :ressource => asset.name) %>">
|
5
|
+
<%= delete_link %>
|
6
|
+
<%- if thumbnail_style -%>
|
7
|
+
<%= render :partial => "papermill/thumbnail_asset", :object => asset, :locals => {:thumbnail_style => thumbnail_style} %>
|
8
|
+
<%- else -%>
|
9
|
+
<%= render :partial => "papermill/raw_asset", :object => asset %>
|
10
|
+
<%- end -%>
|
11
|
+
</li>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= link_to(raw_asset.name, raw_asset.url, :class => "name") -%>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<% if thumbnail_asset.image? %>
|
2
|
+
<span class="image"><%= image_tag(thumbnail_asset.url(thumbnail_style)) %></span>
|
3
|
+
<% else %>
|
4
|
+
<span class="name" title="<%= thumbnail_asset.name %>"><%= truncate(thumbnail_asset.name, :length => 15) %></span>
|
5
|
+
<span class="infos"><%= thumbnail_asset.content_type[1] %></span>
|
6
|
+
<% end %>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
en:
|
2
|
+
papermill:
|
3
|
+
not-processed: "Error/ressource not processed"
|
4
|
+
updated: "{{ressource}} updated"
|
5
|
+
not-deleted: "{{ressource}} could not be deleted"
|
6
|
+
not-created: "Ressource could not be created"
|
7
|
+
not-found: "Asset #{{ressource}} not found"
|
8
|
+
edit-title: "" # You can use {{ressource}}
|
9
|
+
thumbnail-edit-title: ""
|
10
|
+
upload-button-wording: "Upload..."
|
11
|
+
delete: "Remove {{ressource}}"
|
12
|
+
delete-confirmation: "Delete '{{resource}}'?"
|
13
|
+
SWFUPLOAD_PENDING: "Pending..."
|
14
|
+
SWFUPLOAD_LOADING: "Loading..."
|
15
|
+
SWFUPLOAD_ERROR: "Something happened while loading" # + " <file_name> (<swfupload error message> [<error code>])"
|
16
|
+
fr:
|
17
|
+
papermill:
|
18
|
+
not-processed: "Erreur/ressource non trouvée"
|
19
|
+
updated: "{{ressource}} mise à jour"
|
20
|
+
not-deleted: "{{ressource}} n'a pas pu être supprimée"
|
21
|
+
not-created: "La ressource n'a pas pu être créée"
|
22
|
+
not-found: "Asset #{{ressource}} non trouvé"
|
23
|
+
edit-title: ""
|
24
|
+
thumbnail-edit-title: ""
|
25
|
+
upload-button-wording: "Charger.."
|
26
|
+
delete: "Supprimer {{ressource}}"
|
27
|
+
delete-confirmation: "Êtes-vous sûr de vouloir supprimer '{{resource}}' ?"
|
28
|
+
SWFUPLOAD_PENDING: "En attente..."
|
29
|
+
SWFUPLOAD_LOADING: "Chargement..."
|
30
|
+
SWFUPLOAD_ERROR: "Une erreur est survenue pendant le chargement de"
|
data/config/routes.rb
ADDED
@@ -0,0 +1,4 @@
|
|
1
|
+
ActionController::Routing::Routes.draw do |map|
|
2
|
+
map.resources :papermill, :collection => { :sort => :post }
|
3
|
+
map.connect "#{Papermill::PAPERMILL_DEFAULTS[:papermill_prefix]}/#{Papermill::PAPERCLIP_INTERPOLATION_STRING}", :controller => "papermill", :action => "show"
|
4
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class PapermillGenerator < Rails::Generator::NamedBase
|
2
|
+
attr_accessor :class_name, :migration_name
|
3
|
+
|
4
|
+
def initialize(args, options = {})
|
5
|
+
super
|
6
|
+
@class_name = args[0]
|
7
|
+
end
|
8
|
+
|
9
|
+
def manifest
|
10
|
+
@migration_name = file_name.camelize
|
11
|
+
record do |m|
|
12
|
+
# Migration creation
|
13
|
+
m.migration_template "migrate/papermill_migration.rb.erb", "db/migrate", :migration_file_name => migration_name.underscore
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class <%= migration_name %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :papermill_assets do |t|
|
4
|
+
t.string :file_file_name
|
5
|
+
t.string :file_content_type
|
6
|
+
t.integer :file_file_size
|
7
|
+
t.integer :position
|
8
|
+
t.text :description
|
9
|
+
t.string :copyright
|
10
|
+
t.string :title
|
11
|
+
t.integer :assetable_id
|
12
|
+
t.string :assetable_type
|
13
|
+
t.string :assetable_key
|
14
|
+
t.string :type
|
15
|
+
t.timestamps
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.down
|
20
|
+
drop_table :papermill_assets
|
21
|
+
end
|
22
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'core_extensions'
|
2
|
+
Object.send :include, ObjectExtensions
|
3
|
+
Hash.send :include, HashExtensions
|
4
|
+
String.send :include, StringExtensions
|
5
|
+
|
6
|
+
I18n.load_path = [File.join(File.dirname(__FILE__), 'config/locale/papermill.yml')] + I18n.load_path
|
7
|
+
|
8
|
+
require 'papermill'
|
9
|
+
ActionView::Base.send :include, PapermillHelper
|
10
|
+
ActiveRecord::Base.send :include, Papermill
|
data/install.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module HashExtensions
|
2
|
+
def deep_merge(hash)
|
3
|
+
target = dup
|
4
|
+
hash.keys.each do |key|
|
5
|
+
if hash[key].is_a? Hash and self[key].is_a? Hash
|
6
|
+
target[key] = target[key].deep_merge(hash[key])
|
7
|
+
next
|
8
|
+
end
|
9
|
+
target[key] = hash[key]
|
10
|
+
end
|
11
|
+
target
|
12
|
+
end
|
13
|
+
end
|
14
|
+
module StringExtensions
|
15
|
+
def simple_sql_sanitizer
|
16
|
+
gsub(/\\/, '\&\&').gsub(/'/, "''")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module ObjectExtensions
|
21
|
+
# Nil if empty.
|
22
|
+
def nie
|
23
|
+
self.blank? ? nil : self
|
24
|
+
end
|
25
|
+
end
|
data/lib/papermill.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
class ActionView::Helpers::FormBuilder
|
2
|
+
|
3
|
+
def assets_upload(key = nil, method = nil, options = {})
|
4
|
+
papermill_upload_field key, method, { :thumbnail => false }.update(options)
|
5
|
+
end
|
6
|
+
def asset_upload(key = nil, method = nil, options = {})
|
7
|
+
papermill_upload_field key, method, { :gallery => false, :thumbnail => false }.update(options)
|
8
|
+
end
|
9
|
+
def images_upload(key = nil, method = nil, options = {})
|
10
|
+
papermill_upload_field key, method, options
|
11
|
+
end
|
12
|
+
def image_upload(key = nil, method = nil, options = {})
|
13
|
+
papermill_upload_field key, method, { :gallery => false }.update(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def papermill_upload_field(key, method, options = {})
|
18
|
+
assetable = @template.instance_variable_get("@#{@object_name}")
|
19
|
+
method ||= options[:association] || :papermill_assets
|
20
|
+
key ||= options[:key] || nil
|
21
|
+
options = assetable.class.papermill_options.deep_merge(options)
|
22
|
+
assetable_id = assetable.id || assetable.timestamp
|
23
|
+
assetable_type = assetable.class.to_s.underscore
|
24
|
+
id = "papermill_#{assetable_type}_#{assetable_id}_#{key}_#{method}"
|
25
|
+
if options[:thumbnail]
|
26
|
+
w = options[:thumbnail][:width] || options[:thumbnail][:height] && options[:thumbnail][:aspect_ratio] && (options[:thumbnail][:height] * options[:thumbnail][:aspect_ratio]).to_i || nil
|
27
|
+
h = options[:thumbnail][:height] || options[:thumbnail][:width] && options[:thumbnail][:aspect_ratio] && (options[:thumbnail][:width] / options[:thumbnail][:aspect_ratio]).to_i || nil
|
28
|
+
options[:thumbnail][:style] ||= (w || h) && "#{w || options[:thumbnail][:max_width]}x#{h || options[:thumbnail][:max_height]}>" || "original"
|
29
|
+
if options[:thumbnail][:inline_css]
|
30
|
+
size = []
|
31
|
+
size << "width:#{w}px" if w
|
32
|
+
size << "height:#{h}px" if h
|
33
|
+
size = size.join("; ")
|
34
|
+
@template.content_for :inline_css do
|
35
|
+
inline_css = ["\n"]
|
36
|
+
if options[:gallery]
|
37
|
+
vp = options[:gallery][:vpadding].to_i
|
38
|
+
hp = options[:gallery][:hpadding].to_i
|
39
|
+
vm = options[:gallery][:vmargin].to_i
|
40
|
+
hm = options[:gallery][:hmargin].to_i
|
41
|
+
b = options[:gallery][:border_thickness].to_i
|
42
|
+
gallery_width = (options[:gallery][:width] || w) && "width:#{options[:gallery][:width] || options[:gallery][:columns]*(w+(hp+hm+b)*2)}px;" || ""
|
43
|
+
gallery_height = (options[:gallery][:height] || h) && "#{options[:gallery][:autogrow] ? "" : "min-"}height:#{options[:gallery][:height] || options[:gallery][:lines]*(h+(vp+vm+b)*2)}px;" || ""
|
44
|
+
inline_css << %{##{id} { #{gallery_width} #{gallery_height} }}
|
45
|
+
inline_css << %{##{id} li { margin:#{vm}px #{hm}px; border-width:#{b}px; padding:#{vp}px #{hp}px; #{size}; }}
|
46
|
+
else
|
47
|
+
inline_css << %{##{id}, ##{id} li { #{size} }}
|
48
|
+
end
|
49
|
+
inline_css << %{##{id} .name { width:#{w || "100"}px; }}
|
50
|
+
inline_css.join("\n")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
create_url = @template.url_for(:controller => "/papermill", :action => "create", :escape => false, :association => method.to_s, :assetable_key => key, :assetable_id => assetable_id, :assetable_type => assetable_type, :gallery => (options[:gallery] != false), :thumbnail_style => (options[:thumbnail] && options[:thumbnail][:style]))
|
55
|
+
html = []
|
56
|
+
if assetable.new_record? && !@timestamped
|
57
|
+
html << self.hidden_field(:timestamp, :value => assetable.timestamp)
|
58
|
+
@timestamped = true
|
59
|
+
end
|
60
|
+
html << %{<div style="height: #{options[:swfupload][:button_height]}px;"><span id="browse_for_#{id}" class="swf_button"></span></div>}
|
61
|
+
conditions = {:assetable_type => assetable.class.sti_name, :assetable_id => assetable_id}
|
62
|
+
conditions.merge!({:assetable_key => key.to_s}) if key
|
63
|
+
html << @template.content_tag(:ul, :id => id, :class => "papermill #{(options[:thumbnail] ? "papermill-thumb-container" : "papermill-asset-container")} #{(options[:gallery] ? "papermill-multiple-items" : "papermill-unique-item")}") {
|
64
|
+
@template.render :partial => "papermill/asset", :collection => assetable.class.papermill_associations[method][:class].find(:all, :conditions => conditions, :order => "position"), :locals => { :thumbnail_style => (options[:thumbnail] && options[:thumbnail][:style]) }
|
65
|
+
}
|
66
|
+
@template.content_for :inline_js do
|
67
|
+
%{
|
68
|
+
#{%{$("##{id}").sortable({update:function(){jQuery.ajax({async:true, data:jQuery(this).sortable('serialize'), dataType:'script', type:'post', url:'#{@template.controller.send("sort_papermill_url")}'})}})} if options[:gallery]}
|
69
|
+
new SWFUpload({
|
70
|
+
upload_id: "#{id}",
|
71
|
+
upload_url: "#{@template.escape_javascript create_url}",
|
72
|
+
file_size_limit: "#{options[:file_size_limit_mb].megabytes}",
|
73
|
+
file_types: "#{options[:images_only] ? '*.jpg;*.jpeg;*.png;*.gif' : ''}",
|
74
|
+
file_types_description: "#{options[:thumbnail] ? 'Images' : 'Files'}",
|
75
|
+
file_queue_limit: "#{!options[:gallery] ? '1' : '0'}",
|
76
|
+
file_queued_handler: Upload.file_queued,
|
77
|
+
file_dialog_complete_handler: Upload.file_dialog_complete,
|
78
|
+
upload_start_handler: Upload.upload_start,
|
79
|
+
upload_progress_handler: Upload.upload_progress,
|
80
|
+
upload_error_handler: Upload.upload_error,
|
81
|
+
upload_success_handler: Upload.upload_success,
|
82
|
+
upload_complete_handler: Upload.upload_complete,
|
83
|
+
button_placeholder_id : "browse_for_#{id}",
|
84
|
+
#{options[:swfupload].map{ |key, value| ["false", "true"].include?(value.to_s) ? "#{key.to_s}: #{value.to_s}" : "#{key.to_s}: '#{value.to_s}'" }.compact.join(", ")}
|
85
|
+
});
|
86
|
+
}
|
87
|
+
end
|
88
|
+
html.reverse! if options[:button_after_container]
|
89
|
+
html.join("\n")
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class PapermillAsset < ActiveRecord::Base
|
2
|
+
acts_as_list :scope => 'assetable_key=\'#{assetable_key.simple_sql_sanitizer}\' AND assetable_id=#{assetable_id} AND assetable_type=\'#{assetable_type}\''
|
3
|
+
|
4
|
+
belongs_to :assetable, :polymorphic => true
|
5
|
+
before_destroy :destroy_files
|
6
|
+
|
7
|
+
named_scope :key, lambda { |key| { :conditions => { :assetable_key => key } } }
|
8
|
+
|
9
|
+
Paperclip::Attachment.interpolations[:assetable_type] = proc do |attachment, style|
|
10
|
+
attachment.instance.assetable_type.underscore.pluralize
|
11
|
+
end
|
12
|
+
|
13
|
+
Paperclip::Attachment.interpolations[:assetable_id] = proc do |attachment, style|
|
14
|
+
attachment.instance.assetable_id
|
15
|
+
end
|
16
|
+
|
17
|
+
Paperclip::Attachment.interpolations[:assetable_key] = proc do |attachment, style|
|
18
|
+
attachment.instance.assetable_key.to_url
|
19
|
+
end
|
20
|
+
|
21
|
+
Paperclip::Attachment.interpolations[:escaped_basename] = proc do |attachment, style|
|
22
|
+
Paperclip::Attachment.interpolations[:basename].call(attachment, style).to_url
|
23
|
+
end
|
24
|
+
|
25
|
+
has_attached_file :file,
|
26
|
+
:path => "#{Papermill::PAPERMILL_DEFAULTS[:public_root]}/#{Papermill::PAPERMILL_DEFAULTS[:papermill_prefix]}/#{Papermill::PAPERCLIP_INTERPOLATION_STRING}",
|
27
|
+
:url => "/#{Papermill::PAPERMILL_DEFAULTS[:papermill_prefix]}/#{Papermill::PAPERCLIP_INTERPOLATION_STRING}"
|
28
|
+
validates_attachment_presence :file
|
29
|
+
|
30
|
+
#validates_attachment_content_type :file, :content_type => ['image/jpeg', 'image/pjpeg', 'image/jpg', 'image/png', 'image/gif']
|
31
|
+
|
32
|
+
# Fix the mime types. Make sure to require the mime-types gem
|
33
|
+
def swfupload_file=(data)
|
34
|
+
data.content_type = MIME::Types.type_for(data.original_filename).to_s
|
35
|
+
self.file = data
|
36
|
+
end
|
37
|
+
|
38
|
+
def name
|
39
|
+
file_file_name
|
40
|
+
end
|
41
|
+
|
42
|
+
def size
|
43
|
+
file_file_size
|
44
|
+
end
|
45
|
+
|
46
|
+
def url(style = nil)
|
47
|
+
file.url(style && CGI::escape(style.to_s))
|
48
|
+
end
|
49
|
+
|
50
|
+
def content_type
|
51
|
+
file_content_type.split("/") if file_content_type
|
52
|
+
end
|
53
|
+
|
54
|
+
def image?
|
55
|
+
content_type.first == "image" && content_type[1]
|
56
|
+
end
|
57
|
+
|
58
|
+
def interpolated_path(with = {}, up_to = nil)
|
59
|
+
Papermill::papermill_interpolated_path({":id" => self.id, ":assetable_id" => self.assetable_id, ":assetable_type" => self.assetable_type.underscore.pluralize}.merge(with), up_to)
|
60
|
+
end
|
61
|
+
|
62
|
+
# before_filter
|
63
|
+
def destroy_files
|
64
|
+
system "rm -rf #{self.interpolated_path({}, ':id')}/" if image?
|
65
|
+
true
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module PapermillHelper
|
2
|
+
|
3
|
+
def papermill_javascript_tag(options = {})
|
4
|
+
html = []
|
5
|
+
root_folder = options[:path] || "javascripts"
|
6
|
+
if options[:with_jquery] || options[:with_jqueryui]
|
7
|
+
html << %{<script src="http://www.google.com/jsapi"></script>}
|
8
|
+
html << %{<script type="text/javascript">\n//<![CDATA[}
|
9
|
+
html << %{google.load("jquery", "1");} if options[:with_jquery]
|
10
|
+
html << %{google.load("jqueryui", "1");} if options[:with_jquery] || options[:with_jqueryui]
|
11
|
+
html << %{</script>}
|
12
|
+
end
|
13
|
+
html << %{<script src="http://swfupload.googlecode.com/svn/swfupload/tags/swfupload_v2.2.0_core/swfupload.js"></script>}
|
14
|
+
html << %{<script type="text/javascript">\n//<![CDATA[}
|
15
|
+
["SWFUPLOAD_PENDING", "SWFUPLOAD_LOADING", "SWFUPLOAD_ERROR"].each do |js_constant|
|
16
|
+
html << %{var #{js_constant} = "#{I18n.t(js_constant, :scope => "papermill")}";}
|
17
|
+
end
|
18
|
+
html << %{//]]>\n</script>}
|
19
|
+
html << javascript_include_tag("/#{root_folder}/papermill", :cache => "swfupload-papermill")
|
20
|
+
html << '<script type="text/javascript">jQuery(document).ready(function() {'
|
21
|
+
html << @content_for_inline_js
|
22
|
+
html << '});</script>'
|
23
|
+
html.join("\n")
|
24
|
+
end
|
25
|
+
|
26
|
+
def papermill_stylesheet_tag(options = {})
|
27
|
+
html = []
|
28
|
+
root_folder = options[:path] || "stylesheets"
|
29
|
+
html << stylesheet_link_tag("/#{root_folder}/papermill")
|
30
|
+
html << %{<style type="text/css">}
|
31
|
+
html << @content_for_inline_css
|
32
|
+
html << %{</style>}
|
33
|
+
html.join("\n")
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
module Papermill
|
2
|
+
|
3
|
+
# Override these defaults :
|
4
|
+
# - in your application (environment.rb, ..) => in your [environment, development, production].rb file with Papermill::OPTIONS = {thumbnails => {..}, :gallery => {..}, etc. }
|
5
|
+
# - in your class => papermill <assoc_name>, :class_name => MySTIedPapermillAssetSubClass, thumbnails => {<my_thumbnail_parameters>}, :gallery => {<my_gallery_parameters>}, etc.
|
6
|
+
# - in your helper call => images_upload :my_gallery, {thumbnails => {..}, :gallery => {..}, etc. }
|
7
|
+
# Options will cascade as you expect them to.
|
8
|
+
|
9
|
+
# sizes (widths, paddings, etc..) are CSS pixel values.
|
10
|
+
PAPERMILL_DEFAULTS = {
|
11
|
+
:thumbnail => {
|
12
|
+
# you clearly want to override these two values in your templates.
|
13
|
+
# the rest is very optionnal and will "cascade" nicely
|
14
|
+
:width => 100, # Recommended if :gallery[:width] is nil
|
15
|
+
:height => 100, # Recommended if :gallery[:height] is nil
|
16
|
+
# set :width OR :height to nil to use aspect_ratio value. Remember that 4/3 == 1 => Use : 4.0/3
|
17
|
+
:aspect_ratio => nil,
|
18
|
+
:max_width => 1000,
|
19
|
+
:max_height => 1000,
|
20
|
+
# You can override computed ImageMagick transformation strings that defaults to "#{:width}x#{:height}>"
|
21
|
+
# Note that this is required if PAPERMILL_DEFAULTS[:alias_only] is true
|
22
|
+
:style => nil,
|
23
|
+
# set to false if you don't want inline CSS
|
24
|
+
:inline_css => true
|
25
|
+
},
|
26
|
+
# gallery
|
27
|
+
:gallery => {
|
28
|
+
# if thumbnail.inline_css is true, css will be generated automagically with these values. Great for quick scaffolding, and complete enough for real use.
|
29
|
+
:width => nil, # overrides calculated width. Recommended if :thumbnail[:width] is nil.
|
30
|
+
:height => nil, # overrides calculated height. Recommended if :thumbnail[:height] is nil.
|
31
|
+
:columns => 8, # number of columns. If thumbnail.width has a value, sets a width for the gallery, calculated from thumbnails width multiplied by :columns.
|
32
|
+
:lines => 2, # number of default lines. (height will autogrow) If thumbnail.height has a value, sets a min-height for the gallery, calculated from thumbnails height multiplied by :lines
|
33
|
+
:vpadding => 0, # vertical padding around thumbnails
|
34
|
+
:hpadding => 0, # horizontal padding around thumbnails
|
35
|
+
:vmargin => 1, # vertical margin around thumbnails
|
36
|
+
:hmargin => 1, # horizontal margin around thumbnails
|
37
|
+
:border_thickness => 2, # border around thumbnails
|
38
|
+
:autogrow => false # sets a min-height instead of height for the gallery
|
39
|
+
},
|
40
|
+
# options passed on to SWFUpload. To remove an option when overriding, set it to nil.
|
41
|
+
:swfupload => {
|
42
|
+
# !!! Will only work if the swf file comes from the server to where the files are sent. (Flash same origin security policy)
|
43
|
+
:flash_url => '/flashs/swfupload.swf',
|
44
|
+
# You can use upload-blank.png with your own wording or upload.png with default "upload" wording (looks nicer)
|
45
|
+
:button_image_url => '/images/papermill/upload-blank.png',
|
46
|
+
:button_width => 61,
|
47
|
+
:button_height => 22,
|
48
|
+
# Wording and CSS processed through an Adobe Flash styler. Result is terrible. Feel free to put a CSS button overlayed directly on the SWF button. See swfupload website.
|
49
|
+
:button_text => %{<span class="button-text">#{I18n.t("upload-button-wording", :scope => :papermill)}</span>},
|
50
|
+
:button_text_style => %{.button-text { color: red; font-size: 12pt; font-weight: bold; }},
|
51
|
+
:button_disabled => "false",
|
52
|
+
:button_text_top_padding => 4,
|
53
|
+
:button_text_left_padding => 4,
|
54
|
+
:debug => "false",
|
55
|
+
:prevent_swf_caching => "false"
|
56
|
+
# See swfupload.js for details.
|
57
|
+
},
|
58
|
+
:images_only => false, # set to true to forbid upload of anything else than images
|
59
|
+
:file_size_limit_mb => 10, # file max size
|
60
|
+
:button_after_container => false, # set to true to move the upload button below the container
|
61
|
+
|
62
|
+
# DO NOT CHANGE THESE IN YOUR CLASSES. Only application wide (routes depend on it..)
|
63
|
+
:alias_only => false, # set to true so that only aliases are authorized in url/path
|
64
|
+
:aliases => {
|
65
|
+
# "example" => "100x100#",
|
66
|
+
},
|
67
|
+
# path to the root of your public directory
|
68
|
+
:public_root => ":rails_root/public",
|
69
|
+
# added to :public_root as the root folder for all papermill items
|
70
|
+
:papermill_prefix => "papermill"
|
71
|
+
}.deep_merge( Papermill.const_defined?("OPTIONS") ? Papermill::OPTIONS : {} )
|
72
|
+
|
73
|
+
|
74
|
+
PAPERCLIP_INTERPOLATION_STRING = ":assetable_type/:assetable_id/:id/:style/:escaped_basename.:extension"
|
75
|
+
|
76
|
+
def self.included(base)
|
77
|
+
base.extend(ClassMethods)
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.papermill_interpolated_path(replacements_pairs, up_to)
|
81
|
+
replacements_pairs = {"other" => "*", ":rails_root" => RAILS_ROOT}.merge(replacements_pairs)
|
82
|
+
a = "#{PAPERMILL_DEFAULTS[:public_root]}/#{PAPERMILL_DEFAULTS[:papermill_prefix]}/#{PAPERCLIP_INTERPOLATION_STRING}".split("/")
|
83
|
+
"#{a[0..(up_to && a.index(up_to) || -1)].map{ |s| s.starts_with?(':') ? (replacements_pairs[s] || replacements_pairs['other'] || s) : s }.join('/')}"
|
84
|
+
end
|
85
|
+
|
86
|
+
module ClassMethods
|
87
|
+
attr_reader :papermill_options
|
88
|
+
attr_reader :papermill_associations
|
89
|
+
|
90
|
+
# Dealing with STIed Asset table in papermill declaration is dead easy, since papermill follows ActiveRecord :has_many global syntax and the Convention over configuration concept :
|
91
|
+
# papermill <association_name>, :class_name => MySTIedPapermillAssetClassName
|
92
|
+
# class MyAsset < PapermillAsset
|
93
|
+
# ...
|
94
|
+
# end
|
95
|
+
# class MyAssetableClass < ActiveRecord::Base
|
96
|
+
# 1 -> papermill :my_association, :class_name => MyAsset
|
97
|
+
# 2 -> papermill :class_name => MyAsset
|
98
|
+
# 3 -> papermill :my_assets
|
99
|
+
# 4 -> papermill :my_other_assets
|
100
|
+
# 5 -> papermill
|
101
|
+
# end
|
102
|
+
# assetable = MyAssetableClass.new
|
103
|
+
# 1 -> assetable.my_association attached MyAsset objects (no magic here, association and class_name both specified)
|
104
|
+
# 2 -> assetable.my_assets attached MyAsset objects (association infered from :class_name as expected)
|
105
|
+
# 3 -> assetable.my_assets attached MyAsset objects (class_name guessed from association name)
|
106
|
+
# 4 -> assetable.my_other_assets attached PapermillAssets objects (couldn't find MyOtherAsset class or MyOtherAsset is not a PapermillAsset subclass, use default PapermillAsset superclass)
|
107
|
+
# 5 -> assetable.papermill_assets attached PapermillAssets objects (defaults)
|
108
|
+
|
109
|
+
def papermill(assoc = nil, options = {})
|
110
|
+
@papermill_associations ||= {}
|
111
|
+
asset_class = ((klass = options.delete(:class_name)) && (klass = (klass.to_s.singularize.camelize.constantize rescue nil)) && klass.superclass == PapermillAsset && klass || assoc && (klass = (assoc.to_s.singularize.camelize.constantize rescue nil)) && klass.superclass == PapermillAsset && klass || PapermillAsset)
|
112
|
+
assoc ||= asset_class.to_s.pluralize.underscore.to_sym
|
113
|
+
|
114
|
+
@papermill_associations.merge!({assoc => {:class => asset_class}})
|
115
|
+
@papermill_options = Papermill::PAPERMILL_DEFAULTS.deep_merge(options)
|
116
|
+
association_finder = assoc.to_s + "_finder"
|
117
|
+
# using finder_sql because ActiveRecord chokes with STI on polymorphic tables. (Stupidely uses class.to_s instead of class.sti_name in association, god knows when it will get fixed, but tickets seems on the way for rails 3.0)
|
118
|
+
has_many association_finder, :finder_sql => 'SELECT * FROM papermill_assets WHERE papermill_assets.assetable_id = #{id} AND papermill_assets.assetable_type = "#{self.class.sti_name}" AND papermill_assets.type ' + (asset_class == PapermillAsset ? "IS NULL" : %{= "#{asset_class.to_s}"}) + ' ORDER BY papermill_assets.position'
|
119
|
+
after_create :rebase_assets
|
120
|
+
# reinventing the wheel because ActiveRecord chokes on :finder_sql with associations
|
121
|
+
# TODO Clean the mess
|
122
|
+
define_method assoc do |*options|
|
123
|
+
klass = self.class.papermill_associations[assoc.to_sym][:class]
|
124
|
+
options = options.first || {}
|
125
|
+
conditions = {
|
126
|
+
:assetable_type => self.class.sti_name,
|
127
|
+
:assetable_id => self.id,
|
128
|
+
}.merge(options.delete(:conditions) || {})
|
129
|
+
order = (options.delete(:order) || "position ASC")
|
130
|
+
conditions.merge!({:type => klass.to_s}) unless klass == PapermillAsset
|
131
|
+
conditions.merge!({:assetable_key => options[:key].to_s}) if options[:key]
|
132
|
+
conditions.merge!({:type => options[:class_name]}) if options[:class_name]
|
133
|
+
asset_class.find(:all, :conditions => conditions, :order => order)
|
134
|
+
end
|
135
|
+
|
136
|
+
after_destroy :remove_papermill_folder
|
137
|
+
class_eval <<-EOV
|
138
|
+
include Papermill::InstanceMethods
|
139
|
+
EOV
|
140
|
+
end
|
141
|
+
|
142
|
+
def inherited(subclass)
|
143
|
+
subclass.instance_variable_set("@papermill_options", @papermill_options)
|
144
|
+
subclass.instance_variable_set("@papermill_associations", @papermill_associations)
|
145
|
+
super
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
module InstanceMethods
|
150
|
+
attr_writer :timestamp
|
151
|
+
def timestamp
|
152
|
+
@timestamp ||= "-#{(Time.now.to_f * 1000).to_i.to_s[4..-1]}"
|
153
|
+
end
|
154
|
+
|
155
|
+
def interpolated_path(with = {}, up_to = nil)
|
156
|
+
Papermill::papermill_interpolated_path({
|
157
|
+
":assetable_type" => self.class.sti_name.underscore.pluralize,
|
158
|
+
":assetable_id" => self.id
|
159
|
+
}.merge(with), up_to)
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
def rebase_assets
|
165
|
+
return true unless timestamp
|
166
|
+
PapermillAsset.find(:all, :conditions => {:assetable_id => self.timestamp}).each do |asset|
|
167
|
+
if asset.created_at < 2.hours.ago
|
168
|
+
asset.destroy
|
169
|
+
else
|
170
|
+
asset.update_attribute(:assetable_id, self.id)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
system "mv #{interpolated_path({':assetable_id' => timestamp}, ':assetable_id')}/ #{interpolated_path({}, ':assetable_id')}/"
|
174
|
+
true
|
175
|
+
end
|
176
|
+
|
177
|
+
def remove_papermill_folder
|
178
|
+
system "rm -rf #{interpolated_path({}, ':assetable_id')}/"
|
179
|
+
true
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
data/papermill.gemspec
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{papermill}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Benoit B\303\251n\303\251zech"]
|
12
|
+
s.date = %q{2009-08-30}
|
13
|
+
s.description = %q{Paperclip wrapper}
|
14
|
+
s.email = %q{benoit.benezech@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"MIT-LICENSE",
|
21
|
+
"README.rdoc",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"app/controllers/papermill_controller.rb",
|
25
|
+
"app/views/papermill/_asset.html.erb",
|
26
|
+
"app/views/papermill/_raw_asset.html.erb",
|
27
|
+
"app/views/papermill/_thumbnail_asset.html.erb",
|
28
|
+
"config/locale/papermill.yml",
|
29
|
+
"config/routes.rb",
|
30
|
+
"generators/papermill/USAGE",
|
31
|
+
"generators/papermill/papermill_generator.rb",
|
32
|
+
"generators/papermill/templates/migrate/papermill_migration.rb.erb",
|
33
|
+
"init.rb",
|
34
|
+
"install.rb",
|
35
|
+
"lib/core_extensions.rb",
|
36
|
+
"lib/papermill.rb",
|
37
|
+
"lib/papermill/form_builder.rb",
|
38
|
+
"lib/papermill/papermill_asset.rb",
|
39
|
+
"lib/papermill/papermill_helper.rb",
|
40
|
+
"lib/papermill/papermill_module.rb",
|
41
|
+
"papermill.gemspec",
|
42
|
+
"public/.DS_Store",
|
43
|
+
"public/flashs/swfupload.swf",
|
44
|
+
"public/images/.DS_Store",
|
45
|
+
"public/images/papermill/.DS_Store",
|
46
|
+
"public/images/papermill/background.png",
|
47
|
+
"public/images/papermill/container-background.jpg",
|
48
|
+
"public/images/papermill/delete.png",
|
49
|
+
"public/images/papermill/upload-blank.png",
|
50
|
+
"public/images/papermill/upload.png",
|
51
|
+
"public/javascripts/papermill.js",
|
52
|
+
"public/stylesheets/papermill.css",
|
53
|
+
"tasks/papermill_tasks.rake",
|
54
|
+
"test/papermill_test.rb",
|
55
|
+
"test/test_helper.rb",
|
56
|
+
"uninstall.rb"
|
57
|
+
]
|
58
|
+
s.homepage = %q{http://github.com/BBenezech/papermill}
|
59
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
60
|
+
s.require_paths = ["lib"]
|
61
|
+
s.rubygems_version = %q{1.3.5}
|
62
|
+
s.summary = %q{Paperclip wrapper}
|
63
|
+
s.test_files = [
|
64
|
+
"test/papermill_test.rb",
|
65
|
+
"test/test_helper.rb"
|
66
|
+
]
|
67
|
+
|
68
|
+
if s.respond_to? :specification_version then
|
69
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
70
|
+
s.specification_version = 3
|
71
|
+
|
72
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
73
|
+
else
|
74
|
+
end
|
75
|
+
else
|
76
|
+
end
|
77
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,89 @@
|
|
1
|
+
/*
|
2
|
+
Papermill SWFUpload wrapper
|
3
|
+
You'll need jQuery or a **very** little bit of rewriting for native/prototype
|
4
|
+
*/
|
5
|
+
|
6
|
+
notify = function(message, type) {
|
7
|
+
// wrap with your own javascript alert system (here is the thing for jGrowl)
|
8
|
+
//if(type == "notice") { jQuery.noticeAdd({ text: message, stayTime: 4000, stay: false, type: type }) }
|
9
|
+
//if(type == "warning") { jQuery.noticeAdd({ text: message, stayTime: 9000, stay: false, type: type }) }
|
10
|
+
//if(type == "error") { jQuery.noticeAdd({ text: message, stayTime: 20000, stay: false, type: type }) }
|
11
|
+
|
12
|
+
// or simply
|
13
|
+
alert(type + ": " + message)
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
var Upload = {
|
18
|
+
// The total number of files queued with SWFUpload
|
19
|
+
files_queued: 0,
|
20
|
+
|
21
|
+
set_recipient_id: function(dom_id) {
|
22
|
+
this.recipient_id = dom_id
|
23
|
+
},
|
24
|
+
file_dialog_complete: function(num_selected, num_queued)
|
25
|
+
{
|
26
|
+
// SwfUpload doesn't order uploads by name out of the box...
|
27
|
+
this.sorted_queue = [];
|
28
|
+
this.index = 0;
|
29
|
+
if (num_queued > 0) {
|
30
|
+
file_queue = [];
|
31
|
+
global_index = 0;
|
32
|
+
index = 0;
|
33
|
+
do {
|
34
|
+
file = this.callFlash("GetFileByIndex", [global_index]);
|
35
|
+
if(file != null && file.filestatus == -1) {
|
36
|
+
file_queue[index] = file;
|
37
|
+
index++;
|
38
|
+
}
|
39
|
+
global_index++;
|
40
|
+
} while (file != null);
|
41
|
+
this.sorted_queue = file_queue.sort(function(a,b){
|
42
|
+
if(b.name < a.name){return (1)}
|
43
|
+
})
|
44
|
+
self = this;
|
45
|
+
jQuery(this.sorted_queue).each( function(index, file) {
|
46
|
+
li = jQuery('<li></li>').attr({ 'id': file.id, 'class': 'swfupload' });
|
47
|
+
li.append(jQuery('<span></span>').attr('class', 'name').html(file.name.substring(0, 10) + '...'));
|
48
|
+
li.append(jQuery('<span></span>').attr('class', 'status').html(SWFUPLOAD_PENDING));
|
49
|
+
li.append(jQuery('<span></span>').attr('class', 'progress').append('<span></span>'));
|
50
|
+
|
51
|
+
if(self.settings.file_queue_limit == 1) {
|
52
|
+
jQuery("#" + self.settings.upload_id).html(li);
|
53
|
+
} else {
|
54
|
+
jQuery("#" + self.settings.upload_id).append(li);
|
55
|
+
}
|
56
|
+
})
|
57
|
+
this.startUpload(this.sorted_queue[this.index++].id);
|
58
|
+
}
|
59
|
+
},
|
60
|
+
|
61
|
+
upload_start: function(file)
|
62
|
+
{
|
63
|
+
jQuery('#' + file.id + ' .status').html(SWFUPLOAD_LOADING);
|
64
|
+
},
|
65
|
+
upload_progress: function(file, bytes, total)
|
66
|
+
{
|
67
|
+
percent = Math.ceil((bytes / total) * 100);
|
68
|
+
jQuery('#' + file.id + ' .progress span').width(percent + '%');
|
69
|
+
},
|
70
|
+
upload_error: function(file, code, message)
|
71
|
+
{
|
72
|
+
notify(SWFUPLOAD_ERROR + " " + file.name + " (" + message + " [" + code + "])", "error");
|
73
|
+
jQuery('#' + file.id).remove();
|
74
|
+
},
|
75
|
+
upload_success: function(file, data)
|
76
|
+
{
|
77
|
+
jQuery('#' + file.id).replaceWith(jQuery(data));
|
78
|
+
},
|
79
|
+
upload_complete: function(file)
|
80
|
+
{
|
81
|
+
Upload.files_queued -= 1;
|
82
|
+
if(this.sorted_queue[this.index]) {
|
83
|
+
this.startUpload(this.sorted_queue[this.index++].id)
|
84
|
+
}
|
85
|
+
},
|
86
|
+
file_queue_error: function(file, error_code, message) {
|
87
|
+
upload_error(file, error_code, message)
|
88
|
+
}
|
89
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
.papermill a:hover { background:none; color:inherit; }
|
2
|
+
.papermill a img { border:0px; }
|
3
|
+
.papermill li:hover { border-color:blue; }
|
4
|
+
.papermill li a { display:block; }
|
5
|
+
.papermill .progress { display:block; border:1px solid #C2E3EF; text-align:left; height:6px; }
|
6
|
+
.papermill .progress span { background:#7BB963; height:6px; width:0; display:block; }
|
7
|
+
|
8
|
+
.papermill-thumb-container li { border:0px solid transparent; min-height:25px; min-width:25px; }
|
9
|
+
.papermill-thumb-container { position:relative; border:5px solid #EEE; padding:4px; overflow-x:hidden; }
|
10
|
+
.papermill-thumb-container li { display:block; float:left; position:relative; }
|
11
|
+
.papermill-thumb-container .delete { position:absolute; bottom:5px; right:5px; }
|
12
|
+
.papermill-thumb-container span { display:block; }
|
13
|
+
.papermill-thumb-container .name { font-size:10px; overflow:hidden; font-weight:bold; }
|
14
|
+
.papermill-thumb-container .infos { font-size:8px; overflow:hidden; }
|
15
|
+
.papermill-thumb-container .status { margin-bottom:10px; }
|
16
|
+
|
17
|
+
.papermill-asset-container { border:1px solid #EEE; padding:3px; }
|
18
|
+
.papermill-asset-container li { display:block; height:22px; }
|
19
|
+
.papermill-asset-container .swfupload .name { margin-left:21px; }
|
20
|
+
.papermill-asset-container .name { float:left; }
|
21
|
+
.papermill-asset-container .status { margin-left:5px; float:left; }
|
22
|
+
.papermill-asset-container .progress { float:left; margin-top:6px; margin-left:5px; width:100px; }
|
23
|
+
.papermill-asset-container .delete { float:left; margin-top:2px; margin-right:5px; }
|
24
|
+
|
25
|
+
.papermill-asset-container.papermill-multiple-items { padding-left:10px; border-left:5px solid #EEE; min-height:40px; }
|
26
|
+
.papermill-asset-container.papermill-multiple-items li { cursor:row-resize; }
|
27
|
+
.papermill-thumb-container.papermill-multiple-items li { cursor:move; }
|
28
|
+
.papermill-asset-container.papermill-unique-item { padding-left:5px; min-height:22px; }
|
29
|
+
|
30
|
+
/* Need some backgrounds?
|
31
|
+
.papermill li { background:transparent url(/images/papermill/background.png) repeat top left; }
|
32
|
+
.papermill-thumb-container { background:transparent url(/images/papermill/container-background.jpg) repeat top left; }
|
33
|
+
*/
|
@@ -0,0 +1 @@
|
|
1
|
+
|
data/test/test_helper.rb
ADDED
data/uninstall.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Uninstall hook code here
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: BBenezech-papermill
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Benoit B\xC3\xA9n\xC3\xA9zech"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-08-30 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Paperclip wrapper
|
17
|
+
email: benoit.benezech@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- VERSION
|
30
|
+
- app/controllers/papermill_controller.rb
|
31
|
+
- app/views/papermill/_asset.html.erb
|
32
|
+
- app/views/papermill/_raw_asset.html.erb
|
33
|
+
- app/views/papermill/_thumbnail_asset.html.erb
|
34
|
+
- config/locale/papermill.yml
|
35
|
+
- config/routes.rb
|
36
|
+
- generators/papermill/USAGE
|
37
|
+
- generators/papermill/papermill_generator.rb
|
38
|
+
- generators/papermill/templates/migrate/papermill_migration.rb.erb
|
39
|
+
- init.rb
|
40
|
+
- install.rb
|
41
|
+
- lib/core_extensions.rb
|
42
|
+
- lib/papermill.rb
|
43
|
+
- lib/papermill/form_builder.rb
|
44
|
+
- lib/papermill/papermill_asset.rb
|
45
|
+
- lib/papermill/papermill_helper.rb
|
46
|
+
- lib/papermill/papermill_module.rb
|
47
|
+
- papermill.gemspec
|
48
|
+
- public/.DS_Store
|
49
|
+
- public/flashs/swfupload.swf
|
50
|
+
- public/images/.DS_Store
|
51
|
+
- public/images/papermill/.DS_Store
|
52
|
+
- public/images/papermill/background.png
|
53
|
+
- public/images/papermill/container-background.jpg
|
54
|
+
- public/images/papermill/delete.png
|
55
|
+
- public/images/papermill/upload-blank.png
|
56
|
+
- public/images/papermill/upload.png
|
57
|
+
- public/javascripts/papermill.js
|
58
|
+
- public/stylesheets/papermill.css
|
59
|
+
- tasks/papermill_tasks.rake
|
60
|
+
- test/papermill_test.rb
|
61
|
+
- test/test_helper.rb
|
62
|
+
- uninstall.rb
|
63
|
+
has_rdoc: false
|
64
|
+
homepage: http://github.com/BBenezech/papermill
|
65
|
+
licenses:
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options:
|
68
|
+
- --charset=UTF-8
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: "0"
|
82
|
+
version:
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.3.5
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: Paperclip wrapper
|
90
|
+
test_files:
|
91
|
+
- test/papermill_test.rb
|
92
|
+
- test/test_helper.rb
|