netzke-basepack 0.3.1 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/CHANGELOG +22 -0
  2. data/Manifest +6 -4
  3. data/README.rdoc +2 -2
  4. data/Rakefile +1 -1
  5. data/generators/netzke_form_panel/templates/create_netzke_form_panel_fields.rb +5 -6
  6. data/generators/netzke_grid_panel/templates/create_netzke_grid_panel_columns.rb +2 -1
  7. data/javascripts/basepack.js +2 -0
  8. data/lib/app/models/netzke_form_panel_field.rb +35 -3
  9. data/lib/app/models/netzke_grid_panel_column.rb +39 -2
  10. data/lib/netzke-basepack.rb +0 -1
  11. data/lib/netzke/accordion_panel.rb +51 -15
  12. data/lib/netzke/ar_ext.rb +14 -6
  13. data/lib/netzke/basic_app.rb +5 -5
  14. data/lib/netzke/border_layout_panel.rb +19 -4
  15. data/lib/netzke/container.rb +2 -6
  16. data/lib/netzke/db_fields.rb +40 -0
  17. data/lib/netzke/fields_configurator.rb +10 -18
  18. data/lib/netzke/form_panel.rb +42 -128
  19. data/lib/netzke/form_panel_extras/interface.rb +49 -0
  20. data/lib/netzke/form_panel_extras/js_builder.rb +131 -0
  21. data/lib/netzke/grid_panel.rb +20 -12
  22. data/lib/netzke/grid_panel_extras/interface.rb +181 -0
  23. data/lib/netzke/grid_panel_extras/js_builder.rb +322 -0
  24. data/lib/netzke/table_editor.rb +110 -0
  25. data/lib/netzke/wrapper.rb +1 -3
  26. data/netzke-basepack.gemspec +8 -8
  27. data/test/app_root/db/migrate/20090102223811_create_netzke_grid_panel_columns.rb +3 -1
  28. data/test/border_layout_panel_test.rb +8 -12
  29. data/test/grid_panel_test.rb +3 -3
  30. data/test/test_helper.rb +8 -0
  31. metadata +15 -11
  32. data/lib/netzke/column.rb +0 -50
  33. data/lib/netzke/grid_panel_interface.rb +0 -167
  34. data/lib/netzke/grid_panel_js_builder.rb +0 -298
  35. data/test/column_test.rb +0 -27
@@ -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.componentCache['#{v[:widget_class_name]}'](config.#{k.to_js}Config);
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
- # :activate => {:fn => "function(p){this.feedback(p.id)}".l, :scope => this},
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
- # process config[:layout]
9
- config[:conditions] = {:layout_id => (config[:layout] && config[:layout].id)}
10
- config[:columns] = [
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
- :data_class_name => "NetzkeGridPanelColumn",
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', :handler => 'loadDefaults'
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
- NetzkeGridPanelColumn.create_layout_for_widget(parent.parent)
53
+ config[:data_class_name].constantize.create_layout_for_widget(parent.parent)
62
54
  {}
63
55
  end
64
56
 
@@ -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
- #custom configs
34
- :auto_load_data => true,
35
- })
36
- end
37
-
38
-
39
- end
6
+ include Netzke::DbFields
40
7
 
41
- def self.js_extend_properties
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 => false,
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
- :text => 'Previous', :handler => 'previous'
108
- },{
109
- :text => 'Next', :handler => 'next'
110
- },{
111
- :text => 'Apply', :handler => 'submit', :disabled => !@permissions[:update] && !@permissions[:create]
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.items_hash # TODO: bad name!
59
+ layout.items_arry_without_hidden
131
60
  else
132
- Netzke::Column.default_columns_for_widget(self)
61
+ default_db_fields
133
62
  end
134
63
  end
135
-
136
- def submit(params)
137
- params.delete(:authenticity_token)
138
- params.delete(:controller)
139
- params.delete(:action)
140
- book = Book.find(params[:id])
141
- if book.nil?
142
- book = Book.create(params)
143
- else
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