papermill 1.1.6 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  * Formtastic # use :as => :[image|asset](s)_upload
20
20
  * JGrowl # for notifications (included)
21
- * FaceBox/Shadowbox # for popups (included)
21
+ * FaceBox # for popups (included)
22
22
  * Stringex # (or any String#to_url) for asset filename/url generation
23
23
 
24
24
  === Navigator minimal requirements:
@@ -183,7 +183,7 @@ Create the option file config/initializers/papermill.rb
183
183
 
184
184
  === Translations:
185
185
 
186
- Papermill is fully I18n-able.
186
+ Papermill is fully I18n-able, except for javascript error messages. (coming)
187
187
  Copy config/locales/papermill.yml to your root config/locale folder to modify any wording in a any locale.
188
188
 
189
189
  Copyright (c) 2009 Benoit Bénézech, released under the MIT license
data/TODO.txt CHANGED
@@ -1,4 +1,5 @@
1
1
  Edit views :
2
2
  * use Jcrop
3
3
  * try Picnic API
4
- * trad errors
4
+ * trad errors
5
+ * migration with/whithout url_key
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.6
1
+ 1.2.0
@@ -1,12 +1,12 @@
1
1
  class PapermillController < ApplicationController
2
- prepend_before_filter :load_asset, :only => [ "show", "destroy", "update", "edit", "crop" ]
3
- prepend_before_filter :load_assets, :only => [ "sort", "mass_delete", "mass_edit" ]
2
+ prepend_before_filter :load_asset, :only => [ "show", "destroy", "update", "edit", "crop" ]
3
+ prepend_before_filter :load_assets, :only => [ "sort", "mass_delete", "mass_edit", "mass_thumbnail_reset" ]
4
4
 
5
5
  def show
6
- if @asset.create_thumb_file(params[:style])
6
+ if @asset.has_valid_url_key?(params[:url_key], params[:style]) && @asset.create_thumb_file(params[:style])
7
7
  redirect_to @asset.url(params[:style])
8
8
  else
9
- render :nothing => true, :status => 500
9
+ render :nothing => true, :status => 404
10
10
  end
11
11
  end
12
12
 
@@ -29,6 +29,10 @@ class PapermillController < ApplicationController
29
29
  end
30
30
 
31
31
  def update
32
+ if params[:target]
33
+ @asset.create_thumb_file(params[:target], params[:papermill_asset].merge({ :geometry => "original#" }))
34
+ end
35
+
32
36
  render :update do |page|
33
37
  if @asset.update_attributes(params[:papermill_asset])
34
38
  page << %{ notify("#{@asset.name}", "#{ escape_javascript t("papermill.updated", :resource => @asset.name)}", "notice"); close_popup(self); }
@@ -67,6 +71,13 @@ class PapermillController < ApplicationController
67
71
  end
68
72
  end
69
73
 
74
+ def mass_thumbnail_reset
75
+ @assets.each &:destroy_thumbnails
76
+ render :update do |page|
77
+ page << %{ notify("", "#{ escape_javascript t("papermill.updated", :resource => @assets.map(&:name).to_sentence) }", "notice"); } unless @assets.blank?
78
+ end
79
+ end
80
+
70
81
  private
71
82
  def load_asset
72
83
  @asset = PapermillAsset.find(params[:id] || (params[:id0] + params[:id1] + params[:id2]).to_i)
@@ -2,7 +2,7 @@
2
2
  <input type="hidden" value="put" name="_method"/>
3
3
  <div id="error" style="display:none;"></div>
4
4
  <% fields_for :papermill_asset, @asset do |form| %>
5
- <% @asset.assetable_papermill_options[:editable_fields].each do |field| %>
5
+ <% @asset.papermill_options[:editable_fields].each do |field| %>
6
6
  <% key = field.keys.first %>
7
7
  <p>
8
8
  <%= form.label key, field[key][:label] || t("papermill.#{key}") %><br />
@@ -1,6 +1,5 @@
1
1
  <%= image_tag(@asset.url, :id => "cropbox") %>
2
2
 
3
- <!--
4
3
  <form onsubmit="jQuery.ajax({data:jQuery.param(jQuery(this).serializeArray()), dataType:'script', type:'post', url:'/papermill/<%= @asset.id %>'}); return false;" method="post">
5
4
  <input type="hidden" value="put" name="_method"/>
6
5
  <input type="hidden" value="<%= params[:target] %>" name="target"/>
@@ -8,14 +7,14 @@
8
7
  <% for attribute in [:crop_x, :crop_y, :crop_w, :crop_h] %>
9
8
  <%= f.hidden_field attribute, :id => attribute %>
10
9
  <% end %>
11
- <%= submit_tag t('papermill.save') %>
10
+ <%= submit_tag I18n.t('papermill.save') %>
12
11
  <% end -%>
13
12
  </form>
14
- -->
13
+
15
14
  <div style="margin:6px"></div>
16
15
  <%= link_to_function I18n.t("papermill.back"), "popup('#{edit_papermill_path(@asset)}')" %>
17
16
 
18
- <script type="text/javascript" charset="utf-8">/*
17
+ <script type="text/javascript" charset="utf-8">
19
18
  jQuery(function() {
20
19
  jQuery('#cropbox').Jcrop({
21
20
  onChange: update_crop,
@@ -30,5 +29,5 @@
30
29
  jQuery("#crop_y").val(coords.y);
31
30
  jQuery("#crop_w").val(coords.w);
32
31
  jQuery("#crop_h").val(coords.h);
33
- }*/
32
+ }
34
33
  </script>
@@ -1,8 +1,8 @@
1
1
  <div id="papermill-box">
2
2
  <div id="left">
3
3
  <% if @asset.image? %>
4
- <%= link_to image_tag(@asset.url("400x400>")), @asset.url, :popup => true %>
5
- <%# image_tag(@asset.url("400x400>"), :onDblClick => "popup('#{crop_papermill_path(@asset, :target => "original")}'); return false;", :title => I18n.t("papermill.thumbnail-edit-title", :resource => @asset.name)) %>
4
+ <%# link_to image_tag(@asset.url("400x400>")), @asset.url, :popup => true %>
5
+ <%= image_tag(@asset.url("400x400>"), :onDblClick => "popup('#{crop_papermill_path(@asset, :target => "original")}'); return false;", :title => I18n.t("papermill.thumbnail-edit-title", :resource => @asset.name)) %>
6
6
  <div style="clear:both;"></div>
7
7
  <% else %>
8
8
  <%= link_to t("file_type", :type => @asset.content_type, :scope => 'papermill'), @asset.url, :popup => true %>
@@ -15,8 +15,8 @@
15
15
  <tr><td class="left-cell"><%= t("papermill.content_type") %></td><td><%= @asset.content_type %></td></tr>
16
16
  <tr><td class="left-cell"><%= t("papermill.size") %> </td><td><%= number_to_human_size(@asset.size.to_i) %></td></tr>
17
17
  <% if @asset.image? %>
18
- <tr><td class="left-cell"><%= t("papermill.width") %> </td><td><%= @asset.width.to_i %>px</td></tr>
19
- <tr><td class="left-cell"><%= t("papermill.height") %> </td><td><%= @asset.height.to_i %>px</td></tr>
18
+ <tr><td class="left-cell"><%= t("papermill.width") %> </td><td><%= @asset.width.to_i %>px</td></tr>
19
+ <tr><td class="left-cell"><%= t("papermill.height") %> </td><td><%= @asset.height.to_i %>px</td></tr>
20
20
  <% end %>
21
21
  <tr><td class="left-cell"><%= t("papermill.created_at") %> </td><td><%= I18n.l(@asset.created_at) %></td></tr>
22
22
  <tr><td class="left-cell"><%= t("papermill.updated_at") %> </td><td><%= I18n.l(@asset.updated_at) %></td></tr>
@@ -29,7 +29,6 @@
29
29
 
30
30
  <div style="clear:both;"></div>
31
31
  <p id="footer">
32
- <%= t("papermill.location") + @asset.file.path %><br />
33
- <%= t("papermill.url") + @asset.url %>
32
+ <%= t("papermill.url") + link_to(@asset.url, @asset.url, :popup => true) %>
34
33
  </p>
35
34
  </div>
@@ -2,7 +2,7 @@ en:
2
2
  papermill:
3
3
  not-processed: "Error/resource not processed"
4
4
  updated: "'{{resource}}' updated"
5
- not-found: "Asset #{{resource}} not found"
5
+ not-found: "'#{{resource}}' not found"
6
6
  edit-title: "Click to edit '{{resource}}'"
7
7
  thumbnail-edit-title: "Double-click to edit '{{resource}}'"
8
8
  upload-button-wording: "Upload..."
@@ -25,16 +25,17 @@ en:
25
25
  height: "Height"
26
26
  save: "Save"
27
27
  back: "Back"
28
- location: "File : "
29
28
  url: "URL : "
30
29
  modify-all: "Modify all: "
31
30
  delete-all: "Delete all"
32
31
  delete-all-confirmation: "Are you sure?"
32
+ mass-thumbnail-reset: "Delete all thumbnails"
33
+ mass-thumbnail-reset-confirmation: "Are you sure?"
33
34
  fr:
34
35
  papermill:
35
36
  not-processed: "Erreur/resource non trouvée"
36
- updated: "{{resource}} modifiés(s)"
37
- not-found: "Asset #{{resource}} non trouvé"
37
+ updated: "'{{resource}}' modifiés(s)"
38
+ not-found: "'{{resource}}' non trouvé"
38
39
  edit-title: "Cliquer pour éditer '{{resource}}'"
39
40
  thumbnail-edit-title: "Double-cliquer pour éditer '{{resource}}'"
40
41
  upload-button-wording: "Charger.."
@@ -57,8 +58,9 @@ fr:
57
58
  height: "Hauteur"
58
59
  save: "Modifier"
59
60
  back: "Retour"
60
- location: "Fichier : "
61
61
  url: "Lien : "
62
62
  modify-all: "Modifier tout : "
63
63
  delete-all: "Supprimer tout"
64
64
  delete-all-confirmation: "Êtes-vous sûr ?"
65
+ mass-thumbnail-reset: "Supprimer tous les thumbnails"
66
+ mass-thumbnail-reset-confirmation: "Êtes-vous sûr ?"
data/config/routes.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  ActionController::Routing::Routes.draw do |map|
2
- map.resources :papermill, :collection => { :sort => :post, :mass_edit => :post, :mass_delete => :post }, :member => { :crop => :get }
3
- map.connect "#{Papermill::options[:papermill_prefix]}/#{Papermill::PAPERCLIP_INTERPOLATION_STRING.gsub(":id_partition", ":id0/:id1/:id2")}", :controller => "papermill", :action => "show"
2
+ map.resources :papermill, :collection => { :sort => :post, :mass_edit => :post, :mass_delete => :post, :mass_thumbnail_reset => :post }, :member => { :crop => :get }
3
+ map.connect "#{Papermill::options[:papermill_url_prefix]}/#{Papermill::compute_paperclip_path.gsub(":id_partition", ":id0/:id1/:id2")}", :controller => "papermill", :action => "show", :requirements => { :style => /.*/ }
4
4
  end
@@ -55,4 +55,4 @@ module StringToUrlNotFound
55
55
  def to_url
56
56
  gsub(/[^a-zA-Z0-9]/, "-").gsub(/-+/, "-").gsub(/^-|-$/, "").downcase
57
57
  end
58
- end
58
+ end
@@ -45,7 +45,7 @@ module ActionView::Helpers::FormTagHelper
45
45
  assetable = options[:assetable] || @template.instance_variable_get("@#{@object_name}")
46
46
  assetable_id = assetable && (assetable.id || assetable.timestamp) || nil
47
47
  assetable_type = assetable && assetable.class.base_class.name || nil
48
- options = PapermillAsset.assetable_papermill_options(assetable && assetable.class.name, key).deep_merge(options)
48
+ options = PapermillAsset.papermill_options(assetable && assetable.class.name, key).deep_merge(options)
49
49
  dom_id = "papermill_#{assetable_type}_#{assetable_id}_#{key}"
50
50
 
51
51
  if ot = options[:thumbnail]
@@ -71,6 +71,7 @@ module ActionView::Helpers::FormTagHelper
71
71
  %{<option value="#{field.to_s}">#{I18n.t("papermill.#{field.to_s}", :default => field.to_s)}</option>}
72
72
  end.join("\n")}</select>}
73
73
  html[:dashboard][:mass_delete] = %{<a onclick="Papermill.mass_delete('#{dom_id}', '#{@template.escape_javascript I18n.t("papermill.delete-all-confirmation")}'); return false;" style="cursor:pointer">#{I18n.t("papermill.delete-all")}</a>}
74
+ html[:dashboard][:mass_thumbnail_reset] = %{<a onclick="Papermill.mass_thumbnail_reset('#{dom_id}', '#{@template.escape_javascript I18n.t("papermill.mass-thumbnail-reset-confirmation")}'); return false;" style="cursor:pointer">#{I18n.t("papermill.mass-thumbnail-reset")}</a>}
74
75
  html[:dashboard] = @template.content_tag(:ul, options[:dashboard].map{|action| @template.content_tag(:li, html[:dashboard][action], :class => action.to_s) }.join("\n"), :class => "dashboard")
75
76
  end
76
77
 
@@ -131,7 +132,7 @@ module ActionView::Helpers::FormTagHelper
131
132
  upload_success_handler: Papermill.upload_success,
132
133
  upload_complete_handler: Papermill.upload_complete,
133
134
  button_placeholder_id: "browse_for_#{dom_id}",
134
- #{ options[:swfupload].map { |key, value| "#{key}: #{(value.is_a?(String) ? "\"#{@template.escape_javascript(value)}\"" : @template.escape_javascript(value.to_s))}" if value }.compact.join(",\n") }
135
+ #{ options[:swfupload].map { |key, value| "#{key}: #{value}" if value }.compact.join(",\n") }
135
136
  });
136
137
  }
137
138
  end
@@ -1,5 +1,4 @@
1
1
  module Papermill
2
- PAPERCLIP_INTERPOLATION_STRING = ":id_partition/:style/:basename.:extension"
3
2
 
4
3
  def self.included(base)
5
4
  base.extend(ClassMethods)
@@ -9,6 +8,14 @@ module Papermill
9
8
  @options ||= BASE_OPTIONS.deep_merge(defined?(OPTIONS) ? OPTIONS : {})
10
9
  end
11
10
 
11
+ def self.compute_paperclip_path
12
+ path = []
13
+ path << (options[:use_id_partition] ? ":id_partition" : ":id")
14
+ path << (":url_key" if options[:use_url_key])
15
+ path << ":style"
16
+ path << ":basename.:extension"
17
+ path.compact.join("/")
18
+ end
12
19
 
13
20
  module ClassMethods
14
21
  attr_reader :papermill_associations
@@ -36,8 +43,8 @@ module Papermill
36
43
  scope
37
44
  end
38
45
  end
39
- ActionController::Dispatcher.middleware.delete(FlashSessionCookieMiddleware) rescue nil
40
- ActionController::Dispatcher.middleware.insert_before(ActionController::Base.session_store, FlashSessionCookieMiddleware, ActionController::Base.session_options[:key]) rescue nil
46
+ ActionController::Dispatcher.middleware.delete(FlashSessionCookieMiddleware) rescue true
47
+ ActionController::Dispatcher.middleware.insert_before(ActionController::Base.session_store, FlashSessionCookieMiddleware, ActionController::Base.session_options[:key]) rescue true
41
48
  end
42
49
 
43
50
  def inherited(subclass)
@@ -5,8 +5,8 @@ class PapermillAsset < ActiveRecord::Base
5
5
 
6
6
  has_attached_file :file,
7
7
  :processors => [:papermill_paperclip_processor],
8
- :path => "#{Papermill::options[:public_root]}/#{Papermill::options[:papermill_prefix]}/#{Papermill::PAPERCLIP_INTERPOLATION_STRING}",
9
- :url => "/#{Papermill::options[:papermill_prefix]}/#{Papermill::PAPERCLIP_INTERPOLATION_STRING}"
8
+ :url => "/#{Papermill::options[:papermill_url_prefix]}/#{Papermill::compute_paperclip_path.gsub(':style', ':escaped_style')}",
9
+ :path => "#{Papermill::options[:public_root]}/#{Papermill::options[:papermill_path_prefix]}/#{Papermill::compute_paperclip_path}"
10
10
 
11
11
  before_post_process :set_file_name
12
12
 
@@ -17,6 +17,14 @@ class PapermillAsset < ActiveRecord::Base
17
17
 
18
18
  named_scope :key, lambda { |assetable_key| { :conditions => ['assetable_key = ?', assetable_key.to_s] }}
19
19
 
20
+ Paperclip.interpolates :url_key do |attachment, style|
21
+ attachment.instance.compute_url_key((style || "original").to_s)
22
+ end
23
+
24
+ Paperclip.interpolates :escaped_style do |attachment, style|
25
+ CGI::escape((style || "original").to_s)
26
+ end
27
+
20
28
  attr_accessor :crop_h, :crop_w, :crop_x, :crop_y
21
29
 
22
30
  def Filedata=(data)
@@ -27,12 +35,7 @@ class PapermillAsset < ActiveRecord::Base
27
35
  def Filename=(name)
28
36
  @real_file_name = name
29
37
  end
30
-
31
- def create_thumb_file(style_name)
32
- FileUtils.mkdir_p File.dirname(file.path(style_name))
33
- FileUtils.mv(Paperclip::PapermillPaperclipProcessor.make(file, self.class.compute_style(style_name)).path, file.path(style_name))
34
- end
35
-
38
+
36
39
  def id_partition
37
40
  ("%09d" % self.id).scan(/\d{3}/).join("/")
38
41
  end
@@ -50,11 +53,11 @@ class PapermillAsset < ActiveRecord::Base
50
53
  end
51
54
 
52
55
  def width
53
- Paperclip::Geometry.from_file(file).width
56
+ @width ||= Paperclip::Geometry.from_file(file).width
54
57
  end
55
58
 
56
59
  def height
57
- Paperclip::Geometry.from_file(file).height
60
+ @height ||= Paperclip::Geometry.from_file(file).height
58
61
  end
59
62
 
60
63
  def size
@@ -62,18 +65,34 @@ class PapermillAsset < ActiveRecord::Base
62
65
  end
63
66
 
64
67
  def url(style = nil)
65
- file.url(style && CGI::escape(style.to_s))
68
+ return url!(style) if style.is_a?(Hash)
69
+ file.url(style)
66
70
  end
67
71
 
68
72
  def path(style = nil)
73
+ return path!(style) if style.is_a?(Hash)
69
74
  file.path(style)
70
75
  end
71
76
 
77
+ def url!(style = nil)
78
+ create_thumb_file(style_name = style_name(style), style) unless File.exists?(self.path(style_name))
79
+ file.url(style_name)
80
+ end
81
+
82
+ def path!(style = nil)
83
+ create_thumb_file(style_name = style_name(style), style) unless File.exists?(self.path(style_name))
84
+ file.path(style_name)
85
+ end
86
+
72
87
  def content_type
73
88
  file_content_type
74
89
  end
75
90
 
76
- def self.assetable_papermill_options(assetable_class, assetable_key)
91
+ def style_name(style)
92
+ style.is_a?(Hash) ? (style[:name] || style.hash).to_s : (style || "original").to_s
93
+ end
94
+
95
+ def self.papermill_options(assetable_class, assetable_key)
77
96
  if assetable_class
78
97
  assoc = assetable_class.constantize.papermill_associations
79
98
  assoc[assetable_key.try(:to_sym)] || assoc[Papermill::options[:base_association_name]]
@@ -82,19 +101,50 @@ class PapermillAsset < ActiveRecord::Base
82
101
  end
83
102
  end
84
103
 
85
- def assetable_papermill_options
86
- self.class.assetable_papermill_options(assetable_type, assetable_key)
104
+ def papermill_options
105
+ self.class.papermill_options(assetable_type, assetable_key)
87
106
  end
88
107
 
89
108
  def image?
90
109
  content_type.split("/")[0] == "image"
91
110
  end
92
111
 
93
- def self.cleanup
112
+ def create_thumb_file(style_name, style = nil)
113
+ destroy_thumbnails if style_name.to_s == "original"
114
+ style = self.class.compute_style(style_name) unless style.is_a?(Hash)
115
+ FileUtils.mkdir_p File.dirname(file.path(style_name))
116
+ FileUtils.mv(Paperclip::PapermillPaperclipProcessor.make(file, style).path, file.path(style_name))
117
+ end
118
+
119
+ def destroy_thumbnails
120
+ thumbnail_folder_mask = Papermill::options[:use_url_key] ? "*/*/" : "*/"
121
+ original_folder = "#{File.dirname(file.path)}/"
122
+ Dir.glob("#{root_directory}/#{thumbnail_folder_mask}").each do |f|
123
+ FileUtils.rm_r(f) unless f == original_folder
124
+ end
125
+ Dir.glob("#{root_directory}/*/").each do |f|
126
+ FileUtils.rm_r(f) if Dir.entries(f) == [".", ".."]
127
+ end
128
+ end
129
+
130
+ def self.destroy_orphans
94
131
  self.all(:conditions => ["id < 0 AND created_at < ?", DateTime.now.yesterday]).each &:destroy
95
132
  end
96
133
 
134
+ def compute_url_key(style)
135
+ Papermill::options[:url_key_generator].call(style, self)
136
+ end
137
+
138
+ def has_valid_url_key?(key, style)
139
+ !Papermill::options[:use_url_key] || compute_url_key(style) == key
140
+ end
141
+
97
142
  private
143
+
144
+ def root_directory
145
+ deepness_to_root = Papermill::options[:use_url_key] ? -3 : -2
146
+ @root_directory ||= File.dirname(path).split('/')[0..deepness_to_root].join('/')
147
+ end
98
148
 
99
149
  def set_file_name
100
150
  return if @real_file_name.blank?
@@ -107,7 +157,7 @@ class PapermillAsset < ActiveRecord::Base
107
157
  end
108
158
 
109
159
  def destroy_files
110
- FileUtils.rm_r(File.dirname(path).chomp("original")) rescue true
160
+ FileUtils.rm_r(root_directory) rescue true
111
161
  end
112
162
 
113
163
  def self.compute_style(style)
@@ -1,39 +1,29 @@
1
- # DO NOT MOVE OR RENAME THIS FILE.
2
- # It must stand in your RAILS_ROOT/config/initializer folder and be named papermill.rb, because it is explicitely early-loaded by Papermill.
1
+ # DO NOT MOVE OR RENAME THIS FILE
2
+ # It must stand in your RAILS_ROOT/config/initializer folder and be named papermill.rb, because it is explicitely early-loaded by Papermill
3
+
3
4
  module Papermill
4
5
 
5
- # All the options here already are papermill defaults. You can set them :
6
- #
7
- # * here
8
- #
9
- # * in your association. Ex :
10
- # class Article < ActiveRecord::Base
11
- # papermill :diaporama, {
12
- # :class_name => "MyAssetClass",
13
- # :inline_css => false,
14
- # :thumbnail => {:width => 150},
15
- # ...
16
- # }
17
- # end
18
- #
19
- # * in your form helper call. Ex :
20
- # form.image_upload :diaporama, :class_name => "MyAssetClass", :thumbnail => {:width => 150}, :inline_css => false
21
- #
22
- #
23
- # FormHelper options-hash merges with model papermill declaration option-hash, that merges with this Papermill::OPTIONS, that merge with Papermill::DEFAULT_OPTIONS hash.
24
- # Don't freak-out, there's a 99% chance that it is exactly what you expect it to do.
25
- # Merges are recursive (for :gallery, :thumbnail and :swfupload sub-hashs)
26
-
6
+ # All options here already are defaults.
7
+
27
8
  unless defined?(OPTIONS)
28
9
 
29
10
  OPTIONS = {
30
- # Associated PapermillAsset subclass
11
+
12
+ #@@@@@@@@@@@@@@@@@@@ papermill association parameters @@@@@@@@@@@@@@@@@@@@@@@
13
+
14
+ # You can override these parameters here, or in your papermill associations definition.
15
+
16
+ # Associated PapermillAsset subclass (must be STI subclass of PapermillAsset)
31
17
  # :class_name => "PapermillAsset",
32
-
33
- # Helper will generates some inline css styling. You can use it to scaffold, then copy the lines you need in your application css and set it to false.
18
+
19
+ #@@@@@@@@@@@@@@@@@@@ form-helper parameters @@@@@@@@@@@@@@@@@@@@@@@
20
+
21
+ # You can override all these parameters here, or in your papermill associations definition, or in form-helper calls.
22
+
23
+ # Helper can generates inline css styling that adapt to your gallery/images placeholder. You can use it to scaffold, then copy the lines you need in your application css and set it to false.
34
24
  # :inline_css => true,
35
25
 
36
- # SwfUpload will only let the user upload images.
26
+ # SwfUpload will only let the user upload images.
37
27
  # :images_only => false,
38
28
 
39
29
  # Dashboard is only for galleries
@@ -43,12 +33,13 @@ module Papermill
43
33
 
44
34
  # Dashboard elements
45
35
  # You can remove/change order of HTML elements.
46
- # :dashboard => [:mass_edit, :mass_delete],
36
+ # :dashboard => [:mass_edit, :mass_thumbnail_reset, :mass_delete ],
47
37
 
48
38
  # Attributes editable at once for all assets in a gallery
49
39
  # :mass_editable_fields => ["title", "copyright", "description"],
50
40
 
51
- # Attributes you can edit in the form. You can use :type and :label
41
+ # Attributes you can edit in the form. You can use :type (string or text) and :label (any string)
42
+ # if you have more complex needs, you should override app/views/papermill/_form.html.erb in your application.
52
43
  # :editable_fields => [
53
44
  # {:title => {:type => "string"}},
54
45
  # {:alt => {:type => "string"}},
@@ -61,19 +52,19 @@ module Papermill
61
52
  # Great for quick admin scaffolding.
62
53
 
63
54
  :gallery => {
64
- # override calculated gallery width. Ex: "auto"
55
+ # override calculated gallery width. Ex: "auto"
65
56
  # :width => nil,
66
- # override calculated gallery height
57
+ # override calculated gallery height
67
58
  # :height => nil,
68
- # Number of columns and lines in a gallery
59
+ # Number of columns and lines in a gallery
69
60
  # :columns => 8,
70
61
  # :lines => 2,
71
- # vertical/horizontal padding/margin around each thumbnails
62
+ # vertical/horizontal padding/margin around each thumbnails
72
63
  # :vpadding => 0,
73
64
  # :hpadding => 0,
74
65
  # :vmargin => 1,
75
66
  # :hmargin => 1,
76
- # border around thumbnails
67
+ # border around thumbnails
77
68
  # :border_thickness => 2
78
69
  },
79
70
 
@@ -93,40 +84,101 @@ module Papermill
93
84
  # To remove an option when overriding, set it to nil.
94
85
 
95
86
  :swfupload => {
96
- # :flash_url => '/papermill/swfupload.swf',
97
- # :button_image_url => '/papermill/images/upload-blank.png',
87
+ # :flash_url => "'/papermill/swfupload.swf'",
88
+ # :button_image_url => "'/papermill/images/upload-blank.png'",
98
89
  # :button_width => 61,
99
90
  # :button_height => 22,
100
- # :button_text => %{<span class="button-text">#{I18n.t("papermill.upload-button-wording")}</span>},
101
- # :button_text_style => %{.button-text { font-size: 12pt; font-weight: bold; }},
91
+ # :button_text => %{'<span class="button-text">#{I18n.t("papermill.upload-button-wording")}</span>'},
92
+ # :button_text_style => %{'.button-text { font-size: 12pt; font-weight: bold; }'},
102
93
  # :button_text_top_padding => 4,
103
94
  # :button_text_left_padding => 4,
104
95
  # :debug => false,
105
96
  # :prevent_swf_caching => true,
106
- # :file_size_limit => "10 MB"
97
+ # :file_size_limit => "'10 MB'"
107
98
  },
108
99
 
109
- # APPLICATION WIDE PARAMETERS
110
- # Do not change these in your model declaration or form helper call.
100
+ #@@@@@@@@@@@@@@@@@@@ thumbnails style parameters @@@@@@@@@@@@@@@@@@@@@@@
101
+
102
+ # You can override all these parameters here, or in your papermill associations definition, or in thumbnail styling hashes.
103
+
104
+ # 1. COPYRIGHT WATERMARKING
105
+
106
+ # Activate with '©' at the end of your geometry string or pass :copyright => "my_copyright" in alias definition
107
+ # Papermill will use, in that order of priority :
108
+ # * copyright found in geometry string AFTER the @
109
+ # * alternatively :copyright in alias/inline definition hash
110
+ # * asset's copyright column (if found)
111
+ # * associated :copyright definition in your Assetable association definition
112
+ # * below :copyright definition
113
+
114
+ # Set this definition to nil if you don't want a global copyright string (likely)
115
+ # :copyright => "Example Copyright",
116
+
117
+ # Textilize, truncate, transform... your copyright before integration
118
+ # :copyright_text_transform => Proc.new {|c| c },
119
+
120
+ # Watermark ImageMagick command string.
121
+ # * %s gets interpolated with above transformed copyright string
122
+ # * DO NOT change the background color!, change the bordercolor instead. (because background color adds to bordercolor I set it to totally transparent)
123
+ # * for both fill (=foreground color) and bordercolor (=background color), the last two octals control alpha (transparency). FF is opaque, 00 is transparent.
124
+ # * remove -bordercolor if you don't want any background
125
+ # * +antialias to REMOVE antialiasing
126
+ # * font-size is pointsize
127
+ # * type 'identify -list font' to get a list of the fonts you can use (ImageMagick will default to Arial/Times if it can't find it)
128
+ # * use -gravity and -geometry for positionning, -geometry +x+y is relative to -gravity's corner/zone
129
+ # * parenthesis are there to isolate the label creation from the compositing (blending) part.
130
+ # * don't touch things you don't understand, you'll save yourself some time
131
+
132
+ # :copyright_im_command => %{ \\( -font Arial-Bold -pointsize 9 -fill '#FFFFFFE0' -border 3 -bordercolor '#50550080' -background '#00000000' label:' %s ' \\) -gravity South-West -geometry +0+0 -composite },
133
+
134
+ # 2. IMAGE WATERMARKING
135
+
136
+ # Activate with "-wm" at the end of your geometry string BEFORE copyright ('©'), or alternatively with :watermark => <image_path|true> in your alias/inline hash
137
+ # If you pass an image_path to :watermark, it will override below :
138
+
139
+ # you can use a relative path from your public directory (see :public_root), a complete path, or an URI
140
+ # :watermark => "/images/rails.png",
141
+
142
+ # default :watermarking command for image_magick. %s gets interpolated with above image path.
143
+ # :watermark_im_command => %{- | composite \\( %s -resize 100% \\) - -dissolve 20% -gravity center -geometry +0+0 },
144
+
145
+ #@@@@@@@@@@@@@@@@@@@@ Application-wide parameters @@@@@@@@@@@@@@@@@@@@@@@@@
111
146
 
112
147
  # Default named_scope name for catch-all :papermill declaration
113
- # :base_association_name => :assets,
148
+ # :base_association_name => :assets,
114
149
 
115
150
  # Set to true to require aliases in all url/path
116
151
  # Don't forget to give an alias value to options[:thumbnail][:style] if true!
117
- # :alias_only => false,
152
+ # :alias_only => false,
118
153
 
119
154
  # Needed if :alias_only
120
155
  :aliases => {
121
- # 'example' => "100x100#",
122
- # 'example2' => {:geometry => "100x100#"}
156
+ # :mini_crop => "100x100#",
157
+ # :cant_touch_this => {
158
+ # :geometry => "400x>",
159
+ # :copyright => "You sire, can't touch this",
160
+ # :watermark => "http://westsidewill.com/newblog/wp-content/uploads/2009/09/MC-Hammer.jpg"
161
+ # }
123
162
  },
124
-
125
- # path to the root of your public directory (from NGINX/Apache pov)
126
- # :public_root => ":rails_root/public",
163
+
164
+ # To prevent generation of thumbnails and guessing of assets location through URL hacking
165
+ # e.g. if you want to protect access to non-copyrighted original files,
166
+ # or don't want users to browse images by guessing the sequence of ids,
167
+ # an encrypted hash can be generated for each geometry string/alias and added to path/url.
168
+ # Please note that all previous assets paths will be lost if you add/remove or change the :url_key generation.
169
+ # :use_url_key => false,
170
+ # :url_key_salt => "change-me-to-your-favorite-pet-name",
171
+ # :url_key_generator => Proc.new { |style, asset| Digest::SHA512.hexdigest("#{style}#{asset.id}#{Papermill::options[:url_key_salt]}")[0..10] },
127
172
 
128
- # added to :public_root as the root folder for all papermill assets
129
- # :papermill_prefix => "system/papermill"
173
+ # added to :public_root as the root folder for all papermill assets (system is a default for static assets with capistrano)
174
+ # :papermill_url_prefix => "system/papermill",
175
+ # :papermill_path_prefix => ":rails_root/public/system/papermill",
176
+
177
+ # you can set it to false if you don't plan to have too many assets. (dangerous)
178
+ # :use_id_partition => true,
179
+
180
+ # If you use those defaults, the first asset will end-up in RAILS_ROOT/public/system/papermill/000/000/001/original/my_first_asset_name.ext
181
+ # You'll access it with my_domain.com/system/papermill/000/000/001/original/my_first_asset_name.ext
130
182
  }
131
183
  end
132
184
  end
@@ -2,8 +2,9 @@ module Papermill
2
2
  BASE_OPTIONS = {
3
3
  :class_name => "PapermillAsset",
4
4
  :inline_css => true,
5
+ :images_only => false,
5
6
  :form_helper_elements => [:upload_button, :container, :dashboard],
6
- :dashboard => [:mass_edit, :mass_delete],
7
+ :dashboard => [:mass_edit, :mass_thumbnail_reset, :mass_delete],
7
8
  :mass_editable_fields => ["title", "copyright", "description"],
8
9
  :editable_fields => [
9
10
  {:title => {:type => "string"}},
@@ -29,23 +30,31 @@ module Papermill
29
30
  :style => nil
30
31
  },
31
32
  :swfupload => {
32
- :flash_url => '/papermill/swfupload.swf',
33
- :button_image_url => '/papermill/images/upload-blank.png',
33
+ :flash_url => "'/papermill/swfupload.swf'",
34
+ :button_image_url => "'/papermill/images/upload-blank.png'",
34
35
  :button_width => 61,
35
36
  :button_height => 22,
36
- :button_text => %{<span class="button-text">#{I18n.t("papermill.upload-button-wording")}</span>},
37
- :button_text_style => %{.button-text { font-size: 12pt; font-weight: bold; }},
37
+ :button_text => %{'<span class="button-text">#{I18n.t("papermill.upload-button-wording")}</span>'},
38
+ :button_text_style => %{'.button-text { font-size: 12pt; font-weight: bold; }'},
38
39
  :button_text_top_padding => 4,
39
- :button_text_left_padding => 4,
40
- :debug => false,
41
- :prevent_swf_caching => true,
42
- :file_size_limit => "10 MB"
40
+ :button_text_left_padding => 4,
41
+ :debug => false,
42
+ :prevent_swf_caching => true,
43
+ :file_size_limit => "'10 MB'"
43
44
  },
44
- :images_only => false,
45
+ :copyright => "Example Copyright",
46
+ :copyright_text_transform => Proc.new {|c| c },
47
+ :copyright_im_command => %{\\( -font Arial-Bold -pointsize 9 -fill '#FFFFFFE0' -border 3 -bordercolor '#50550080' -background '#00000000' label:' %s ' \\) -gravity South-West -geometry +0+0 -composite},
48
+ :watermark => "/images/rails.png",
49
+ :watermark_im_command => %{- | composite \\( %s -resize 100% \\) - -dissolve 20% -gravity center -geometry +0+0 },
45
50
  :base_association_name => :assets,
46
51
  :alias_only => false,
47
52
  :aliases => {},
48
- :public_root => ":rails_root/public",
49
- :papermill_prefix => "system/papermill"
53
+ :use_url_key => false,
54
+ :url_key_salt => "change-me-please",
55
+ :url_key_generator => Proc.new { |style, asset| Digest::SHA512.hexdigest("#{style}#{asset.id}#{Papermill::options[:url_key_salt]}")[0..10] },
56
+ :use_id_partition => true,
57
+ :papermill_url_prefix => "system/papermill",
58
+ :papermill_path_prefix => ":rails_root/public/system/papermill",
50
59
  }
51
60
  end
@@ -3,33 +3,41 @@ module Paperclip
3
3
  # Handles thumbnailing images that are uploaded.
4
4
  class PapermillPaperclipProcessor < Thumbnail
5
5
 
6
- attr_accessor :crop_h, :crop_w, :crop_x, :crop_y, :copyright
6
+ attr_accessor :crop_h, :crop_w, :crop_x, :crop_y, :copyright, :watermark_path
7
7
 
8
8
  def initialize(file, options = {}, attachment = nil)
9
9
  @crop_h, @crop_w, @crop_x, @crop_y = options[:crop_h], options[:crop_w], options[:crop_x], options[:crop_y]
10
10
 
11
- if options[:geometry] =~ /©/
12
- options[:geometry], *@copyright = options[:geometry].split("©")
13
- @copyright = @copyright.join("©").nie || options[:copyright] || @attachment.instance.respond_to?(:copyright) && @attachment.instance.copyright
11
+ # copyright extraction
12
+ if options[:geometry] =~ /©/ || options[:copyright]
13
+ options[:geometry], *@copyright = options[:geometry].split("©", -1)
14
+ @copyright = options[:copyright] || @copyright.join("©").nie || file.instance.respond_to?(:copyright) && file.instance.copyright.nie || file.instance.papermill_options[:copyright].nie
15
+ @copyright = (options[:copyright_text_transform] || file.instance.papermill_options[:copyright_text_transform]).try(:call, @copyright) || @copyright if @copyright
14
16
  end
15
17
 
18
+ # watermark extraction
19
+ if options[:watermark] || options[:geometry] =~ /\-wm/
20
+ options[:geometry] = options[:geometry].chomp("-wm")
21
+ @watermark_path = options[:watermark].is_a?(String) && options[:watermark] || file.instance.papermill_options[:watermark]
22
+ @watermark_path = file.instance.papermill_options[:public_root].sub(":rails_root", RAILS_ROOT) + @watermark_path if @watermark_path.starts_with?("/")
23
+ end
24
+
25
+
16
26
  if options[:geometry] =~ /#.+/
17
-
18
- # <@target_geometry.width>x<@target_geometry.height>#<@crop_w>x<@crop_h>:<@crop_x>:<@crop_y>
19
- # <@target_geometry.width>x<@target_geometry.height>#<@crop_w>x<@crop_h>
20
- # <@target_geometry.width>x<@target_geometry.height>#<@crop_x>:<@crop_y>
27
+ # let's parse :
28
+ # <width>x<height>#<crop_w>x<crop_h>:<crop_x>:<crop_y>
29
+ # <width>x<height>#<crop_w>x<crop_h>
30
+ # <width>x<height>#<crop_x>:<crop_y>
21
31
 
22
32
  options[:geometry], manual_crop = options[:geometry].split("#")
23
-
24
33
  crop_dimensions, @crop_x, @crop_y = manual_crop.split("+")
25
-
34
+
26
35
  if crop_dimensions =~ /x/
27
36
  @crop_w, @crop_h = crop_dimensions.split("x")
28
37
  else
29
38
  @crop_x, @crop_y = crop_dimensions, @crop_x
30
39
  end
31
-
32
-
40
+
33
41
  options[:geometry] = (options[:geometry].nie || "#{@crop_x}x#{@crop_y}") + "#"
34
42
 
35
43
  unless @crop_w && @crop_h
@@ -42,9 +50,15 @@ module Paperclip
42
50
  end
43
51
 
44
52
  def transformation_command
45
- #puts "crop_command= #{crop_command ? super.sub(/ -crop \S+/, crop_command) : super}"
46
-
47
- crop_command ? super.sub(/ -crop \S+/, crop_command) : super
53
+ "#{(crop_command ? super.sub(/ -crop \S+/, crop_command) : super)} #{copyright_command} #{watermark_command}".sub(%{-resize "0x" }, "")
54
+ end
55
+
56
+ def copyright_command
57
+ (options[:copyright_im_command] || @file.instance.papermill_options[:copyright_im_command]).gsub(/%s/, @copyright.gsub(/'/, %{'"'"'}).sub("-slash-", "/").sub("-backslash-", %{\\\\\\})) if @copyright
58
+ end
59
+
60
+ def watermark_command
61
+ (options[:watermark_im_command] || @file.instance.papermill_options[:watermark_im_command]).gsub(/%s/, @watermark_path) if @watermark_path
48
62
  end
49
63
 
50
64
  def crop_command
data/lib/papermill.rb CHANGED
@@ -1,5 +1,6 @@
1
+ #require "digest/sha2"
1
2
  I18n.load_path = [File.join(File.dirname(__FILE__), "../config/locales/papermill.yml")] + I18n.load_path
2
- require 'extensions'
3
+ require 'papermill/extensions'
3
4
  require 'papermill/flash_session_cookie_middleware.rb'
4
5
 
5
6
  Object.send :include, PapermillObjectExtensions
data/public/.DS_Store CHANGED
Binary file
Binary file
@@ -5,7 +5,7 @@
5
5
  {
6
6
  font-size: 0;
7
7
  position: absolute;
8
- background: white url('Jcrop.gif') top left repeat;
8
+ background: white url('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; }
@@ -32,9 +32,10 @@ background: red;
32
32
  .papermill .progress { display:block; border:1px solid #C2E3EF; text-align:left; height:6px; }
33
33
  .papermill .progress span { background:#7BB963; height:6px; width:0; display:block; }
34
34
 
35
- .papermill .dashboard li a { display:inline; padding-left:20px; }
35
+ .papermill .dashboard li a { display:inline; padding-left:20px }
36
36
  .papermill .dashboard li.mass_edit a { background:transparent url(/papermill/images/mass-edit.png) no-repeat top left; }
37
37
  .papermill .dashboard li.mass_delete a { background:transparent url(/papermill/images/mass-delete.png) no-repeat top left; }
38
+ .papermill .dashboard li.mass_thumbnail_reset a { background:transparent url(/papermill/images/mass-thumbnail-reset.png) no-repeat top left; }
38
39
 
39
40
  .papermill-thumb-container { position:relative; border:5px solid #EEE; padding:4px; overflow:hidden; }
40
41
  .papermill-thumb-container .asset { border:0px solid transparent; min-height:25px; min-width:25px; display:block; float:left; position:relative; }
@@ -138,6 +138,12 @@ var Papermill = {
138
138
  if(confirm(wording)){
139
139
  jQuery.ajax({async:true, data:jQuery('#' + papermill_id).sortable('serialize'), dataType:'script', type:'post', url:'/papermill/mass_delete'})
140
140
  }
141
+ },
142
+
143
+ mass_thumbnail_reset: function(papermill_id, wording) {
144
+ if(confirm(wording)){
145
+ jQuery.ajax({async:true, data:jQuery('#' + papermill_id).sortable('serialize'), dataType:'script', type:'post', url:'/papermill/mass_thumbnail_reset'})
146
+ }
141
147
  }
142
148
  }
143
149
 
@@ -91,7 +91,7 @@ class PapermillTest < Test::Unit::TestCase
91
91
  assert_equal @article.papermill_assets.key(:asset1).all(:order => "position DESC").map(&:id), [1,2]
92
92
  assert_equal @article.papermill_assets.key(:asset1).all(:order => "position DESC", :limit => 1).map(&:id), [1]
93
93
  end
94
-
94
+
95
95
  def test_id_partition
96
96
  assert_equal @asset1.id_partition, "000/000/001"
97
97
  end
@@ -111,17 +111,7 @@ class PapermillTest < Test::Unit::TestCase
111
111
  def test_size
112
112
  assert_equal @asset1.size, 4456
113
113
  end
114
-
115
- def test_url
116
- assert_equal @asset1.url, "/system/papermill/000/000/001/original/5k.png"
117
- assert_equal @asset1.url("400x300#"), "/system/papermill/000/000/001/400x300%23/5k.png"
118
- end
119
-
120
- def test_path
121
- assert_equal @asset1.path, "./test/../../../../public/system/papermill/000/000/001/original/5k.png"
122
- assert_equal @asset1.path("400x300#"), "./test/../../../../public/system/papermill/000/000/001/400x300#/5k.png"
123
- end
124
-
114
+
125
115
  def test_content_type
126
116
  assert_equal @file.get_content_type, "image/png"
127
117
  assert_equal @asset1.content_type, "image/png"
@@ -142,4 +132,22 @@ class PapermillTest < Test::Unit::TestCase
142
132
  Papermill::options[:alias_only] = true
143
133
  assert_equal PapermillAsset.compute_style("100x100"), false
144
134
  end
145
- end
135
+ end
136
+
137
+ # Filedata=(data)
138
+ # Filename=(name)
139
+ # create_thumb_file(style_name)
140
+ # basename
141
+ # extension
142
+ # url(style = nil)
143
+ # path(style = nil)
144
+ # self.papermill_options(assetable_class, assetable_key)
145
+ # papermill_options
146
+ # destroy_thumbnails
147
+ # self.destroy_orphans
148
+ # compute_url_key(style)
149
+ # has_valid_url_key?(key, style)
150
+ # root_directory
151
+ # set_file_name
152
+ # set_position
153
+ # destroy_files
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: papermill
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.6
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Benoit B\xC3\xA9n\xC3\xA9zech"
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-01 00:00:00 +01:00
12
+ date: 2009-12-08 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -56,8 +56,8 @@ files:
56
56
  - generators/papermill_table/templates/migrate/papermill_migration.rb.erb
57
57
  - init.rb
58
58
  - install.rb
59
- - lib/extensions.rb
60
59
  - lib/papermill.rb
60
+ - lib/papermill/extensions.rb
61
61
  - lib/papermill/flash_session_cookie_middleware.rb
62
62
  - lib/papermill/form_builder.rb
63
63
  - lib/papermill/papermill.rb
@@ -74,20 +74,19 @@ files:
74
74
  - public/facebox/closelabel.gif
75
75
  - public/facebox/facebox.css
76
76
  - public/facebox/facebox.js
77
- - public/facebox/fbx-border-sprite.png
78
77
  - public/facebox/loading.gif
79
- - public/facebox/logo.png
80
- - public/facebox/shadow.gif
81
78
  - public/facebox/tl.png
82
79
  - public/facebox/tr.png
83
80
  - public/jgrowl/jquery.jgrowl.css
84
81
  - public/jgrowl/jquery.jgrowl_minimized.js
85
82
  - public/papermill/README
83
+ - public/papermill/images/Jcrop.gif
86
84
  - public/papermill/images/background.png
87
85
  - public/papermill/images/container-background.jpg
88
86
  - public/papermill/images/delete.png
89
87
  - public/papermill/images/mass-delete.png
90
88
  - public/papermill/images/mass-edit.png
89
+ - public/papermill/images/mass-thumbnail-reset.png
91
90
  - public/papermill/images/upload-blank.png
92
91
  - public/papermill/images/upload.png
93
92
  - public/papermill/jquery-1.3.2.min.js
Binary file
Binary file
Binary file