papermill 1.4.3 → 2.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,130 +1,122 @@
1
1
  class ActionView::Helpers::FormBuilder
2
2
  include ActionView::Helpers::FormTagHelper
3
3
 
4
- def assets_upload(key = nil, options = {})
5
- papermill_upload_tag key, { :thumbnail => false }.update(options)
4
+ def assets_upload(method, options = {})
5
+ papermill_upload_tag method, { :thumbnail => false }.update(options)
6
6
  end
7
- def asset_upload(key = nil, options = {})
8
- papermill_upload_tag key, { :gallery => false, :thumbnail => false }.update(options)
7
+ def asset_upload(method, options = {})
8
+ papermill_upload_tag method, { :gallery => false, :thumbnail => false }.update(options)
9
9
  end
10
- def images_upload(key = nil, options = {})
11
- papermill_upload_tag key, options
10
+ def images_upload(method, options = {})
11
+ papermill_upload_tag method, options
12
12
  end
13
- def image_upload(key = nil, options = {})
14
- papermill_upload_tag key, { :gallery => false }.update(options)
13
+ def image_upload(method, options = {})
14
+ papermill_upload_tag method, { :gallery => false }.update(options)
15
15
  end
16
16
  end
17
17
 
18
18
  module ActionView::Helpers::FormTagHelper
19
19
 
20
- def assets_upload_tag(assetable, key = nil, options = {})
21
- papermill_upload_tag key, { :thumbnail => false, :assetable => assetable }.update(options)
20
+ def assets_upload_tag(assetable, method, options = {})
21
+ papermill_upload_tag method, { :thumbnail => false, :assetable => assetable }.update(options)
22
22
  end
23
23
 
24
- def asset_upload_tag(assetable, key = nil, options = {})
25
- papermill_upload_tag key, { :gallery => false, :thumbnail => false, :assetable => assetable }.update(options)
24
+ def asset_upload_tag(assetable, method, options = {})
25
+ papermill_upload_tag method, { :gallery => false, :thumbnail => false, :assetable => assetable }.update(options)
26
26
  end
27
27
 
28
- def images_upload_tag(assetable, key = nil, options = {})
29
- papermill_upload_tag key, { :assetable => assetable }.update(options)
28
+ def images_upload_tag(assetable, method, options = {})
29
+ papermill_upload_tag method, { :assetable => assetable }.update(options)
30
30
  end
31
31
 
32
- def image_upload_tag(assetable, key = nil, options = {})
33
- papermill_upload_tag key, { :gallery => false, :assetable => assetable }.update(options)
32
+ def image_upload_tag(assetable, method, options = {})
33
+ papermill_upload_tag method, { :gallery => false, :assetable => assetable }.update(options)
34
34
  end
35
35
 
36
36
  private
37
37
 
38
- def papermill_upload_tag(key, options)
38
+ def papermill_upload_tag(method, options)
39
+ assetable = options[:object] || options[:assetable] || @object || @template.instance_variable_get("@#{@object_name}")
39
40
 
40
- if key.nil? && [String, Symbol].include?(options[:assetable].class)
41
- key = options[:assetable].to_s
42
- options[:assetable] = nil
43
- end
44
-
45
- assetable = @object || options[:object] || options[:assetable] || @template.instance_variable_get("@#{@object_name}")
46
-
47
- raise PapermillException.new("Your form instance object is not @#{@object_name}, and therefor cannot be found. \nPlease provide your object name in your form_for initialization. \nform_for :my_object_name, @my_object_name, :url => { :action => 'create'/'update'}") if @object_name && !assetable
41
+ raise PapermillException.new("Form object not found. Please provide it with :object => @assetable with the Papermill helper call") unless assetable
42
+ assetable_name = @object_name && "#{@object_name}#{(i = @options[:index]) ? "[#{i}]" : ""}"
48
43
 
49
- assetable_id = assetable && (assetable.id || assetable.timestamp) || nil
50
- assetable_type = assetable && assetable.class.base_class.name || nil
51
-
52
- options = PapermillAsset.papermill_options(assetable && assetable.class.name, key).deep_merge(options)
53
-
54
- dom_id = "papermill_#{assetable_type}_#{assetable_id}_#{key}"
44
+ sanitized_method = method.to_s.gsub(/[\?\/\-]$/, '')
45
+ sanitized_object_name = @object_name.to_s.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
46
+ field_id = @object_name && "#{sanitized_object_name}#{(i = @options[:index]) ? "_#{i}" : ""}_#{sanitized_method}"
47
+ assetable.class.papermill(method)
48
+ association_options = assetable.class.papermill_options[method.to_sym]
49
+
50
+ raise PapermillException.new("Papermill association #{method} failed to be generated dynamically for #{assetable.class.name}") unless association_options
51
+ options = association_options.deep_merge(options)
52
+ field_name = "#{assetable_name}[papermill_#{method}_ids][]"
55
53
 
56
54
  if ot = options[:thumbnail]
57
55
  w = ot[:width] || ot[:height] && ot[:aspect_ratio] && (ot[:height] * ot[:aspect_ratio]).to_i || nil
58
- h = ot[:height] || ot[:width] && ot[:aspect_ratio] && (ot[:width] / ot[:aspect_ratio]).to_i || nil
59
-
56
+ h = ot[:height] || ot[:width] && ot[:aspect_ratio] && (ot[:width] / ot[:aspect_ratio]).to_i || nil
60
57
  computed_style = ot[:style] || (w || h) && "#{w}x#{h}>" || "original"
61
- set_papermill_inline_css(dom_id, w, h, options)
58
+ set_papermill_inline_css(field_id, w, h, options)
62
59
  end
63
60
 
64
- set_papermill_inline_js(dom_id, compute_papermill_create_url(assetable_id, assetable_type, key, computed_style, options), options)
61
+ set_papermill_inline_js(field_id, compute_papermill_url(:create, computed_style, field_name, field_id, options), options)
65
62
 
66
63
  html = {}
67
- html[:upload_button] = %{<div id="#{dom_id}-button-wrapper" class="papermill-button-wrapper" style="height: #{options[:swfupload][:button_height]}px;"><span id="browse_for_#{dom_id}" class="swf_button"></span></div>}
68
- html[:container] = @template.content_tag(:div, :id => dom_id, :class => "papermill-#{key.to_s} #{(options[:thumbnail] ? "papermill-thumb-container" : "papermill-asset-container")} #{(options[:gallery] ? "papermill-multiple-items" : "papermill-unique-item")}") do
69
- conditions = {:assetable_type => assetable_type, :assetable_id => assetable_id}
70
- conditions.merge!({:assetable_key => key.to_s}) if key
71
- @template.render :partial => "papermill/asset", :collection => PapermillAsset.all(:conditions => conditions), :locals => { :thumbnail_style => computed_style, :targetted_size => options[:targetted_size] }
72
- end
64
+ html[:upload_button] = %{\
65
+ <div id="#{field_id}-button-wrapper" class="papermill-button-wrapper" style="height: #{options[:swfupload][:button_height]}px;">
66
+ <span id="browse_for_#{field_id}" class="swf_button"></span>
67
+ </div>}
73
68
 
74
- if options[:gallery]
75
- html[:dashboard] = {}
76
- html[:dashboard][:mass_edit] = %{<a onclick="Papermill.modify_all('#{dom_id}'); return false;" style="cursor:pointer">#{I18n.t("papermill.modify-all")}</a><select id="batch_#{dom_id}">#{options[:mass_editable_fields].map do |field|
77
- %{<option value="#{field.to_s}">#{I18n.t("papermill.#{field.to_s}", :default => field.to_s)}</option>}
78
- end.join("\n")}</select>}
79
- 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>}
80
- 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>}
81
- 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")
69
+ # I don't use the full :through association that is not updated if assetable.new_record?.
70
+ collection = association_options[:through] ? assetable.send("#{method}_associations").map(&:papermill_asset) : assetable.send(method)
71
+ locals = { :thumbnail_style => computed_style, :targetted_size => options[:targetted_size], :field_name => field_name, :field_id => field_id }
72
+ html[:container] = @template.content_tag(:div, :id => field_id, :class => "papermill-#{method.to_s} #{(options[:thumbnail] ? "papermill-thumb-container" : "papermill-asset-container")} #{(options[:gallery] ? "papermill-multiple-items" : "papermill-unique-item")}") do
73
+ @template.render(:partial => "papermill/asset",
74
+ :collection => collection,
75
+ :locals => locals)
82
76
  end
83
-
84
- if assetable && assetable.new_record? && !@timestamped
85
- @timestamp_field = @template.hidden_field(@object_name && "#{@object_name}#{(i = @options[:index]) ? "[#{i}]" : ""}" || assetable_type.underscore, :timestamp, :value => assetable.timestamp)
86
- @timestamped = true
77
+
78
+ if options[:gallery] && options[:mass_edit]
79
+ html[:mass_edit] = %{\
80
+ <a onclick="Papermill.modify_all('#{field_id}'); return false;" style="cursor:pointer">#{I18n.t("papermill.modify-all")}</a>
81
+ <select id="batch_#{field_id}">#{options[:mass_editable_fields].map do |field|
82
+ %{<option value="#{field.to_s}">#{I18n.t("papermill.#{field.to_s}", :default => field.to_s)}</option>}
83
+ end.join("\n")}</select>}
87
84
  end
88
85
 
89
- %{<div class="papermill">#{@timestamp_field.to_s + options[:form_helper_elements].map{|element| html[element] || ""}.join("\n")}</div>}
86
+ if options[:through]
87
+ browser_url = compute_papermill_url(:browser, computed_style, field_name, field_id, options)
88
+ html[:browser] = %{<a onclick="popup('#{@template.escape_javascript(browser_url)}&list_id=#{field_id}&' + jQuery('##{field_id}').sortable('serialize')); return false;" style="cursor:pointer">Ajouter...</a>}
89
+ end
90
+
91
+ # hidden_field needed to empty a list.
92
+ %{<div class="papermill">
93
+ #{@template.hidden_field("#{assetable_name}[papermill_#{method}_ids]", nil)}
94
+ #{options[:form_helper_elements].map{|element| html[element] || ""}.join("\n")}
95
+ </div>}
90
96
  end
91
97
 
92
98
 
93
- def compute_papermill_create_url(assetable_id, assetable_type, key, computed_style, options)
94
- create_url_options = {
95
- :escape => false, :controller => "/papermill", :action => "create",
99
+ def compute_papermill_url(action, computed_style, field_name, field_id, options)
100
+ @template.url_for({
101
+ :escape => false, :controller => "/papermill", :action => action,
96
102
  :asset_class => (options[:class_name] || PapermillAsset).to_s,
97
- :gallery => !!options[:gallery], :thumbnail_style => computed_style, :targetted_size => options[:targetted_size]
98
- }
99
- create_url_options.merge!({ :assetable_id => assetable_id, :assetable_type => assetable_type }) if assetable_id
100
- create_url_options.merge!({ :assetable_key => key }) if key
101
- @template.url_for(create_url_options)
103
+ :gallery => !!options[:gallery], :thumbnail_style => computed_style, :targetted_size => options[:targetted_size],
104
+ :field_name => field_name, :field_id => field_id
105
+ })
102
106
  end
103
107
 
104
- def set_papermill_inline_js(dom_id, create_url, options)
108
+ def set_papermill_inline_js(field_id, create_url, options)
105
109
  return unless options[:inline_css]
106
110
  @template.content_for :papermill_inline_js do
107
- %{
108
- jQuery("##{dom_id}").sortable({
109
- update:function(){
110
- jQuery.ajax({
111
- async: true,
112
- data: jQuery(this).sortable('serialize'),
113
- dataType: 'script',
114
- type: 'post',
115
- url: '#{@template.controller.send("sort_papermill_path")}'
116
- })
117
- }
118
- })
119
- } if options[:gallery]
111
+ %{ jQuery("##{field_id}").sortable() } if options[:gallery]
120
112
  end
121
113
  @template.content_for :papermill_inline_js do
122
114
  %{
123
115
  new SWFUpload({
124
- post_params: {
116
+ post_params: {
125
117
  "#{ ActionController::Base.session_options[:key] }": "#{ @template.cookies[ActionController::Base.session_options[:key]] }"
126
118
  },
127
- upload_id: "#{ dom_id }",
119
+ upload_id: "#{ field_id }",
128
120
  upload_url: "#{ @template.escape_javascript create_url }",
129
121
  file_types: "#{ options[:images_only] ? '*.jpg;*.jpeg;*.png;*.gif' : '' }",
130
122
  file_queue_limit: "#{ !options[:gallery] ? '1' : '0' }",
@@ -136,26 +128,26 @@ module ActionView::Helpers::FormTagHelper
136
128
  upload_error_handler: Papermill.upload_error,
137
129
  upload_success_handler: Papermill.upload_success,
138
130
  upload_complete_handler: Papermill.upload_complete,
139
- button_placeholder_id: "browse_for_#{dom_id}",
131
+ button_placeholder_id: "browse_for_#{field_id}",
140
132
  #{ options[:swfupload].map { |key, value| "#{key}: #{value}" if value }.compact.join(",\n") }
141
133
  });
142
134
  }
143
135
  end
144
136
  end
145
137
 
146
- def set_papermill_inline_css(dom_id, width, height, options)
138
+ def set_papermill_inline_css(field_id, width, height, options)
147
139
  html = ["\n"]
148
140
  size = [width && "width:#{width}px", height && "height:#{height}px"].compact.join("; ")
149
141
  if og = options[:gallery]
150
142
  vp, hp, vm, hm, b = [og[:vpadding], og[:hpadding], og[:vmargin], og[:hmargin], og[:border_thickness]].map &:to_i
151
143
  gallery_width = (og[:width] || width) && "width:#{og[:width] || og[:columns]*(width.to_i+(hp+hm+b)*2)}px;" || ""
152
144
  gallery_height = (og[:height] || height) && "min-height:#{og[:height] || og[:lines]*(height.to_i+(vp+vm+b)*2)}px;" || ""
153
- html << %{##{dom_id} { #{gallery_width} #{gallery_height} }}
154
- html << %{##{dom_id} .asset { margin:#{vm}px #{hm}px; border-width:#{b}px; padding:#{vp}px #{hp}px; #{size}; }}
145
+ html << %{##{field_id} { #{gallery_width} #{gallery_height} }}
146
+ html << %{##{field_id} .asset { margin:#{vm}px #{hm}px; border-width:#{b}px; padding:#{vp}px #{hp}px; #{size}; }}
155
147
  else
156
- html << %{##{dom_id}, ##{dom_id} .asset { #{size} }}
148
+ html << %{##{field_id}, ##{field_id} .asset { #{size} }}
157
149
  end
158
- html << %{##{dom_id} .name { width:#{width || "100"}px; }}
150
+ html << %{##{field_id} .name { width:#{width || "100"}px; }}
159
151
  @template.content_for :papermill_inline_css do
160
152
  html.join("\n")
161
153
  end
@@ -1,15 +1,10 @@
1
1
  module Papermill
2
-
3
- def self.included(base)
4
- base.extend(ClassMethods)
5
- end
2
+ MSWIN = (Config::CONFIG['host_os'] =~ /mswin|mingw/)
6
3
 
7
4
  def self.options
8
5
  @options ||= BASE_OPTIONS.deep_merge(defined?(OPTIONS) ? OPTIONS : {})
9
6
  end
10
7
 
11
- MSWIN = (Config::CONFIG['host_os'] =~ /mswin|mingw/)
12
-
13
8
  def self.compute_paperclip_path
14
9
  path = []
15
10
  path << (options[:use_id_partition] ? ":id_partition" : ":id")
@@ -19,52 +14,69 @@ module Papermill
19
14
  path.compact.join("/")
20
15
  end
21
16
 
22
- module ClassMethods
23
- attr_reader :papermill_associations
24
-
25
- def papermill(*args)
26
- assoc_name = (!args.first.is_a?(Hash) && args.shift || Papermill::options[:base_association_name]).to_sym
27
- local_options = args.first || {}
28
-
29
- (@papermill_associations ||= {}).merge!( assoc_name => Papermill::options.deep_merge(local_options) )
17
+ def self.included(base)
18
+ base.extend(ClassMethods)
19
+ base.class_eval do
20
+ def papermill(key, through = ((po = self.class.papermill_options) && (po[key.to_sym] || po[:default]) || Papermill::options)[:through])
21
+ PapermillAsset.papermill(self.class.base_class.name, self.id, key.to_s, through)
22
+ end
30
23
 
31
- include Papermill::InstanceMethods
32
- after_create :rebase_assets
33
- has_many :papermill_assets, :as => "assetable", :dependent => :destroy
34
-
35
- [assoc_name, Papermill::options[:base_association_name].to_sym].uniq.each do |assoc|
36
- define_method assoc do |*options|
37
- scope = PapermillAsset.scoped(:conditions => {:assetable_id => self.id, :assetable_type => self.class.base_class.name})
38
- if assoc != Papermill::options[:base_association_name]
39
- scope = scope.scoped(:conditions => { :assetable_key => assoc.to_s })
40
- elsif options.first && !options.first.is_a?(Hash)
41
- scope = scope.scoped(:conditions => { :assetable_key => options.shift.to_s.nie })
42
- end
43
- scope = scope.scoped(options.shift) if options.first
44
- scope
24
+ def respond_to_with_papermill?(method, *args, &block)
25
+ respond_to_without_papermill?(method, *args, &block) || (method.to_s =~ /^papermill_.+_ids=$/) == 0
26
+ end
27
+
28
+ def method_missing_with_papermill(method, *args, &block)
29
+ if method.to_s =~ /^papermill_.+_ids=$/
30
+ self.class.papermill(method.to_s[10..-6])
31
+ self.send(method, *args, &block)
32
+ else
33
+ method_missing_without_papermill(method, *args, &block)
45
34
  end
46
35
  end
47
- ActionController::Dispatcher.middleware.delete(FlashSessionCookieMiddleware) rescue true
48
- ActionController::Dispatcher.middleware.insert_before(ActionController::Base.session_store, FlashSessionCookieMiddleware, ActionController::Base.session_options[:key]) rescue true
49
36
  end
37
+ base.send :alias_method_chain, :method_missing, :papermill
38
+ base.send :alias_method_chain, :respond_to?, :papermill
39
+ ActionController::Dispatcher.middleware.insert_before(ActionController::Base.session_store, FlashSessionCookieMiddleware, ActionController::Base.session_options[:key]) unless ActionController::Dispatcher.middleware.include?(FlashSessionCookieMiddleware)
40
+ end
41
+
42
+ module ClassMethods
43
+ attr_reader :papermill_options
50
44
 
51
45
  def inherited(subclass)
52
- subclass.instance_variable_set("@papermill_associations", @papermill_associations)
46
+ subclass.instance_variable_set("@papermill_options", @papermill_options)
53
47
  super
54
48
  end
55
- end
56
-
57
- module InstanceMethods
58
- attr_writer :timestamp
59
- def timestamp
60
- @timestamp ||= "-#{(Time.now.to_f * 1000).to_i.to_s[4..-1]}"
61
- end
62
49
 
63
- private
64
-
65
- def rebase_assets
66
- PapermillAsset.all(:conditions => { :assetable_id => self.timestamp, :assetable_type => self.class.base_class.name }).each do |asset|
67
- asset.created_at < 2.hours.ago ? asset.destroy : asset.update_attribute(:assetable_id, self.id)
50
+ def papermill(assoc_key, assoc_options = (@papermill_options && @papermill_options[:default] || {}))
51
+ return if @papermill_options && @papermill_options[assoc_key.to_sym] # already defined
52
+ raise PapermillException.new("Can't use '#{assoc_key}' association : #{self.name} instances already responds to it !") if self.new.respond_to?(assoc_key)
53
+ (@papermill_options ||= {}).merge!( { assoc_key.to_sym => Papermill::options.deep_merge(assoc_options) } )
54
+ return if assoc_key.to_sym == :default
55
+ unless papermill_options[assoc_key.to_sym][:through]
56
+ self.class_eval %{
57
+ has_many :#{assoc_key}, :as => "assetable", :dependent => :delete_all, :order => :position, :class_name => "PapermillAsset", :conditions => {:assetable_key => '#{assoc_key}'}, :before_add => Proc.new{|a, asset| asset.assetable_key = '#{assoc_key}'}
58
+ def papermill_#{assoc_key}_ids=(ids)
59
+ unless (assets_ids = ids.map(&:to_i).select{|i|i>0}) == self.#{assoc_key}.map(&:id)
60
+ assets = PapermillAsset.find(assets_ids)
61
+ self.#{assoc_key} = assets_ids.map{|asset_id| assets.select{|asset|asset.id==asset_id}.first}
62
+ PapermillAsset.update_all("position = CASE id " + assets_ids.map_with_index{|asset_id, index| " WHEN " + asset_id.to_s + " THEN " + (index+1).to_s }.join + " END",
63
+ :id => assets_ids) unless assets_ids.empty?
64
+ end
65
+ end
66
+ }
67
+ else
68
+ self.class_eval %{
69
+ has_many(:#{assoc_key}_associations, :as => "assetable", :class_name => "PapermillAssociation", :include => :papermill_asset, :dependent => :delete_all, :order => :position, :conditions => {:assetable_key => '#{assoc_key}'}, :before_add => Proc.new{|a, assoc| assoc.assetable_key = '#{assoc_key}'})
70
+ has_many(:#{assoc_key}, :through => :#{assoc_key}_associations, :source => :papermill_asset)
71
+ def papermill_#{assoc_key}_ids=(ids)
72
+ unless (assets_ids = ids.map(&:to_i).select{|i|i>0}) == self.#{assoc_key}_associations.map(&:papermill_asset_id)
73
+ self.#{assoc_key}_associations.delete_all
74
+ self.#{assoc_key}_associations = assets_ids.map_with_index do |asset_id, index|
75
+ PapermillAssociation.new(:papermill_asset_id => asset_id, :position => (index+1))
76
+ end
77
+ end
78
+ end
79
+ }
68
80
  end
69
81
  end
70
82
  end
@@ -1,8 +1,6 @@
1
1
  class PapermillAsset < ActiveRecord::Base
2
-
3
2
  before_destroy :destroy_files
4
- before_create :set_position
5
-
3
+
6
4
  has_attached_file :file,
7
5
  :processors => [:papermill_paperclip_processor],
8
6
  :url => "#{Papermill::options[:papermill_url_prefix]}/#{Papermill::compute_paperclip_path.gsub(':style', ':escape_style_in_url')}",
@@ -12,10 +10,26 @@ class PapermillAsset < ActiveRecord::Base
12
10
 
13
11
  validates_attachment_presence :file
14
12
 
15
- belongs_to :assetable, :polymorphic => true, :touch => Papermill::options[:touch]
16
- default_scope :order => 'position'
17
-
18
- named_scope :key, lambda { |assetable_key| { :conditions => ['assetable_key = ?', assetable_key.to_s] }}
13
+ belongs_to :assetable, :polymorphic => true
14
+ has_many :papermill_associations, :dependent => :delete_all
15
+
16
+ named_scope :papermill, lambda { |assetable_type, assetable_id, assetable_key, through|
17
+ through ?
18
+ { :joins => "INNER JOIN papermill_associations ON papermill_assets.id = papermill_associations.papermill_asset_id \
19
+ AND papermill_associations.assetable_type = #{connection.quote assetable_type} \
20
+ AND papermill_associations.assetable_id = #{assetable_id.to_i} \
21
+ AND papermill_associations.assetable_key = #{connection.quote assetable_key}",
22
+ :order => "papermill_associations.position" } :
23
+ { :conditions => {
24
+ :assetable_type => assetable_type,
25
+ :assetable_id => assetable_id,
26
+ :assetable_key => assetable_key.to_s },
27
+ :order => "papermill_assets.position" }
28
+ }
29
+
30
+ def assetable_type=(sType)
31
+ super(sType.to_s.classify.constantize.base_class.to_s)
32
+ end
19
33
 
20
34
  Paperclip.interpolates :url_key do |attachment, style|
21
35
  attachment.instance.compute_url_key((style || "original").to_s)
@@ -103,10 +117,10 @@ class PapermillAsset < ActiveRecord::Base
103
117
  style.is_a?(Hash) ? (style[:name] || style.hash).to_s : (style || "original").to_s
104
118
  end
105
119
 
106
- def self.papermill_options(assetable_class, assetable_key)
107
- if assetable_class
108
- assoc = assetable_class.constantize.papermill_associations
109
- assoc[assetable_key.try(:to_sym)] || assoc[Papermill::options[:base_association_name]]
120
+ def self.papermill_options(assetable_type, assetable_key)
121
+ if assetable_type
122
+ assoc = assetable_type.constantize.papermill_options
123
+ assoc[assetable_key.try(:to_sym)] || assoc[:default] || Papermill::options
110
124
  else
111
125
  Papermill::options
112
126
  end
@@ -121,12 +135,14 @@ class PapermillAsset < ActiveRecord::Base
121
135
  end
122
136
 
123
137
  def create_thumb_file(style_name, style = nil)
138
+ return false unless self.image?
124
139
  destroy_thumbnails if style_name.to_s == "original"
125
140
  style = self.class.compute_style(style_name) unless style.is_a?(Hash)
126
141
  FileUtils.mkdir_p File.dirname(new_path = file.path(style_name))
127
142
  FileUtils.cp((tmp_path = Paperclip::PapermillPaperclipProcessor.make(file, style).path), new_path)
128
143
  FileUtils.chmod(0644, new_path) unless Papermill::MSWIN
129
144
  File.delete(tmp_path)
145
+ return true
130
146
  end
131
147
 
132
148
  def destroy_thumbnails
@@ -141,7 +157,9 @@ class PapermillAsset < ActiveRecord::Base
141
157
  end
142
158
 
143
159
  def self.destroy_orphans
144
- self.all(:conditions => ["id < 0 AND created_at < ?", DateTime.now.yesterday]).each &:destroy
160
+ self.name != self.base_class.name ?
161
+ PapermillAsset.delete_all(["created_at < ? AND assetable_id IS NULL AND type = ?", 1.hour.ago, self.name]) :
162
+ PapermillAsset.delete_all(["created_at < ? AND assetable_id IS NULL AND type IS NULL", 1.hour.ago])
145
163
  end
146
164
 
147
165
  def compute_url_key(style)
@@ -153,7 +171,7 @@ class PapermillAsset < ActiveRecord::Base
153
171
  end
154
172
 
155
173
  private
156
-
174
+
157
175
  def root_directory
158
176
  deepness_to_root = Papermill::options[:use_url_key] ? -3 : -2
159
177
  @root_directory ||= File.dirname(path).split('/')[0..deepness_to_root].join('/')
@@ -165,10 +183,6 @@ class PapermillAsset < ActiveRecord::Base
165
183
  self.file.instance_write(:file_name, "#{basename.to_url}#{extension}")
166
184
  end
167
185
 
168
- def set_position
169
- self.position ||= PapermillAsset.maximum(:position, :conditions => { :assetable_type => assetable_type, :assetable_id => assetable_id, :assetable_key => assetable_key } ).to_i + 1
170
- end
171
-
172
186
  def destroy_files
173
187
  FileUtils.rm_r(root_directory) rescue true
174
188
  end
@@ -0,0 +1,8 @@
1
+ class PapermillAssociation < ActiveRecord::Base
2
+ belongs_to :papermill_asset
3
+ belongs_to :assetable, :polymorphic => true
4
+
5
+ def assetable_type=(sType)
6
+ super(sType.to_s.classify.constantize.base_class.to_s)
7
+ end
8
+ end
@@ -1,10 +1,11 @@
1
1
  module Papermill
2
2
  BASE_OPTIONS = {
3
3
  :class_name => "PapermillAsset",
4
+ :through => false,
4
5
  :inline_css => true,
5
6
  :images_only => false,
6
- :form_helper_elements => [:upload_button, :container, :dashboard],
7
- :dashboard => [:mass_edit, :mass_delete],
7
+ :form_helper_elements => [:upload_button, :container, :browser, :mass_edit],
8
+ :mass_edit => true,
8
9
  :mass_editable_fields => ["title", "copyright", "description"],
9
10
  :editable_fields => [
10
11
  {:title => {:type => "string"}},
@@ -48,8 +49,6 @@ module Papermill
48
49
  :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},
49
50
  :watermark => "/images/rails.png",
50
51
  :watermark_im_command => %{- | composite \\( %s -resize 100% \\) - -dissolve 20% -gravity center -geometry +0+0 },
51
- :base_association_name => :assets,
52
- :touch => false,
53
52
  :alias_only => false,
54
53
  :aliases => {},
55
54
  :use_url_key => false,
@@ -57,9 +56,6 @@ module Papermill
57
56
  :url_key_generator => Proc.new { |style, asset| Digest::SHA512.hexdigest("#{style}#{asset.id}#{Papermill::options[:url_key_salt]}")[0..10] },
58
57
  :use_id_partition => true,
59
58
  :papermill_url_prefix => "/system/papermill",
60
- :papermill_path_prefix => ":rails_root/public/system/papermill",
61
- :authorize_create => "true",
62
- :authorize_update_and_destroy => "true",
63
- :authorize_multiple_modification => "true",
59
+ :papermill_path_prefix => ":rails_root/public/system/papermill"
64
60
  }
65
61
  end
data/lib/papermill.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "rbconfig"
2
+ require "acts_as_list"
2
3
  begin
3
4
  require "mime/types"
4
5
  MIME_TYPE_LOADED = true
@@ -12,6 +13,7 @@ require 'papermill/flash_session_cookie_middleware.rb'
12
13
 
13
14
  Object.send :include, PapermillObjectExtensions
14
15
  Hash.send :include, PapermillHashExtensions
16
+ Array.send :include, PapermillArrayExtensions
15
17
  String.send :include, StringToUrlNotFound unless String.instance_methods.include? "to_url"
16
18
  Formtastic::SemanticFormBuilder.send(:include, PapermillFormtasticExtensions) rescue NameError
17
19
 
@@ -23,6 +25,7 @@ end
23
25
  require 'paperclip' unless defined?(Paperclip)
24
26
  require 'papermill/papermill_paperclip_processor'
25
27
  require 'papermill/papermill'
28
+ require 'papermill/papermill_association'
26
29
  require 'papermill/papermill_asset'
27
30
  require 'papermill/form_builder'
28
31
  require 'papermill/papermill_helper'
@@ -23,8 +23,6 @@
23
23
 
24
24
  .papermill .dashboard li a { display:inline; padding-left:20px }
25
25
  .papermill .dashboard li.mass_edit a { background:transparent url(/papermill/images/mass-edit.png) no-repeat top left; }
26
- .papermill .dashboard li.mass_delete a { background:transparent url(/papermill/images/mass-delete.png) no-repeat top left; }
27
- .papermill .dashboard li.mass_thumbnail_reset a { background:transparent url(/papermill/images/mass-thumbnail-reset.png) no-repeat top left; }
28
26
 
29
27
  .papermill-thumb-container { position:relative; border:5px solid #EEE; padding:4px; overflow:hidden; }
30
28
  .papermill-thumb-container .asset { border:0px solid transparent; min-height:25px; min-width:25px; display:block; float:left; position:relative; }
@@ -6,14 +6,15 @@ If you have your own popup solution, override popup and close_popup in your appl
6
6
  popup = function(url) {
7
7
  jQuery.facebox(function() {
8
8
  jQuery.get(url, function(data) {
9
- jQuery.facebox(data)
9
+ jQuery.facebox(data);
10
10
  })
11
11
  })
12
12
  return false;
13
- }
13
+ };
14
+
14
15
  close_popup = function(source) {
15
16
  jQuery(document).trigger('close.facebox');
16
- }
17
+ };
17
18
 
18
19
  jQuery(document).ajaxError(function(){
19
20
  switch (arguments[1].status) {
@@ -37,10 +38,11 @@ If you have your own notification solution, override notify
37
38
  */
38
39
 
39
40
  notify = function(title, message, type) {
40
- if(type == "notice") { jQuery.jGrowl(message, { header: title, life: 4000, theme: type }) }
41
- if(type == "warning") { jQuery.jGrowl(message, { header: title, life: 15000, theme: type }) }
42
- if(type == "error") { jQuery.jGrowl(message, { header: title, sticky: true, theme: type }) }
43
- }
41
+ if(type == "notice") { jQuery.jGrowl(message, { header: title, life: 4000, theme: type }) };
42
+ if(type == "warning") { jQuery.jGrowl(message, { header: title, life: 15000, theme: type }) };
43
+ if(type == "error") { jQuery.jGrowl(message, { header: title, sticky: true, theme: type }) };
44
+ };
45
+
44
46
  var Papermill = {
45
47
  files_queued: 0,
46
48
  file_dialog_complete: function(num_selected, num_queued)
@@ -62,7 +64,7 @@ var Papermill = {
62
64
  } while (file != null);
63
65
  this.sorted_queue = file_queue.sort(function(a,b){
64
66
  if(b.name < a.name) { return (1) } else { return (-1) }
65
- })
67
+ });
66
68
  var self = this;
67
69
  jQuery(this.sorted_queue).each( function(index, file) {
68
70
  div = jQuery('<div></div>').attr({ 'id': file.id, 'class': 'swfupload asset' });
@@ -76,7 +78,7 @@ var Papermill = {
76
78
  }
77
79
  }
78
80
  jQuery("#" + self.settings.upload_id).append(div);
79
- })
81
+ });
80
82
  this.startUpload(this.sorted_queue[this.index++].id);
81
83
  }
82
84
  },
@@ -84,6 +86,12 @@ var Papermill = {
84
86
  {
85
87
  jQuery('#' + file.id + ' .status').html(SWFUPLOAD_LOADING);
86
88
  this.addFileParam(file.id, "Fileid", file.id);
89
+ if(this.settings.file_queue_limit == 1) {
90
+ old_asset = jQuery("#" + this.settings.upload_id).children()[0];
91
+ if (old_asset && old_asset.id != file.id) {
92
+ this.addFileParam(file.id, "Oldfileid", old_asset.id);
93
+ }
94
+ }
87
95
  },
88
96
  upload_progress: function(file, bytes, total)
89
97
  {
@@ -107,7 +115,7 @@ var Papermill = {
107
115
  {
108
116
  Papermill.files_queued -= 1;
109
117
  if(this.sorted_queue[this.index]) {
110
- this.startUpload(this.sorted_queue[this.index++].id)
118
+ this.startUpload(this.sorted_queue[this.index++].id);
111
119
  }
112
120
  },
113
121
  file_queue_error: function(file, errorCode, message) {
@@ -127,23 +135,12 @@ var Papermill = {
127
135
  },
128
136
  modify_all: function(papermill_id) {
129
137
  container = jQuery("#" + papermill_id)[0];
130
- attribute_name = jQuery("#batch_" + papermill_id)[0].value
138
+ attribute_name = jQuery("#batch_" + papermill_id)[0].value;
131
139
  attribute_wording = jQuery("#batch_" + papermill_id + " option:selected").text();
132
- value = prompt(attribute_wording + ":")
140
+ value = prompt(attribute_wording + ":");
133
141
  if(value != null) {
134
- jQuery.ajax({async:true, data:jQuery(container).sortable('serialize'), dataType:'script', type:'post', url:'/papermill/mass_edit?attribute=' + attribute_name + "&value=" + value})
142
+ jQuery.ajax({async:true, data:jQuery(container).sortable('serialize') + "&list_id=" + container.id, dataType:'script', type:'post', url:'/papermill/mass_edit?attribute=' + attribute_name + "&value=" + value});
135
143
  }
136
- },
137
- mass_delete: function(papermill_id, wording) {
138
- if(confirm(wording)){
139
- jQuery.ajax({async:true, data:jQuery('#' + papermill_id).sortable('serialize'), dataType:'script', type:'post', url:'/papermill/mass_delete'})
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
- }
147
144
  }
148
- }
145
+ };
149
146