netzke-basepack 0.5.8 → 0.5.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +18 -0
- data/README.rdoc +11 -4
- data/Rakefile +19 -3
- data/TODO.rdoc +1 -1
- data/generators/netzke_basepack/netzke_basepack_generator.rb +13 -0
- data/generators/netzke_basepack/templates/create_netzke_field_lists.rb +18 -0
- data/generators/netzke_basepack/templates/public_assets/ts-checkbox.gif +0 -0
- data/install.rb +1 -1
- data/javascripts/basepack.js +124 -30
- data/lib/app/models/netzke_field_list.rb +261 -0
- data/lib/app/models/netzke_model_attr_list.rb +21 -0
- data/lib/app/models/netzke_persistent_array_auto_model.rb +58 -0
- data/lib/netzke-basepack.rb +17 -2
- data/lib/netzke/active_record.rb +10 -0
- data/lib/netzke/active_record/association_attributes.rb +102 -0
- data/lib/netzke/active_record/attributes.rb +100 -0
- data/lib/netzke/active_record/combobox_options.rb +43 -0
- data/lib/netzke/active_record/data_accessor.rb +9 -12
- data/lib/netzke/attributes_configurator.rb +195 -0
- data/lib/netzke/basic_app.rb +47 -4
- data/lib/netzke/configuration_panel.rb +1 -1
- data/lib/netzke/data_accessor.rb +7 -30
- data/lib/netzke/fields_configurator.rb +106 -41
- data/lib/netzke/form_panel.rb +28 -125
- data/lib/netzke/form_panel/form_panel_api.rb +2 -3
- data/lib/netzke/form_panel/form_panel_fields.rb +147 -0
- data/lib/netzke/form_panel/form_panel_js.rb +35 -15
- data/lib/netzke/grid_panel.rb +130 -213
- data/lib/netzke/grid_panel/grid_panel_api.rb +254 -257
- data/lib/netzke/grid_panel/grid_panel_columns.rb +226 -0
- data/lib/netzke/grid_panel/grid_panel_js.rb +126 -119
- data/lib/netzke/grid_panel/record_form_window.rb +7 -1
- data/lib/netzke/json_array_editor.rb +61 -0
- data/lib/netzke/plugins/configuration_tool.rb +1 -1
- data/lib/netzke/property_editor.rb +3 -3
- data/lib/netzke/search_panel.rb +164 -27
- data/lib/netzke/tab_panel.rb +14 -12
- data/stylesheets/basepack.css +43 -2
- data/test/app_root/app/models/book.rb +1 -1
- data/test/app_root/app/models/role.rb +3 -0
- data/test/app_root/app/models/user.rb +3 -0
- data/test/app_root/config/database.yml +1 -1
- data/test/app_root/db/migrate/20090102223630_create_netzke_field_lists.rb +18 -0
- data/test/app_root/db/migrate/20090423214303_create_roles.rb +11 -0
- data/test/app_root/db/migrate/20090423222114_create_users.rb +12 -0
- data/test/fixtures/books.yml +4 -2
- data/test/fixtures/categories.yml +2 -2
- data/test/fixtures/genres.yml +6 -6
- data/test/fixtures/roles.yml +8 -0
- data/test/fixtures/users.yml +11 -0
- data/test/test_helper.rb +2 -0
- data/test/unit/active_record_basepack_test.rb +2 -2
- data/test/unit/fields_configuration_test.rb +18 -0
- data/test/unit/grid_panel_test.rb +29 -27
- metadata +41 -16
- data/lib/app/models/netzke_auto_column.rb +0 -4
- data/lib/app/models/netzke_auto_field.rb +0 -4
- data/lib/app/models/netzke_auto_table.rb +0 -61
- data/lib/netzke/active_record/basepack.rb +0 -134
- data/lib/netzke/grid_panel/javascripts/filters.js +0 -7
- data/test/app_root/db/migrate/20090102223630_create_netzke_layouts.rb +0 -14
- data/test/unit/helper_model_test.rb +0 -30
data/lib/netzke/basic_app.rb
CHANGED
@@ -182,6 +182,42 @@ module Netzke
|
|
182
182
|
}
|
183
183
|
END_OF_JAVASCRIPT
|
184
184
|
|
185
|
+
# NOT USED
|
186
|
+
:show_login_window => <<-END_OF_JAVASCRIPT.l,
|
187
|
+
function(){
|
188
|
+
var w = new Ext.Window({
|
189
|
+
title: "Please, login",
|
190
|
+
modal: true,
|
191
|
+
width: 350,
|
192
|
+
height: 200,
|
193
|
+
layout: 'fit',
|
194
|
+
items: [{
|
195
|
+
xtype: 'form',
|
196
|
+
padding: 20,
|
197
|
+
defaults: {anchor: '100%'},
|
198
|
+
frame: true,
|
199
|
+
border: false,
|
200
|
+
items: [
|
201
|
+
{xtype: 'textfield', fieldLabel: 'Username', name: 'login'},
|
202
|
+
{name: 'password', xtype: 'textfield', inputType: 'password', fieldLabel: "Password"}
|
203
|
+
],
|
204
|
+
buttons: [{
|
205
|
+
name: "submit",
|
206
|
+
text: "Login",
|
207
|
+
app: this,
|
208
|
+
handler: function() {
|
209
|
+
this.ownerCt.ownerCt.getForm().submit({
|
210
|
+
url: this.app.buildApiUrl("submit_login"),
|
211
|
+
});
|
212
|
+
}
|
213
|
+
}]
|
214
|
+
}],
|
215
|
+
});
|
216
|
+
|
217
|
+
w.show();
|
218
|
+
}
|
219
|
+
END_OF_JAVASCRIPT
|
220
|
+
|
185
221
|
|
186
222
|
# Masquerade selector window
|
187
223
|
:show_masquerade_selector => <<-END_OF_JAVASCRIPT.l
|
@@ -315,10 +351,17 @@ module Netzke
|
|
315
351
|
api :masquerade_as
|
316
352
|
def masquerade_as(params)
|
317
353
|
session = Netzke::Base.session
|
318
|
-
session[:masq_world] = params[:world]
|
319
|
-
session[:masq_role] = params[:role]
|
320
|
-
session[:masq_user] = params[:user]
|
321
|
-
{:js => "window.location.reload()"}
|
354
|
+
session[:masq_world] = params[:world] == "true"
|
355
|
+
session[:masq_role] = params[:role].try(:to_i)
|
356
|
+
session[:masq_user] = params[:user].try(:to_i)
|
357
|
+
{:js => "window.location.reload();"}
|
358
|
+
end
|
359
|
+
|
360
|
+
# Login request from the in-app login form
|
361
|
+
api :submit_login
|
362
|
+
def submit_login(params)
|
363
|
+
# TODO: implement me
|
364
|
+
{:feedback => "OK"}
|
322
365
|
end
|
323
366
|
|
324
367
|
end
|
@@ -6,7 +6,7 @@ module Netzke
|
|
6
6
|
def commit(params)
|
7
7
|
commit_data = ActiveSupport::JSON.decode params[:commit_data]
|
8
8
|
commit_data.each_pair do |k,v|
|
9
|
-
aggregatee_instance(k).commit(v)
|
9
|
+
aggregatee_instance(k).commit(v) if aggregatee_instance(k).respond_to?(:commit)
|
10
10
|
end
|
11
11
|
{:reload_parent => true, :feedback => (@flash.empty? ? nil : @flash)}
|
12
12
|
end
|
data/lib/netzke/data_accessor.rb
CHANGED
@@ -14,38 +14,15 @@ module Netzke
|
|
14
14
|
# Generic extensions to the data model
|
15
15
|
if data_class # because some widgets, like FormPanel, may have it optional
|
16
16
|
data_class.send(:include, Netzke::ActiveRecord::DataAccessor) if !data_class.include?(Netzke::ActiveRecord::DataAccessor)
|
17
|
-
|
18
|
-
# Model helpers
|
19
|
-
const_name = "Netzke::Helpers::#{data_class.name}"
|
20
|
-
model_extensions = const_name.constantize rescue nil
|
21
|
-
data_class.send(:include, model_extensions) if model_extensions && !data_class.include?(model_extensions)
|
22
17
|
end
|
23
18
|
end
|
24
|
-
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
if helper_module
|
32
|
-
exposed_attributes = helper_module.respond_to?(:exposed_attributes) ? normalize_array_of_columns(helper_module.exposed_attributes) : nil
|
33
|
-
virtual_attributes = helper_module.respond_to?(:virtual_attributes) ? helper_module.virtual_attributes : []
|
34
|
-
excluded_attributes = helper_module.respond_to?(:excluded_attributes) ? helper_module.excluded_attributes : []
|
35
|
-
attributes_config = helper_module.respond_to?(:attributes_config) ? helper_module.attributes_config : {}
|
36
|
-
|
37
|
-
res = exposed_attributes || data_class_columns + virtual_attributes
|
38
|
-
|
39
|
-
res = normalize_columns(res)
|
40
|
-
|
41
|
-
res.reject!{ |c| excluded_attributes.include? c[:name] }
|
42
|
-
|
43
|
-
res.map!{ |c| c.merge!(attributes_config[c[:name]] || {})}
|
44
|
-
else
|
45
|
-
res = normalize_columns(data_class_columns)
|
19
|
+
|
20
|
+
# [:col1, "col2", {:name => :col3}] =>
|
21
|
+
# [{:name => "col1"}, {:name => "col2"}, {:name => "col3"}]
|
22
|
+
def normalize_attr_config(cols)
|
23
|
+
cols.map do |c|
|
24
|
+
c.is_a?(Symbol) || c.is_a?(String) ? {:name => c.to_s} : c.merge(:name => c[:name].to_s)
|
46
25
|
end
|
47
|
-
|
48
|
-
res
|
49
26
|
end
|
50
27
|
|
51
28
|
# Make sure we have keys as symbols, not strings
|
@@ -61,7 +38,7 @@ module Netzke
|
|
61
38
|
|
62
39
|
# From symbol to config hash
|
63
40
|
def normalize_column(field)
|
64
|
-
field.is_a?(Symbol) ? {:name => field} : field
|
41
|
+
field.is_a?(Symbol) ? {:name => field.to_s} : field
|
65
42
|
end
|
66
43
|
|
67
44
|
# From symbols to config hashes
|
@@ -3,42 +3,26 @@ module Netzke
|
|
3
3
|
# Provides dynamic configuring columns/fields for GridPanel and FormPanel.
|
4
4
|
# Configuration parameters:
|
5
5
|
# * <tt>:widget</tt> - widget to configure columns/fields for
|
6
|
-
class FieldsConfigurator <
|
6
|
+
class FieldsConfigurator < JsonArrayEditor
|
7
7
|
api :load_defaults
|
8
8
|
|
9
|
-
def initialize(*args)
|
10
|
-
super
|
11
|
-
@auto_table_klass = is_for_grid? ? NetzkeAutoColumn : NetzkeAutoField
|
12
|
-
@auto_table_klass.widget = client_widget
|
13
|
-
end
|
14
|
-
|
15
|
-
# widget that uses us
|
16
|
-
def client_widget
|
17
|
-
@passed_config[:widget]
|
18
|
-
end
|
19
|
-
|
20
|
-
# is our client widget a grid (as opposed to a form)?
|
21
|
-
def is_for_grid?
|
22
|
-
client_widget.class.ancestors.include?(GridPanel)
|
23
|
-
end
|
24
|
-
|
25
9
|
def default_config
|
26
10
|
super.deep_merge({
|
27
11
|
:name => 'columns',
|
28
|
-
:model => is_for_grid? ? "NetzkeAutoColumn" : "NetzkeAutoField",
|
29
12
|
:ext_config => {
|
13
|
+
:config_tool => false,
|
30
14
|
:header => false,
|
31
15
|
:enable_extended_search => false,
|
32
16
|
:enable_edit_in_form => false,
|
33
17
|
:enable_rows_reordering => GridPanel.config[:rows_reordering_available],
|
34
18
|
:enable_pagination => false
|
35
|
-
}
|
19
|
+
}
|
36
20
|
})
|
37
21
|
end
|
38
22
|
|
39
23
|
def actions
|
40
24
|
super.merge(
|
41
|
-
:defaults => {:text => 'Restore defaults'}
|
25
|
+
:defaults => {:text => 'Restore defaults', :icon => Netzke::Base.config[:with_icons] && (Netzke::Base.config[:icons_uri] + "wand.png")}
|
42
26
|
)
|
43
27
|
end
|
44
28
|
|
@@ -46,12 +30,52 @@ module Netzke
|
|
46
30
|
%w{ add edit apply del - defaults }
|
47
31
|
end
|
48
32
|
|
49
|
-
|
50
|
-
|
33
|
+
# Default columns for the configurator
|
34
|
+
def default_columns
|
35
|
+
[
|
36
|
+
{:name => "id", :attr_type => :integer, :meta => true},
|
37
|
+
{:name => "position", :attr_type => :integer, :meta => true},
|
38
|
+
{:name => "attr_type", :attr_type => :string, :meta => true},
|
39
|
+
*config[:owner].class.meta_columns.map { |c| c[:name] == "name" ? inject_combo_for_name_column(c) : c }
|
40
|
+
]
|
51
41
|
end
|
52
42
|
|
53
43
|
def self.js_extend_properties
|
54
44
|
{
|
45
|
+
:init_component => <<-END_OF_JAVASCRIPT.l,
|
46
|
+
function(){
|
47
|
+
#{js_full_class_name}.superclass.initComponent.call(this);
|
48
|
+
|
49
|
+
// Automatically set the correct editor for the default_value column
|
50
|
+
this.on('beforeedit', function(e){
|
51
|
+
var column = this.getColumnModel().getColumnById(this.getColumnModel().getColumnId(e.column));
|
52
|
+
var record = this.getStore().getAt(e.row);
|
53
|
+
|
54
|
+
if (column.dataIndex === "default_value") {
|
55
|
+
if (record.get("name") === this.pri) {
|
56
|
+
// Don't allow setting default value for the primary key
|
57
|
+
column.setEditor(null);
|
58
|
+
} else {
|
59
|
+
// Auto set the editor, dependent on the field type
|
60
|
+
var attrType = record.get("attr_type");
|
61
|
+
column.setEditor(Ext.create({xtype: this.attrTypeEditorMap[attrType] || "textfield"}));
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
}, this);
|
66
|
+
|
67
|
+
}
|
68
|
+
END_OF_JAVASCRIPT
|
69
|
+
|
70
|
+
:attr_type_editor_map => {
|
71
|
+
:integer => "numberfield",
|
72
|
+
:boolean => "checkbox",
|
73
|
+
:decimal => "numberfield",
|
74
|
+
:datetime => "xdatetime",
|
75
|
+
:date => "datefield",
|
76
|
+
:string => "textfield"
|
77
|
+
},
|
78
|
+
|
55
79
|
# Disable the 'gear' tool for now
|
56
80
|
:on_gear => <<-END_OF_JAVASCRIPT.l,
|
57
81
|
function(){
|
@@ -79,31 +103,72 @@ module Netzke
|
|
79
103
|
end
|
80
104
|
|
81
105
|
def load_defaults(params)
|
82
|
-
|
83
|
-
|
106
|
+
# Reload the temp table with default values
|
107
|
+
data_class.replace_data(default_owner_fields)
|
108
|
+
|
109
|
+
# ... and reflect it in the persistent storage
|
110
|
+
on_data_changed
|
111
|
+
|
112
|
+
# Update the grid
|
84
113
|
{:load_store_data => get_data}
|
85
114
|
end
|
86
115
|
|
87
|
-
|
88
|
-
defaults_hash = config[:widget].class.config_columns.inject({}){ |r, c| r.merge!(c[:name] => c[:default]) }
|
89
|
-
config[:widget].persistent_config[:layout__columns] = @auto_table_klass.all_columns.map do |c|
|
90
|
-
# reject all keys that are 1) same as defaults, 2) 'position'
|
91
|
-
c.reject!{ |k,v| defaults_hash[k.to_sym].to_s == v.to_s || k == 'position'}
|
92
|
-
c = c["name"] if c.keys.count == 1 # denormalize the column
|
93
|
-
c
|
94
|
-
end
|
95
|
-
{}
|
96
|
-
end
|
97
|
-
|
98
|
-
# each time that we are loaded into the app, rebuild the table
|
99
|
-
def before_load
|
100
|
-
@auto_table_klass.rebuild_table
|
101
|
-
end
|
102
|
-
|
103
|
-
# Don't show the config tool
|
116
|
+
# Never show the config tool
|
104
117
|
def config_tool_needed?
|
105
118
|
false
|
106
119
|
end
|
107
120
|
|
121
|
+
private
|
122
|
+
|
123
|
+
# An override
|
124
|
+
def process_data(data, operation)
|
125
|
+
if operation == :update
|
126
|
+
meta_attrs_to_update = data.inject({}) do |r,el|
|
127
|
+
r.merge({
|
128
|
+
data_class.find(el["id"]).name => el.reject{ |k,v| k == "id" }
|
129
|
+
})
|
130
|
+
end
|
131
|
+
|
132
|
+
res = super
|
133
|
+
|
134
|
+
NetzkeFieldList.update_fields(config[:owner].global_id, meta_attrs_to_update)
|
135
|
+
|
136
|
+
res
|
137
|
+
else
|
138
|
+
super
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# An override
|
143
|
+
def store_data(data)
|
144
|
+
NetzkeFieldList.update_list_for_current_authority(config[:owner].global_id, data, config[:owner].data_class.name)
|
145
|
+
end
|
146
|
+
|
147
|
+
# An override
|
148
|
+
def initial_data
|
149
|
+
NetzkeFieldList.read_list(config[:owner].global_id) || default_owner_fields
|
150
|
+
end
|
151
|
+
|
152
|
+
# Set strict combo for the "name" column, with options of the attributes provided by the data_class
|
153
|
+
def inject_combo_for_name_column(c)
|
154
|
+
netzke_attrs = config[:owner].data_class.netzke_attributes.map{ |a| a[:name] }
|
155
|
+
c.merge(:editor => {:xtype => :combo, :store => netzke_attrs, :force_selection => true})
|
156
|
+
end
|
157
|
+
|
158
|
+
def default_owner_fields
|
159
|
+
config[:owner].initial_columns(false).map(&:deebeefy_values)
|
160
|
+
end
|
161
|
+
|
162
|
+
# This is an override of GridPanel#on_data_changed
|
163
|
+
def on_data_changed
|
164
|
+
# Default column settings taken from
|
165
|
+
defaults_hash = config[:owner].class.meta_columns.inject({}){ |r, c| r.merge!(c[:name] => c[:default_value]) }
|
166
|
+
stripped_columns = data_class.all_columns.map do |c|
|
167
|
+
# reject all keys that are 1) same as defaults
|
168
|
+
c.reject{ |k,v| defaults_hash[k.to_sym].to_s == v.to_s }
|
169
|
+
end
|
170
|
+
store_data(stripped_columns)
|
171
|
+
end
|
172
|
+
|
108
173
|
end
|
109
174
|
end
|
data/lib/netzke/form_panel.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "netzke/form_panel/form_panel_js"
|
2
2
|
require "netzke/form_panel/form_panel_api"
|
3
|
+
require "netzke/form_panel/form_panel_fields"
|
3
4
|
require "netzke/plugins/configuration_tool"
|
4
5
|
require "netzke/data_accessor"
|
5
6
|
|
@@ -19,6 +20,7 @@ module Netzke
|
|
19
20
|
class FormPanel < Base
|
20
21
|
include FormPanelJs # javascript (client-side)
|
21
22
|
include FormPanelApi # API (server-side)
|
23
|
+
include FormPanelFields # fields
|
22
24
|
include Netzke::DataAccessor # some code shared between GridPanel, FormPanel, and other widgets that use database attributes
|
23
25
|
|
24
26
|
# Class-level configuration with defaults
|
@@ -61,14 +63,22 @@ module Netzke
|
|
61
63
|
def initialize(*args)
|
62
64
|
super
|
63
65
|
apply_helpers
|
64
|
-
@record = config[:record] || config[:record_id] && data_class && data_class.find(:first, :conditions => {data_class.primary_key => config[:record_id]})
|
65
66
|
end
|
66
67
|
|
67
68
|
# (We can't memoize this method because at some point we extend it, e.g. in Netzke::DataAccessor)
|
68
69
|
def data_class
|
69
|
-
|
70
|
-
|
71
|
-
|
70
|
+
@data_class ||= begin
|
71
|
+
klass = "Netzke::ModelExtensions::#{config[:model]}For#{short_widget_class_name}".constantize rescue nil
|
72
|
+
klass || begin
|
73
|
+
::ActiveSupport::Deprecation.warn("data_class_name option is deprecated. Use model instead", caller) if config[:data_class_name]
|
74
|
+
model_name = config[:model] || config[:data_class_name]
|
75
|
+
model_name && model_name.constantize
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def record
|
81
|
+
@record ||= config[:record] || config[:record_id] && data_class && data_class.find(:first, :conditions => {data_class.primary_key => config[:record_id]})
|
72
82
|
end
|
73
83
|
|
74
84
|
def configuration_widgets
|
@@ -78,7 +88,7 @@ module Netzke
|
|
78
88
|
:name => 'fields',
|
79
89
|
:class_name => "FieldsConfigurator",
|
80
90
|
:active => true,
|
81
|
-
:
|
91
|
+
:owner => self,
|
82
92
|
:persistent_config => true
|
83
93
|
}
|
84
94
|
|
@@ -93,137 +103,30 @@ module Netzke
|
|
93
103
|
end
|
94
104
|
|
95
105
|
def actions
|
96
|
-
{
|
106
|
+
actions = {
|
97
107
|
:apply => {:text => 'Apply'}
|
98
108
|
}
|
109
|
+
|
110
|
+
if Netzke::Base.config[:with_icons]
|
111
|
+
icons_uri = Netzke::Base.config[:icons_uri]
|
112
|
+
actions.deep_merge!(
|
113
|
+
:apply => {:icon => icons_uri + "tick.png"}
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
actions
|
99
118
|
end
|
100
119
|
|
101
|
-
def columns
|
102
|
-
@columns ||= get_columns.deep_convert_keys{|k| k.to_sym}
|
103
|
-
end
|
104
|
-
|
105
|
-
# parameters used to instantiate the JS object
|
106
|
-
def js_config
|
107
|
-
res = super
|
108
|
-
res.merge!(:clmns => columns)
|
109
|
-
res.merge!(:model => data_class.name) if data_class
|
110
|
-
res.merge!(:pri => data_class.primary_key) if data_class
|
111
|
-
res
|
112
|
-
end
|
113
|
-
|
114
|
-
# columns to be displayed by the FieldConfigurator (which is GridPanel-based)
|
115
|
-
def self.config_columns
|
116
|
-
[
|
117
|
-
{:name => :name, :type => :string, :editor => :combobox, :width => 200},
|
118
|
-
{:name => :hidden, :type => :boolean, :editor => :checkbox, :width => 40, :header => "Excl"},
|
119
|
-
{:name => :disabled, :type => :boolean, :editor => :checkbox, :width => 40, :header => "Dis"},
|
120
|
-
{:name => :xtype, :type => :string, :editor => {:xtype => :combobox, :options => Netzke::Ext::FORM_FIELD_XTYPES}},
|
121
|
-
{:name => :value, :type => :string},
|
122
|
-
{:name => :field_label, :type => :string},
|
123
|
-
{:name => :input_type, :type => :string, :hidden => true}
|
124
|
-
]
|
125
|
-
end
|
126
|
-
|
127
120
|
def self.property_fields
|
128
121
|
res = [
|
129
|
-
{:name =>
|
130
|
-
{:name =>
|
131
|
-
{:name =>
|
122
|
+
{:name => "ext_config__title", :type => :string},
|
123
|
+
{:name => "ext_config__header", :type => :boolean, :default => true},
|
124
|
+
# {:name => "ext_config__bbar", :type => :json}
|
132
125
|
]
|
133
126
|
|
134
127
|
res
|
135
128
|
end
|
136
129
|
|
137
|
-
# Normalized columns
|
138
|
-
def normalized_columns
|
139
|
-
@normalized_columns ||= normalize_columns(columns)
|
140
|
-
end
|
141
|
-
|
142
|
-
|
143
|
-
def get_columns
|
144
|
-
if persistent_config_enabled?
|
145
|
-
persistent_config['layout__columns'] ||= default_columns
|
146
|
-
res = normalize_array_of_columns(persistent_config['layout__columns'])
|
147
|
-
else
|
148
|
-
res = default_columns
|
149
|
-
end
|
150
|
-
|
151
|
-
# merge values for each field if the record is specified
|
152
|
-
@record && res.map! do |c|
|
153
|
-
value = @record.send(normalize_column(c)[:name])
|
154
|
-
value.nil? ? c : normalize_column(c).merge(:value => value)
|
155
|
-
end
|
156
|
-
|
157
|
-
res
|
158
|
-
end
|
159
|
-
|
160
|
-
XTYPE_MAP = {
|
161
|
-
:integer => :numberfield,
|
162
|
-
:boolean => :xcheckbox,
|
163
|
-
:date => :datefield,
|
164
|
-
:datetime => :xdatetime,
|
165
|
-
:text => :textarea,
|
166
|
-
:json => :jsonfield
|
167
|
-
# :string => :textfield
|
168
|
-
}
|
169
|
-
|
170
|
-
def default_columns
|
171
|
-
# columns specified in widget's config
|
172
|
-
columns_from_config = config[:columns] && normalize_columns(config[:columns])
|
173
|
-
|
174
|
-
if columns_from_config
|
175
|
-
# reverse-merge each column hash from config with each column hash from exposed_attributes (columns from config have higher priority)
|
176
|
-
for c in columns_from_config
|
177
|
-
corresponding_exposed_column = predefined_columns.find{ |k| k[:name] == c[:name] }
|
178
|
-
c.reverse_merge!(corresponding_exposed_column) if corresponding_exposed_column
|
179
|
-
end
|
180
|
-
columns_for_create = columns_from_config
|
181
|
-
elsif predefined_columns
|
182
|
-
# we didn't have columns configured in widget's config, so, use the columns from the data class
|
183
|
-
columns_for_create = predefined_columns
|
184
|
-
else
|
185
|
-
raise ArgumentError, "No columns specified for widget '#{global_id}'"
|
186
|
-
end
|
187
|
-
|
188
|
-
columns_for_create.map! do |c|
|
189
|
-
if data_class
|
190
|
-
# Try to figure out the configuration from data class
|
191
|
-
# detect :assoc__method
|
192
|
-
if c[:name].to_s.index('__')
|
193
|
-
assoc_name, method = c[:name].to_s.split('__').map(&:to_sym)
|
194
|
-
if assoc = data_class.reflect_on_association(assoc_name)
|
195
|
-
assoc_column = assoc.klass.columns_hash[method.to_s]
|
196
|
-
assoc_method_type = assoc_column.try(:type)
|
197
|
-
if assoc_method_type
|
198
|
-
c[:xtype] ||= XTYPE_MAP[assoc_method_type] == :xcheckbox ? :xcheckbox : :combobox
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
# detect association column (e.g. :category_id)
|
204
|
-
if assoc = data_class.reflect_on_all_associations.detect{|a| a.primary_key_name.to_sym == c[:name]}
|
205
|
-
c[:xtype] ||= :combobox
|
206
|
-
assoc_method = %w{name title label id}.detect{|m| (assoc.klass.instance_methods + assoc.klass.column_names).include?(m) } || assoc.klass.primary_key
|
207
|
-
c[:name] = "#{assoc.name}__#{assoc_method}".to_sym
|
208
|
-
end
|
209
|
-
c[:hidden] = true if c[:name] == data_class.primary_key.to_sym && c[:hidden].nil? # hide ID column by default
|
210
|
-
|
211
|
-
end
|
212
|
-
|
213
|
-
# detect column type
|
214
|
-
type = c[:type] || data_class && data_class.columns_hash[c[:name].to_s].try(:type) || :string
|
215
|
-
c[:type] ||= type
|
216
|
-
|
217
|
-
c[:xtype] ||= XTYPE_MAP[type] unless XTYPE_MAP[type].nil?
|
218
|
-
|
219
|
-
# if the column is finally simply {:name => "something"}, cut it down to "something"
|
220
|
-
c.reject{ |k,v| k == :name }.empty? ? c[:name] : c
|
221
|
-
end
|
222
|
-
|
223
|
-
columns_for_create
|
224
|
-
|
225
|
-
end
|
226
|
-
|
227
130
|
include Plugins::ConfigurationTool if config[:config_tool_available] # it will load ConfigurationPanel into a modal window
|
228
131
|
end
|
229
132
|
end
|