netzke-basepack 0.4.2 → 0.5.1

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 (62) hide show
  1. data/.autotest +1 -0
  2. data/.gitignore +6 -0
  3. data/{CHANGELOG → CHANGELOG.rdoc} +26 -0
  4. data/README.rdoc +11 -11
  5. data/Rakefile +37 -11
  6. data/TODO.rdoc +8 -0
  7. data/VERSION +1 -0
  8. data/javascripts/basepack.js +71 -28
  9. data/lib/app/models/netzke_auto_column.rb +56 -0
  10. data/lib/netzke-basepack.rb +5 -3
  11. data/lib/netzke/accordion_panel.rb +69 -67
  12. data/lib/netzke/active_record/basepack.rb +104 -0
  13. data/lib/netzke/active_record/data_accessor.rb +33 -0
  14. data/lib/netzke/basic_app.rb +233 -124
  15. data/lib/netzke/border_layout_panel.rb +97 -98
  16. data/lib/netzke/configuration_panel.rb +24 -0
  17. data/lib/netzke/data_accessor.rb +71 -0
  18. data/lib/netzke/ext.rb +6 -0
  19. data/lib/netzke/field_model.rb +1 -1
  20. data/lib/netzke/fields_configurator.rb +62 -37
  21. data/lib/netzke/form_panel.rb +161 -51
  22. data/lib/netzke/form_panel_api.rb +74 -0
  23. data/lib/netzke/form_panel_js.rb +129 -0
  24. data/lib/netzke/grid_panel.rb +385 -80
  25. data/lib/netzke/grid_panel_api.rb +352 -0
  26. data/lib/netzke/grid_panel_extras/javascripts/rows-dd.js +280 -0
  27. data/lib/netzke/grid_panel_js.rb +721 -0
  28. data/lib/netzke/masquerade_selector.rb +53 -0
  29. data/lib/netzke/panel.rb +9 -0
  30. data/lib/netzke/plugins/configuration_tool.rb +121 -0
  31. data/lib/netzke/property_editor.rb +95 -7
  32. data/lib/netzke/property_editor_extras/helper_model.rb +55 -34
  33. data/lib/netzke/search_panel.rb +62 -0
  34. data/lib/netzke/tab_panel.rb +97 -37
  35. data/lib/netzke/table_editor.rb +49 -44
  36. data/lib/netzke/tree_panel.rb +15 -16
  37. data/lib/netzke/wrapper.rb +29 -5
  38. data/netzke-basepack.gemspec +151 -19
  39. data/stylesheets/basepack.css +5 -0
  40. data/test/app_root/app/models/book.rb +1 -1
  41. data/test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb +1 -1
  42. data/test/unit/accordion_panel_test.rb +1 -2
  43. data/test/unit/active_record_basepack_test.rb +54 -0
  44. data/test/unit/grid_panel_test.rb +8 -12
  45. data/test/unit/helper_model_test.rb +30 -0
  46. metadata +69 -78
  47. data/Manifest +0 -86
  48. data/TODO +0 -3
  49. data/lib/app/models/netzke_hash_record.rb +0 -180
  50. data/lib/app/models/netzke_layout_item.rb +0 -11
  51. data/lib/netzke/ar_ext.rb +0 -269
  52. data/lib/netzke/configuration_tool.rb +0 -80
  53. data/lib/netzke/container.rb +0 -77
  54. data/lib/netzke/db_fields.rb +0 -44
  55. data/lib/netzke/fields_configurator_old.rb +0 -62
  56. data/lib/netzke/form_panel_extras/interface.rb +0 -56
  57. data/lib/netzke/form_panel_extras/js_builder.rb +0 -134
  58. data/lib/netzke/grid_panel_extras/interface.rb +0 -206
  59. data/lib/netzke/grid_panel_extras/js_builder.rb +0 -352
  60. data/test/unit/ar_ext_test.rb +0 -53
  61. data/test/unit/netzke_hash_record_test.rb +0 -52
  62. data/test/unit/netzke_layout_item_test.rb +0 -28
@@ -1,36 +1,98 @@
1
1
  module Netzke
2
- #
3
2
  # TabPanel
4
3
  #
5
4
  # Features:
6
5
  # * Dynamically loads widgets for the tabs that get activated for the first time
7
6
  # * Is loaded along with the active widget - saves a request to the server
7
+ # * Provides the method markTabsOutdated to mark all inactive tabs as 'outdated', and calls "update" method on widgets in tabs when they get activated
8
8
  #
9
9
  # TODO:
10
10
  # * Stores the last active tab in persistent_config
11
+ # * Introduce a second or two delay before informing the server about a tab switched
11
12
  #
12
13
  class TabPanel < Base
14
+ api :api_activate_tab
15
+
13
16
  def self.js_base_class
14
17
  "Ext.TabPanel"
15
18
  end
16
19
 
17
20
  def self.js_extend_properties
18
21
  {
19
- # loads widget into the panel if it wasn't loaded yet
20
- :load_item_widget => <<-JS.l
21
- function(panel) {
22
- if (!panel.getWidget()) {
23
- if (preloadedItemConfig = this.initialConfig[panel.widget+"Config"]){
24
- // preloaded widget only needs to be instantiated, as its class and configuration have already been loaded
25
- panel.add(new Ext.netzke.cache[preloadedItemConfig.widgetClassName](preloadedItemConfig));
26
- panel.doLayout(); // always needed after adding a component
27
- } else {
28
- // load the widget from the server
29
- panel.loadWidget(this.id + "__" + panel.widget + "__get_widget");
22
+ :id_delimiter => "___", # the default was "__", which conflicts with Netzke's double underscore notation
23
+ :defaults => {:layout => 'fit'}, # all tabs will be Ext.Panel-s with layout 'fit' ("fit-panels")
24
+
25
+ :render => <<-END_OF_JAVASCRIPT.l,
26
+ function(el){
27
+ Ext.netzke.cache.#{short_widget_class_name}.superclass.render.call(this, el);
28
+
29
+ // We do this all in +render+ because only at this moment the activeTab is actually activated
30
+ var activeTab = this.getActiveTab();
31
+ this.loadWidgetInto(activeTab);
32
+ this.on('tabchange', this.onTabChange, this);
33
+ }
34
+ END_OF_JAVASCRIPT
35
+
36
+ :load_widget_into => <<-END_OF_JAVASCRIPT.l,
37
+ function(fitPanel){
38
+ var preloadedItemConfig = this[fitPanel.widget.camelize(true)+"Config"];
39
+ if (preloadedItemConfig){
40
+ // preloaded widget only needs to be instantiated, as its class and configuration have already been loaded
41
+ fitPanel.add(new Ext.netzke.cache[preloadedItemConfig.widgetClassName](preloadedItemConfig));
42
+ fitPanel.doLayout();
43
+ } else {
44
+ // load the widget from the server
45
+ this.loadAggregatee({id:fitPanel.widget, container:fitPanel.id});
46
+ }
47
+ }
48
+ END_OF_JAVASCRIPT
49
+
50
+ :mark_tabs_outdated => <<-END_OF_JAVASCRIPT.l,
51
+ function(){
52
+ this.items.each(function(i){
53
+ if (this.getActiveTab() != i){
54
+ i.outdated = true
30
55
  }
56
+ }, this);
57
+ }
58
+ END_OF_JAVASCRIPT
59
+
60
+ # bulkExecute in active tab
61
+ :execute_in_active_tab => <<-END_OF_JAVASCRIPT.l,
62
+ function(commands){
63
+ this.getActiveTab().getWidget().bulkExecute(commands);
64
+ }
65
+ END_OF_JAVASCRIPT
66
+
67
+ :get_loaded_children => <<-END_OF_JAVASCRIPT.l,
68
+ function(){
69
+ var res = [];
70
+ this.items.each(function(tab){
71
+ var kid = tab.getWidget();
72
+ if (kid) { res.push(kid) }
73
+ }, this);
74
+ return res;
75
+ }
76
+ END_OF_JAVASCRIPT
77
+
78
+ :on_tab_change => <<-END_OF_JAVASCRIPT.l
79
+ function(self, tab) {
80
+ // load widget into the panel if it wasn't loaded yet
81
+ if (!tab.getWidget()) {
82
+ this.loadWidgetInto(tab);
83
+ }
84
+
85
+ // inform the server about active tab change
86
+ this.apiActivateTab({tab:tab.widget});
87
+
88
+ // call "update" on the widget
89
+ if (tab.outdated) {
90
+ tab.outdated = false;
91
+ var widget = tab.getWidget();
92
+ if (widget && widget.update) {widget.update.call(widget)};
31
93
  }
32
94
  }
33
- JS
95
+ END_OF_JAVASCRIPT
34
96
  }
35
97
  end
36
98
 
@@ -39,11 +101,9 @@ module Netzke
39
101
  end
40
102
 
41
103
  def js_config
42
- # active_item_config = items.detect{|i| i[:active]}
43
104
  super.merge({
44
105
  :items => fit_panels,
45
- :active_tab => id_name + '_active'
46
- # :active_tab => active_item_config && id_name + '_active'
106
+ :active_tab => id_name + '_active' # id of the fit panel that is active
47
107
  })
48
108
  end
49
109
 
@@ -51,8 +111,8 @@ module Netzke
51
111
  def initialize(*args)
52
112
  super
53
113
 
54
- # to remove duplicated active panels
55
- seen_active = false
114
+ # to remove duplicated active tabs
115
+ first_active = nil
56
116
 
57
117
  items.each_with_index do |item, i|
58
118
  # if the item is provided without a name, give it a generated name
@@ -60,10 +120,18 @@ module Netzke
60
120
 
61
121
  # remove duplicated "active" configuration
62
122
  if item[:active]
63
- item[:active] = nil if seen_active
64
- seen_active = true
123
+ if first_active.nil?
124
+ first_active = item.name
125
+ else
126
+ item[:active] = nil
127
+ end
65
128
  end
66
129
  end
130
+
131
+ # the first tab is forced to become active, if none was configured as active
132
+ items.first[:active] = true and first_active = items.first.name if first_active.nil?
133
+
134
+ widget_session[:active_tab] = first_active
67
135
  end
68
136
 
69
137
  # the items are late aggregatees, besides the one that is configured active
@@ -76,23 +144,7 @@ module Netzke
76
144
  res
77
145
  end
78
146
 
79
- def self.js_default_config
80
- super.merge({
81
- :id_delimiter => "___", # the default is "__", which conflicts with Netzke
82
- :defaults => {:layout => 'fit'}, # all tabs will be Ext.Panel-s with layout 'fit' ("fit-panels")
83
- :listeners => {
84
- # when tab is activated, its content gets loaded from the server
85
- :tabchange => {
86
- :fn => <<-JS.l
87
- function(self, tab){
88
- this.loadItemWidget(tab);
89
- }
90
- JS
91
- }
92
- }
93
- })
94
- end
95
-
147
+ # "Fit panels" - Panels with layout 'fit' that serve as containers for (dynamically) loaded widgets
96
148
  def fit_panels
97
149
  res = []
98
150
  items.each_with_index do |item, i|
@@ -106,5 +158,13 @@ module Netzke
106
158
  res
107
159
  end
108
160
 
161
+ def api_activate_tab(params)
162
+ widget_session[:active_tab] = params[:tab]
163
+ {}
164
+ end
165
+
166
+ def get_active_tab
167
+ aggregatee_instance(widget_session[:active_tab])
168
+ end
109
169
  end
110
170
  end
@@ -1,20 +1,54 @@
1
1
  module Netzke
2
- #
2
+ # == TableEditor CURRENTLY NOT SUPPORTED AND MAY BE BROKEN. Instead, use GridPanel's adding/editing records in form.
3
+ #
3
4
  # A widget used for editing a DB table. It contains a grid and a form which may display different DB fields,
4
5
  # configured by grid_columns and form_fields configuration options respectively
5
- #
6
6
  class TableEditor < BorderLayoutPanel
7
7
 
8
8
  def self.js_extend_properties
9
- super.merge({
10
- :get_form_widget => <<-JS.l,
9
+ {
10
+ :init_component => <<-END_OF_JAVASCRIPT.l,
11
+ function(){
12
+ Ext.netzke.cache.#{short_widget_class_name}.superclass.initComponent.call(this);
13
+
14
+ var setCentralWidgetEvents = function(){
15
+ this.getCenterWidget().on('addclick', function(){
16
+ this.getFormWidget().getForm().reset();
17
+
18
+ var firstEditableField = null;
19
+ this.getFormWidget().getForm().items.each(function(f){
20
+ if (!f.hidden && !f.disabled){
21
+ firstEditableField = f;
22
+ return false; // break the loop
23
+ }
24
+ })
25
+ if (firstEditableField) firstEditableField.focus();
26
+
27
+ this.getFormWidget().ownerCt.expand();
28
+
29
+ this.getCenterWidget().getSelectionModel().clearSelections();
30
+ this.lastSelectedRow = null;
31
+ return false;
32
+ }, this)
33
+
34
+ this.getCenterWidget().on('rowclick', this.onRowClick, this);
35
+ };
36
+
37
+ this.getCenterWidget().ownerCt.on('add', setCentralWidgetEvents, this);
38
+ setCentralWidgetEvents.call(this);
39
+
40
+ }
41
+ END_OF_JAVASCRIPT
42
+
43
+
44
+ :get_form_widget => <<-END_OF_JAVASCRIPT.l,
11
45
  function(){
12
- return this.getRegionWidget(this.initialConfig.region);
46
+ return this.getRegionWidget(this.region);
13
47
  }
14
- JS
48
+ END_OF_JAVASCRIPT
15
49
 
16
50
  # a grid row clicked
17
- :on_row_click => <<-JS.l,
51
+ :on_row_click => <<-END_OF_JAVASCRIPT.l,
18
52
  function(grid, index, e){
19
53
  // don't react if the selection hasn't changed
20
54
  if (index == this.lastSelectedRow) return false;
@@ -24,20 +58,20 @@ module Netzke
24
58
  var recordId = this.getCenterWidget().getStore().getAt(index).get('id');
25
59
 
26
60
  // load the form with the record id
27
- this.getRegionWidget(this.initialConfig.region).loadRecord(recordId);
61
+ this.getRegionWidget(this.region).loadRecord(recordId);
28
62
  }
29
- JS
63
+ END_OF_JAVASCRIPT
30
64
 
31
65
  # after the form is submitted, reload the grid
32
- :on_form_actioncomplete => <<-JS.l
66
+ :on_form_actioncomplete => <<-END_OF_JAVASCRIPT.l
33
67
  function(grid, index, e){
34
68
  this.getRegionWidget('center').store.load()
35
69
  }
36
- JS
37
- })
70
+ END_OF_JAVASCRIPT
71
+ }
38
72
  end
39
73
 
40
- def initial_config
74
+ def default_config
41
75
  # don't show the title on the top level
42
76
  super.merge!({:ext_config => {:title => false}})
43
77
  end
@@ -49,35 +83,6 @@ module Netzke
49
83
  })
50
84
  end
51
85
 
52
- def self.js_after_constructor
53
- super << <<-JS
54
- var setCentralWidgetEvents = function(){
55
- this.getCenterWidget().on('addclick', function(){
56
- this.getFormWidget().getForm().reset();
57
-
58
- var firstEditableField = null;
59
- this.getFormWidget().getForm().items.each(function(f){
60
- if (!f.hidden && !f.disabled){
61
- firstEditableField = f;
62
- return false; // break the loop
63
- }
64
- })
65
- if (firstEditableField) firstEditableField.focus();
66
-
67
- this.getFormWidget().ownerCt.expand();
68
-
69
- this.getCenterWidget().getSelectionModel().clearSelections();
70
- this.lastSelectedRow = null;
71
- return false;
72
- }, this)
73
-
74
- this.getCenterWidget().on('rowclick', this.onRowClick, this);
75
- };
76
- this.getCenterWidget().ownerCt.on('add', setCentralWidgetEvents, this);
77
- setCentralWidgetEvents.call(this);
78
- JS
79
- end
80
-
81
86
  def initial_aggregatees
82
87
  split_region = config[:split_region] || :east
83
88
  split_size = config[:split_size] || 200
@@ -88,7 +93,7 @@ module Netzke
88
93
  :ext_config => {
89
94
  :title => config[:grid_title] || config[:data_class_name].pluralize
90
95
  }
91
- }.recursive_merge(config[:grid_config] || {}),
96
+ }.deep_merge(config[:grid_config] || {}),
92
97
 
93
98
  split_region => {
94
99
  :widget_class_name => "FormPanel",
@@ -105,7 +110,7 @@ module Netzke
105
110
  :fn => "function(f, a){this.ownerCt.ownerCt.onFormActioncomplete(f,a)}".l
106
111
  }}
107
112
  }
108
- }.recursive_merge(config[:form_config] || {})
113
+ }.deep_merge(config[:form_config] || {})
109
114
  }
110
115
  end
111
116
 
@@ -1,52 +1,51 @@
1
1
  class Netzke::TreePanel < Netzke::Base
2
- interface :get_children
2
+ api :get_children
3
3
 
4
4
  def self.js_base_class
5
5
  "Ext.tree.TreePanel"
6
6
  end
7
7
 
8
- def self.js_default_config
8
+ def self.js_common_config_for_constructor
9
9
  super.merge({
10
10
  :root => {:text => '/', :id => 'source'},
11
- :loader => {:data_url => "config.interface.getChildren".l}
11
+ :loader => {:data_url => "config.api.getChildren".l}
12
12
  })
13
13
  end
14
14
 
15
15
  def self.js_extend_properties
16
16
  {
17
- :on_widget_load => <<-JS.l,
18
- function(){
19
- }
20
- JS
21
- :refresh_handler => <<-JS.l,
17
+ :refresh_handler => <<-END_OF_JAVASCRIPT.l,
22
18
  function(){
23
19
  console.info('refresh!');
24
20
  }
25
- JS
26
- :add_handler => <<-JS.l,
21
+ END_OF_JAVASCRIPT
22
+
23
+ :add_handler => <<-END_OF_JAVASCRIPT.l,
27
24
  function(e){
28
25
  console.info(e);
29
26
  }
30
- JS
31
- :edit_handler => <<-JS.l,
27
+ END_OF_JAVASCRIPT
28
+
29
+ :edit_handler => <<-END_OF_JAVASCRIPT.l,
32
30
  function(e){
33
31
  console.info(e);
34
32
 
35
33
  }
36
- JS
37
- :delete_handler => <<-JS.l
34
+ END_OF_JAVASCRIPT
35
+
36
+ :delete_handler => <<-END_OF_JAVASCRIPT.l
38
37
  function(e){
39
38
  console.info(e);
40
39
 
41
40
  }
42
- JS
41
+ END_OF_JAVASCRIPT
43
42
  }
44
43
  end
45
44
 
46
45
  def actions
47
46
  { :add => {:text => 'Add'},
48
47
  :edit => {:text => 'Edit'},
49
- :delete => {:text => 'Delete', :disabled => true}
48
+ :del => {:text => 'Delete', :disabled => true}
50
49
  }
51
50
  end
52
51
 
@@ -1,18 +1,42 @@
1
1
  module Netzke
2
+ # = Wrapper
3
+ #
4
+ # Simple Ext.Panel with layout 'fit' that wraps up another Netzke widget. Can be useful in HTML pages where
5
+ # a widget should be dynamically configured, to not reload the entire page after configuration (Wrapper
6
+ # will reload the widget automatically).
7
+ #
8
+ # == Configuration
9
+ # * <tt>:item</tt> - configuration hash for wrapped widget
10
+ #
11
+ # Example:
12
+ #
13
+ # netzke :wrapper, :item => {
14
+ # :widget_class_name => "FormPanel",
15
+ # :data_class_name => "User"
16
+ # }
2
17
  class Wrapper < Base
3
- def self.js_default_config
4
- # make us an invisible 'fit'-layout panel
18
+ def self.js_extend_properties
5
19
  super.merge({
6
20
  :layout => 'fit',
7
- :title => false,
21
+
22
+ # invisible
23
+ :header => false,
8
24
  :border => false,
9
- :items => ["new Ext.netzke.cache[config.itemConfig.widgetClassName](config.itemConfig)".l]
25
+
26
+ :init_component => <<-END_OF_JAVASCRIPT.l,
27
+ function(){
28
+ Ext.netzke.cache.#{short_widget_class_name}.superclass.initComponent.call(this);
29
+
30
+ // instantiate the item
31
+ this.instantiateChild(this.itemConfig);
32
+ }
33
+ END_OF_JAVASCRIPT
10
34
  })
11
35
  end
12
36
 
13
37
  def initial_aggregatees
14
38
  {:item => config[:item]}
15
39
  end
40
+
16
41
  end
17
-
18
42
  end