populate-me 0.0.33 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/LICENSE +1 -1
- data/README.md +399 -4
- data/Rakefile +14 -0
- data/example/config.ru +67 -0
- data/lib/populate_me.rb +2 -0
- data/lib/populate_me/admin.rb +143 -0
- data/lib/populate_me/admin/__assets__/css/main.css +174 -0
- data/lib/populate_me/admin/__assets__/js/columnav.js +82 -0
- data/lib/populate_me/admin/__assets__/js/main.js +251 -0
- data/lib/populate_me/admin/__assets__/js/mustache.js +578 -0
- data/lib/populate_me/admin/__assets__/js/sortable.js +2 -0
- data/lib/populate_me/admin/views/page.erb +163 -0
- data/lib/populate_me/api.rb +124 -0
- data/lib/populate_me/attachment.rb +182 -0
- data/lib/populate_me/document.rb +178 -0
- data/lib/populate_me/document_mixins/admin_adapter.rb +131 -0
- data/lib/populate_me/document_mixins/callbacks.rb +104 -0
- data/lib/populate_me/document_mixins/outcasting.rb +49 -0
- data/lib/populate_me/document_mixins/persistence.rb +92 -0
- data/lib/populate_me/document_mixins/schema.rb +99 -0
- data/lib/populate_me/document_mixins/typecasting.rb +60 -0
- data/lib/populate_me/document_mixins/validation.rb +44 -0
- data/lib/populate_me/file_system_attachment.rb +40 -0
- data/lib/populate_me/grid_fs_attachment.rb +127 -0
- data/lib/populate_me/mongo.rb +98 -3
- data/lib/populate_me/variation.rb +34 -0
- data/lib/populate_me/version.rb +4 -0
- data/populate-me.gemspec +20 -12
- data/test/helper.rb +37 -0
- data/test/test_admin.rb +161 -0
- data/test/test_api.rb +246 -0
- data/test/test_attachment.rb +155 -0
- data/test/test_document.rb +120 -0
- data/test/test_document_admin_adapter.rb +43 -0
- data/test/test_document_callbacks.rb +107 -0
- data/test/test_document_persistence.rb +56 -0
- data/test/test_document_typecasting.rb +121 -0
- data/test/test_mongo.rb +217 -0
- data/test/test_variation.rb +91 -0
- data/test/test_version.rb +11 -0
- metadata +115 -66
- data/lib/populate_me/control.rb +0 -196
- data/lib/populate_me/control/_public/css/main.css +0 -207
- data/lib/populate_me/control/_public/css/plugin.asmselect.css +0 -63
- 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 +0 -430
- data/lib/populate_me/control/_public/img/grip.png +0 -0
- data/lib/populate_me/control/_public/img/icons-cms-solarized.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 +0 -20
- data/lib/populate_me/control/_public/js/jquery-ui.js +0 -114
- data/lib/populate_me/control/_public/js/jquery.js +0 -167
- data/lib/populate_me/control/_public/js/jquery.mustache.js +0 -559
- data/lib/populate_me/control/_public/js/main.js +0 -144
- data/lib/populate_me/control/_public/js/plugin.asmselect.js +0 -407
- data/lib/populate_me/control/_public/js/plugin.form.js +0 -11
- data/lib/populate_me/control/_public/js/plugin.quicksearch.js +0 -1
- data/lib/populate_me/control/_public/js/plugin.underwood.js +0 -4
- data/lib/populate_me/control/views/populate_me_layout.erb +0 -75
- data/lib/populate_me/ext.rb +0 -16
- data/lib/populate_me/mongo/backend_api_plug.rb +0 -78
- data/lib/populate_me/mongo/crushyform.rb +0 -243
- data/lib/populate_me/mongo/mutation.rb +0 -324
- data/lib/populate_me/mongo/plug.rb +0 -134
- data/lib/populate_me/mongo/stash.rb +0 -171
- data/test/spec_ext.rb +0 -29
- data/test/spec_mongo_mutation.rb +0 -279
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'web_utils'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
require 'populate_me/document_mixins/typecasting'
|
5
|
+
require 'populate_me/document_mixins/outcasting'
|
6
|
+
require 'populate_me/document_mixins/schema'
|
7
|
+
require 'populate_me/document_mixins/admin_adapter'
|
8
|
+
require 'populate_me/document_mixins/callbacks'
|
9
|
+
require 'populate_me/document_mixins/validation'
|
10
|
+
require 'populate_me/document_mixins/persistence'
|
11
|
+
|
12
|
+
module PopulateMe
|
13
|
+
|
14
|
+
class MissingDocumentError < StandardError; end
|
15
|
+
class MissingAttachmentClassError < StandardError; end
|
16
|
+
|
17
|
+
class Document
|
18
|
+
|
19
|
+
# PopulateMe::Document is the base for any document
|
20
|
+
# the Backend is supposed to deal with.
|
21
|
+
#
|
22
|
+
# Any module for a specific ORM or ODM should
|
23
|
+
# subclass it.
|
24
|
+
# It contains what is not specific to a particular kind
|
25
|
+
# of database and it provides defaults.
|
26
|
+
#
|
27
|
+
# It can be used on its own but it keeps everything
|
28
|
+
# in memory. Which means it is only for tests and conceptual
|
29
|
+
# understanding.
|
30
|
+
|
31
|
+
include DocumentMixins::Typecasting
|
32
|
+
include DocumentMixins::Outcasting
|
33
|
+
include DocumentMixins::Schema
|
34
|
+
include DocumentMixins::AdminAdapter
|
35
|
+
include DocumentMixins::Callbacks
|
36
|
+
include DocumentMixins::Validation
|
37
|
+
include DocumentMixins::Persistence
|
38
|
+
|
39
|
+
class << self
|
40
|
+
|
41
|
+
def inherited sub
|
42
|
+
super
|
43
|
+
sub.callbacks = WebUtils.deep_copy callbacks
|
44
|
+
sub.settings = settings.dup # no deep copy because of Mongo.settings.db
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_s
|
48
|
+
super.gsub(/[A-Z]/, ' \&')[1..-1].gsub('::','')
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s_short
|
52
|
+
self.name[/[^:]+$/].gsub(/[A-Z]/, ' \&')[1..-1]
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_s_plural; WebUtils.pluralize(self.to_s); end
|
56
|
+
def to_s_short_plural; WebUtils.pluralize(self.to_s_short); end
|
57
|
+
|
58
|
+
def from_hash hash, o={}
|
59
|
+
self.new(_is_new: false).set_from_hash(hash, o).snapshot
|
60
|
+
end
|
61
|
+
|
62
|
+
def cast o={}, &block
|
63
|
+
target = block.arity==0 ? instance_eval(&block) : block.call(self)
|
64
|
+
return nil if target.nil?
|
65
|
+
return from_hash(target, o) if target.is_a?(Hash)
|
66
|
+
return target.map{|t| from_hash(t,o)} if target.respond_to?(:map)
|
67
|
+
raise(TypeError, "The block passed to #{self.name}::cast is meant to return a Hash or a list of Hash which respond to `map`")
|
68
|
+
end
|
69
|
+
|
70
|
+
# inheritable settings
|
71
|
+
attr_accessor :settings
|
72
|
+
def set name, value
|
73
|
+
self.settings[name] = value
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
attr_accessor :id, :_is_new, :_old
|
79
|
+
|
80
|
+
def initialize attributes=nil
|
81
|
+
self._is_new = true
|
82
|
+
set attributes if attributes
|
83
|
+
self._errors = {}
|
84
|
+
end
|
85
|
+
|
86
|
+
def inspect
|
87
|
+
"#<#{self.class.name}:#{to_h.inspect}>"
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_s
|
91
|
+
return inspect if self.class.label_field.nil?
|
92
|
+
me = self.__send__(self.class.label_field)
|
93
|
+
WebUtils.blank?(me) ? inspect : me
|
94
|
+
end
|
95
|
+
|
96
|
+
def new?; self._is_new; end
|
97
|
+
|
98
|
+
def to_h
|
99
|
+
persistent_instance_variables.inject({'_class'=>self.class.name}) do |h,var|
|
100
|
+
k = var.to_s[1..-1]
|
101
|
+
v = instance_variable_get var
|
102
|
+
if v.is_a? Array
|
103
|
+
h[k] = v.map(&:to_h)
|
104
|
+
else
|
105
|
+
h[k] = v
|
106
|
+
end
|
107
|
+
h
|
108
|
+
end
|
109
|
+
end
|
110
|
+
alias_method :to_hash, :to_h
|
111
|
+
|
112
|
+
def snapshot
|
113
|
+
self._old = self.to_h
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
117
|
+
def nested_docs
|
118
|
+
persistent_instance_variables.map do |var|
|
119
|
+
instance_variable_get var
|
120
|
+
end.find_all do |val|
|
121
|
+
val.is_a? Array
|
122
|
+
end.flatten
|
123
|
+
end
|
124
|
+
|
125
|
+
def == other
|
126
|
+
return false unless other.respond_to?(:to_h)
|
127
|
+
other.to_h==to_h
|
128
|
+
end
|
129
|
+
|
130
|
+
def set attributes
|
131
|
+
attributes.dup.each do |k,v|
|
132
|
+
setter = "#{k}="
|
133
|
+
if respond_to? setter
|
134
|
+
__send__ setter, v
|
135
|
+
end
|
136
|
+
end
|
137
|
+
self
|
138
|
+
end
|
139
|
+
|
140
|
+
def set_defaults o={}
|
141
|
+
self.class.fields.each do |k,v|
|
142
|
+
if v.key?(:default)&&(__send__(k).nil?||o[:force])
|
143
|
+
set k.to_sym => WebUtils.get_value(v[:default],self)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
149
|
+
def set_from_hash hash, o={}
|
150
|
+
raise(TypeError, "#{hash} is not a Hash") unless hash.is_a? Hash
|
151
|
+
hash = hash.dup # Leave original untouched
|
152
|
+
hash.delete('_class')
|
153
|
+
hash.each do |k,v|
|
154
|
+
getter = k.to_sym
|
155
|
+
if v.is_a? Array
|
156
|
+
break unless respond_to?(getter)
|
157
|
+
__send__(getter).clear
|
158
|
+
v.each do |d|
|
159
|
+
obj = WebUtils.resolve_class_name(d['_class']).new.set_from_hash(d,o)
|
160
|
+
__send__(getter) << obj
|
161
|
+
end
|
162
|
+
else
|
163
|
+
v = typecast(getter,v) if o[:typecast]
|
164
|
+
set getter => v
|
165
|
+
end
|
166
|
+
end
|
167
|
+
self
|
168
|
+
end
|
169
|
+
|
170
|
+
# class settings
|
171
|
+
def settings
|
172
|
+
self.class.settings
|
173
|
+
end
|
174
|
+
self.settings = OpenStruct.new
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module PopulateMe
|
2
|
+
module DocumentMixins
|
3
|
+
module AdminAdapter
|
4
|
+
|
5
|
+
def to_admin_url
|
6
|
+
"#{Utils.dasherize_class_name(self.class.name)}/#{id}".sub(/\/$/,'')
|
7
|
+
end
|
8
|
+
|
9
|
+
def admin_image_url
|
10
|
+
thefield = self.class.admin_image_field
|
11
|
+
return nil if thefield.nil?
|
12
|
+
self.attachment(thefield).url(:populate_me_thumb)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_admin_list_item o={}
|
16
|
+
{
|
17
|
+
class_name: self.class.name,
|
18
|
+
id: self.id,
|
19
|
+
admin_url: to_admin_url,
|
20
|
+
title: to_s,
|
21
|
+
image_url: admin_image_url,
|
22
|
+
local_menu: self.class.relationships.inject([]) do |out,(k,v)|
|
23
|
+
unless v[:hidden]
|
24
|
+
out << {
|
25
|
+
title: "#{v[:label]}",
|
26
|
+
href: "#{o[:request].script_name}/list/#{Utils.dasherize_class_name(v[:class_name])}?filter[#{v[:foreign_key]}]=#{self.id}"
|
27
|
+
}
|
28
|
+
out
|
29
|
+
end
|
30
|
+
end
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_admin_form o={}
|
35
|
+
o[:input_name_prefix] ||= 'data'
|
36
|
+
class_item = {
|
37
|
+
type: :hidden,
|
38
|
+
input_name: "#{o[:input_name_prefix]}[_class]",
|
39
|
+
input_value: self.class.name,
|
40
|
+
}
|
41
|
+
self.class.complete_field_options :_class, class_item
|
42
|
+
items = self.class.fields.inject([class_item]) do |out,(k,item)|
|
43
|
+
item = item.dup
|
44
|
+
if item[:form_field]
|
45
|
+
outcast k, item, o
|
46
|
+
out << item
|
47
|
+
end
|
48
|
+
out
|
49
|
+
end
|
50
|
+
{
|
51
|
+
template: "template#{'_nested' if o[:nested]}_form",
|
52
|
+
page_title: self.new? ? "New #{self.class.to_s_short}" : self.to_s,
|
53
|
+
admin_url: self.to_admin_url,
|
54
|
+
is_new: self.new?,
|
55
|
+
fields: items
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.included(base)
|
60
|
+
base.extend(ClassMethods)
|
61
|
+
end
|
62
|
+
|
63
|
+
module ClassMethods
|
64
|
+
|
65
|
+
def admin_image_field
|
66
|
+
res = self.fields.find do |k,v|
|
67
|
+
if v[:type]==:attachment and !v[:variations].nil?
|
68
|
+
v[:variations].any?{|var|var.name==:populate_me_thumb}
|
69
|
+
else
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
res.nil? ? nil : res[0]
|
74
|
+
end
|
75
|
+
|
76
|
+
def admin_get id
|
77
|
+
self.cast do
|
78
|
+
documents.find{|doc| doc[id_string_key]==id }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def admin_find o={}
|
83
|
+
o[:query] ||= {}
|
84
|
+
docs = self.cast{documents}.find_all do |d|
|
85
|
+
o[:query].inject(true) do |out,(k,v)|
|
86
|
+
out && (d.__send__(k)==v)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
docs.sort!(&@sort_proc) if @sort_proc.is_a?(Proc)
|
90
|
+
docs
|
91
|
+
end
|
92
|
+
|
93
|
+
def sort_field_for o={}
|
94
|
+
filter = o[:params][:filter]
|
95
|
+
return nil if !filter.nil?&&filter.size>1
|
96
|
+
expected_scope = filter.nil? ? nil : filter.keys[0].to_sym
|
97
|
+
f = self.fields.find do |k,v|
|
98
|
+
v[:type]==:position&&v[:scope]==expected_scope
|
99
|
+
end
|
100
|
+
f.nil? ? nil : f[0]
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_admin_list o={}
|
104
|
+
o[:params] ||= {}
|
105
|
+
unless o[:params][:filter].nil?
|
106
|
+
query = o[:params][:filter].inject({}) do |q, (k,v)|
|
107
|
+
q[k.to_sym] = self.new.typecast(k,v)
|
108
|
+
q
|
109
|
+
end
|
110
|
+
new_data = Rack::Utils.build_nested_query(data: o[:params][:filter])
|
111
|
+
end
|
112
|
+
{
|
113
|
+
template: 'template_list',
|
114
|
+
page_title: self.to_s_short_plural,
|
115
|
+
dasherized_class_name: PopulateMe::Utils.dasherize_class_name(self.name),
|
116
|
+
new_data: new_data,
|
117
|
+
sort_field: self.sort_field_for(o),
|
118
|
+
# 'command_plus'=> !self.populate_config[:no_plus],
|
119
|
+
# 'command_search'=> !self.populate_config[:no_search],
|
120
|
+
items: self.admin_find(query: query).map do |d|
|
121
|
+
d.to_admin_list_item(o)
|
122
|
+
end
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module PopulateMe
|
2
|
+
module DocumentMixins
|
3
|
+
module Callbacks
|
4
|
+
|
5
|
+
def exec_callback name
|
6
|
+
name = name.to_sym
|
7
|
+
return self if self.class.callbacks[name].nil?
|
8
|
+
self.class.callbacks[name].each do |job|
|
9
|
+
if job.respond_to?(:call)
|
10
|
+
self.instance_exec name, &job
|
11
|
+
else
|
12
|
+
meth = self.method(job)
|
13
|
+
meth.arity==1 ? meth.call(name) : meth.call
|
14
|
+
end
|
15
|
+
end
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def recurse_callback name
|
20
|
+
nested_docs.each do |d|
|
21
|
+
d.exec_callback name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def ensure_id
|
26
|
+
if self.id.nil?
|
27
|
+
self.id = WebUtils::generate_random_id
|
28
|
+
end
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def ensure_not_new; self._is_new = false; end
|
33
|
+
|
34
|
+
def ensure_delete_related
|
35
|
+
self.class.relationships.each do |k,v|
|
36
|
+
if v[:dependent]
|
37
|
+
klass = WebUtils.resolve_class_name v[:class_name]
|
38
|
+
next if klass.nil?
|
39
|
+
klass.admin_find(query: {v[:foreign_key]=>self.id}).each do |d|
|
40
|
+
d.delete
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def ensure_delete_attachments
|
47
|
+
self.class.fields.each do |k,v|
|
48
|
+
if v[:type]==:attachment
|
49
|
+
self.attachment(k).delete_all
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def ensure_new; self._is_new = true; end
|
55
|
+
|
56
|
+
def self.included(base)
|
57
|
+
base.extend(ClassMethods)
|
58
|
+
base.class_eval do
|
59
|
+
[:save,:create,:update,:delete].each do |cb|
|
60
|
+
before cb, :recurse_callback
|
61
|
+
after cb, :recurse_callback
|
62
|
+
end
|
63
|
+
before :create, :ensure_id
|
64
|
+
after :create, :ensure_not_new
|
65
|
+
after :save, :snapshot
|
66
|
+
before :delete, :ensure_delete_related
|
67
|
+
before :delete, :ensure_delete_attachments
|
68
|
+
after :delete, :ensure_new
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
module ClassMethods
|
73
|
+
|
74
|
+
attr_accessor :callbacks
|
75
|
+
|
76
|
+
def register_callback name, item=nil, options={}, &block
|
77
|
+
name = name.to_sym
|
78
|
+
if block_given?
|
79
|
+
options = item || {}
|
80
|
+
item = block
|
81
|
+
end
|
82
|
+
self.callbacks ||= {}
|
83
|
+
self.callbacks[name] ||= []
|
84
|
+
if options[:prepend]
|
85
|
+
self.callbacks[name].unshift item
|
86
|
+
else
|
87
|
+
self.callbacks[name] << item
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def before name, item=nil, options={}, &block
|
92
|
+
register_callback "before_#{name}", item, options, &block
|
93
|
+
end
|
94
|
+
|
95
|
+
def after name, item=nil, options={}, &block
|
96
|
+
register_callback "after_#{name}", item, options, &block
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module PopulateMe
|
2
|
+
module DocumentMixins
|
3
|
+
module Outcasting
|
4
|
+
|
5
|
+
# This module prepares the field for being send to the Admin API
|
6
|
+
# and build the form.
|
7
|
+
# It compiles the value and all other info in a hash.
|
8
|
+
# Therefore, it is a complement to the AdminAdapter module.
|
9
|
+
|
10
|
+
def outcast field, item, o={}
|
11
|
+
item[:input_name] = "#{o[:input_name_prefix]}[#{item[:field_name]}]"
|
12
|
+
unless item[:type]==:list
|
13
|
+
WebUtils.ensure_key! item, :input_value, self.__send__(field)
|
14
|
+
end
|
15
|
+
meth = "outcast_#{item[:type]}".to_sym
|
16
|
+
__send__(meth, field, item, o) if respond_to?(meth)
|
17
|
+
end
|
18
|
+
|
19
|
+
def outcast_list field, item, o={}
|
20
|
+
item[:items] = self.__send__(field).map do |nested|
|
21
|
+
nested.to_admin_form(o.merge(input_name_prefix: item[:input_name]+'[]'))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def outcast_select field, item, o={}
|
26
|
+
unless item[:select_options].nil?
|
27
|
+
opts = WebUtils.get_value(item[:select_options],self).dup
|
28
|
+
opts.map! do |opt|
|
29
|
+
if opt.is_a?(String)||opt.is_a?(Symbol)
|
30
|
+
opt = [opt.to_s.capitalize,opt]
|
31
|
+
end
|
32
|
+
if opt.is_a?(Array)
|
33
|
+
opt = {description: opt[0].to_s, value: opt[1].to_s}
|
34
|
+
end
|
35
|
+
opt[:selected] = true if item[:input_value]==opt[:value]
|
36
|
+
opt
|
37
|
+
end
|
38
|
+
item[:select_options] = opts
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def outcast_attachment field, item, o={}
|
43
|
+
item[:url] = self.attachment(field).url
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|