netzke-basepack 0.3.1 → 0.3.3
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 +22 -0
- data/Manifest +6 -4
- data/README.rdoc +2 -2
- data/Rakefile +1 -1
- data/generators/netzke_form_panel/templates/create_netzke_form_panel_fields.rb +5 -6
- data/generators/netzke_grid_panel/templates/create_netzke_grid_panel_columns.rb +2 -1
- data/javascripts/basepack.js +2 -0
- data/lib/app/models/netzke_form_panel_field.rb +35 -3
- data/lib/app/models/netzke_grid_panel_column.rb +39 -2
- data/lib/netzke-basepack.rb +0 -1
- data/lib/netzke/accordion_panel.rb +51 -15
- data/lib/netzke/ar_ext.rb +14 -6
- data/lib/netzke/basic_app.rb +5 -5
- data/lib/netzke/border_layout_panel.rb +19 -4
- data/lib/netzke/container.rb +2 -6
- data/lib/netzke/db_fields.rb +40 -0
- data/lib/netzke/fields_configurator.rb +10 -18
- data/lib/netzke/form_panel.rb +42 -128
- data/lib/netzke/form_panel_extras/interface.rb +49 -0
- data/lib/netzke/form_panel_extras/js_builder.rb +131 -0
- data/lib/netzke/grid_panel.rb +20 -12
- data/lib/netzke/grid_panel_extras/interface.rb +181 -0
- data/lib/netzke/grid_panel_extras/js_builder.rb +322 -0
- data/lib/netzke/table_editor.rb +110 -0
- data/lib/netzke/wrapper.rb +1 -3
- data/netzke-basepack.gemspec +8 -8
- data/test/app_root/db/migrate/20090102223811_create_netzke_grid_panel_columns.rb +3 -1
- data/test/border_layout_panel_test.rb +8 -12
- data/test/grid_panel_test.rb +3 -3
- data/test/test_helper.rb +8 -0
- metadata +15 -11
- data/lib/netzke/column.rb +0 -50
- data/lib/netzke/grid_panel_interface.rb +0 -167
- data/lib/netzke/grid_panel_js_builder.rb +0 -298
- data/test/column_test.rb +0 -27
data/lib/netzke/container.rb
CHANGED
@@ -37,7 +37,7 @@ module Netzke
|
|
37
37
|
item_aggregatees.each_pair do |k,v|
|
38
38
|
next if v[:late_aggregation]
|
39
39
|
res << <<-JS
|
40
|
-
var #{k.to_js} = new Ext.
|
40
|
+
var #{k.to_js} = new Ext.netzke.cache['#{v[:widget_class_name]}'](config.#{k.to_js}Config);
|
41
41
|
JS
|
42
42
|
end
|
43
43
|
res
|
@@ -49,13 +49,10 @@ module Netzke
|
|
49
49
|
:title => i.to_s.humanize,
|
50
50
|
:layout => 'fit',
|
51
51
|
:id => i.to_s,
|
52
|
-
# :id => "#{config[:name]}_#{i.to_s}",
|
53
52
|
:items => ([i.to_s.to_js.l] if !aggregatees[i][:late_aggregation]),
|
54
|
-
# these listeners will be different for tab_panel and accordion
|
55
53
|
:collapsed => !aggregatees[i][:active],
|
56
54
|
:listeners => {
|
57
|
-
|
58
|
-
:expand => {:fn => "this.loadItemWidget".l, :scope => this}
|
55
|
+
:expand => {:fn => "this.loadItemWidget".l, :scope => this}
|
59
56
|
}
|
60
57
|
}
|
61
58
|
end
|
@@ -67,7 +64,6 @@ module Netzke
|
|
67
64
|
:load_item_widget => <<-JS.l,
|
68
65
|
function(panel) {
|
69
66
|
if (!panel.getWidget()) panel.loadWidget(this.id + "__" + panel.id + "__get_widget");
|
70
|
-
// if (!this.getWidgetByPanel(panel)) this.loadWidget(panel, this.initialConfig[panel.id+'Config'].interface.getWidget);
|
71
67
|
}
|
72
68
|
JS
|
73
69
|
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Netzke
|
2
|
+
module DbFields
|
3
|
+
def default_db_fields
|
4
|
+
config[:data_class_name].nil? && raise(ArgumentError, "No data_class_name specified for widget #{config[:name]}")
|
5
|
+
|
6
|
+
data_class = config[:data_class_name].constantize
|
7
|
+
exposed_columns = normalize_columns(data_class.exposed_columns) # columns exposed from the data class
|
8
|
+
columns_from_config = (config[:fields] || config[:columns]) && normalize_columns(config[:fields] || config[:columns]) # columns specified in widget's config
|
9
|
+
|
10
|
+
if columns_from_config
|
11
|
+
# reverse-merge each column hash from config with each column hash from exposed_columns (columns from config have higher priority)
|
12
|
+
for c in columns_from_config
|
13
|
+
corresponding_exposed_column = exposed_columns.find{ |k| k[:name] == c[:name] }
|
14
|
+
c.reverse_merge!(corresponding_exposed_column) if corresponding_exposed_column
|
15
|
+
end
|
16
|
+
columns_for_create = columns_from_config
|
17
|
+
else
|
18
|
+
# we didn't have columns configured in widget's config, so, use the columns from the data class
|
19
|
+
columns_for_create = exposed_columns
|
20
|
+
end
|
21
|
+
|
22
|
+
res = []
|
23
|
+
for c in columns_for_create
|
24
|
+
# finally reverse-merge them with the defaults from the data_class
|
25
|
+
res << (self.class.widget_type == :grid ? data_class.default_column_config(c) : data_class.default_field_config(c))
|
26
|
+
end
|
27
|
+
|
28
|
+
res
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
# [:col1, {:name => :col2}, :col3]
|
34
|
+
# => [{:name => :col1}, {:name => :col2}, {:name => :col3}]
|
35
|
+
def normalize_columns(items)
|
36
|
+
items.map{|c| c.is_a?(Symbol) ? {:name => c} : c}
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -1,38 +1,30 @@
|
|
1
1
|
module Netzke
|
2
2
|
class FieldsConfigurator < GridPanel
|
3
3
|
interface :load_defaults
|
4
|
+
|
5
|
+
def self.js_base_class
|
6
|
+
GridPanel
|
7
|
+
end
|
4
8
|
|
5
9
|
def initialize(*args)
|
6
10
|
super
|
7
11
|
|
8
|
-
|
9
|
-
config[:
|
10
|
-
config[:
|
11
|
-
:id,
|
12
|
-
:label,
|
13
|
-
{:name => :read_only, :label => "R/O"},
|
14
|
-
:hidden,
|
15
|
-
{:name => :width, :width => 50},
|
16
|
-
{:name => :editor, :editor => :combo_box},
|
17
|
-
{:name => :renderer, :editor => :combo_box}
|
18
|
-
]
|
19
|
-
|
12
|
+
config[:conditions] = {:layout_id => config[:layout].id}
|
13
|
+
config[:data_class_name] = config[:layout].items_class
|
14
|
+
# config[:persistent_layout] = false
|
20
15
|
end
|
21
16
|
|
22
17
|
def initial_config
|
23
18
|
super.recursive_merge({
|
24
19
|
:name => 'columns',
|
25
20
|
:widget_class_name => "GridPanel",
|
26
|
-
:
|
27
|
-
:ext_config => {:title => false},
|
28
|
-
# :conditions => {:layout_id => config[:layout].id},
|
29
|
-
:active => true
|
21
|
+
:ext_config => {:title => false}
|
30
22
|
})
|
31
23
|
end
|
32
24
|
|
33
25
|
def actions
|
34
26
|
super + [{
|
35
|
-
:text => 'Restore defaults', :
|
27
|
+
:text => 'Restore defaults', :handler_name => 'loadDefaults', :id => 'defaults'
|
36
28
|
}]
|
37
29
|
end
|
38
30
|
|
@@ -58,7 +50,7 @@ module Netzke
|
|
58
50
|
|
59
51
|
def load_defaults(params)
|
60
52
|
NetzkeLayout.destroy(config[:layout].id)
|
61
|
-
|
53
|
+
config[:data_class_name].constantize.create_layout_for_widget(parent.parent)
|
62
54
|
{}
|
63
55
|
end
|
64
56
|
|
data/lib/netzke/form_panel.rb
CHANGED
@@ -1,164 +1,77 @@
|
|
1
1
|
module Netzke
|
2
2
|
class FormPanel < Base
|
3
|
+
include_extras(__FILE__)
|
3
4
|
interface :submit, :load
|
4
|
-
|
5
|
-
class << self
|
6
|
-
def js_base_class
|
7
|
-
"Ext.FormPanel"
|
8
|
-
end
|
9
|
-
|
10
|
-
def js_before_constructor
|
11
|
-
<<-JS
|
12
|
-
var fields = config.fields; // TODO: remove hidden fields
|
13
|
-
var recordFields = [];
|
14
|
-
var index = 0;
|
15
|
-
Ext.each(config.fields, function(field){recordFields.push({name:field.name, mapping:index++})});
|
16
|
-
var Record = Ext.data.Record.create(recordFields);
|
17
|
-
this.reader = new Ext.data.RecordArrayReader({}, Record);
|
18
|
-
|
19
|
-
JS
|
20
|
-
end
|
21
|
-
|
22
|
-
def js_default_config
|
23
|
-
super.merge({
|
24
|
-
:auto_scroll => true,
|
25
|
-
:bbar => "config.actions".l,
|
26
|
-
# :plugins => "plugins".l,
|
27
|
-
:items => "fields".l,
|
28
|
-
:default_type => 'textfield',
|
29
|
-
:body_style => 'padding:5px 5px 0',
|
30
|
-
:label_width => 150,
|
31
|
-
:listeners => {:afterlayout => {:fn => "this.afterlayoutHandler".l, :scope => this}},
|
32
5
|
|
33
|
-
|
34
|
-
:auto_load_data => true,
|
35
|
-
})
|
36
|
-
end
|
37
|
-
|
38
|
-
|
39
|
-
end
|
6
|
+
include Netzke::DbFields
|
40
7
|
|
41
|
-
def self.
|
42
|
-
|
43
|
-
:load_record => <<-JS.l,
|
44
|
-
function(id, neighbour){
|
45
|
-
var proxy = new Ext.data.HttpProxy({url:this.initialConfig.interface.load});
|
46
|
-
proxy.load({id:id, neighbour:neighbour}, this.reader, function(data){
|
47
|
-
if (data){
|
48
|
-
this.form.loadRecord(data.records[0])
|
49
|
-
}
|
50
|
-
}, this)
|
51
|
-
}
|
52
|
-
JS
|
53
|
-
:afterlayout_handler => <<-JS.l,
|
54
|
-
function() {
|
55
|
-
// Load initial data into the form
|
56
|
-
if (this.initialConfig.recordData){
|
57
|
-
var record = this.reader.readRecord(this.initialConfig.recordData);
|
58
|
-
this.form.loadRecord(record);
|
59
|
-
}
|
60
|
-
}
|
61
|
-
JS
|
62
|
-
:refresh_click => <<-JS.l,
|
63
|
-
function() {
|
64
|
-
this.loadRecord(3)
|
65
|
-
}
|
66
|
-
JS
|
67
|
-
:previous => <<-JS.l,
|
68
|
-
function() {
|
69
|
-
var currentId = this.form.getValues().id;
|
70
|
-
this.loadRecord(currentId, 'previous');
|
71
|
-
}
|
72
|
-
JS
|
73
|
-
:next => <<-JS.l,
|
74
|
-
function() {
|
75
|
-
var currentId = this.form.getValues().id;
|
76
|
-
this.loadRecord(currentId, 'next');
|
77
|
-
}
|
78
|
-
JS
|
79
|
-
:submit => <<-JS.l,
|
80
|
-
function() {
|
81
|
-
this.form.submit({
|
82
|
-
url:this.initialConfig.interface.submit
|
83
|
-
})
|
84
|
-
}
|
85
|
-
JS
|
86
|
-
}
|
8
|
+
def self.widget_type
|
9
|
+
:form
|
87
10
|
end
|
88
|
-
|
11
|
+
|
89
12
|
# default configuration
|
90
13
|
def initial_config
|
91
14
|
{
|
92
15
|
:ext_config => {
|
93
|
-
:config_tool =>
|
94
|
-
:border => true
|
16
|
+
:config_tool => true
|
95
17
|
},
|
96
18
|
:layout_manager => "NetzkeLayout",
|
97
|
-
:field_manager => "NetzkeFormPanelField"
|
19
|
+
:field_manager => "NetzkeFormPanelField",
|
20
|
+
|
21
|
+
:persistent_layout => true,
|
22
|
+
:persistent_config => true
|
98
23
|
}
|
99
24
|
end
|
100
25
|
|
26
|
+
def property_widgets
|
27
|
+
res = []
|
28
|
+
res << {
|
29
|
+
:name => 'fields',
|
30
|
+
:widget_class_name => "FieldsConfigurator",
|
31
|
+
:ext_config => {:title => false},
|
32
|
+
:active => true,
|
33
|
+
:layout => NetzkeLayout.by_widget(id_name),
|
34
|
+
:fields_for => :form
|
35
|
+
} if config[:persistent_layout]
|
36
|
+
res
|
37
|
+
end
|
38
|
+
|
101
39
|
def tools
|
102
40
|
[{:id => 'refresh', :on => {:click => 'refreshClick'}}]
|
103
41
|
end
|
104
42
|
|
105
43
|
def actions
|
106
44
|
[{
|
107
|
-
|
108
|
-
},{
|
109
|
-
|
110
|
-
},{
|
111
|
-
:text => 'Apply', :
|
45
|
+
# :text => 'Previous', :handler => 'previous'
|
46
|
+
# },{
|
47
|
+
# :text => 'Next', :handler => 'next'
|
48
|
+
# },{
|
49
|
+
:text => 'Apply', :handler_name => 'submit', :disabled => !@permissions[:update] && !@permissions[:create], :id => 'apply'
|
112
50
|
}]
|
113
51
|
end
|
114
52
|
|
115
|
-
def js_config
|
116
|
-
res = super
|
117
|
-
# we pass column config at the time of instantiating the JS class
|
118
|
-
res.merge!(:fields => get_fields || config[:fields]) # first try to get columns from DB, then from config
|
119
|
-
res.merge!(:data_class_name => config[:data_class_name])
|
120
|
-
res.merge!(:record_data => config[:record].to_array(get_fields))
|
121
|
-
res
|
122
|
-
end
|
123
|
-
|
124
53
|
# get fields from layout manager
|
125
54
|
def get_fields
|
126
55
|
@fields ||=
|
127
|
-
if layout_manager_class && field_manager_class
|
56
|
+
if config[:persistent_layout] && layout_manager_class && field_manager_class
|
128
57
|
layout = layout_manager_class.by_widget(id_name)
|
129
58
|
layout ||= field_manager_class.create_layout_for_widget(self)
|
130
|
-
layout.
|
59
|
+
layout.items_arry_without_hidden
|
131
60
|
else
|
132
|
-
|
61
|
+
default_db_fields
|
133
62
|
end
|
134
63
|
end
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
book.update_attributes(params)
|
145
|
-
end
|
146
|
-
rescue ActiveRecord::UnknownAttributeError # unknown attributes get ignored
|
147
|
-
book.save
|
148
|
-
[book.to_array(get_fields)].to_json
|
149
|
-
end
|
150
|
-
|
151
|
-
def load(params)
|
152
|
-
logger.debug { "!!! params: #{params.inspect}" }
|
153
|
-
klass = config[:data_class_name].constantize
|
154
|
-
case params[:neighbour]
|
155
|
-
when "previous" then book = klass.previous(params[:id])
|
156
|
-
when "next" then book = klass.next(params[:id])
|
157
|
-
else book = klass.find(params[:id])
|
158
|
-
end
|
159
|
-
[book && book.to_array(get_fields)].to_json
|
64
|
+
|
65
|
+
# parameters used to instantiate the JS object
|
66
|
+
def js_config
|
67
|
+
res = super
|
68
|
+
# we pass column config at the time of instantiating the JS class
|
69
|
+
res.merge!(:fields => get_fields || config[:fields]) # first try to get columns from DB, then from config
|
70
|
+
res.merge!(:data_class_name => config[:data_class_name])
|
71
|
+
res.merge!(:record_data => config[:record].to_array(get_fields)) if config[:record]
|
72
|
+
res
|
160
73
|
end
|
161
|
-
|
74
|
+
|
162
75
|
protected
|
163
76
|
|
164
77
|
def layout_manager_class
|
@@ -177,6 +90,7 @@ module Netzke
|
|
177
90
|
%w(read update create delete)
|
178
91
|
end
|
179
92
|
|
93
|
+
include PropertiesTool # it will load aggregation with name :properties into a modal window
|
180
94
|
|
181
95
|
end
|
182
96
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Netzke
|
2
|
+
module FormPanelExtras
|
3
|
+
module Interface
|
4
|
+
def submit(params)
|
5
|
+
params.delete(:authenticity_token)
|
6
|
+
params.delete(:controller)
|
7
|
+
params.delete(:action)
|
8
|
+
|
9
|
+
klass = config[:data_class_name].constantize
|
10
|
+
record = klass.find_by_id(params[:id])
|
11
|
+
success = true
|
12
|
+
|
13
|
+
if record.nil?
|
14
|
+
record = klass.create(params)
|
15
|
+
else
|
16
|
+
params.each_pair do |k,v|
|
17
|
+
begin
|
18
|
+
record.send("#{k}=",v)
|
19
|
+
rescue ArgumentError => exc
|
20
|
+
flash :error => exc.message
|
21
|
+
success = false
|
22
|
+
break
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if success && record.save
|
28
|
+
{:data => [record.to_array(get_fields)], :success => true}
|
29
|
+
else
|
30
|
+
# flash eventual errors
|
31
|
+
record.errors.each_full do |msg|
|
32
|
+
flash :error => msg
|
33
|
+
end
|
34
|
+
{:success => false, :flash => @flash}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def load(params)
|
39
|
+
klass = config[:data_class_name].constantize
|
40
|
+
case params[:neighbour]
|
41
|
+
when "previous" then record = klass.previous(params[:id])
|
42
|
+
when "next" then record = klass.next(params[:id])
|
43
|
+
else record = klass.find(params[:id])
|
44
|
+
end
|
45
|
+
{:data => [record && record.to_array(get_fields)]}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module Netzke
|
2
|
+
module FormPanelExtras
|
3
|
+
module JsBuilder
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def js_base_class
|
10
|
+
"Ext.FormPanel"
|
11
|
+
end
|
12
|
+
|
13
|
+
def js_before_constructor
|
14
|
+
<<-JS
|
15
|
+
var fields = config.fields;
|
16
|
+
var recordFields = [];
|
17
|
+
var index = 0;
|
18
|
+
Ext.each(fields, function(field){
|
19
|
+
recordFields.push({
|
20
|
+
name:field.name,
|
21
|
+
mapping:index++
|
22
|
+
});
|
23
|
+
field.hideLabel = field.hidden; // completely hide the field marked "hidden"
|
24
|
+
var extConfig;
|
25
|
+
try{
|
26
|
+
extConfig = Ext.decode(field.extConfig)
|
27
|
+
}
|
28
|
+
catch(err){
|
29
|
+
extConfig = {}
|
30
|
+
}
|
31
|
+
delete(field.extConfig);
|
32
|
+
Ext.apply(field, extConfig);
|
33
|
+
});
|
34
|
+
var Record = Ext.data.Record.create(recordFields);
|
35
|
+
this.reader = new Ext.data.RecordArrayReader({root:"data"}, Record);
|
36
|
+
JS
|
37
|
+
end
|
38
|
+
|
39
|
+
def js_default_config
|
40
|
+
super.merge({
|
41
|
+
:auto_scroll => true,
|
42
|
+
:bbar => "config.actions".l,
|
43
|
+
# :plugins => "plugins".l,
|
44
|
+
:items => "fields".l,
|
45
|
+
:default_type => 'textfield',
|
46
|
+
:body_style => 'padding:5px 5px 0',
|
47
|
+
:label_width => 150,
|
48
|
+
:listeners => {
|
49
|
+
:afterlayout => {
|
50
|
+
:fn => "this.afterlayoutHandler".l,
|
51
|
+
:scope => this
|
52
|
+
}
|
53
|
+
},
|
54
|
+
:defaults => {
|
55
|
+
:anchor => '-20', # to leave some space for the scrollbar
|
56
|
+
:listeners => {
|
57
|
+
:specialkey => {
|
58
|
+
:fn => <<-JS.l,
|
59
|
+
function(field, event){
|
60
|
+
if (event.getKey() == 13) this.submit();
|
61
|
+
}
|
62
|
+
JS
|
63
|
+
:scope => this
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
})
|
68
|
+
end
|
69
|
+
|
70
|
+
def js_extend_properties
|
71
|
+
{
|
72
|
+
:load_record => <<-JS.l,
|
73
|
+
function(id, neighbour){
|
74
|
+
var proxy = new Ext.data.HttpProxy({url:this.initialConfig.interface.load});
|
75
|
+
proxy.load({id:id, neighbour:neighbour}, this.reader, function(data){
|
76
|
+
if (data){
|
77
|
+
this.form.loadRecord(data.records[0])
|
78
|
+
}
|
79
|
+
}, this)
|
80
|
+
}
|
81
|
+
JS
|
82
|
+
:afterlayout_handler => <<-JS.l,
|
83
|
+
function() {
|
84
|
+
// Load initial data into the form
|
85
|
+
if (this.initialConfig.recordData){
|
86
|
+
var record = this.reader.readRecord(this.initialConfig.recordData);
|
87
|
+
this.form.loadRecord(record);
|
88
|
+
}
|
89
|
+
}
|
90
|
+
JS
|
91
|
+
:refresh_click => <<-JS.l,
|
92
|
+
function() {
|
93
|
+
this.feedback('Implement me!');
|
94
|
+
// this.loadRecord(3)
|
95
|
+
}
|
96
|
+
JS
|
97
|
+
:previous => <<-JS.l,
|
98
|
+
function() {
|
99
|
+
var currentId = this.form.getValues().id;
|
100
|
+
this.loadRecord(currentId, 'previous');
|
101
|
+
}
|
102
|
+
JS
|
103
|
+
:next => <<-JS.l,
|
104
|
+
function() {
|
105
|
+
var currentId = this.form.getValues().id;
|
106
|
+
this.loadRecord(currentId, 'next');
|
107
|
+
}
|
108
|
+
JS
|
109
|
+
:submit => <<-JS.l,
|
110
|
+
function() {
|
111
|
+
this.form.submit({
|
112
|
+
url:this.initialConfig.interface.submit,
|
113
|
+
success :function(form, action){
|
114
|
+
if (action.result.flash) this.feedback(action.result.flash);
|
115
|
+
this.form.loadRecord(this.reader.readRecord(action.result.data[0]));
|
116
|
+
},
|
117
|
+
failure :function(form, action){
|
118
|
+
this.feedback(action.result.flash)
|
119
|
+
},
|
120
|
+
scope :this
|
121
|
+
})
|
122
|
+
}
|
123
|
+
JS
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|