netzke-basepack 0.5.8 → 0.5.9
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/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
|