populate-me 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +9 -0
- data/lib/populate_me/control/_public/css/main.css +180 -0
- data/lib/populate_me/control/_public/css/plugin.asmselect.css +63 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_flat_30_cccccc_40x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_flat_50_5c5c5c_40x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_glass_20_555555_1x400.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_glass_40_0078a3_1x400.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_glass_40_ffc73d_1x400.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_gloss-wave_25_333333_500x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_highlight-soft_80_eeeeee_1x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_inset-soft_25_000000_1x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_inset-soft_30_f58400_1x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_222222_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_4b8e0b_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_a83300_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_cccccc_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_ffffff_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/jquery-ui-1.8.17.custom.css +430 -0
- data/lib/populate_me/control/_public/img/handle-pattern.png +0 -0
- data/lib/populate_me/control/_public/img/icons-cms.png +0 -0
- data/lib/populate_me/control/_public/img/placeholder.png +0 -0
- data/lib/populate_me/control/_public/img/placeholder.stash_thumb.gif +0 -0
- data/lib/populate_me/control/_public/img/placeholder.stash_thumb.png +0 -0
- data/lib/populate_me/control/_public/img/small-loader.gif +0 -0
- data/lib/populate_me/control/_public/js/addon.timepicker.js +20 -0
- data/lib/populate_me/control/_public/js/jquery-ui.js +114 -0
- data/lib/populate_me/control/_public/js/jquery.js +167 -0
- data/lib/populate_me/control/_public/js/jquery.mustache.js +559 -0
- data/lib/populate_me/control/_public/js/main.js +144 -0
- data/lib/populate_me/control/_public/js/plugin.asmselect.js +407 -0
- data/lib/populate_me/control/_public/js/plugin.form.js +11 -0
- data/lib/populate_me/control/_public/js/plugin.quicksearch.js +1 -0
- data/lib/populate_me/control/_public/js/plugin.underwood.js +4 -0
- data/lib/populate_me/control/views/layout.erb +77 -0
- data/lib/populate_me/control.rb +193 -0
- data/lib/populate_me/mongo/backend_api_plug.rb +77 -0
- data/lib/populate_me/mongo/crushyform.rb +225 -0
- data/lib/populate_me/mongo/mutation.rb +266 -0
- data/lib/populate_me/mongo/plug.rb +132 -0
- data/lib/populate_me/mongo/stash.rb +119 -0
- data/lib/populate_me/mongo.rb +1 -0
- data/populate-me.gemspec +14 -0
- metadata +120 -0
@@ -0,0 +1,266 @@
|
|
1
|
+
module PopulateMe
|
2
|
+
module Mongo
|
3
|
+
module Mutation
|
4
|
+
|
5
|
+
# Most important MongoDB module
|
6
|
+
# It defines the ODM
|
7
|
+
|
8
|
+
def self.included(weak)
|
9
|
+
weak.extend(MutateClass)
|
10
|
+
weak.db = DB
|
11
|
+
weak.schema = BSON::OrderedHash.new
|
12
|
+
weak.relationships = BSON::OrderedHash.new
|
13
|
+
end
|
14
|
+
|
15
|
+
module MutateClass
|
16
|
+
attr_accessor :db, :schema, :relationships
|
17
|
+
attr_writer :label_column, :sorting_order
|
18
|
+
|
19
|
+
LABEL_COLUMNS = ['title', 'label', 'fullname', 'full_name', 'surname', 'lastname', 'last_name', 'name', 'firstname', 'first_name', 'login', 'caption', 'reference', 'file_name', 'body', '_id']
|
20
|
+
def label_column; @label_column ||= LABEL_COLUMNS.find{|c| @schema.keys.include?(c)||c=='_id'}; end
|
21
|
+
def foreign_key_name(plural=false); "id#{'s' if plural}_"+self.name; end
|
22
|
+
def human_name; self.name.gsub(/([A-Z])/, ' \1')[1..-1]; end
|
23
|
+
def human_plural_name; human_name+'s'; end
|
24
|
+
def collection; db[self.name]; end
|
25
|
+
def ref(id)
|
26
|
+
if id.is_a?(String)&&BSON::ObjectId.legal?(id)
|
27
|
+
id = BSON::ObjectId.from_string(id)
|
28
|
+
elsif !id.is_a?(BSON::ObjectId)
|
29
|
+
id = ''
|
30
|
+
end
|
31
|
+
{'_id'=>id}
|
32
|
+
end
|
33
|
+
def find(selector={},opts={})
|
34
|
+
opts = {:sort=>self.sorting_order}.update(opts)
|
35
|
+
collection.find(selector,opts).extend(CursorMutation)
|
36
|
+
end
|
37
|
+
def find_one(spec_or_object_id=nil,opts={})
|
38
|
+
opts = {:sort=>self.sorting_order}.update(opts)
|
39
|
+
item = collection.find_one(spec_or_object_id,opts)
|
40
|
+
item.nil? ? nil : self.new(item)
|
41
|
+
end
|
42
|
+
def count(opts={}); collection.count(opts); end
|
43
|
+
|
44
|
+
def sorting_order
|
45
|
+
@sorting_order ||= if @schema.key?('position')&&!@schema['position'][:scope].nil?
|
46
|
+
[[@schema['position'][:scope], :asc], ['position', :asc]]
|
47
|
+
elsif @schema.key?('position')
|
48
|
+
[['position', :asc],['_id', :asc]]
|
49
|
+
else
|
50
|
+
['_id', :asc]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def sort(id_list)
|
55
|
+
id_list.each_with_index do |id, position|
|
56
|
+
collection.update(ref(id), {'$set' => {'position'=>position}})
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# CRUD
|
61
|
+
def get(id, opts={}); doc = collection.find_one(ref(id), opts); doc.nil? ? nil : self.new(doc); end
|
62
|
+
def delete(id); collection.remove(ref(id)); end
|
63
|
+
|
64
|
+
def is_unique(doc={})
|
65
|
+
return unless collection.count==0
|
66
|
+
doc = {'_id'=>BSON::ObjectId('000000000000000000000000')}.update(doc)
|
67
|
+
d = self.new
|
68
|
+
d.doc.update(doc)
|
69
|
+
d.save
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
def slot(name,opts={}); @schema[name] = {:type=>:string}.update(opts); end
|
74
|
+
def image_slot(name='image',opts={})
|
75
|
+
slot name, {:type=>:attachment}.update(opts)
|
76
|
+
slot "#{name}_tooltip"
|
77
|
+
slot "#{name}_alternative_text"
|
78
|
+
end
|
79
|
+
def has_many(k,opts={}); @relationships[k] = opts; end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Instance Methods
|
83
|
+
|
84
|
+
attr_accessor :doc, :old_doc, :errors, :is_new
|
85
|
+
def initialize(document=nil); @errors={}; @doc = document || default_doc; end
|
86
|
+
def default_doc
|
87
|
+
@is_new = true
|
88
|
+
out = {}
|
89
|
+
model.schema.each { |k,v| out.store(k,v[:default].is_a?(Proc) ? v[:default].call : v[:default]) }
|
90
|
+
out
|
91
|
+
end
|
92
|
+
def model; self.class; end
|
93
|
+
def id; @doc['_id']; end
|
94
|
+
def [](field); @doc[field]; end
|
95
|
+
def []=(field,val); @doc[field] = val; end
|
96
|
+
def to_label; @doc[model.label_column].to_s.tr("\n\r", ' '); end
|
97
|
+
def to_param; "#{@doc['_id']}-#{to_label.scan(/\w+/).join('-')}"; end
|
98
|
+
def field_id_for(col); "%s-%s-%s" % [id||'new',model.name,col]; end
|
99
|
+
|
100
|
+
# relationships
|
101
|
+
def resolve_class(k); k.kind_of?(Class) ? k : Kernel.const_get(k); end
|
102
|
+
def parent(k, opts={})
|
103
|
+
if k.kind_of?(String)
|
104
|
+
key = k
|
105
|
+
klass = resolve_class(model.schema[k][:parent_class])
|
106
|
+
else
|
107
|
+
klass = resolve_class(k)
|
108
|
+
key = klass.foreign_key_name
|
109
|
+
end
|
110
|
+
klass.get(@doc[key], opts)
|
111
|
+
end
|
112
|
+
def slot_children(k, opts={})
|
113
|
+
if k.kind_of?(String)
|
114
|
+
key = k
|
115
|
+
klass = resolve_class(model.schema[k][:children_class])
|
116
|
+
else
|
117
|
+
klass = resolve_class(k)
|
118
|
+
key = klass.foreign_key_name(true)
|
119
|
+
end
|
120
|
+
ids = (@doc[key]||[]).map{|i| BSON::ObjectId.from_string(i) }
|
121
|
+
selector = {'_id'=>{'$in'=>ids}}
|
122
|
+
sort_proc = proc{ |a,b| ids.index(a['_id'])<=>ids.index(b['_id']) }
|
123
|
+
klass.find(selector, opts).to_a.sort(&sort_proc)
|
124
|
+
end
|
125
|
+
def first_slot_child(k, opts={})
|
126
|
+
if k.kind_of?(String)
|
127
|
+
key = k
|
128
|
+
klass = resolve_class(model.schema[k][:children_class])
|
129
|
+
else
|
130
|
+
klass = resolve_class(k)
|
131
|
+
key = klass.foreign_key_name(true)
|
132
|
+
end
|
133
|
+
klass.get((@doc[key]||[])[0], opts)
|
134
|
+
end
|
135
|
+
def children(k,opts={})
|
136
|
+
k = resolve_class(k)
|
137
|
+
slot_name = opts.delete(:slot_name) || model.foreign_key_name
|
138
|
+
k.find({slot_name=>@doc['_id'].to_s}, opts)
|
139
|
+
end
|
140
|
+
def first_child(k,opts={})
|
141
|
+
k = resolve_class(k)
|
142
|
+
slot_name = opts.delete(:slot_name) || model.foreign_key_name
|
143
|
+
d = k.find_one({slot_name=>@doc['_id'].to_s}, opts)
|
144
|
+
end
|
145
|
+
def children_count(k,sel={})
|
146
|
+
k = resolve_class(k)
|
147
|
+
slot_name = sel.delete(:slot_name) || model.foreign_key_name
|
148
|
+
k.collection.count(:query => {slot_name=>@doc['_id'].to_s}.update(sel))
|
149
|
+
end
|
150
|
+
|
151
|
+
# CRUD
|
152
|
+
def delete
|
153
|
+
before_delete
|
154
|
+
model.delete(@doc['_id'])
|
155
|
+
after_delete
|
156
|
+
end
|
157
|
+
|
158
|
+
# saving and hooks
|
159
|
+
def new?; @is_new ||= !@doc.key?('_id'); end
|
160
|
+
def update_doc(fields); @old_doc = @doc.dup; @doc.update(fields); @is_new = false; self; end
|
161
|
+
# Getter and setter in one
|
162
|
+
def errors_on(col,message=nil)
|
163
|
+
message.nil? ? @errors[col] : @errors[col] = (@errors[col]||[]) << message
|
164
|
+
end
|
165
|
+
def before_delete; @old_doc = @doc.dup; end
|
166
|
+
alias before_destroy before_delete
|
167
|
+
def after_delete
|
168
|
+
model.relationships.each do |k,v|
|
169
|
+
Kernel.const_get(k).find({model.foreign_key_name=>@old_doc['_id'].to_s}).each{|m| m.delete} unless v[:independent]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
alias after_destroy after_delete
|
173
|
+
def valid?
|
174
|
+
before_validation
|
175
|
+
validate
|
176
|
+
after_validation
|
177
|
+
@errors.empty?
|
178
|
+
end
|
179
|
+
def before_validation
|
180
|
+
@errors = {}
|
181
|
+
@doc.each do |k,v|
|
182
|
+
next unless model.schema.key?(k)
|
183
|
+
type = k=='_id' ? :primary_key : model.schema[k][:type]
|
184
|
+
fix_method = "fix_type_#{type}"
|
185
|
+
if v==''
|
186
|
+
default = model.schema[k][:default]
|
187
|
+
@doc[k] = default.is_a?(Proc) ? default.call : default
|
188
|
+
else
|
189
|
+
self.__send__(fix_method, k, v) if self.respond_to?(fix_method)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
def validate; end
|
194
|
+
def after_validation; end
|
195
|
+
def fix_type_integer(k,v); @doc[k] = v.to_i; end
|
196
|
+
def fix_type_boolean(k,v); @doc[k] = (v=='true'||v==true) ? true : false; end
|
197
|
+
def fix_type_date(k,v)
|
198
|
+
if v.is_a?(String)
|
199
|
+
if v[/\d\d\d\d-\d\d-\d\d/]
|
200
|
+
@doc[k] = ::Time.utc(*v.split('-'))
|
201
|
+
else
|
202
|
+
default = model.schema[k][:default]
|
203
|
+
@doc[k] = default.is_a?(Proc) ? default.call : default
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
def fix_type_datetime(k,v)
|
208
|
+
if v.is_a?(String)
|
209
|
+
if v[/\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/]
|
210
|
+
@doc[k] = ::Time.utc(*v.split(/[-:\s]/))
|
211
|
+
else
|
212
|
+
default = model.schema[k][:default]
|
213
|
+
@doc[k] = default.is_a?(Proc) ? default.call : default
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def save
|
219
|
+
return nil unless valid?
|
220
|
+
before_save
|
221
|
+
if new?
|
222
|
+
before_create
|
223
|
+
id = model.collection.insert(@doc)
|
224
|
+
@doc['_id'] = id
|
225
|
+
after_create
|
226
|
+
else
|
227
|
+
before_update
|
228
|
+
id = model.collection.update({'_id'=>@doc['_id']}, @doc)
|
229
|
+
after_update
|
230
|
+
end
|
231
|
+
after_save
|
232
|
+
id.nil? ? nil : self
|
233
|
+
end
|
234
|
+
def before_save; end
|
235
|
+
def before_create; end
|
236
|
+
def before_update; end
|
237
|
+
def after_save; end
|
238
|
+
def after_create; @is_new = false; end
|
239
|
+
def after_update; end
|
240
|
+
|
241
|
+
# ==========
|
242
|
+
# = Cursor =
|
243
|
+
# ==========
|
244
|
+
module CursorMutation
|
245
|
+
# Extend the cursor provided by the Ruby MongoDB driver
|
246
|
+
# We must keep the regular cursor
|
247
|
+
# so we should extend on demand.
|
248
|
+
# Meaning the cursor object should be extended, not the cursor class.
|
249
|
+
def self.extended(into)
|
250
|
+
into.set_mutant_class
|
251
|
+
end
|
252
|
+
def set_mutant_class
|
253
|
+
@mutant_class = Kernel.const_get(collection.name)
|
254
|
+
end
|
255
|
+
def next
|
256
|
+
n = super
|
257
|
+
n.nil? ? nil : @mutant_class.new(n)
|
258
|
+
end
|
259
|
+
# legacy
|
260
|
+
def each_mutant(&b); each(&b); end
|
261
|
+
def each_mutant_with_index(&b); each_with_index(&b); end
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'populate_me/mongo/mutation'
|
2
|
+
require 'populate_me/mongo/stash'
|
3
|
+
require 'populate_me/mongo/crushyform'
|
4
|
+
require 'populate_me/mongo/backend_api_plug'
|
5
|
+
|
6
|
+
module PopulateMe
|
7
|
+
module Mongo
|
8
|
+
module Plug
|
9
|
+
|
10
|
+
# This module is the one that plugs the model to the CMS
|
11
|
+
|
12
|
+
def self.included(base)
|
13
|
+
base.class_eval do
|
14
|
+
include PopulateMe::Mongo::Mutation
|
15
|
+
include PopulateMe::Mongo::Stash if (base.const_defined?(:WITH_STASH) && base::WITH_STASH)
|
16
|
+
include PopulateMe::Mongo::BackendApiPlug
|
17
|
+
include PopulateMe::Mongo::Crushyform
|
18
|
+
include InstanceMethods
|
19
|
+
end
|
20
|
+
base.extend(ClassMethods)
|
21
|
+
base.populate_config = {:nut_tree_class=>'sortable-grid'}
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
|
26
|
+
attr_accessor :populate_config
|
27
|
+
|
28
|
+
# def list_view(r)
|
29
|
+
# @list_options = {:request=>r, :destination=>r.fullpath, :path=>r.script_name, :filter=>r['filter'] }
|
30
|
+
# @list_options.store(:sortable,sortable_on_that_page?)
|
31
|
+
# out = list_view_header
|
32
|
+
# out << many_to_many_picker unless populate_config[:minilist_class].nil?
|
33
|
+
# out << "<ul class='nut-tree #{'sortable' if @list_options[:sortable]} #{populate_config[:nut_tree_class]}' id='#{self.name}' rel='#{@list_options[:path]}/#{self.name}'>"
|
34
|
+
# self.find(@list_options[:filter]||{}).each {|m| out << m.to_nutshell }
|
35
|
+
# out << "</ul>"
|
36
|
+
# end
|
37
|
+
|
38
|
+
def sortable_on_that_page?(r)
|
39
|
+
@schema.key?('position') && (@schema['position'][:scope].nil? || (r['filter']||{}).key?(@schema['position'][:scope]))
|
40
|
+
end
|
41
|
+
|
42
|
+
# def minilist_view
|
43
|
+
# o = "<ul class='minilist'>\n"
|
44
|
+
# self.collection.find.each_mutant do |m|
|
45
|
+
# thumb = m.respond_to?(:to_populate_thumb) ? m.to_populate_thumb('stash_thumb.gif') : m.placeholder_thumb('stash_thumb.gif')
|
46
|
+
# o << "<li title='#{m.to_label}' id='mini-#{m.id}'>#{thumb}<div>#{m.to_label}</div></li>\n"
|
47
|
+
# end
|
48
|
+
# o << "</ul>\n"
|
49
|
+
# end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def image_slot(name='image',opts={})
|
54
|
+
super(name,opts)
|
55
|
+
# First image slot is considered the best populate thumb by default
|
56
|
+
unless instance_methods.include?(:to_populate_thumb)
|
57
|
+
define_method :to_populate_thumb do |style|
|
58
|
+
generic_thumb(name, style)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
module InstanceMethods
|
66
|
+
|
67
|
+
def after_stash(col)
|
68
|
+
convert(col, "-resize '100x75^' -gravity center -extent 100x75", 'stash_thumb.gif')
|
69
|
+
end
|
70
|
+
|
71
|
+
def generic_thumb(img , size='stash_thumb.gif', obj=self)
|
72
|
+
return placeholder_thumb(size) if obj.nil?
|
73
|
+
current = obj.doc[img]
|
74
|
+
if !current.nil? && !current[size].nil?
|
75
|
+
"/gridfs/#{current[size]}"
|
76
|
+
else
|
77
|
+
placeholder_thumb(size)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def placeholder_thumb(size)
|
82
|
+
"/_public/img/placeholder.#{size}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_nutshell
|
86
|
+
{
|
87
|
+
'class_name'=>model.name,
|
88
|
+
'id'=>@doc['_id'].to_s,
|
89
|
+
'foreign_key_name'=>model.foreign_key_name,
|
90
|
+
'title'=>self.to_label,
|
91
|
+
'thumb'=>self.respond_to?(:to_populate_thumb) ? self.to_populate_thumb('stash_thumb.gif') : nil,
|
92
|
+
'children'=>nutshell_children,
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
def in_nutshell
|
97
|
+
o = model.list_options
|
98
|
+
out = "<div class='in-nutshell'>\n"
|
99
|
+
out << self.to_populate_thumb('nutshell.jpg') if self.respond_to?(:to_populate_thumb)
|
100
|
+
cols = model.populate_config[:quick_update_fields] || nutshell_backend_columns.select{|col|
|
101
|
+
[:boolean,:select].include?(model.schema[col][:type]) && !model.schema[col][:multiple] && !model.schema[col][:no_quick_update]
|
102
|
+
}
|
103
|
+
cols.each do |c|
|
104
|
+
column_label = c.to_s.sub(/^id_/, '').tr('_', ' ').capitalize
|
105
|
+
out << "<div class='quick-update'><form><span class='column-title'>#{column_label}:</span> #{self.crushyinput(c)}</form></div>\n"
|
106
|
+
end
|
107
|
+
out << "</div>\n"
|
108
|
+
end
|
109
|
+
|
110
|
+
def nutshell_backend_associations
|
111
|
+
model.relationships
|
112
|
+
end
|
113
|
+
|
114
|
+
def nutshell_children
|
115
|
+
nutshell_backend_associations.inject([]) do |arr, (k, opts)|
|
116
|
+
unless opts[:hidden]
|
117
|
+
klass = Kernel.const_get(k)
|
118
|
+
arr << {
|
119
|
+
'children_class_name'=>k,
|
120
|
+
'title'=>opts[:link_text] || "#{klass.human_name}(s)",
|
121
|
+
'count'=>self.children_count(klass),
|
122
|
+
}
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module PopulateMe
|
2
|
+
module Mongo
|
3
|
+
module Stash
|
4
|
+
|
5
|
+
# This module gives models the ability to deal with attachments
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
Stash.classes << base
|
9
|
+
base.extend(ClassMethods)
|
10
|
+
base.gridfs = GRID
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
attr_accessor :gridfs
|
15
|
+
end
|
16
|
+
|
17
|
+
# Instance Methods
|
18
|
+
|
19
|
+
def build_image_tag(col='image', style='original', html_attributes={})
|
20
|
+
return '' if @doc[col].nil?||@doc[col][style].nil?
|
21
|
+
title_field, alt_field = col+'_tooltip', col+'_alternative_text'
|
22
|
+
title = @doc[title_field] if model.schema.keys.include?(title_field)
|
23
|
+
alt = @doc[alt_field] if model.schema.keys.include?(alt_field)
|
24
|
+
html_attributes = {:src => "/gridfs/#{@doc[col][style]}", :title => title, :alt => alt}.update(html_attributes)
|
25
|
+
html_attributes = html_attributes.map do |k,v|
|
26
|
+
%{#{k}="#{model.html_escape(v.to_s)}"}
|
27
|
+
end.join(' ')
|
28
|
+
"<img #{html_attributes} />"
|
29
|
+
end
|
30
|
+
|
31
|
+
def fix_type_attachment(k,v)
|
32
|
+
if v=='nil'
|
33
|
+
delete_files_for(k) unless new?
|
34
|
+
@doc[k] = nil
|
35
|
+
elsif v.is_a?(Hash)&&v.key?(:tempfile)
|
36
|
+
delete_files_for(k) unless new?
|
37
|
+
@temp_attachments ||= {}
|
38
|
+
@temp_attachments[k] = v
|
39
|
+
attachment_id = model.gridfs.put(v[:tempfile], {:filename=>v[:filename], :content_type=>v[:type]})
|
40
|
+
@doc[k] = {'original'=>attachment_id}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def delete_files_for(col)
|
45
|
+
obj = (@old_doc||@doc)[col]
|
46
|
+
if obj.respond_to?(:each)
|
47
|
+
obj.each do |k,v|
|
48
|
+
model.gridfs.delete(v)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def after_delete
|
54
|
+
super
|
55
|
+
model.schema.each do |k,v|
|
56
|
+
delete_files_for(k) if v[:type]==:attachment
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def after_save
|
61
|
+
super
|
62
|
+
unless @temp_attachments.nil?
|
63
|
+
@temp_attachments.each do |k,v|
|
64
|
+
after_stash(k)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def after_stash(col); end
|
70
|
+
|
71
|
+
def convert(col, convert_steps, style)
|
72
|
+
return if @doc[col].nil?
|
73
|
+
if @temp_attachments.nil? || @temp_attachments[col].nil?
|
74
|
+
f = GRID.get(@doc[col]['original'])
|
75
|
+
return unless f.content_type[/^image\//]
|
76
|
+
src = Tempfile.new('MongoStash_src')
|
77
|
+
src.binmode
|
78
|
+
src.write(f.read(4096)) until f.eof?
|
79
|
+
src.close
|
80
|
+
@temp_attachments ||= {}
|
81
|
+
@temp_attachments[col] ||= {}
|
82
|
+
@temp_attachments[col][:tempfile] = src
|
83
|
+
@temp_attachments[col][:type] = f.content_type
|
84
|
+
else
|
85
|
+
return unless @temp_attachments[col][:type][/^image\//]
|
86
|
+
src = @temp_attachments[col][:tempfile]
|
87
|
+
end
|
88
|
+
model.gridfs.delete(@doc[col][style]) unless @doc[col][style].nil?
|
89
|
+
ext = style[/\..*$/]
|
90
|
+
dest = Tempfile.new(['MongoStash_dest', ext])
|
91
|
+
dest.binmode
|
92
|
+
dest.close
|
93
|
+
system "convert \"#{src.path}\" #{convert_steps} \"#{dest.path}\""
|
94
|
+
filename = "#{model.name}/#{self.id}/#{style}"
|
95
|
+
content_type = Rack::Mime.mime_type(ext)
|
96
|
+
attachment_id = model.gridfs.put(dest.open, {:filename=>filename, :content_type=>content_type})
|
97
|
+
@doc[col] = @doc[col].update({style=>attachment_id})
|
98
|
+
model.collection.update({'_id'=>@doc['_id']}, @doc)
|
99
|
+
#src.close!
|
100
|
+
dest.close!
|
101
|
+
end
|
102
|
+
|
103
|
+
class << self
|
104
|
+
attr_accessor :classes
|
105
|
+
Stash.classes = []
|
106
|
+
def all_after_stash
|
107
|
+
Stash.classes.each do |m|
|
108
|
+
m.collection.find.each do |i|
|
109
|
+
m.schema.each do |k,v|
|
110
|
+
m.new(i).after_stash(k) if v[:type]==:attachment
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|