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.
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