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.
- data/.autotest +1 -0
- data/.gitignore +6 -0
- data/{CHANGELOG → CHANGELOG.rdoc} +26 -0
- data/README.rdoc +11 -11
- data/Rakefile +37 -11
- data/TODO.rdoc +8 -0
- data/VERSION +1 -0
- data/javascripts/basepack.js +71 -28
- data/lib/app/models/netzke_auto_column.rb +56 -0
- data/lib/netzke-basepack.rb +5 -3
- data/lib/netzke/accordion_panel.rb +69 -67
- data/lib/netzke/active_record/basepack.rb +104 -0
- data/lib/netzke/active_record/data_accessor.rb +33 -0
- data/lib/netzke/basic_app.rb +233 -124
- data/lib/netzke/border_layout_panel.rb +97 -98
- data/lib/netzke/configuration_panel.rb +24 -0
- data/lib/netzke/data_accessor.rb +71 -0
- data/lib/netzke/ext.rb +6 -0
- data/lib/netzke/field_model.rb +1 -1
- data/lib/netzke/fields_configurator.rb +62 -37
- data/lib/netzke/form_panel.rb +161 -51
- data/lib/netzke/form_panel_api.rb +74 -0
- data/lib/netzke/form_panel_js.rb +129 -0
- data/lib/netzke/grid_panel.rb +385 -80
- data/lib/netzke/grid_panel_api.rb +352 -0
- data/lib/netzke/grid_panel_extras/javascripts/rows-dd.js +280 -0
- data/lib/netzke/grid_panel_js.rb +721 -0
- data/lib/netzke/masquerade_selector.rb +53 -0
- data/lib/netzke/panel.rb +9 -0
- data/lib/netzke/plugins/configuration_tool.rb +121 -0
- data/lib/netzke/property_editor.rb +95 -7
- data/lib/netzke/property_editor_extras/helper_model.rb +55 -34
- data/lib/netzke/search_panel.rb +62 -0
- data/lib/netzke/tab_panel.rb +97 -37
- data/lib/netzke/table_editor.rb +49 -44
- data/lib/netzke/tree_panel.rb +15 -16
- data/lib/netzke/wrapper.rb +29 -5
- data/netzke-basepack.gemspec +151 -19
- data/stylesheets/basepack.css +5 -0
- data/test/app_root/app/models/book.rb +1 -1
- data/test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb +1 -1
- data/test/unit/accordion_panel_test.rb +1 -2
- data/test/unit/active_record_basepack_test.rb +54 -0
- data/test/unit/grid_panel_test.rb +8 -12
- data/test/unit/helper_model_test.rb +30 -0
- metadata +69 -78
- data/Manifest +0 -86
- data/TODO +0 -3
- data/lib/app/models/netzke_hash_record.rb +0 -180
- data/lib/app/models/netzke_layout_item.rb +0 -11
- data/lib/netzke/ar_ext.rb +0 -269
- data/lib/netzke/configuration_tool.rb +0 -80
- data/lib/netzke/container.rb +0 -77
- data/lib/netzke/db_fields.rb +0 -44
- data/lib/netzke/fields_configurator_old.rb +0 -62
- data/lib/netzke/form_panel_extras/interface.rb +0 -56
- data/lib/netzke/form_panel_extras/js_builder.rb +0 -134
- data/lib/netzke/grid_panel_extras/interface.rb +0 -206
- data/lib/netzke/grid_panel_extras/js_builder.rb +0 -352
- data/test/unit/ar_ext_test.rb +0 -53
- data/test/unit/netzke_hash_record_test.rb +0 -52
- data/test/unit/netzke_layout_item_test.rb +0 -28
data/lib/netzke/tab_panel.rb
CHANGED
@@ -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
|
-
|
20
|
-
:
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
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
|
55
|
-
|
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
|
-
|
64
|
-
|
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
|
-
|
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
|
data/lib/netzke/table_editor.rb
CHANGED
@@ -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
|
-
|
10
|
-
:
|
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.
|
46
|
+
return this.getRegionWidget(this.region);
|
13
47
|
}
|
14
|
-
|
48
|
+
END_OF_JAVASCRIPT
|
15
49
|
|
16
50
|
# a grid row clicked
|
17
|
-
:on_row_click => <<-
|
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.
|
61
|
+
this.getRegionWidget(this.region).loadRecord(recordId);
|
28
62
|
}
|
29
|
-
|
63
|
+
END_OF_JAVASCRIPT
|
30
64
|
|
31
65
|
# after the form is submitted, reload the grid
|
32
|
-
:on_form_actioncomplete => <<-
|
66
|
+
:on_form_actioncomplete => <<-END_OF_JAVASCRIPT.l
|
33
67
|
function(grid, index, e){
|
34
68
|
this.getRegionWidget('center').store.load()
|
35
69
|
}
|
36
|
-
|
37
|
-
}
|
70
|
+
END_OF_JAVASCRIPT
|
71
|
+
}
|
38
72
|
end
|
39
73
|
|
40
|
-
def
|
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
|
-
}.
|
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
|
-
}.
|
113
|
+
}.deep_merge(config[:form_config] || {})
|
109
114
|
}
|
110
115
|
end
|
111
116
|
|
data/lib/netzke/tree_panel.rb
CHANGED
@@ -1,52 +1,51 @@
|
|
1
1
|
class Netzke::TreePanel < Netzke::Base
|
2
|
-
|
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.
|
8
|
+
def self.js_common_config_for_constructor
|
9
9
|
super.merge({
|
10
10
|
:root => {:text => '/', :id => 'source'},
|
11
|
-
:loader => {:data_url => "config.
|
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
|
-
:
|
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
|
-
|
26
|
-
|
21
|
+
END_OF_JAVASCRIPT
|
22
|
+
|
23
|
+
:add_handler => <<-END_OF_JAVASCRIPT.l,
|
27
24
|
function(e){
|
28
25
|
console.info(e);
|
29
26
|
}
|
30
|
-
|
31
|
-
|
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
|
-
|
37
|
-
|
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
|
-
|
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
|
-
:
|
48
|
+
:del => {:text => 'Delete', :disabled => true}
|
50
49
|
}
|
51
50
|
end
|
52
51
|
|
data/lib/netzke/wrapper.rb
CHANGED
@@ -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.
|
4
|
-
# make us an invisible 'fit'-layout panel
|
18
|
+
def self.js_extend_properties
|
5
19
|
super.merge({
|
6
20
|
:layout => 'fit',
|
7
|
-
|
21
|
+
|
22
|
+
# invisible
|
23
|
+
:header => false,
|
8
24
|
:border => false,
|
9
|
-
|
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
|