engine2 1.0.4 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +0 -0
  3. data/Rakefile +4 -4
  4. data/app/{engine2actions.coffee → actions.coffee} +341 -215
  5. data/app/app.coffee +0 -0
  6. data/app/app.css +17 -0
  7. data/app/engine2.coffee +158 -208
  8. data/app/modal.coffee +138 -0
  9. data/bower.json +4 -2
  10. data/conf/message.yaml +5 -0
  11. data/conf/message_pl.yaml +7 -2
  12. data/config.coffee +24 -12
  13. data/engine2.gemspec +8 -8
  14. data/lib/engine2.rb +12 -10
  15. data/lib/engine2/action.rb +1338 -133
  16. data/lib/engine2/action/array.rb +189 -0
  17. data/lib/engine2/{meta/decode_meta.rb → action/decode.rb} +52 -21
  18. data/lib/engine2/action/delete.rb +64 -0
  19. data/lib/engine2/action/form.rb +16 -0
  20. data/lib/engine2/{meta/infra_meta.rb → action/infra.rb} +123 -89
  21. data/lib/engine2/action/link.rb +117 -0
  22. data/lib/engine2/action/list.rb +333 -0
  23. data/lib/engine2/action/save.rb +28 -0
  24. data/lib/engine2/action/view.rb +8 -0
  25. data/lib/engine2/action_node.rb +221 -0
  26. data/lib/engine2/core.rb +175 -87
  27. data/lib/engine2/handler.rb +14 -13
  28. data/lib/engine2/model.rb +85 -43
  29. data/lib/engine2/models/Files.rb +4 -1
  30. data/lib/engine2/models/UserInfo.rb +6 -3
  31. data/lib/engine2/post_bootstrap.rb +4 -3
  32. data/lib/engine2/pre_bootstrap.rb +10 -6
  33. data/lib/engine2/scheme.rb +107 -65
  34. data/lib/engine2/templates.rb +41 -6
  35. data/lib/engine2/type_info.rb +51 -23
  36. data/lib/engine2/version.rb +2 -1
  37. data/package.json +22 -16
  38. data/public/favicon.ico +0 -0
  39. data/public/img/ajax-loader-dark.gif +0 -0
  40. data/public/img/ajax-loader.gif +0 -0
  41. data/views/fields/blob.slim +1 -1
  42. data/views/fields/bs_select.slim +2 -2
  43. data/views/fields/bsselect_picker.slim +4 -4
  44. data/views/fields/bsselect_picker_opt.slim +5 -5
  45. data/views/fields/checkbox.slim +4 -4
  46. data/views/fields/checkbox_button.slim +6 -0
  47. data/views/fields/checkbox_buttons.slim +3 -3
  48. data/views/fields/checkbox_buttons_opt.slim +3 -3
  49. data/views/fields/currency.slim +2 -2
  50. data/views/fields/date.slim +4 -4
  51. data/views/fields/date_range.slim +9 -9
  52. data/views/fields/date_time.slim +9 -9
  53. data/views/fields/datetime.slim +8 -8
  54. data/views/fields/decimal.slim +1 -1
  55. data/views/fields/decimal_date.slim +3 -3
  56. data/views/fields/decimal_time.slim +3 -3
  57. data/views/fields/email.slim +3 -3
  58. data/views/fields/file_store.slim +11 -11
  59. data/views/fields/input_text.slim +4 -4
  60. data/views/fields/integer.slim +1 -1
  61. data/views/fields/list_bsmselect.slim +20 -0
  62. data/views/fields/list_bsselect.slim +5 -5
  63. data/views/fields/list_bsselect_opt.slim +6 -6
  64. data/views/fields/list_buttons.slim +1 -1
  65. data/views/fields/list_buttons_opt.slim +2 -2
  66. data/views/fields/list_mbuttons.slim +9 -0
  67. data/views/fields/list_mbuttons_opt.slim +11 -0
  68. data/views/fields/list_mselect.slim +12 -0
  69. data/views/fields/list_select.slim +4 -4
  70. data/views/fields/list_select_opt.slim +5 -5
  71. data/views/fields/password.slim +4 -4
  72. data/views/fields/radio_checkbox.slim +3 -3
  73. data/views/fields/scaffold.slim +2 -2
  74. data/views/fields/scaffold_picker.slim +5 -5
  75. data/views/fields/select_picker.slim +3 -3
  76. data/views/fields/select_picker_opt.slim +4 -4
  77. data/views/fields/text_area.slim +4 -3
  78. data/views/fields/time.slim +5 -4
  79. data/views/fields/typeahead_picker.slim +12 -9
  80. data/views/index.slim +3 -3
  81. data/views/infra/index.slim +0 -0
  82. data/views/infra/inspect.slim +41 -10
  83. data/views/modals/close_m.slim +0 -0
  84. data/views/modals/confirm_m.slim +0 -0
  85. data/views/modals/empty_m.slim +0 -0
  86. data/views/modals/menu_m.slim +1 -1
  87. data/views/modals/yes_no_m.slim +0 -0
  88. data/views/panels/menu_m.slim +1 -1
  89. data/views/scaffold/confirm.slim +0 -0
  90. data/views/scaffold/fields.slim +6 -4
  91. data/views/scaffold/form.slim +1 -1
  92. data/views/scaffold/form_collapse.slim +4 -3
  93. data/views/scaffold/form_tabs.slim +3 -2
  94. data/views/scaffold/list.slim +0 -0
  95. data/views/scaffold/message.slim +0 -0
  96. data/views/scaffold/search.slim +4 -4
  97. data/views/scaffold/search_collapse.slim +8 -7
  98. data/views/scaffold/search_tabs.slim +6 -5
  99. data/views/scaffold/view.slim +2 -2
  100. data/views/scaffold/view_collapse.slim +5 -4
  101. data/views/scaffold/view_tabs.slim +4 -3
  102. data/views/search_fields/bsmselect_picker.slim +4 -4
  103. data/views/search_fields/bsselect_picker.slim +4 -4
  104. data/views/search_fields/checkbox.slim +3 -3
  105. data/views/search_fields/checkbox2.slim +5 -5
  106. data/views/search_fields/checkbox_buttons.slim +3 -3
  107. data/views/search_fields/date.slim +20 -0
  108. data/views/search_fields/date_range.slim +8 -8
  109. data/views/search_fields/decimal_date_range.slim +5 -5
  110. data/views/search_fields/input_text.slim +2 -2
  111. data/views/search_fields/integer.slim +1 -1
  112. data/views/search_fields/integer_range.slim +2 -2
  113. data/views/search_fields/list_bsmselect.slim +4 -4
  114. data/views/search_fields/list_bsselect.slim +4 -4
  115. data/views/search_fields/list_buttons.slim +2 -2
  116. data/views/search_fields/list_mbuttons.slim +12 -0
  117. data/views/search_fields/list_select.slim +3 -3
  118. data/views/search_fields/scaffold_picker.slim +2 -2
  119. data/views/search_fields/select_picker.slim +3 -3
  120. data/views/search_fields/typeahead_picker.slim +8 -7
  121. metadata +53 -48
  122. data/lib/engine2/meta.rb +0 -1216
  123. data/lib/engine2/meta/array_meta.rb +0 -82
  124. data/lib/engine2/meta/delete_meta.rb +0 -60
  125. data/lib/engine2/meta/form_meta.rb +0 -15
  126. data/lib/engine2/meta/link_meta.rb +0 -134
  127. data/lib/engine2/meta/list_meta.rb +0 -281
  128. data/lib/engine2/meta/save_meta.rb +0 -50
  129. data/lib/engine2/meta/view_meta.rb +0 -7
  130. data/public/__sinatra__/404.png +0 -0
  131. data/public/__sinatra__/500.png +0 -0
@@ -1,82 +0,0 @@
1
- # coding: utf-8
2
-
3
- module Engine2
4
- class ArrayListMeta < Meta
5
- meta_type :list
6
- include MetaListSupport
7
-
8
- (DefaultFilters ||= {}).merge!(
9
- exact: lambda{|entries, name, value, type_info, hash|
10
- entries.select{|e|e[name] == value}
11
- },
12
- string: lambda{|entries, name, value, type_info, hash|
13
- entries.select{|e|e[name].to_s[value]}
14
- },
15
- boolean: lambda{|*args| DefaultFilters[:exact].(*args)},
16
- integer: lambda{|entries, name, value, type_info, hash|
17
- if value.is_a? Hash
18
- from, to = value[:from], value[:to]
19
- if from && to
20
- entries.select{|e|e[name] >= from.to_i && e[name] <= to.to_i}
21
- else
22
- entries.select{|e| from ? e[name] >= from.to_i : e[name] <= to.to_i}
23
- end
24
- elsif value.is_a? Integer
25
- entries.select{|e|e[name] == value.to_i}
26
- else
27
- nil
28
- end
29
- }
30
- )
31
-
32
- def data_source handler
33
- []
34
- end
35
-
36
- def invoke handler
37
- params = handler.params
38
- # if params[:initial] || params[:refresh]
39
- entries = data_source(handler)
40
-
41
- per_page = lookup(:config, :per_page)
42
- page = params[:page].to_i
43
- handler.permit page >= 0 && page < 1000
44
-
45
- if order_str = params[:order]
46
- order = order_str.to_sym
47
- handler.permit lookup(:info, order, :sort)
48
- entries = entries.sort_by{|e|e[order].to_s}
49
- entries = entries.reverse if params[:asc] == "true"
50
- end
51
-
52
- if search = params[:search]
53
- entries = list_search(entries, handler, search)
54
- end
55
-
56
- {entries: entries.drop(page).take(per_page), count: entries.size}
57
- end
58
-
59
- def list_search entries, handler, search
60
- hash = JSON.parse(search, symbolize_names: true) rescue handler.halt_forbidden
61
- model = assets[:model]
62
- sfields = lookup(:search_fields)
63
- handler.permit sfields
64
- hash.each_pair do |name, value|
65
- handler.permit sfields.include?(name)
66
-
67
- type_info = get_type_info(name)
68
- entries = if filter = (@filters && @filters[name]) || (dynamic? && (static.filters && static.filters[name]))
69
- filter.(entries, hash, handler)
70
- elsif filter = DefaultFilters[type_info[:otype]]
71
- filter.(entries, name, value, type_info, hash)
72
- else
73
- raise E2Error.new("Filter not found for field '#{name}' in model '#{model}'") unless filter
74
- end
75
-
76
- handler.permit entries
77
- end
78
-
79
- entries
80
- end
81
- end
82
- end
@@ -1,60 +0,0 @@
1
- # coding: utf-8
2
-
3
- module Engine2
4
- class DeleteMetaBase < Meta
5
-
6
- def invoke_delete_db handler, ids
7
- begin
8
- model = assets[:model]
9
- model.db.transaction do
10
- ids.each do |id|
11
- keys = split_keys(id)
12
- restrict = model.association_reflections.select do |name, rel|
13
- case rel[:type]
14
- when :one_to_many
15
- !model.db[name].where(Hash[rel[:keys].zip(keys)]).empty?
16
- when :many_to_many
17
- !model.db[rel[:join_table]].where(Hash[rel[:left_keys].zip(keys)]).empty?
18
- when :many_to_one
19
- when :one_to_one
20
- else
21
- unsupported_association rel[:type]
22
- end
23
- end
24
- raise Sequel::DestroyFailed.new("Blokujące relacje: #{restrict.map{|name, rel| name}.join(', ')}" ) unless restrict.empty?
25
-
26
- rec = model.call(Hash[model.primary_keys.zip(keys)])
27
- rec.destroy(transaction: false)
28
- # model.where(model.primary_keys_hash(keys)).delete # model.dataset[model.primary_key => id].delete
29
- end
30
- end
31
- {}
32
- rescue Sequel::NoExistingObject
33
- handler.halt_not_found LOCS[:no_entry]
34
- rescue Sequel::DestroyFailed => failure
35
- handler.halt_forbidden failure.error.to_s
36
- end
37
- end
38
-
39
- end
40
-
41
- class DeleteMeta < DeleteMetaBase
42
- include MetaDeleteSupport
43
-
44
- def invoke handler
45
- handler.permit id = handler.params[:id]
46
- invoke_delete_db(handler, [id])
47
- end
48
- end
49
-
50
- class BulkDeleteMeta < DeleteMetaBase
51
- include MetaBulkDeleteSupport
52
-
53
- def invoke handler
54
- ids = handler.param_to_json(:ids)
55
- handler.permit ids.is_a?(Array)
56
- invoke_delete_db(handler, ids)
57
- end
58
- end
59
-
60
- end
@@ -1,15 +0,0 @@
1
- # coding: utf-8
2
-
3
- module Engine2
4
- class FormMeta < Meta
5
- include MetaQuerySupport
6
- end
7
-
8
- class CreateMeta < FormMeta
9
- include MetaCreateSupport
10
- end
11
-
12
- class ModifyMeta < FormMeta
13
- include MetaModifySupport
14
- end
15
- end
@@ -1,134 +0,0 @@
1
- # coding: utf-8
2
-
3
- module Engine2
4
- class StarToManyLinkMeta < Meta
5
- include MetaModelSupport
6
- http_method :post
7
- meta_type :star_to_many_link
8
-
9
- def invoke handler
10
- json = handler.post_to_json
11
- parent = json[:parent_id]
12
- ids = json[:ids]
13
- handler.permit parent && ids
14
- model = assets[:model]
15
- assoc = assets[:assoc]
16
- case assoc[:type]
17
- when :one_to_many
18
- model.db.transaction do
19
- self.class.one_to_many_link_db model, assoc, split_keys(parent), ids
20
- end
21
- {}
22
- when :many_to_many
23
- self.class.many_to_many_link_db model, assoc, split_keys(parent), ids
24
- {}
25
- else unsupported_association
26
- end
27
- end
28
-
29
- def self.one_to_many_link_db model, assoc, parent, ids
30
- pk = Hash[assoc[:keys].zip(parent)]
31
- ids.each do |id|
32
- model.where(model.primary_keys_hash(Sequel::split_keys(id))).update(pk)
33
- end
34
- end
35
-
36
- def self.many_to_many_link_db model, assoc, parent, ids
37
- p_pk = Hash[assoc[:left_keys].zip(parent)]
38
- values = ids.map do |id|
39
- p_pk.merge Hash[assoc[:right_keys].zip(Sequel::split_keys(id))]
40
- end
41
- model.db[assoc[:join_table]].multi_insert values
42
- end
43
- end
44
-
45
- class StarToManyUnlinkMetaBase < Meta
46
- include MetaModelSupport
47
- http_method :delete
48
-
49
- def one_to_many_unlink_db handler, ids
50
- model = assets[:model]
51
- assoc = assets[:assoc]
52
- keys = assoc[:keys]
53
- if keys.all?{|k|model.db_schema[k][:allow_null] == true}
54
- model.db.transaction do
55
- self.class.one_to_many_unlink_db model, assoc, ids
56
- end
57
- {}
58
- else
59
- handler.halt_method_not_allowed LOCS[:"non_nullable"]
60
- end
61
- end
62
-
63
- def self.one_to_many_unlink_db model, assoc, ids
64
- keys = assoc[:keys]
65
- ids.each do |id|
66
- model.where(model.primary_keys_hash(Sequel::split_keys(id))).update(Hash[keys.zip([nil])])
67
- end
68
- end
69
-
70
- def many_to_many_unlink_db parent, ids
71
- model = assets[:model]
72
- assoc = assets[:assoc]
73
-
74
- model.db.transaction do
75
- self.class.many_to_many_unlink_db model, assoc, Sequel::split_keys(parent), ids
76
- end
77
- {}
78
- end
79
-
80
- def self.many_to_many_unlink_db model, assoc, parent, ids
81
- p_pk = Hash[assoc[:left_keys].zip(parent)]
82
- ds = model.db[assoc[:join_table]]
83
- ids.each do |id|
84
- ds.where(p_pk, Hash[assoc[:right_keys].zip(Sequel::split_keys(id))]).delete
85
- end
86
- end
87
- end
88
-
89
- class StarToManyUnlinkMeta < StarToManyUnlinkMetaBase
90
- meta_type :star_to_many_unlink
91
-
92
- def pre_run
93
- super
94
- action.parent.parent.*.menu(:item_menu).option :confirm_unlink, icon: "minus", show: "action.selected_size() == 0", button_loc: false
95
- end
96
-
97
- def invoke handler
98
- handler.permit id = handler.params[:id]
99
- assoc = assets[:assoc]
100
- case assoc[:type]
101
- when :one_to_many
102
- one_to_many_unlink_db(handler, [id])
103
- when :many_to_many
104
- handler.permit parent = handler.params[:parent_id]
105
- many_to_many_unlink_db(parent, [id])
106
- else unsupported_association
107
- end
108
- end
109
- end
110
-
111
- class StarToManyBulkUnlinkMeta < StarToManyUnlinkMetaBase
112
- meta_type :star_to_many_bulk_unlink
113
-
114
- def pre_run
115
- super
116
- action.parent.parent.*.select_toggle_menu
117
- action.parent.parent.*.menu(:menu).option_after :default_order, :confirm_bulk_unlink, icon: "minus", show: "action.selected_size() > 0", button_loc: false
118
- end
119
-
120
- def invoke handler
121
- ids = handler.param_to_json(:ids)
122
- handler.permit ids.is_a?(Array)
123
- assoc = assets[:assoc]
124
- case assoc[:type]
125
- when :one_to_many
126
- one_to_many_unlink_db(handler, ids)
127
- when :many_to_many
128
- handler.permit parent = handler.params[:parent_id]
129
- many_to_many_unlink_db(parent, ids)
130
- else unsupported_association
131
- end
132
- end
133
- end
134
- end
@@ -1,281 +0,0 @@
1
- # coding: utf-8
2
-
3
- module Engine2
4
- class ListMeta < Meta
5
- meta_type :list
6
- include MetaListSupport, MetaQuerySupport
7
-
8
- (DefaultFilters ||= {}).merge!(
9
- string: lambda{|query, name, value, type_info, hash|
10
- case type_info[:type]
11
- when :many_to_one
12
- query.where(name => value)
13
- else
14
- query.where(name.like("%#{value}%"))
15
- end
16
- },
17
- date: lambda{|query, name, value, type_info, hash|
18
- if value.is_a? Hash
19
- from, to = value[:from], value[:to]
20
- if from && to
21
- query.where(name => from .. to)
22
- elsif from
23
- query.where(name >= Sequel.string_to_date(from))
24
- elsif to
25
- query.where(name <= Sequel.string_to_date(to))
26
- else
27
- query # ?
28
- end
29
- else
30
- query.where(name => Sequel.string_to_date(value))
31
- end
32
- },
33
- integer: lambda{|query, name, value, type_info, hash|
34
- if value.is_a? Hash
35
- from, to = value[:from], value[:to]
36
- if from && to
37
- query.where(name => from .. to)
38
- else
39
- query.where(from ? name >= from.to_i : name <= to.to_i)
40
- end
41
- elsif value.is_a? Integer
42
- query.where(name => value)
43
- elsif value.is_a? Array
44
- if !value.empty?
45
- case type_info[:type]
46
- when :many_to_one
47
- keys = type_info[:keys]
48
- if keys.length == 1
49
- query.where(name => value)
50
- else
51
- query.where(keys.map{|k| hash[k]}.transpose.map{|vals| Hash[keys.zip(vals)]}.inject{|q, c| q | c})
52
- end
53
- when :list_select
54
- query.where(name => value) # decode in sql query ?
55
- when :integer
56
- query
57
- else
58
- nil
59
- end
60
- else
61
- nil
62
- end
63
- else
64
- nil
65
- end
66
- }
67
- )
68
-
69
- def post_run
70
- query select(*assets[:model].columns.reject{|col| assets[:model].type_info[col][:length].to_i > 20}.take(10)) unless @query
71
- super
72
- end
73
-
74
- def invoke handler
75
- params = handler.params
76
- model = assets[:model]
77
- query = list_context(get_query, handler)
78
-
79
- if search = params[:search]
80
- query = list_search(query, handler, search)
81
- end
82
-
83
- count = query.count if lookup(:config, :use_count)
84
-
85
- if order_str = params[:order]
86
- order = order_str.to_sym
87
- handler.permit lookup(:info, order, :sort)
88
-
89
- if order_blk = (@orders && @orders[order]) || (dynamic? && (static.orders && static.orders[order]))
90
- query = order_blk.(query, handler)
91
- else
92
- order = order.qualify(model.table_name) if model.type_info[order]
93
- query = query.order(order)
94
- end
95
-
96
- query = query.reverse if params[:asc] == "true"
97
- end
98
-
99
- per_page = lookup(:config, :per_page)
100
- page = params[:page].to_i
101
- handler.permit page >= 0 && page < 1000
102
-
103
- query = query.limit(per_page, page)
104
-
105
- res = {entries: query.all}
106
- res[:count] = count if count
107
- res
108
- end
109
-
110
- def list_search query, handler, search
111
- hash = JSON.parse(search, symbolize_names: true) rescue handler.halt_forbidden
112
- model = assets[:model]
113
- sfields = lookup(:search_fields)
114
- handler.permit sfields
115
- hash.each_pair do |name, value|
116
- handler.permit sfields.include?(name)
117
-
118
- type_info = get_type_info(name)
119
- query = if filter = (@filters && @filters[name]) || (dynamic? && (static.filters && static.filters[name]))
120
- filter.(query, hash, handler)
121
- elsif filter = DefaultFilters[type_info[:otype]]
122
- name = model.type_info[name] ? name.qualify(model.table_name) : Sequel.expr(name)
123
- filter.(query, name, value, type_info, hash)
124
- else
125
- raise E2Error.new("Filter not found for field '#{name}' in model '#{model}'") unless filter
126
- end
127
-
128
- handler.permit query
129
- end
130
- query
131
- end
132
-
133
- def list_context query, handler
134
- query
135
- end
136
- end
137
-
138
- #
139
- # Many to One
140
- #
141
- class ManyToOneListMeta < ListMeta
142
- meta_type :many_to_one_list
143
-
144
- def pre_run
145
- super
146
- end
147
- end
148
-
149
- #
150
- # * to Many
151
- #
152
- class StarToManyListMeta < ListMeta
153
- meta_type :star_to_many_list
154
- def pre_run
155
- super
156
- menu(:panel_menu).option_at 0, :cancel, icon: "remove"
157
- panel_title "#{:list.icon} #{LOCS[assets[:assoc][:name]]}"
158
- end
159
-
160
- # def decode_panel_title handler
161
- # if handler.initial?
162
- # # Hash[assets[:model].primary_keys.zip(split_keys(id))]]
163
- # p action.parent.decode_entry.*.invoke_decode([[handler.params[:parent_id]]])
164
- # panel_title "ADFASDF"
165
- # end
166
- # end
167
-
168
- # def post_run
169
- # super
170
- # unless @request_meta_proc
171
- # request{|h| decode_panel_title h}
172
- # end
173
- # end
174
-
175
- def list_context query, handler
176
- handler.permit parent = handler.params[:parent_id]
177
- model = assets[:model]
178
- assoc = assets[:assoc]
179
- parent_keys = split_keys(parent)
180
- case assoc[:type]
181
- when :one_to_many
182
- keys = assoc[:keys]
183
- condition = parent_keys.all?(&:empty?) ? false : Hash[keys.map{|k| k.qualify(model.table_name)}.zip(parent_keys)]
184
- if handler.params[:negate]
185
- query = query.exclude(condition)
186
- query = query.or(Hash[keys.zip([nil])]) if keys.all?{|k|model.db_schema[k][:allow_null] == true} # type_info[:required] ?
187
- query
188
- else
189
- query.where(condition)
190
- end
191
- when :many_to_many
192
- q_pk = model.primary_keys_qualified
193
- j_table = assoc[:join_table]
194
- l_keys = assoc[:left_keys].map{|k| k.qualify(j_table)}
195
- r_keys = assoc[:right_keys].map{|k| k.qualify(j_table)}
196
- r_keys_vals = Hash[r_keys.zip(q_pk)]
197
- l_keys_vals = parent_keys.all?(&:empty?) ? false : Hash[l_keys.zip(parent_keys)]
198
-
199
- if handler.params[:negate]
200
- query.exclude(model.db[j_table].select(nil).where(r_keys_vals, l_keys_vals).exists)
201
- else
202
- # query.qualify.join(j_table, [r_keys_vals, l_keys_vals])
203
- query.qualify.left_join(j_table, r_keys_vals).filter(l_keys_vals)
204
- end
205
- else unsupported_association
206
- end
207
- end
208
- end
209
-
210
- class StarToManyLinkListMeta < StarToManyListMeta
211
- meta_type :star_to_many_link_list
212
- def pre_run
213
- super
214
- panel_title LOCS[:link_title]
215
- menu(:panel_menu).option_at 0, :link, icon: "ok", enabled: "action.selected_size() > 0"
216
- action.parent.*.menu(:menu).option_at 0, :link_list, icon: "paperclip", button_loc: false
217
- end
218
- end
219
-
220
- # *_to_many_field
221
- class StarToManyFieldMeta < StarToManyListMeta
222
- meta_type :star_to_many_field
223
-
224
- def pre_run
225
- super
226
- modal_action false
227
- panel_panel_template false
228
- end
229
-
230
- def list_context query, handler
231
- unlinked = handler.param_to_json(:unlinked)
232
- linked = handler.param_to_json(:linked)
233
- query = super(query, handler)
234
- model = assets[:model]
235
- pks = model.primary_keys_qualified
236
-
237
- if handler.params[:negate]
238
- query = unlinked.map{|ln| pks.zip(split_keys(ln))}.inject(query){|q, c| q.or c}
239
- # query = query.or *unlinked.map{|unl| Hash[model.primary_keys.zip(split_keys(unl))]}.inject{|q, c| q | c}
240
- query = query.where *linked.map{|ln| pks.zip(split_keys(ln)).sql_negate}
241
-
242
- else
243
- query = query.where *unlinked.map{|unl| pks.zip(split_keys(unl)).sql_negate}
244
- # query = query.or *linked.map{|ln| model.primary_keys.zip(split_keys(ln))}
245
- # query = query.or *linked.map{|ln| Hash[model.primary_keys.zip(split_keys(ln))]}.inject{|q, c| q | c}
246
- case assets[:assoc][:type]
247
- when :one_to_many
248
- query = linked.map{|ln| pks.zip(split_keys(ln))}.inject(query){|q, c| q.or c}
249
- when :many_to_many
250
- query = linked.map{|ln| pks.zip(split_keys(ln))}.inject(query){|q, c| q.or c}.distinct
251
- else unsupported_association
252
- end unless linked.empty?
253
- end
254
-
255
- query
256
- end
257
- end
258
-
259
- class StarToManyFieldUnlinkMeta < Meta
260
- meta_type :star_to_many_field_unlink
261
-
262
- def pre_run
263
- super
264
- action.parent.parent.*.menu(:item_menu).option :confirm_unlink, icon: "minus", show: "action.selected_size() == 0", button_loc: false
265
- end
266
- end
267
-
268
- class StarToManyFieldLinkListMeta < StarToManyFieldMeta
269
- meta_type :star_to_many_field_link_list
270
-
271
- def pre_run
272
- super
273
- modal_action true
274
- panel_panel_template 'scaffold/list'
275
- panel_title LOCS[:link_title]
276
- menu(:panel_menu).option_at 0, :link, icon: "ok", enabled: "action.selected_size() > 0"
277
- action.parent.*.menu(:menu).option_at 0, :link_list, icon: "paperclip", button_loc: false
278
- end
279
- end
280
- end
281
-