papermill 0.14.3 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -1,6 +1,8 @@
1
1
  .DS_Store
2
+ test/*.log
2
3
  log/*.log
3
4
  tmp/**/*
4
5
  config/database.yml
5
6
  db/*.sqlite3
7
+ test.sqlte3
6
8
  papermill.gemspec
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 gem
5
+ == Install the gems
6
6
 
7
- $ gem source -a http://gemcutter.org # Needed for paperclip (installed as a dependency) : Rubyforge's version is too old..
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
- $ cd papermill-example
15
- $ ./script/server
16
- Open localhost:3000 in your browser and try to create an article with assets but without title
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 my_option_hash # in your papermilled assetable model
23
- assets_upload(:my_key, my_option_hash) # form helper call
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, my_option_hash # in your papermilled assetable model
30
- assets_upload(:my_association, my_option_hash) # form helper call
31
- @assetable.my_association # data access in your view
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
- In both case, you can specify a PapermillAsset subclass to use with :class_name => MyPapermillAssetSubclass in the option hash.
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 can have a catch-all declaration and as many specific association as you want in your model (as long as they use different keys).
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
- It's up to you. You can use the first one only, the second only or both.
83
+ === Form helpers
39
84
 
40
- See papermill_module.rb for the complete list of options.
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 you've installed the gem, generate a migration and copy a couple of static assets:
144
+ === Once gem is installed :
45
145
 
46
- # Generate the migration and migrate:
146
+ # Generate migration :
47
147
  $ ./script/generate papermill_table PapermillMigration
48
148
  $ rake db:migrate
49
- # copy some needed static assets to your public directory:
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 won't need :with_jquery if you have it already.
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
@@ -1,5 +1,3 @@
1
- * non-regression tests
2
- * write rake task to delete all forgotten images.
3
1
  Edit views :
4
2
  * use Jcrop
5
3
  * try Picnic API
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.14.3
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
- begin
8
- complete_id = (params[:id0] + params[:id1] + params[:id2]).to_i
9
- asset = PapermillAsset.find(complete_id)
10
- raise if asset.nil? || params[:style] == "original"
11
- style = Papermill::PAPERMILL_DEFAULTS[:aliases][params[:style]] || !Papermill::PAPERMILL_DEFAULTS[:alias_only] && params[:style]
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.find_by_id(params[:id])
16
+ @asset = PapermillAsset.find params[:id]
31
17
  render :update do |page|
32
- if @asset && @asset.destroy
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((@asset && "papermill.not-deleted" || "papermill.not-found"), :ressource => @asset.name)}", "error") }
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.find_by_id(params[:id])
28
+ @asset = PapermillAsset.find params[:id]
43
29
  render :update do |page|
44
- if @asset && @asset.update_attributes(params[:papermill_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("#{@asset && @asset.errors.full_messages.to_sentence || t("papermill.not-found", :ressource => params[:id].to_s)}", "warning") }
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
- asset_class = params[:asset_class].constantize
58
- params[:assetable_id] = params[:assetable_id].try :to_i
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 => "500"
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)}')){ $.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("papermill.delete", :ressource => asset.name)}" src="/papermill/images/delete.png" alt="delete"/></a>} %>
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
- <p>
2
- <%= form.label :title, t("papermill.title") %><br />
3
- <%= form.text_field :title, :class => "text_field" %>
4
- </p>
5
- <p>
6
- <%= form.label :copyright, t("papermill.copyright") %><br />
7
- <%= form.text_field :copyright, :class => "text_field" %>
8
- </p>
9
- <p>
10
- <%= form.label :description, t("papermill.description") %><br />
11
- <%= form.text_area :description %>
12
- </p>
13
- <%= submit_tag t('papermill.save') %>
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#{Papermill::PAPERMILL_DEFAULTS[:max_height]}>")) : t("file_type", :type => @asset.content_type, :scope => 'papermill'), @asset.url, :popup => true) %>
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
- <form onsubmit="jQuery.ajax({data:jQuery.param(jQuery(this).serializeArray()), dataType:'script', type:'post', url:'/papermill/<%= @asset.id %>'}); return false;" method="post" action="/papermill/<%= @asset.id %>">
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>