populate-me 0.0.16 → 0.0.17
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/lib/populate_me/mongo/backend_api_plug.rb +11 -11
- data/lib/populate_me/mongo/crushyform.rb +29 -29
- data/lib/populate_me/mongo/mutation.rb +167 -170
- data/lib/populate_me/mongo/plug.rb +71 -71
- data/lib/populate_me/mongo/stash.rb +95 -95
- data/populate-me.gemspec +1 -1
- metadata +2 -2
@@ -13,16 +13,16 @@ module PopulateMe
|
|
13
13
|
end
|
14
14
|
|
15
15
|
module ClassMethods
|
16
|
-
|
17
|
-
|
16
|
+
def backend_get(id); id=='unique' ? find_one : get(id); end
|
17
|
+
def backend_post(doc=nil); inst = new(doc); inst.is_new = true; inst; end
|
18
18
|
end
|
19
19
|
|
20
20
|
# Instance Methods
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
def backend_delete; delete; end
|
23
|
+
def backend_put(fields); update_doc(fields); end
|
24
|
+
def backend_values; @doc; end
|
25
|
+
def backend_save?; !save.nil?; end
|
26
26
|
def backend_form(url, cols=nil, opts={})
|
27
27
|
cols ||= default_backend_columns
|
28
28
|
if block_given?
|
@@ -66,11 +66,11 @@ module PopulateMe
|
|
66
66
|
end
|
67
67
|
o
|
68
68
|
end
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
69
|
+
def backend_form_title; self.new? ? "New #{model.human_name}" : "Edit #{self.to_label}"; end
|
70
|
+
def backend_show; 'OK'; end
|
71
|
+
|
72
|
+
def default_backend_columns; model.schema.keys; end
|
73
|
+
def cloning_backend_columns; default_backend_columns.reject{|c| model.schema[c][:type]==:attachment}; end
|
74
74
|
|
75
75
|
end
|
76
76
|
end
|
@@ -75,7 +75,7 @@ module PopulateMe
|
|
75
75
|
@crushyform_types[:select].call(m,c,opts)
|
76
76
|
end,
|
77
77
|
:attachment => proc do |m,c,o|
|
78
|
-
|
78
|
+
deleter = "<input type='checkbox' name='#{o[:input_name]}' class='deleter' value='nil' /> Delete this file<br />" unless m.doc[c].nil?
|
79
79
|
"%s%s<input type='file' name='%s' id='%s' class='%s' />%s\n" % [m.to_thumb(c), deleter, o[:input_name], m.field_id_for(c), o[:input_class], o[:required]]
|
80
80
|
end,
|
81
81
|
:select => proc do |m,c,o|
|
@@ -103,43 +103,43 @@ module PopulateMe
|
|
103
103
|
end
|
104
104
|
out << "</select>%s\n" % [o[:required]]
|
105
105
|
end,
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
106
|
+
:string_list => proc do |m,c,o|
|
107
|
+
if o[:autocompleted]
|
108
|
+
values = o[:autocomplete_options] || m.class.collection.distinct(c)
|
109
|
+
js = <<-EOJS
|
110
110
|
<script type="text/javascript" charset="utf-8">
|
111
111
|
$(function(){
|
112
112
|
$( "##{m.field_id_for(c)}" )
|
113
113
|
.bind( "keydown", function( event ) {
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
114
|
+
if ( event.keyCode === $.ui.keyCode.TAB &&
|
115
|
+
$( this ).data( "autocomplete" ).menu.active ) {
|
116
|
+
event.preventDefault();
|
117
|
+
}
|
118
118
|
})
|
119
119
|
.autocomplete({
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
120
|
+
minLength: 0,
|
121
|
+
source: function( request, response ) {
|
122
|
+
response($.ui.autocomplete.filter(["#{values.join('","')}"], request.term.split(/,\s*/).pop()));
|
123
|
+
},
|
124
|
+
focus: function() { return false; },
|
125
|
+
select: function( event, ui ) {
|
126
|
+
var terms = this.value.split(/,\s*/);
|
127
|
+
terms.pop();
|
128
|
+
terms.push(ui.item.value);
|
129
|
+
terms.push("");
|
130
|
+
this.value = terms.join( ", " );
|
131
|
+
return false;
|
132
|
+
}
|
133
133
|
});
|
134
134
|
});
|
135
135
|
</script>
|
136
136
|
EOJS
|
137
137
|
o[:autocompleted] = false # reset so that it does not autocomplete for :string type below
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
138
|
+
end
|
139
|
+
tag = @crushyform_types[:string].call(m,c,o.update({:input_value=>(o[:input_value]||[]).join(',')}))
|
140
|
+
"#{tag}#{js}"
|
141
|
+
end,
|
142
|
+
:permalink => proc do |instance, column_name, options|
|
143
143
|
values = "<option value=''>Or Browse the list</option>\n"
|
144
144
|
tag = @crushyform_types[:string].call(instance, column_name, options)
|
145
145
|
return tag if options[:permalink_classes].nil?
|
@@ -222,8 +222,8 @@ module PopulateMe
|
|
222
222
|
# Reset dropdowns on hooks
|
223
223
|
def after_save; model.reset_dropdown_cache; super; end
|
224
224
|
def after_delete; model.reset_dropdown_cache; super; end
|
225
|
-
|
226
|
-
|
225
|
+
# Fix types
|
226
|
+
def fix_type_string_list(k,v); @doc[k] = v.to_s.strip.split(/\s*,\s*/).compact if v.is_a?(String); end
|
227
227
|
|
228
228
|
|
229
229
|
end
|
@@ -6,33 +6,33 @@ module PopulateMe
|
|
6
6
|
# Most important MongoDB module
|
7
7
|
# It defines the ODM
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
def self.included(weak)
|
10
|
+
weak.extend(MutateClass)
|
11
|
+
weak.db = DB if defined?(DB)
|
12
|
+
weak.schema = BSON::OrderedHash.new
|
13
|
+
weak.relationships = BSON::OrderedHash.new
|
14
|
+
end
|
15
15
|
|
16
16
|
module MutateClass
|
17
|
-
|
18
|
-
|
17
|
+
attr_accessor :db, :schema, :relationships
|
18
|
+
attr_writer :label_column, :slug_column, :sorting_order
|
19
19
|
|
20
20
|
LABEL_COLUMNS = ['title', 'label', 'fullname', 'full_name', 'surname', 'lastname', 'last_name', 'name', 'firstname', 'first_name', 'login', 'caption', 'reference', 'file_name', 'body', '_id']
|
21
|
-
|
21
|
+
def label_column; @label_column ||= LABEL_COLUMNS.find{|c| @schema.keys.include?(c)||c=='_id'}; end
|
22
22
|
def slug_column; @slug_column ||= (@schema.find{|k,v| v[:type]==:slug}||[])[0]; end
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
23
|
+
def foreign_key_name(plural=false); "id#{'s' if plural}_"+self.name; end
|
24
|
+
def human_name; self.name.gsub(/([A-Z])/, ' \1')[1..-1]; end
|
25
|
+
def human_plural_name; human_name+'s'; end
|
26
|
+
def collection; db[self.name]; end
|
27
|
+
def ref(id)
|
28
|
+
if id.is_a?(String)&&BSON::ObjectId.legal?(id)
|
29
|
+
id = BSON::ObjectId.from_string(id)
|
30
|
+
elsif !id.is_a?(BSON::ObjectId)
|
31
|
+
id = ''
|
32
|
+
end
|
33
|
+
{'_id'=>id}
|
34
|
+
end
|
35
|
+
def find(selector={},opts={})
|
36
36
|
selector.update(opts.delete(:selector)||{})
|
37
37
|
opts = {:sort=>self.sorting_order}.update(opts)
|
38
38
|
collection.find(selector,opts).extend(CursorMutation)
|
@@ -46,62 +46,59 @@ module PopulateMe
|
|
46
46
|
def count(opts={}); collection.count(opts); end
|
47
47
|
|
48
48
|
def sorting_order
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
49
|
+
@sorting_order ||= if @schema.key?('position')&&!@schema['position'][:scope].nil?
|
50
|
+
[[@schema['position'][:scope], :asc], ['position', :asc]]
|
51
|
+
elsif @schema.key?('position')
|
52
|
+
[['position', :asc],['_id', :asc]]
|
53
|
+
else
|
54
|
+
['_id', :asc]
|
55
|
+
end
|
56
|
+
end
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
def sort(id_list)
|
59
|
+
id_list.each_with_index do |id, position|
|
60
|
+
collection.update(ref(id), {'$set' => {'position'=>position}})
|
61
|
+
end
|
62
|
+
end
|
63
63
|
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
# CRUD
|
65
|
+
def get(id, opts={}); doc = collection.find_one(ref(id), opts); doc.nil? ? nil : self.new(doc); end
|
66
|
+
def delete(id); collection.remove(ref(id)); end
|
67
67
|
|
68
68
|
def is_unique(doc={})
|
69
69
|
return unless collection.count==0
|
70
|
-
|
71
|
-
d = self.new
|
72
|
-
d.doc.update(doc)
|
73
|
-
d.save
|
70
|
+
self.new(doc).save
|
74
71
|
end
|
75
72
|
|
76
|
-
|
73
|
+
private
|
77
74
|
def slot(name,opts={})
|
78
75
|
@schema[name] = {:type=>:string}.update(opts)
|
79
76
|
define_method(name) { @doc[name] }
|
80
77
|
define_method("#{name}=") { |x| @doc[name] = x }
|
81
78
|
end
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
79
|
+
def image_slot(name='image',opts={})
|
80
|
+
slot name, {:type=>:attachment}.update(opts)
|
81
|
+
slot "#{name}_tooltip"
|
82
|
+
slot "#{name}_alternative_text"
|
83
|
+
end
|
84
|
+
def has_many(k,opts={}); @relationships[k] = opts; end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Instance Methods
|
91
88
|
|
92
89
|
attr_accessor :doc, :old_doc, :errors, :is_new
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
90
|
+
def initialize(document=nil); @errors={}; @doc = document || default_doc; end
|
91
|
+
def default_doc
|
92
|
+
@is_new = true
|
93
|
+
out = {}
|
94
|
+
model.schema.each { |k,v| out.store(k,v[:default].is_a?(Proc) ? v[:default].call : v[:default]) }
|
95
|
+
out
|
96
|
+
end
|
97
|
+
def model; self.class; end
|
98
|
+
def id; @doc['_id']; end
|
99
|
+
def [](field); @doc[field]; end
|
100
|
+
def []=(field,val); @doc[field] = val; end
|
101
|
+
def to_label; @doc[model.label_column].to_s.tr("\n\r", ' '); end
|
105
102
|
ACCENTS_FROM =
|
106
103
|
"ÀÁÂÃÄÅàáâãäåĀāĂ㥹ÇçĆćĈĉĊċČčÐðĎďĐđÈÉÊËèéêëĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħÌÍÎÏìíîïĨĩĪīĬĭĮįİıĴĵĶķĸĹĺĻļĽľĿŀŁłÑñŃńŅņŇňʼnŊŋÒÓÔÕÖØòóôõöøŌōŎŏŐőŔŕŖŗŘřŚśŜŝŞ"
|
107
104
|
ACCENTS_TO =
|
@@ -113,25 +110,25 @@ module PopulateMe
|
|
113
110
|
def to_slug; @doc[model.slug_column]||self.auto_slug; end
|
114
111
|
# To param will be deprecated
|
115
112
|
# Use a URL like .../<id>/<slug> instead
|
116
|
-
|
113
|
+
def to_param; "#{@doc['_id']}-#{to_label.scan(/\w+/).join('-')}"; end
|
117
114
|
def field_id_for(col); "%s-%s-%s" % [id||'new',model.name,col]; end
|
118
115
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
116
|
+
# relationships
|
117
|
+
def resolve_class(k); k.kind_of?(Class) ? k : Kernel.const_get(k); end
|
118
|
+
def parent(k, opts={})
|
119
|
+
if k.kind_of?(String)
|
120
|
+
key = k
|
121
|
+
klass = resolve_class(model.schema[k][:parent_class])
|
125
122
|
else
|
126
123
|
klass = resolve_class(k)
|
127
124
|
key = klass.foreign_key_name
|
128
125
|
end
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
126
|
+
klass.get(@doc[key], opts)
|
127
|
+
end
|
128
|
+
def slot_children(k, opts={})
|
129
|
+
if k.kind_of?(String)
|
130
|
+
key = k
|
131
|
+
klass = resolve_class(model.schema[k][:children_class])
|
135
132
|
else
|
136
133
|
klass = resolve_class(k)
|
137
134
|
key = klass.foreign_key_name(true)
|
@@ -143,123 +140,123 @@ module PopulateMe
|
|
143
140
|
end
|
144
141
|
def first_slot_child(k, opts={})
|
145
142
|
if k.kind_of?(String)
|
146
|
-
|
147
|
-
|
143
|
+
key = k
|
144
|
+
klass = resolve_class(model.schema[k][:children_class])
|
148
145
|
else
|
149
146
|
klass = resolve_class(k)
|
150
147
|
key = klass.foreign_key_name(true)
|
151
148
|
end
|
152
149
|
klass.get((@doc[key]||[])[0], opts)
|
153
150
|
end
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
151
|
+
def children(k,opts={})
|
152
|
+
k = resolve_class(k)
|
153
|
+
slot_name = opts.delete(:slot_name) || model.foreign_key_name
|
154
|
+
k.find({slot_name=>@doc['_id'].to_s}, opts)
|
155
|
+
end
|
156
|
+
def first_child(k,opts={})
|
157
|
+
k = resolve_class(k)
|
158
|
+
slot_name = opts.delete(:slot_name) || model.foreign_key_name
|
159
|
+
d = k.find_one({slot_name=>@doc['_id'].to_s}, opts)
|
160
|
+
end
|
161
|
+
def children_count(k,sel={})
|
162
|
+
k = resolve_class(k)
|
163
|
+
slot_name = sel.delete(:slot_name) || model.foreign_key_name
|
164
|
+
k.collection.count(:query => {slot_name=>@doc['_id'].to_s}.update(sel))
|
168
165
|
end
|
169
166
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
167
|
+
# CRUD
|
168
|
+
def delete
|
169
|
+
before_delete
|
170
|
+
model.delete(@doc['_id'])
|
171
|
+
after_delete
|
172
|
+
end
|
176
173
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
174
|
+
# saving and hooks
|
175
|
+
def new?; @is_new ||= !@doc.key?('_id'); end
|
176
|
+
def update_doc(fields); @old_doc = @doc.dup; @doc.update(fields); @is_new = false; self; end
|
177
|
+
# Getter and setter in one
|
178
|
+
def errors_on(col,message=nil)
|
179
|
+
message.nil? ? @errors[col] : @errors[col] = (@errors[col]||[]) << message
|
183
180
|
end
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
181
|
+
def before_delete; @old_doc = @doc.dup; end
|
182
|
+
alias before_destroy before_delete
|
183
|
+
def after_delete
|
184
|
+
model.relationships.each do |k,v|
|
185
|
+
Kernel.const_get(k).find({model.foreign_key_name=>@old_doc['_id'].to_s}).each{|m| m.delete} unless v[:independent]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
alias after_destroy after_delete
|
189
|
+
def valid?
|
190
|
+
before_validation
|
191
|
+
validate
|
192
|
+
after_validation
|
193
|
+
@errors.empty?
|
194
|
+
end
|
195
|
+
def before_validation
|
196
|
+
@errors = {}
|
197
|
+
@doc.each do |k,v|
|
198
|
+
next unless model.schema.key?(k)
|
199
|
+
type = k=='_id' ? :primary_key : model.schema[k][:type]
|
200
|
+
fix_method = "fix_type_#{type}"
|
201
|
+
if v==''
|
202
|
+
default = model.schema[k][:default]
|
203
|
+
@doc[k] = default.is_a?(Proc) ? default.call : default
|
207
204
|
else
|
208
|
-
|
205
|
+
self.__send__(fix_method, k, v) if self.respond_to?(fix_method)
|
209
206
|
end
|
210
207
|
end
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
208
|
+
end
|
209
|
+
def validate; end
|
210
|
+
def after_validation; end
|
211
|
+
def fix_type_integer(k,v); @doc[k] = v.to_i; end
|
215
212
|
def fix_type_price(k,v)
|
216
213
|
@doc[k] = v.respond_to?(:to_price_integer) ? v.to_price_integer : v
|
217
214
|
end
|
218
|
-
|
215
|
+
def fix_type_boolean(k,v); @doc[k] = (v=='true'||v==true) ? true : false; end
|
219
216
|
def fix_type_slug(k,v); @doc[k] = self.auto_slug if v.to_s==''; end
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
217
|
+
def fix_type_date(k,v)
|
218
|
+
if v.is_a?(String)
|
219
|
+
if v[/\d\d\d\d-\d\d-\d\d/]
|
220
|
+
@doc[k] = ::Time.utc(*v.split('-'))
|
224
221
|
else
|
225
|
-
|
222
|
+
default = model.schema[k][:default]
|
226
223
|
@doc[k] = default.is_a?(Proc) ? default.call : default
|
227
224
|
end
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
225
|
+
end
|
226
|
+
end
|
227
|
+
def fix_type_datetime(k,v)
|
228
|
+
if v.is_a?(String)
|
229
|
+
if v[/\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/]
|
230
|
+
@doc[k] = ::Time.utc(*v.split(/[-:\s]/))
|
234
231
|
else
|
235
|
-
|
232
|
+
default = model.schema[k][:default]
|
236
233
|
@doc[k] = default.is_a?(Proc) ? default.call : default
|
237
234
|
end
|
238
|
-
|
239
|
-
|
235
|
+
end
|
236
|
+
end
|
240
237
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
238
|
+
def save
|
239
|
+
return nil unless valid?
|
240
|
+
before_save
|
241
|
+
if new?
|
242
|
+
before_create
|
243
|
+
id = model.collection.insert(@doc)
|
244
|
+
@doc['_id'] = id
|
245
|
+
after_create
|
246
|
+
else
|
247
|
+
before_update
|
248
|
+
id = model.collection.update({'_id'=>@doc['_id']}, @doc)
|
249
|
+
after_update
|
250
|
+
end
|
251
|
+
after_save
|
252
|
+
id.nil? ? nil : self
|
253
|
+
end
|
254
|
+
def before_save; end
|
255
|
+
def before_create; end
|
256
|
+
def before_update; end
|
257
|
+
def after_save; end
|
258
|
+
def after_create; @is_new = false; end
|
259
|
+
def after_update; end
|
263
260
|
|
264
261
|
# ==========
|
265
262
|
# = Cursor =
|
@@ -11,17 +11,17 @@ module PopulateMe
|
|
11
11
|
|
12
12
|
# This module is the one that plugs the model to the CMS
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
def self.included(base)
|
15
|
+
base.class_eval do
|
16
|
+
include PopulateMe::Mongo::Mutation
|
17
|
+
include PopulateMe::Mongo::Stash if (base.const_defined?(:WITH_STASH) && base::WITH_STASH)
|
18
|
+
include PopulateMe::Mongo::BackendApiPlug
|
19
|
+
include PopulateMe::Mongo::Crushyform
|
20
|
+
include InstanceMethods
|
21
21
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
base.extend(ClassMethods)
|
23
|
+
base.populate_config = {:nut_tree_class=>'sortable-grid'}
|
24
|
+
end
|
25
25
|
|
26
26
|
module ClassMethods
|
27
27
|
|
@@ -36,8 +36,8 @@ module PopulateMe
|
|
36
36
|
# self.find(@list_options[:filter]||{}).each {|m| out << m.to_nutshell }
|
37
37
|
# out << "</ul>"
|
38
38
|
# end
|
39
|
-
|
40
|
-
|
39
|
+
|
40
|
+
def sortable_on_that_page?(r)
|
41
41
|
@schema.key?('position') && (@schema['position'][:scope].nil? || (r['filter']||{}).key?(@schema['position'][:scope]))
|
42
42
|
end
|
43
43
|
|
@@ -53,80 +53,80 @@ module PopulateMe
|
|
53
53
|
private
|
54
54
|
|
55
55
|
def image_slot(name='image',opts={})
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
56
|
+
super(name,opts)
|
57
|
+
# First image slot is considered the best populate thumb by default
|
58
|
+
unless instance_methods.include?(:to_populate_thumb)
|
59
|
+
define_method :to_populate_thumb do |style|
|
60
|
+
generic_thumb(name, style)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
64
|
|
65
|
-
|
65
|
+
end
|
66
66
|
|
67
67
|
module InstanceMethods
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
69
|
+
def after_stash(col)
|
70
|
+
convert(col, "-resize '100x75^' -gravity center -extent 100x75", 'stash_thumb_gif')
|
71
|
+
end
|
72
72
|
|
73
73
|
def generic_thumb(img , size='stash_thumb_gif', obj=self)
|
74
74
|
return placeholder_thumb(size) if obj.nil?
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
75
|
+
current = obj.doc[img]
|
76
|
+
if !current.nil? && !current[size].nil?
|
77
|
+
"/gridfs/#{current[size]}"
|
78
|
+
else
|
79
|
+
placeholder_thumb(size)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def placeholder_thumb(size)
|
84
84
|
"/_public/img/placeholder.#{size.gsub(/^(.*)_([a-zA-Z]+)$/, '\1.\2')}"
|
85
85
|
end
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
86
|
+
|
87
|
+
def to_nutshell
|
88
|
+
{
|
89
|
+
'class_name'=>model.name,
|
90
|
+
'id'=>@doc['_id'].to_s,
|
91
|
+
'foreign_key_name'=>model.foreign_key_name,
|
92
|
+
'title'=>self.to_label,
|
93
|
+
'thumb'=>self.respond_to?(:to_populate_thumb) ? self.to_populate_thumb('stash_thumb_gif') : nil,
|
94
|
+
'children'=>nutshell_children,
|
95
|
+
}
|
96
96
|
end
|
97
|
-
|
98
|
-
|
97
|
+
|
98
|
+
def in_nutshell
|
99
99
|
o = model.list_options
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
100
|
+
out = "<div class='in-nutshell'>\n"
|
101
|
+
out << self.to_populate_thumb('nutshell_jpg') if self.respond_to?(:to_populate_thumb)
|
102
|
+
cols = model.populate_config[:quick_update_fields] || nutshell_backend_columns.select{|col|
|
103
|
+
[:boolean,:select].include?(model.schema[col][:type]) && !model.schema[col][:multiple] && !model.schema[col][:no_quick_update]
|
104
|
+
}
|
105
|
+
cols.each do |c|
|
106
|
+
column_label = c.to_s.sub(/^id_/, '').tr('_', ' ').capitalize
|
107
|
+
out << "<div class='quick-update'><form><span class='column-title'>#{column_label}:</span> #{self.crushyinput(c)}</form></div>\n"
|
108
|
+
end
|
109
|
+
out << "</div>\n"
|
110
110
|
end
|
111
111
|
|
112
|
-
|
113
|
-
|
114
|
-
|
112
|
+
def nutshell_backend_associations
|
113
|
+
model.relationships
|
114
|
+
end
|
115
115
|
|
116
116
|
def nutshell_children
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
117
|
+
nutshell_backend_associations.inject([]) do |arr, (k, opts)|
|
118
|
+
unless opts[:hidden]
|
119
|
+
klass = Kernel.const_get(k)
|
120
|
+
arr << {
|
121
|
+
'children_class_name'=>k,
|
122
|
+
'title'=>opts[:link_text] || "#{klass.human_name}(s)",
|
123
|
+
'count'=>self.children_count(klass),
|
124
|
+
}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
130
|
|
131
131
|
end
|
132
132
|
end
|
@@ -5,14 +5,14 @@ module PopulateMe
|
|
5
5
|
|
6
6
|
# This module gives models the ability to deal with attachments
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
def self.included(base)
|
9
|
+
Stash.classes << base
|
10
|
+
base.extend(ClassMethods)
|
11
|
+
base.gridfs = GRID
|
12
|
+
end
|
13
13
|
|
14
14
|
module ClassMethods
|
15
|
-
|
15
|
+
attr_accessor :gridfs
|
16
16
|
def all_after_stash
|
17
17
|
self.collection.find.each do |i|
|
18
18
|
self.schema.each do |k,v|
|
@@ -21,110 +21,110 @@ module PopulateMe
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
24
|
+
end
|
25
|
+
|
26
|
+
# Instance Methods
|
27
|
+
|
28
|
+
def build_image_tag(col='image', style='original', html_attributes={})
|
29
|
+
return '' if @doc[col].nil?||@doc[col][style].nil?
|
30
|
+
title_field, alt_field = col+'_tooltip', col+'_alternative_text'
|
31
|
+
title = @doc[title_field] if model.schema.keys.include?(title_field)
|
32
|
+
alt = @doc[alt_field] if model.schema.keys.include?(alt_field)
|
33
|
+
html_attributes = {:src => "/gridfs/#{@doc[col][style]}", :title => title, :alt => alt}.update(html_attributes)
|
34
|
+
html_attributes = html_attributes.map do |k,v|
|
35
|
+
%{#{k}="#{model.html_escape(v.to_s)}"}
|
36
|
+
end.join(' ')
|
37
|
+
"<img #{html_attributes} />"
|
38
|
+
end
|
39
39
|
|
40
|
-
|
41
|
-
|
40
|
+
def fix_type_attachment(k,v)
|
41
|
+
if v=='nil'
|
42
42
|
delete_files_for(k) unless new?
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
@doc[k] = nil
|
44
|
+
elsif v.is_a?(Hash)&&v.key?(:tempfile)
|
45
|
+
delete_files_for(k) unless new?
|
46
|
+
@temp_attachments ||= {}
|
47
|
+
@temp_attachments[k] = v
|
48
48
|
attachment_id = model.gridfs.put(v[:tempfile], {:filename=>v[:filename], :content_type=>v[:type]})
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
@doc[k] = {'original'=>attachment_id}
|
50
|
+
end
|
51
|
+
end
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
53
|
+
def delete_files_for(col)
|
54
|
+
obj = (@old_doc||@doc)[col]
|
55
|
+
if obj.respond_to?(:each)
|
56
|
+
obj.each do |k,v|
|
57
|
+
model.gridfs.delete(v)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
61
|
|
62
|
-
|
63
|
-
|
62
|
+
def after_delete
|
63
|
+
super
|
64
64
|
model.schema.each do |k,v|
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
delete_files_for(k) if v[:type]==:attachment
|
66
|
+
end
|
67
|
+
end
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
69
|
+
def after_save
|
70
|
+
super
|
71
|
+
unless @temp_attachments.nil?
|
72
|
+
@temp_attachments.each do |k,v|
|
73
|
+
after_stash(k)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
77
|
|
78
|
-
|
78
|
+
def after_stash(col); end
|
79
79
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
80
|
+
def convert(col, convert_steps, style)
|
81
|
+
return if @doc[col].nil?
|
82
|
+
if @temp_attachments.nil? || @temp_attachments[col].nil?
|
83
|
+
f = model.gridfs.get(@doc[col]['original']) rescue nil
|
84
|
+
return if f.nil?
|
85
|
+
return unless f.content_type[/^image\//]
|
86
|
+
src = Tempfile.new('MongoStash_src')
|
87
|
+
src.binmode
|
88
|
+
src.write(f.read(4096)) until f.eof?
|
89
|
+
src.close
|
90
|
+
@temp_attachments ||= {}
|
91
|
+
@temp_attachments[col] ||= {}
|
92
|
+
@temp_attachments[col][:tempfile] = src
|
93
|
+
@temp_attachments[col][:type] = f.content_type
|
94
|
+
else
|
95
|
+
return unless @temp_attachments[col][:type][/^image\//]
|
96
|
+
src = @temp_attachments[col][:tempfile]
|
97
|
+
end
|
98
|
+
model.gridfs.delete(@doc[col][style]) unless @doc[col][style].nil?
|
99
|
+
ext = style[/[a-zA-Z]+$/].insert(0,'.')
|
100
|
+
content_type = Rack::Mime.mime_type(ext)
|
101
101
|
unless content_type[/^image\//]
|
102
102
|
ext = '.jpg'
|
103
103
|
content_type = 'image/jpeg'
|
104
104
|
end
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
105
|
+
dest = Tempfile.new(['MongoStash_dest', ext])
|
106
|
+
dest.binmode
|
107
|
+
dest.close
|
108
|
+
system "convert \"#{src.path}\" #{convert_steps} \"#{dest.path}\""
|
109
|
+
filename = "#{model.name}/#{self.id}/#{style}"
|
110
|
+
attachment_id = model.gridfs.put(dest.open, {:filename=>filename, :content_type=>content_type})
|
111
111
|
@doc[col] = @doc[col].update({style=>attachment_id})
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
112
|
+
model.collection.update({'_id'=>@doc['_id']}, @doc)
|
113
|
+
#src.close!
|
114
|
+
dest.close!
|
115
|
+
end
|
116
116
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
117
|
+
class << self
|
118
|
+
attr_accessor :classes
|
119
|
+
Stash.classes = []
|
120
|
+
|
121
|
+
def all_after_stash
|
122
|
+
Stash.classes.each do |m|
|
123
123
|
m.all_after_stash
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def fix_dots_in_keys(c, for_real=false)
|
128
128
|
puts "\n#{c}" unless for_real
|
129
129
|
img_keys = c.schema.select{|k,v| v[:type]==:attachment }.keys
|
130
130
|
c.find({}, {:fields=>img_keys}).each do |e|
|
@@ -153,7 +153,7 @@ module PopulateMe
|
|
153
153
|
end
|
154
154
|
end
|
155
155
|
|
156
|
-
|
156
|
+
end
|
157
157
|
|
158
158
|
end
|
159
159
|
end
|
data/populate-me.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'populate-me'
|
3
|
-
s.version = "0.0.
|
3
|
+
s.version = "0.0.17"
|
4
4
|
s.platform = Gem::Platform::RUBY
|
5
5
|
s.summary = "ALPHA !!! Populate Me is relatively complete but simple CMS"
|
6
6
|
s.description = "ALPHA !!! Populate Me is relatively complete but simple CMS. It includes a Rack middleware for putting in your Rack stack, and a bespoke MongoDB ODM. But Populate Me is not really finished yet."
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: populate-me
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.17
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-10-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack-golem
|