papermill 1.3.6 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -29,91 +29,266 @@ Check your audience.
29
29
 
30
30
  === Server requirements:
31
31
 
32
- * Makes internal use of JQuery (but loaded in compatibility mode by default, compatible with Prototype/whatever... JRails not needed.)
33
- * Rails 2.3.4 min (rail's I18n, engine. older 2.3.x have issues with CRSF or try to check for CRSF stamp against AJAX request, useless with AJAX same origin policy, fixed with 2.3.4)
34
- * Paperclip 2.3 branch (installed by default as a gem dependency, will be loaded internally if needed => You can require your own version of Paperclip if you want to)
35
- * Front web server serving static assets if present, and forwarding demand to rails if not. (Usually a no-brainer on any classic installation. Works with Webrick)
36
-
37
- == Features
32
+ * Rails 2.3.4
33
+ * Paperclip 2.3
34
+ * Front web server serving static assets if present, and forwarding demand to rails if not. Any classic installation will do that by default.
35
+ * NOT compatible with Heroku/S3
38
36
 
39
- === Ajax uploading form helpers through SWFUpload => [image|asset](s)_upload
37
+ == Installation
40
38
 
41
- See the demo to get an idea:
39
+ === Once gem is installed
42
40
 
43
- * image_upload => one image, with thumbnail preview
44
- * images_upload => sortable image thumbnail gallery
45
- * asset_upload => one asset
46
- * assets_upload => sortable asset list
41
+ Generate the migration
42
+ ./script/generate papermill_table PapermillMigration
47
43
 
48
- === Asset edit form:
44
+ Edit it and migrate
45
+ rake db:migrate
49
46
 
50
- * double-click on any asset in any helper to access & edit his properties
47
+ Copy static assets to your public directory
48
+ ./script/generate papermill_assets
49
+
50
+ Create the option file config/initializers/papermill.rb
51
+ ./script/generate papermill_initializer
52
+
53
+ Go have a look at config/initializers/papermill.rb
51
54
 
52
- === Lazy created thumbnails
55
+ === In environment.rb
53
56
 
54
- * thumbnails are generated the first time they are asked-for, and only in the requested size.
55
- * no need to register thumbnail size anywhere: my_asset.url("100x100>")
56
- * .. but you can use application-wide aliases, see below :
57
+ ...
58
+ Rails::Initializer.run do |config|
59
+ ...
60
+ config.gem papermill
61
+ end
62
+
63
+ === In your layout
64
+
65
+
66
+ ==== Quick version
67
+
68
+ Inside <head></head>
69
+ <%= papermill_stylesheet_tag %>
70
+
71
+ Before </body> (best practice for javascript loading)
72
+ <%= papermill_javascript_tag :with_jquery => "no_conflict" %>
73
+
74
+ You don't need :with_jquery if load it by yourself. Pass "no_conflict" if you use the default Prototype library, or some other '$' library (mootools..)
75
+
76
+ ==== In a real-world production application, you could use something like this, and adapt it to your own needs
57
77
 
58
- === Alias handling, declaration application-wide (in config/initializers/papermill.rb, do a ./script/generate papermill_initializer)
78
+ Inside <head></head>
79
+ <% unless @content_for_papermill_inline_js.blank? %>
80
+ <%= javascript_include_tag "/facebox/facebox.js", "/jgrowl/jquery.jgrowl_minimized.js", "/papermill/jquery.Jcrop.min.js", "/swfupload/swfupload.js", "/papermill/papermill.js", :cache => "papermill" %>
81
+ <script type="text/javascript">
82
+ jQuery(document).ready(function() {
83
+ <%= yield :content_for_papermill_inline_js %>
84
+ }
85
+ </script>
86
+ <% end %>
59
87
 
60
- * :big_alias => {:geometry => "1000x>"}
61
- * :other_alias => "100x>"
62
- * :third_alias => {:geometry => '100:122', :my_other_keys => 'blblabla'} # if you have a customed Paperclip::Thumbnail processor, you can pass any values you need.
63
- * Use them when you need them : my_asset.url(:big_alias)
88
+ Before </body>
89
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js" type="text/javascript"></script>
90
+ <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js" type="text/javascript"></script>
91
+ <% unless @content_for_papermill_inline_js.blank? %>
92
+ <%= stylesheet_link_tag("/facebox/facebox.css", "/jgrowl/jquery.jgrowl.css", "/Jcrop/jquery.Jcrop.css", "/papermill/papermill.css", :cache => "papermill") %>
93
+ <style type="text/css">
94
+ <%= yield :papermill_inline_css %>
95
+ </style>
96
+ <script type="text/javascript">
97
+ var SWFUPLOAD_PENDING = "Waiting...";
98
+ var SWFUPLOAD_LOADING = "Loading...";
99
+ </script>
100
+ <% end %>
64
101
 
65
- === Model declaration
102
+ == Security
103
+
104
+ === URL-hacking
105
+
106
+ Maybe you don't want users to use your application as a thumbnailing farm for their own uploaded images, or you have protected members areas and you don't want users to 'browse' others members file.
107
+
108
+ * Brute solution: pass :use_url_key to true in the options (config/initializers/papermill.rb). A crypted hash unique to your application and to each asset and to the requested style will be added to the URL. No more happy-guessing of anything. Do that first before going live, or you'll have to migrate all assets...
109
+ * pass :alias_only to true. This will disable the possibility to generate thumbnails with a papermill string in the url, but won't do anything for the member area thing. Plus you will have to use aliases only, form helpers included (pass :thumbnail => { :style => :some_alias })
110
+
111
+ === Restricted-area/back-office
112
+
113
+ Go to the options and look for :
114
+ :authorize_create => true,
115
+ :authorize_update_and_destroy => true,
116
+ :authorize_multiple_modification => true,
117
+
118
+ You will find a quick & dirty solution to pass your authorizations rules in before_filters, before any asset gets hurt.
119
+
120
+ == Usage
121
+
122
+ Assetable is the class that has_many papermill_assets (i.e. the class with the papermill declaration)
123
+
124
+ === Assetable declaration
66
125
 
67
126
  You can have a generic association and as many declarative associations as you want in your model. Papermill will always use specific if found.
68
127
 
69
128
  article.rb
70
129
 
71
130
  class Article < ActiveRecord::Base
72
- papermill :class_name => ColorAsset, other_options..
131
+ papermill :class_name => ColorAsset, other_options.. # generic, will use ColorAsset instead of PapermillAsset (ColorAsset must be an STIed PapermillAsset)
73
132
  end
74
133
 
75
134
  entry.rb
76
135
 
77
136
  class Entry < ActiveRecord::Base
78
- papermill :mug_shot, other_options..
79
- papermill :diaporama, :class_name => ColorAsset, other_options..
137
+ papermill :mug_shot, other_options.. # specific association on :mug_shot
138
+ papermill :diaporama, :class_name => ColorAsset, other_options.. # specific association on :diaporama will use ColorAssets
80
139
  end
81
140
 
82
- 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, or use a polymorphic association)
141
+ color_asset.rb # You can add columns to papermill_assets and use STI on PapermillAsset to extend defaults abilities (or re-open PapermillAsset/monkey-patch it/use a polymorphic association on PapermillAsset to extend it with behaviors..)
83
142
 
84
143
  class ColorAsset < PapermillAsset
85
144
  named_scope :red, :conditions => {:color => 'red'}
86
145
  end
87
146
 
88
147
  === Form helpers
148
+
149
+ Example form:
150
+
151
+ form_for @assetable do
152
+ # I need a simple asset upload field :
153
+ f.asset_upload :pdf_version
154
+
155
+ # Now I need to be able to upload as many documents as I need, and sort them at will
156
+ # no document should be bigger than 1MB (respect the quoting!)
157
+ # and I don't want any dashboard mass_edit feature, just mass_delete (delete all)
158
+ f.assets_upload :documentation, :swfupload => { :file_size_limit => "'1 MB'" }, :dashboard => [:mass_delete]
159
+
160
+ # I need to display *one* cover *image*, format will be 200x200
161
+ # targetted_size will give the uploader hints when cropping the image after upload : desired display size and wanted aspect-ratio.
162
+ # Better than cropping automatically in the center if the character's head is in the upper-left corner..
163
+ # :thumbnail => { :width & :height } set the dimensions of the preview thumbnail
164
+ # And finally, I need a 200x200# crop for preview, not the default 200x200> that would be generated by default ("#{:width}x#{:heigth}>")
165
+ f.image_upload :cover_image, :targetted_size => "200x200", :thumbnail => { :width => 200, :height => 200, :style => "200x200#" }
166
+
167
+ # Now the image gallery, sortable.
168
+ # I use :gallery => { :lines & :columns } to give the number of lines/columns,
169
+ # and some CSS will be generated to size the gallery perfectly,
170
+ # according to the thumb size inside the gallery and their padding/margin/border sizes.
171
+ # the number of lines will increase if needed when uploading
172
+ f.images_upload :illustrations, {
173
+ :thumbnail => {
174
+ :width => 100,
175
+ :height => 70
176
+ },
177
+ :gallery => {
178
+ :columns => 8, # number of columns
179
+ :lines => 2, # number of lines
180
+ :vpadding => 2, # vertical padding around each thumb
181
+ :hpadding => 2, # horizontal one
182
+ :vmargin => 3, # vertical margin
183
+ :hmargin => 1, # horizontal one
184
+ :border_thickness => 2 # border size around each thumb
185
+ }
186
+ }
187
+ end
188
+
189
+ With Formtastic, pass
190
+
191
+ :as => (:image_upload | :images_upload | :asset_upload | :assets_upload)
192
+ And add your options as you would with the normal helpers.
89
193
 
90
- FormHelpers
194
+ With FormTagHelpers, use (image_upload_tag | images_upload_tag | asset_upload_tag | assets_upload_tag) @assetable, :key, options
195
+
196
+ image_upload_tag @article, :cover_image, :targetted_size => "200x200"
197
+
198
+ For resources not linked to any assetable model, you can use upload_tags without any Assetable
199
+
200
+ image_upload_tag "#{current_organization.name}_logo", :targetted_size => "200x200"
201
+
202
+ === Asset editing
203
+
204
+ * double-click on any uploaded asset in any form-helper to access & edit his properties
205
+ * then double-click image to crop it if it's an image. You'll then access a Jcrop window. Pass :targetted_size => "widthxheigth" to lock aspect-ratio and default the selection size to widthxheigth.
206
+
207
+ === Thumbnails
91
208
 
92
- form_for @article do
93
- f.image_upload :cover_image, options_hash
94
- f.images_upload :illustrations, options_hash
95
- f.asset_upload :pdf, options_hash
96
- f.image_upload :other_resources, options_hash
97
- end
98
209
 
99
- Or with formtastic :
210
+ ==== On-the-fly request time processing:
100
211
 
101
- semantic_form_for @article do |f|
102
- f.input @article, :cover_image, options_hash, :as => :image_upload
103
- f.input @article, :illustrations, options_hash, :as => :images_upload
104
- f.input @article, :pdf, options_hash, :as => :asset_upload
105
- f.input @article, :other_resources, options_hash, :as => :image_upload
106
- end
212
+ PapermillAsset#url(papermill string (see 1.)) # path and url behave the same way
213
+ PapermillAsset#url(papermill alias (see 2.))
214
+
215
+ Pros: fast. Nothing done upon page rendering. If asset isn't found by Apache/NGinx, then request is passed to rails, which will create it, once.
216
+
217
+ Cons: need to setup an alias in the options if you want to define use a hash instead of a papermill string (for custom watermark)
218
+
219
+ ==== Render time processing:
220
+
221
+ PapermillAsset#url!(papermill string (see 1.)) # path! and url! behave the same way
222
+ PapermillAsset#url!(papermill alias (see 2.))
223
+ PapermillAsset#url!(papermill hash (see 3.))
224
+
225
+ Pros: can use a hash directly in the url call.
226
+
227
+ Cons: needs a thumbnail presence check at each render.
228
+
229
+ ==== 1. Papermill String
230
+
231
+ Consist of:
232
+
233
+ * an ImageMagick geometry string (ex: "100x100>", "original", "100x#", etc.)
234
+ * an optional watermark (-wm) flag # will use option[:watemark] for URI
235
+ * an optional copyright (©) flag # will use copyright text after the "©" or options[:copyright]
236
+
237
+ Examples:
107
238
 
108
- FormTagHelpers
239
+ image_tag @article.covers.first.url("100x100")
240
+ image_tag @article.covers.first.url("original©")
241
+ image_tag @article.covers.first.url("100x100#-wm©")
242
+ image_tag @article.covers.first.url("100x200#©papermill")
109
243
 
110
- image_upload_tag @article, :cover_image, options_hash
111
- images_upload_tag @article, :illustrations, options_hash
112
- asset_upload_tag @article, :pdf, options_hash
113
- image_upload_tag @article, :other_resources, options_hash
244
+ ==== 2. Papermill Alias
114
245
 
115
- For resources not linked to any assetable model :
116
- image_upload_tag "#{current_organization.name}_logo", options_hash
246
+ Those are application-wide, set them in the options
247
+
248
+ Consist of:
249
+
250
+ :geometry => "ImageMagick-geometry-string"
251
+ :copyright => true | "copyright" # If true, the asset copyright field will be used. Edit the asset.
252
+ :watermark => URI | true # If true, will use options[:watemark]
253
+
254
+ Examples:
255
+
256
+ #config/initilializers/papermill.rb
257
+
258
+ # snip
259
+ :aliases => {
260
+ :thumb_copyrighted => {
261
+ :geometry => "100x100",
262
+ :copyright => "papermill",
263
+ },
264
+ :thumb_copyrighted_dynamically => {
265
+ :geometry => "100x100",
266
+ :copyright => true
267
+ },
268
+ :thumb_watermarked_with_rails => {
269
+ :width => "100",
270
+ :height => "100",
271
+ :watermark => "/images/rails.png"
272
+ }
273
+ }
274
+
275
+ Then in your views, simply do
276
+
277
+ image_tag @article.covers.first.url(:thumb_copyrighted)
278
+
279
+ ==== 3. Papermill Hash
280
+
281
+ Same as aliases, but defined directly in #url!()
282
+ Plus you can add a :name that will be used for style-name (defaults to a md5 of the hash)
283
+
284
+ Example:
285
+
286
+ image_tag @article.covers.first.url(
287
+ :geometry => "100x100",
288
+ :watermark => "/images/rails.png",
289
+ :copyright => "papermill",
290
+ :name => "thumbnail_watermarked_and_copyrighted"
291
+ )
117
292
 
118
293
  === Resource access
119
294
 
@@ -148,41 +323,9 @@ Or for non-assetable resources :
148
323
  @asset.path("100x>")
149
324
  # etc.
150
325
 
151
- == Installation
152
-
153
- === Once gem is installed :
154
-
155
- Generate the migration :
156
- ./script/generate papermill_table PapermillMigration
157
-
158
- Edit its fields and migrate :
159
- rake db:migrate
160
-
161
- Copy static assets to your public directory:
162
- ./script/generate papermill_assets
163
-
164
- Create the option file config/initializers/papermill.rb
165
- ./script/generate papermill_initializer
166
-
167
- Go have a look to config/initializers/papermill.rb, lots of info there.
168
-
169
- === environment.rb:
170
-
171
- ...
172
- Rails::Initializer.run do |config|
173
- ...
174
- config.gem papermill
175
- end
176
-
177
- === In your layout:
178
-
179
- <%= papermill_stylesheet_tag %>
180
- <%= papermill_javascript_tag :with_jquery => "no_conflict" %>
181
- # you don't need :with_jquery if you already had it loaded.
182
-
183
326
  === Translations:
184
327
 
185
- Papermill is fully I18n-able, except for javascript error messages. (coming)
328
+ Papermill is fully I18n-able.
186
329
  Copy config/locales/papermill.yml to your root config/locale folder to modify any wording in a any locale.
187
330
 
188
331
  Copyright (c) 2009 Benoit Bénézech, released under the MIT license
data/TODO.txt CHANGED
@@ -1,6 +0,0 @@
1
- Edit views :
2
- * try Picnic API
3
- * trad errors
4
- * migration with/whithout url_key
5
-
6
- Errors on asset #create (to handle Paperclip validation)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.6
1
+ 1.4.0
@@ -36,14 +36,15 @@ class PapermillController < ApplicationController
36
36
  @asset = params[:asset_class].constantize.new(params.reject{|k, v| !(PapermillAsset.columns.map(&:name)+["Filedata", "Filename"]).include?(k)})
37
37
  if @asset.save
38
38
  @old_asset.destroy if @old_asset
39
+ output = render_to_string(:partial => "papermill/asset", :object => @asset, :locals => { :gallery => params[:gallery], :thumbnail_style => params[:thumbnail_style], :targetted_geometry => params[:targetted_geometry] })
39
40
  render :update do |page|
40
- page.replace params[:Fileid], :partial => "papermill/asset", :object => @asset, :locals => { :gallery => params[:gallery], :thumbnail_style => params[:thumbnail_style], :targetted_geometry => params[:targetted_geometry] }
41
- page.remove "papermill_asset_#{@old_asset.id}" if @old_asset
41
+ page << %{ jQuery('##{params[:Fileid]}').replaceWith('#{escape_javascript output}'); }
42
+ page << %{ jQuery('#papermill_asset_#{@old_asset.id}').remove() } if @old_asset
42
43
  end
43
44
  else
44
45
  page << %{ notify("#{@asset.name}", @asset.errors.full_messages.join('<br />'), "error"); }
45
- page.remove params[:Fileid]
46
- page.show "papermill_asset_#{@old_asset.id}" if @old_asset
46
+ page << %{ jQuery('##{params[:Fileid]}').remove() }
47
+ page << %{ jQuery('#papermill_asset_#{@old_asset.id}').show() } if @old_asset
47
48
  end
48
49
  end
49
50
 
@@ -111,7 +111,7 @@ module Papermill
111
111
  # To remove an option when overriding, set it to nil.
112
112
 
113
113
  :swfupload => {
114
- # :flash_url => "'/papermill/swfupload.swf'",
114
+ # :flash_url => "'/swfupload/swfupload.swf'",
115
115
  # :button_image_url => "'/papermill/images/upload-blank.png'",
116
116
  # :button_width => 61,
117
117
  # :button_height => 22,
@@ -230,8 +230,7 @@ module Papermill
230
230
  # :authorize_update_and_destroy => "true",
231
231
 
232
232
  # For example, this is my own setup.
233
- # You'll need a public ApplicationController#current_user,
234
- # adapt the authorization part (can_edit(Assetable)) to your own needs :
233
+ # adapt the authorization part (can_edit(Assetable)) to your own authorization solution
235
234
 
236
235
  # :authorize_create => %{
237
236
  # unless @assetable.nil? || current_user.can_edit?(@assetable)
@@ -3,27 +3,25 @@
3
3
  module PapermillHelper
4
4
 
5
5
  # Sets all the javascript needed for papermill.
6
- # If jQuery and JQueryUI (with Sortable included) are already loaded, call papermill_javascript_tag
7
- # If you don't use jQuery at all or use some other library, call papermill_javascript_tag(:with_jquery => "no_conflict")
8
- # If you want to rely on this helper to load jQuery and use it, call papermill_javascript_tag(:with_jquery => true)
9
- # If jQuery is loaded, load only jQueryUI-Sortable with papermill_javascript_tag(:with_jqueryui_only => true)
6
+ # If jQuery and JQueryUI (with Sortable) are already loaded, call papermill_javascript_tag
7
+ # If you use some other JS Framework, call papermill_javascript_tag(:with_jquery => "no_conflict")
8
+ # If you want to rely on this helper to load jQuery and JQueryUI and use them after, call papermill_javascript_tag(:with_jquery => true)
9
+
10
10
  def papermill_javascript_tag(options = {})
11
11
  html = []
12
+ html << %{<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js" type="text/javascript"></script>\
13
+ <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js" type="text/javascript"></script>} if options[:with_jquery]
12
14
  html << %{<script type="text/javascript">}
13
- ["SWFUPLOAD_PENDING", "SWFUPLOAD_LOADING"].each do |js_constant|
15
+ ["SWFUPLOAD_PENDING", "SWFUPLOAD_LOADING"].each do |js_constant|
14
16
  html << %{var #{escape_javascript js_constant} = "#{t("papermill.#{escape_javascript js_constant}")}";}
15
17
  end
18
+ html << %{jQuery.noConflict();} if options[:with_jquery].to_s == "no_conflict"
16
19
  html << %{</script>}
17
- html << javascript_include_tag([options[:with_jquery] && "/papermill/jquery-1.3.2.min.js", (options[:with_jquery] || options[:with_jqueryui_only]) && "/papermill/jquery-ui-1.7.2.custom.min.js", "/facebox/facebox.js", "/jgrowl/jquery.jgrowl_minimized.js", "/papermill/jquery.Jcrop.min.js", "/papermill/swfupload.js", "/papermill/papermill.js"].compact, :cache => "papermill")
18
- html << %{<script type="text/javascript">jQuery.noConflict();</script>} if options[:with_jquery].to_s == "no_conflict"
20
+ html << javascript_include_tag("/facebox/facebox.js", "/jgrowl/jquery.jgrowl_minimized.js", "/Jcrop/jquery.Jcrop.min.js", "/swfupload/swfupload.js", "/papermill/papermill.js", :cache => "papermill")
19
21
  unless @content_for_papermill_inline_js.blank?
20
- html << '<script type="text/javascript">'
21
- html << '//<![CDATA['
22
- html << 'jQuery(document).ready(function() {'
23
- html << @content_for_papermill_inline_js
24
- html << '});'
25
- html << '//]]>'
26
- html << '</script>'
22
+ html << %{<script type="text/javascript">}
23
+ html << %{jQuery(document).ready(function() {#{@content_for_papermill_inline_js}});}
24
+ html << %{</script>}
27
25
  end
28
26
  html.join("\n")
29
27
  end
@@ -31,7 +29,7 @@ module PapermillHelper
31
29
  # Sets the css tags needed for papermill.
32
30
  def papermill_stylesheet_tag(options = {})
33
31
  html = []
34
- html << stylesheet_link_tag("/facebox/facebox.css", "/jgrowl/jquery.jgrowl.css", "/papermill/jquery.Jcrop.css", "/papermill/papermill.css", :cache => "papermill")
32
+ html << stylesheet_link_tag("/facebox/facebox.css", "/jgrowl/jquery.jgrowl.css", "/Jcrop/jquery.Jcrop.css", "/papermill/papermill.css", :cache => "papermill")
35
33
  unless @content_for_papermill_inline_css.blank?
36
34
  html << %{<style type="text/css">}
37
35
  html << @content_for_papermill_inline_css
@@ -31,7 +31,7 @@ module Papermill
31
31
  :style => nil
32
32
  },
33
33
  :swfupload => {
34
- :flash_url => "'/papermill/swfupload.swf'",
34
+ :flash_url => "'/swfupload/swfupload.swf'",
35
35
  :button_image_url => "'/papermill/images/upload-blank.png'",
36
36
  :button_width => 61,
37
37
  :button_height => 22,
data/public/.DS_Store CHANGED
Binary file
File without changes
@@ -5,7 +5,7 @@
5
5
  {
6
6
  font-size: 0;
7
7
  position: absolute;
8
- background: white url('images/Jcrop.gif') top left repeat;
8
+ background: white url('/Jcrop/images/Jcrop.gif') top left repeat;
9
9
  }
10
10
  .jcrop-vline { height: 100%; width: 1px !important; }
11
11
  .jcrop-hline { width: 100%; height: 1px !important; }