papermill 0.14.3 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/README.rdoc +125 -79
- data/TODO.txt +0 -2
- data/VERSION +1 -1
- data/app/controllers/papermill_controller.rb +41 -40
- data/app/views/papermill/_asset.html.erb +1 -1
- data/app/views/papermill/_form.html.erb +20 -13
- data/app/views/papermill/edit.html.erb +2 -7
- data/config/locales/papermill.yml +6 -0
- data/config/routes.rb +2 -2
- data/generators/papermill_initializer/USAGE +4 -0
- data/generators/papermill_initializer/papermill_initializer_generator.rb +15 -0
- data/generators/papermill_table/templates/migrate/papermill_migration.rb.erb +8 -3
- data/installation-template.txt +4 -4
- data/lib/{core_extensions.rb → extensions.rb} +23 -15
- data/lib/papermill.rb +11 -4
- data/lib/papermill/form_builder.rb +62 -49
- data/lib/papermill/papermill.rb +70 -0
- data/lib/papermill/papermill_asset.rb +57 -15
- data/lib/papermill/papermill_options.rb +125 -0
- data/public/papermill/README +13 -0
- data/public/papermill/images/delete.png +0 -0
- data/public/papermill/images/mass-delete.png +0 -0
- data/public/papermill/images/mass-edit.png +0 -0
- data/public/papermill/papermill.css +8 -2
- data/public/papermill/papermill.js +42 -12
- data/test/fixtures/12k.png +0 -0
- data/test/fixtures/50x50.png +0 -0
- data/test/fixtures/5k.png +0 -0
- data/test/fixtures/bad.png +1 -0
- data/test/fixtures/s3.yml +8 -0
- data/test/fixtures/text.txt +0 -0
- data/test/fixtures/twopage.pdf +0 -0
- data/test/papermill_test.rb +109 -19
- metadata +19 -5
- data/lib/papermill/papermill_module.rb +0 -219
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -1,125 +1,171 @@
|
|
1
1
|
= Papermill
|
2
2
|
|
3
|
-
Asset management made easy.
|
3
|
+
Asset management made easy. Now in pre-1.0.0 release!
|
4
4
|
|
5
|
-
== Install the
|
5
|
+
== Install the gems
|
6
6
|
|
7
|
-
$ gem source -a http://gemcutter.org
|
7
|
+
$ gem source -a http://gemcutter.org
|
8
8
|
$ sudo gem install papermill
|
9
9
|
|
10
10
|
== Try the demo
|
11
11
|
|
12
12
|
$ sudo gem install sqlite3-ruby
|
13
13
|
$ rails -m http://github.com/bbenezech/papermill/raw/master/installation-template.txt papermill-example
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
|
15
|
+
== Features
|
16
|
+
|
17
|
+
Loads of them
|
18
|
+
|
19
|
+
=== Ajax uploading form helpers through SWFUpload:
|
20
|
+
|
21
|
+
* image_upload => unique image upload field, with preview
|
22
|
+
* images_upload => sortable image gallery upload field
|
23
|
+
* asset_upload => simple one asset field
|
24
|
+
* assets_upload => sortable asset list field
|
25
|
+
|
26
|
+
=== Choose thumbnail size for images previews :
|
27
|
+
|
28
|
+
* {:thumbnail => {:width => 100, :height => 100}}
|
29
|
+
* {:thumbnail => {:style => "100x100>"}}
|
30
|
+
* {:thumbnail => {:width => 100, :aspect_ratio => 4.0/3.0 }}
|
31
|
+
|
32
|
+
=== Asset edit form:
|
33
|
+
|
34
|
+
* double-click on any asset in any helper to access&edit his properties
|
35
|
+
* with pop-up/shadowbox/facebox, out of the box (or use your own pop-up system, dead-easy)
|
36
|
+
|
37
|
+
=== Lazy created thumbnails
|
38
|
+
|
39
|
+
* thumbnails are generated the first time they are asked-for, and only in the requested size.
|
40
|
+
* no need to register thumbnail size anywhere: my_asset.url("100x100>")
|
41
|
+
|
42
|
+
=== Alias handling, declaration application-wide
|
43
|
+
|
44
|
+
* :big_alias => {:geometry => "1000x>"}
|
45
|
+
* :other_alias => "100x>"
|
46
|
+
* :third_alias => {:geometry => '100:122', :my_other_keys => 'blblabla'} # if you have a customed Paperclip::Thumbnail processor, you can pass any values you need.
|
47
|
+
* and use them when you need them : my_asset.url(:big_alias)
|
48
|
+
|
18
49
|
== Papermill comes in 2 flavors:
|
19
50
|
|
20
51
|
=== Generic catch-all declaration
|
21
52
|
|
22
|
-
papermill
|
23
|
-
|
24
|
-
f.input :my_key, :as => :assets_upload, my_option_hash # if you are using formtastic
|
25
|
-
@assetable.assets(:my_key) # data access in your view
|
53
|
+
papermill {options} # in your papermilled assetable model
|
54
|
+
@article.assets(:any_key, options_hash) # data access
|
26
55
|
|
27
56
|
=== Association specific declaration
|
28
57
|
|
29
|
-
papermill :my_association,
|
30
|
-
|
31
|
-
|
58
|
+
papermill :my_association, options_hash # in your papermilled assetable model
|
59
|
+
@article.my_association # data access
|
60
|
+
|
61
|
+
== Usage:
|
32
62
|
|
63
|
+
=== Model declaration
|
33
64
|
|
34
|
-
|
65
|
+
You can have a generic association and as many declarative associations as you want in your model. Papermill will always use specific if found.
|
66
|
+
|
67
|
+
article.rb
|
68
|
+
class Article < ActiveRecord::Base
|
69
|
+
papermill :class_name => ColorAsset, other_options..
|
70
|
+
end
|
71
|
+
|
72
|
+
entry.rb
|
73
|
+
class Entry < ActiveRecord::Base
|
74
|
+
papermill :mug_shot, other_options.. # default class_name is built-in PapermillAsset
|
75
|
+
papermill :diaporama, :class_name => ColorAsset, other_options..
|
76
|
+
end
|
35
77
|
|
36
|
-
You
|
78
|
+
color_asset.rb # You should add columns to papermill_assets and use STI on PapermillAsset to extend defaults capabilities (or re-open PapermillAsset and monkey-patch it..)
|
79
|
+
class ColorAsset < PapermillAsset
|
80
|
+
named_scope :red, :conditions => {:color => 'red'}
|
81
|
+
end
|
37
82
|
|
38
|
-
|
83
|
+
=== Form helpers
|
39
84
|
|
40
|
-
|
85
|
+
FormHelpers
|
86
|
+
form_for @article do
|
87
|
+
f.image_upload :cover_image, options_hash
|
88
|
+
f.images_upload :illustrations, options_hash
|
89
|
+
f.asset_upload :pdf, options_hash
|
90
|
+
f.image_upload :other_ressources, options_hash
|
91
|
+
end
|
92
|
+
|
93
|
+
Or with formtastic :
|
94
|
+
semantic_form_for @article do |f|
|
95
|
+
f.input @article, :cover_image, options_hash, :as => :image_upload
|
96
|
+
f.input @article, :illustrations, options_hash, :as => :images_upload
|
97
|
+
f.input @article, :pdf, options_hash, :as => :asset_upload
|
98
|
+
f.input @article, :other_ressources, options_hash, :as => :image_upload
|
99
|
+
end
|
41
100
|
|
101
|
+
FormTagHelpers
|
102
|
+
image_upload_tag @article, :cover_image, options_hash
|
103
|
+
images_upload_tag @article, :illustrations, options_hash
|
104
|
+
asset_upload_tag @article, :pdf, options_hash
|
105
|
+
image_upload_tag @article, :other_ressources, options_hash
|
106
|
+
# For resources not linked to any assetable model :
|
107
|
+
image_upload_tag #{current_organization.name}_logo
|
108
|
+
|
109
|
+
=== Resources access
|
110
|
+
|
111
|
+
With generic papermill association, Papermill generates an #assets(:key, *args) named_scope
|
112
|
+
@article.assets(:illustrations)
|
113
|
+
@article.assets(:illustrations, :order => "created_at DESC")
|
114
|
+
@article.illustrations.red.first
|
115
|
+
@article.assets(:illustrations, :order => "created_at DESC").red.first
|
116
|
+
# etc.
|
117
|
+
|
118
|
+
With declarative papermill associations, Papermill generates an #<association_key>(*args) named_scope
|
119
|
+
@entry.mug_shot.first
|
120
|
+
@entry.diaporama
|
121
|
+
@entry.diaporama(:order => "created_at DESC")
|
122
|
+
@entry.diaporama.red
|
123
|
+
# === @entry.diaporama(:conditions => {:color => "red"})
|
124
|
+
# etc.
|
125
|
+
|
126
|
+
Or for non-assetable resources :
|
127
|
+
PapermillAsset.all(:conditions => { :assetable_key => "#{current_organization.name}_logo" }).first
|
128
|
+
ColorAsset.all.red
|
129
|
+
|
130
|
+
=== Using PapermillAsset
|
131
|
+
|
132
|
+
@asset = @entry.mug_shot.first
|
133
|
+
image_tag @asset.url # original
|
134
|
+
image_tag @asset.url("100x>")
|
135
|
+
image_tag @asset.url(:big) # assuming you have a :big alias in your environment.rb
|
136
|
+
@asset.name
|
137
|
+
@asset.content_type
|
138
|
+
@asset.path # original
|
139
|
+
@asset.path("100x>")
|
140
|
+
# etc.
|
141
|
+
|
42
142
|
== Installation
|
43
143
|
|
44
|
-
=== Once
|
144
|
+
=== Once gem is installed :
|
45
145
|
|
46
|
-
# Generate
|
146
|
+
# Generate migration :
|
47
147
|
$ ./script/generate papermill_table PapermillMigration
|
48
148
|
$ rake db:migrate
|
49
|
-
# copy
|
149
|
+
# copy static assets to your public directory:
|
50
150
|
$ ./script/generate papermill_assets
|
151
|
+
# create the option hash in config/initializers/papermill.rb
|
152
|
+
$ ./script/generate papermill_initializer
|
51
153
|
|
52
154
|
=== Then in environment.rb:
|
53
155
|
|
54
156
|
...
|
55
|
-
|
56
157
|
Rails::Initializer.run do |config|
|
57
158
|
...
|
58
159
|
config.gem papermill
|
59
|
-
|
60
|
-
# You can set application-wide options inside or before Rails::Initializer :
|
61
|
-
module Papermill
|
62
|
-
OPTIONS = {
|
63
|
-
:thumbnail => {
|
64
|
-
:width => 150,
|
65
|
-
:height => 100
|
66
|
-
},
|
67
|
-
:aliases => {
|
68
|
-
:big => "500x500>",
|
69
|
-
:small => "100x100>"
|
70
|
-
},
|
71
|
-
:public_root => ":rails_root/public", # already a default
|
72
|
-
:papermill_prefix => "system/papermill" # already a default
|
73
|
-
}
|
74
|
-
end
|
75
|
-
# see lib/papermill/papermill_module.rb
|
76
|
-
|
77
|
-
# You can use stringex's String#to_url (papermill will use its own String#to_url if none exists)
|
78
|
-
config.gem 'stringex'
|
79
|
-
...
|
80
|
-
# You can use Mime-Type to get the correct mime type from upload - flash garbles it.. (default is a UNIX call to "file --mime")
|
81
|
-
# needed for Windows OS
|
160
|
+
# Needed for Windows OS (mime type from file extension):
|
82
161
|
config.gem "mime-types", :lib => "mime/types"
|
83
162
|
end
|
84
|
-
|
85
|
-
=== In your assetable model:
|
86
|
-
|
87
|
-
# You can set a catch-all papermill association :
|
88
|
-
papermill :class_name => MyAssetClass
|
89
|
-
|
90
|
-
# or create an association for the specific :my_gallery key
|
91
|
-
papermill :my_gallery_assets, :class_name => MyGalleryAsset
|
92
163
|
|
93
164
|
=== In your layout:
|
94
165
|
|
95
166
|
<%= papermill_stylesheet_tag %>
|
96
167
|
<%= papermill_javascript_tag :with_jquery => "no_conflict" %>
|
97
|
-
# you
|
98
|
-
|
99
|
-
=== In your edit form:
|
100
|
-
|
101
|
-
f.images_upload(:my_gallery) # use specific papermill :my_gallery declaration
|
102
|
-
f.assets_upload(:my_assets) # use catch-all
|
103
|
-
f.asset_upload(:my_other_asset) # use catch-all
|
104
|
-
|
105
|
-
=== Access them with:
|
106
|
-
|
107
|
-
@assetable.my_gallery_assets.each{ |image| image_tag image.url("100x100") }
|
108
|
-
# equivalent to:
|
109
|
-
@assetable.assets(:my_gallery_assets).each{ |image| image_tag image.url("100x100") }
|
110
|
-
# also equivalent to:
|
111
|
-
@assetable.assets(:conditions => {:assetable_key => 'my_gallery_assets'}).each{ |image| image_tag image.url("100x100") }
|
112
|
-
|
113
|
-
@assetable.assets(:my_assets).each{ |asset| asset.url }
|
114
|
-
# if your association name is singularizable, you can do smtg like :
|
115
|
-
@assetable.asset(:my_other_asset).try(:url)
|
116
|
-
# equivalent to:
|
117
|
-
@assetable.assets(:my_other_asset).first.try(:url)
|
118
|
-
|
119
|
-
# You can change assets/asset with :base_association_name in Papermill::OPTIONS (choose a plural word and you'll get singular association for free)
|
120
|
-
|
121
|
-
Also see http://github.com/bbenezech/papermill/raw/master/installation-template.txt
|
122
|
-
Have a look at the API here http://rdoc.info/projects/bbenezech/papermill
|
168
|
+
# you don't need :with_jquery if you already had it loaded.
|
123
169
|
|
124
170
|
=== Translations:
|
125
171
|
|
data/TODO.txt
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.16.0
|
@@ -4,72 +4,48 @@ class PapermillController < ApplicationController
|
|
4
4
|
skip_before_filter :verify_authenticity_token, :only => [:create]
|
5
5
|
|
6
6
|
def show
|
7
|
-
|
8
|
-
|
9
|
-
asset
|
10
|
-
|
11
|
-
|
12
|
-
raise unless style
|
13
|
-
style = {:geometry => style} unless style.is_a? Hash
|
14
|
-
|
15
|
-
if asset.image?
|
16
|
-
temp_thumbnail = Paperclip::Thumbnail.make(asset_file = asset.file, style)
|
17
|
-
new_parent_folder_path = File.dirname(new_image_path = asset_file.path(params[:style]))
|
18
|
-
FileUtils.mkdir_p new_parent_folder_path unless File.exists? new_parent_folder_path
|
19
|
-
FileUtils.cp temp_thumbnail.path, new_image_path
|
20
|
-
redirect_to asset.url(params[:style])
|
21
|
-
else
|
22
|
-
redirect_to asset.url
|
23
|
-
end
|
24
|
-
rescue
|
25
|
-
render :text => t('papermill.not-found'), :status => "404"
|
7
|
+
@asset = PapermillAsset.find_by_id_partition params
|
8
|
+
if @asset.create_thumb_file(params[:style])
|
9
|
+
redirect_to @asset.url(params[:style])
|
10
|
+
else
|
11
|
+
render :nothing => true, :status => 500
|
26
12
|
end
|
27
13
|
end
|
28
14
|
|
29
15
|
def destroy
|
30
|
-
@asset = PapermillAsset.
|
16
|
+
@asset = PapermillAsset.find params[:id]
|
31
17
|
render :update do |page|
|
32
|
-
if @asset
|
18
|
+
if @asset.destroy
|
33
19
|
page << "jQuery('#papermill_asset_#{params[:id]}').remove()"
|
34
20
|
else
|
35
21
|
page << "jQuery('#papermill_asset_#{params[:id]}').show()"
|
36
|
-
page << %{ notify("#{t(
|
22
|
+
page << %{ notify("#{ escape_javascript t("papermill.not-deleted", :ressource => @asset.name) }", "error") }
|
37
23
|
end
|
38
24
|
end
|
39
25
|
end
|
40
26
|
|
41
27
|
def update
|
42
|
-
@asset = PapermillAsset.
|
28
|
+
@asset = PapermillAsset.find params[:id]
|
43
29
|
render :update do |page|
|
44
|
-
if @asset
|
45
|
-
page << %{ notify("#{t("papermill.updated", :ressource => @asset.name)}", "notice") }
|
30
|
+
if @asset.update_attributes(params[:papermill_asset])
|
31
|
+
page << %{ notify("#{ escape_javascript t("papermill.updated", :ressource => @asset.name)}", "notice") }
|
46
32
|
else
|
47
|
-
page << %{ notify("#{
|
33
|
+
page << %{ notify("#{ escape_javascript @asset.errors.full_messages.to_sentence }", "warning") }
|
48
34
|
end
|
49
35
|
end
|
50
36
|
end
|
51
37
|
|
52
38
|
def edit
|
53
39
|
@asset = PapermillAsset.find params[:id]
|
40
|
+
render :action => "edit", :layout => (params[:layout] || "none")
|
54
41
|
end
|
55
42
|
|
56
43
|
def create
|
57
|
-
|
58
|
-
|
59
|
-
params[:assetable_type] = params[:assetable_type].try :camelize
|
60
|
-
params[:assetable_key] = params[:assetable_key].try :to_s
|
61
|
-
params[:swfupload_file] = params.delete(:Filedata)
|
62
|
-
unless params[:gallery]
|
63
|
-
@old_asset = asset_class.find(:first, :conditions => params.reject{|k, v| !["assetable_key", "assetable_type", "assetable_id"].include?(k)})
|
64
|
-
end
|
65
|
-
@asset = asset_class.new(params.reject{|k, v| !(PapermillAsset.columns.map(&:name)+["swfupload_file"]).include?(k)})
|
66
|
-
@asset.position = asset_class.find(:first, :conditions => params.reject{|k, v| !["assetable_key", "assetable_type", "assetable_id"].include?(k)}, :order => "position DESC" ).try(:position).to_i + 1
|
67
|
-
|
68
|
-
if @asset.save
|
69
|
-
@old_asset.destroy if @old_asset
|
44
|
+
@asset = params[:asset_class].constantize.new(params.reject{|k, v| !(PapermillAsset.columns.map(&:name)+["Filedata", "Filename"]).include?(k)})
|
45
|
+
if @asset.save(:unique => !params[:gallery])
|
70
46
|
render :partial => "papermill/asset", :object => @asset, :locals => {:gallery => params[:gallery], :thumbnail_style => params[:thumbnail_style]}
|
71
47
|
else
|
72
|
-
render :text => @asset.errors.full_messages.join('<br />'), :status =>
|
48
|
+
render :text => @asset.errors.full_messages.join('<br />'), :status => 500
|
73
49
|
end
|
74
50
|
end
|
75
51
|
|
@@ -79,4 +55,29 @@ class PapermillController < ApplicationController
|
|
79
55
|
end
|
80
56
|
render :nothing => true
|
81
57
|
end
|
58
|
+
|
59
|
+
def mass_delete
|
60
|
+
render :update do |page|
|
61
|
+
(params[:papermill_asset] || []).each do |id|
|
62
|
+
@asset = PapermillAsset.find(id)
|
63
|
+
if @asset.destroy
|
64
|
+
page << "jQuery('#papermill_asset_#{id}').remove()"
|
65
|
+
else
|
66
|
+
page << %{ notify('#{ escape_javascript t("papermill.not-deleted", :ressource => @asset.name)}', 'error') }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def mass_edit
|
73
|
+
message = []
|
74
|
+
(params[:papermill_asset] || []).each do |id|
|
75
|
+
@asset = PapermillAsset.find(id)
|
76
|
+
@asset.update_attribute(params[:attribute], params[:value])
|
77
|
+
message << t("papermill.updated", :ressource => @asset.name)
|
78
|
+
end
|
79
|
+
render :update do |page|
|
80
|
+
page << %{ notify('#{ escape_javascript message.join("<br />")}', "notice") } unless message.empty?
|
81
|
+
end
|
82
|
+
end
|
82
83
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<%- dom_id = "papermill_asset_#{asset.id}" -%>
|
2
|
-
<%- delete_link = %{<a onclick="if(confirm('#{escape_javascript t("papermill.delete-confirmation", :resource => asset.name)}')){
|
2
|
+
<%- delete_link = %{<a onclick="if(confirm('#{escape_javascript t("papermill.delete-confirmation", :resource => asset.name)}')){ jQuery.ajax({async:true, beforeSend:function(request){jQuery('##{dom_id}').hide();}, dataType:'script', error:function(request){jQuery('##{dom_id}').show();}, type:'delete', url:'#{papermill_url(asset)}'})}; return false;" href="#" class="delete"><img title="#{escape_javascript t("papermill.delete", :ressource => asset.name)}" src="/papermill/images/delete.png" alt="delete"/></a>} %>
|
3
3
|
|
4
4
|
<li id="<%= dom_id %>" title="<%= t("papermill.#{thumbnail_style ? "thumbnail-" : ""}edit-title", :ressource => asset.name) %>" onDblClick="popup(jQuery(this).attr('rel')); return false;" rel="<%= edit_papermill_url(asset) %>">
|
5
5
|
<%= delete_link %>
|
@@ -1,13 +1,20 @@
|
|
1
|
-
<
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
<p>
|
6
|
-
|
7
|
-
|
8
|
-
</p>
|
9
|
-
<p>
|
10
|
-
|
11
|
-
|
12
|
-
</p>
|
13
|
-
|
1
|
+
<form onsubmit="jQuery.ajax({data:jQuery.param(jQuery(this).serializeArray()), dataType:'script', type:'post', url:'/papermill/<%= @asset.id %>'}); try {jQuery(document).trigger('close.facebox');} catch (e) {}; try{Shadowbox.close();} catch (e) {}; try{self.close();} catch (e) {}; return false;" method="post" action="/papermill/<%= @asset.id %>">
|
2
|
+
<input type="hidden" value="put" name="_method"/>
|
3
|
+
|
4
|
+
<% fields_for :papermill_asset, @asset do |form| %>
|
5
|
+
<p>
|
6
|
+
<%= form.label :title, t("papermill.title") %><br />
|
7
|
+
<%= form.text_field :title, :class => "text_field" %>
|
8
|
+
</p>
|
9
|
+
<p>
|
10
|
+
<%= form.label :copyright, t("papermill.copyright") %><br />
|
11
|
+
<%= form.text_field :copyright, :class => "text_field" %>
|
12
|
+
</p>
|
13
|
+
<p>
|
14
|
+
<%= form.label :description, t("papermill.description") %><br />
|
15
|
+
<%= form.text_area :description %>
|
16
|
+
</p>
|
17
|
+
<%= submit_tag t('papermill.save') %>
|
18
|
+
<% end %>
|
19
|
+
</form>
|
20
|
+
<%= javascript_include_tag("http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js") if params[:with_jquery] %>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<div id="papermill-box">
|
2
2
|
<div id="left">
|
3
|
-
<%= link_to(@asset.image? ? image_tag(@asset.url("400x
|
3
|
+
<%= link_to(@asset.image? ? image_tag(@asset.url("400x>")) : t("file_type", :type => @asset.content_type, :scope => 'papermill'), @asset.url, :popup => true) %>
|
4
4
|
</div>
|
5
5
|
<div id="right">
|
6
6
|
<div id="read-only">
|
@@ -17,12 +17,7 @@
|
|
17
17
|
</table>
|
18
18
|
</div>
|
19
19
|
<div id="read-write">
|
20
|
-
|
21
|
-
<input type="hidden" value="put" name="_method"/>
|
22
|
-
<% fields_for :papermill_asset, @asset do |form| %>
|
23
|
-
<%= render :partial => 'form', :object => form %>
|
24
|
-
<% end %>
|
25
|
-
</form>
|
20
|
+
<%= render :partial => 'form' %>
|
26
21
|
</div>
|
27
22
|
</div>
|
28
23
|
<div style="clear:both;"></div>
|