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
@@ -1,97 +1,103 @@
|
|
1
1
|
module Netzke
|
2
|
+
# Represents the Ext.Panel with layout 'border'. May serve as parent class for compound widgets.
|
3
|
+
#
|
4
|
+
# == Features:
|
5
|
+
# * Responds to region resizing, storing the sizes in persistent config
|
6
|
+
#
|
7
|
+
# == Future features:
|
8
|
+
# * Stores expand/collapse state in the persistent config
|
9
|
+
#
|
10
|
+
# == Non-functional features:
|
11
|
+
# * (JavaScript) Creates convinient methods to access aggregatees inside the regions, like
|
12
|
+
# <tt>getCenterWidget()</tt>, <tt>getWestWidget()</tt>, etc
|
13
|
+
#
|
14
|
+
# == Configuration:
|
15
|
+
# <tt>:regions</tt> - a hash in form:
|
16
|
+
#
|
17
|
+
# {:center => {<netzke widget config>}, :east => {<another netzke widget config>}, ...}
|
18
|
+
#
|
19
|
+
# <tt>:regions => :center/:west/:etc => :region_config</tt> - configuration options for
|
20
|
+
# Ext.layout.BorderLayout.SplitRegion.
|
21
|
+
#
|
22
|
+
# == Example configuration:
|
23
|
+
#
|
24
|
+
# :regions => {
|
25
|
+
# :center => {:widget_class_name => "Panel", :ext_config => {:html => "A panel"}},
|
26
|
+
# :west => {
|
27
|
+
# :widget_class_name => "GridPanel",
|
28
|
+
# :data_class_name => "User",
|
29
|
+
# :region_config => {
|
30
|
+
# :width => 100,
|
31
|
+
# :split => true
|
32
|
+
# }
|
33
|
+
# }
|
34
|
+
# }
|
2
35
|
class BorderLayoutPanel < Base
|
3
|
-
interface :resize_region
|
4
|
-
|
5
36
|
REGIONS = %w(center west east south north).map(&:to_sym)
|
6
37
|
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
:afterlayout => {:fn => "this.setResizeEvents".l, :scope => this}
|
14
|
-
}
|
15
|
-
end
|
16
|
-
|
17
|
-
def js_before_constructor
|
18
|
-
<<-JS.l
|
19
|
-
var items = [];
|
20
|
-
Ext.each(['center', 'west', 'east', 'south', 'north'], function(r){
|
21
|
-
var configName = r+'Config';
|
22
|
-
if (config[configName]){
|
23
|
-
var regionConfig = config.regions[r] || {};
|
24
|
-
regionConfig.layout = 'fit';
|
25
|
-
regionConfig.region = r;
|
26
|
-
regionConfig.items = [new Ext.netzke.cache[config[configName].widgetClassName](config[configName])]
|
27
|
-
items.push(regionConfig);
|
28
|
-
|
29
|
-
// A function to access a region widget (even if the widget gets reloaded, the function will work).
|
30
|
-
// E.g.: getEastWidget()
|
31
|
-
this['get'+r.capitalize()+'Widget'] = function(){
|
32
|
-
return this.find('region', r)[0].getWidget()
|
33
|
-
}.createDelegate(this)
|
34
|
-
|
35
|
-
|
36
|
-
};
|
37
|
-
}, this)
|
38
|
-
JS
|
39
|
-
end
|
40
|
-
|
41
|
-
def js_default_config
|
42
|
-
super.merge({
|
43
|
-
:layout => 'border',
|
44
|
-
:items => "items".l
|
45
|
-
})
|
46
|
-
end
|
47
|
-
|
48
|
-
def js_extend_properties
|
49
|
-
{
|
50
|
-
:get_region_widget => <<-JS.l,
|
51
|
-
function(region){
|
52
|
-
return this.find('region', region)[0].getWidget()
|
53
|
-
}
|
54
|
-
JS
|
55
|
-
:set_resize_events => <<-JS.l,
|
38
|
+
# JavaScript part
|
39
|
+
def self.js_extend_properties
|
40
|
+
{
|
41
|
+
:layout => 'border',
|
42
|
+
|
43
|
+
:init_component => <<-END_OF_JAVASCRIPT.l,
|
56
44
|
function(){
|
57
|
-
this.items
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
params: {region_name: panel.region, new_height:h}
|
74
|
-
});
|
75
|
-
panel.oldSize.height = h;
|
76
|
-
}
|
77
|
-
return true;
|
78
|
-
}, this);
|
45
|
+
this.items = [];
|
46
|
+
Ext.each(['center', 'west', 'east', 'south', 'north'], function(r){
|
47
|
+
var configName = r+'Config';
|
48
|
+
if (this[configName]){
|
49
|
+
var regionConfig = this.regions[r] || {};
|
50
|
+
regionConfig.layout = 'fit';
|
51
|
+
regionConfig.region = r;
|
52
|
+
regionConfig.items = [new Ext.netzke.cache[this[configName].widgetClassName](this[configName])]
|
53
|
+
this.items.push(regionConfig);
|
54
|
+
|
55
|
+
// A function to access a region widget (even if the widget gets reloaded, the function will work).
|
56
|
+
// E.g.: getEastWidget()
|
57
|
+
this['get'+r.capitalize()+'Widget'] = function(){
|
58
|
+
return this.find('region', r)[0].getWidget()
|
59
|
+
}.createDelegate(this);
|
60
|
+
};
|
79
61
|
}, this);
|
80
|
-
|
62
|
+
|
63
|
+
// Now let Ext.Panel do the rest
|
64
|
+
Ext.netzke.cache.BorderLayoutPanel.superclass.initComponent.call(this);
|
65
|
+
|
66
|
+
// First time on "afterlayout", set resize events
|
67
|
+
this.on('afterlayout', this.setResizeEvents, this, {single: true});
|
81
68
|
}
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
69
|
+
END_OF_JAVASCRIPT
|
70
|
+
|
71
|
+
:get_region_widget => <<-END_OF_JAVASCRIPT.l,
|
72
|
+
function(region){
|
73
|
+
return this.find('region', region)[0].getWidget();
|
74
|
+
}
|
75
|
+
END_OF_JAVASCRIPT
|
76
|
+
|
77
|
+
:set_resize_events => <<-END_OF_JAVASCRIPT.l,
|
78
|
+
function(){
|
79
|
+
this.items.each(function(item, index, length){
|
80
|
+
if (!item.oldSize) item.oldSize = item.getSize();
|
81
|
+
if (item.region == 'east' || item.region == 'west') item.on('resize', function(panel, w, h){
|
82
|
+
if (panel.oldSize.width != w) {
|
83
|
+
this.resizeRegion({region_name: panel.region, new_width:w});
|
84
|
+
panel.oldSize.width = w;
|
85
|
+
}
|
86
|
+
return true;
|
87
|
+
}, this);
|
88
|
+
else if (item.region == 'south' || item.region == 'north') item.on('resize', function(panel, w, h){
|
89
|
+
if (panel.oldSize.height != h) {
|
90
|
+
this.resizeRegion({region_name: panel.region, new_height:h});
|
91
|
+
panel.oldSize.height = h;
|
92
|
+
}
|
93
|
+
return true;
|
94
|
+
}, this);
|
95
|
+
}, this);
|
96
|
+
}
|
97
|
+
END_OF_JAVASCRIPT
|
98
|
+
}
|
93
99
|
end
|
94
|
-
|
100
|
+
|
95
101
|
def initial_aggregatees
|
96
102
|
config[:regions] || {}
|
97
103
|
end
|
@@ -105,25 +111,18 @@ module Netzke
|
|
105
111
|
REGIONS.each do |r|
|
106
112
|
if region_aggr = aggregatees[r]
|
107
113
|
regions.merge!(r => region_aggr[:region_config] || {})
|
108
|
-
height = persistent_config["#{r}_height"] ||= regions[r][:height] if regions[r][:height]
|
109
|
-
width = persistent_config["#{r}_width"] ||= regions[r][:width] if regions[r][:width]
|
110
|
-
regions[r].merge!(:height => height)
|
111
|
-
regions[r].merge!(:width => width)
|
112
114
|
end
|
113
115
|
end
|
114
116
|
super.merge(:regions => regions)
|
115
117
|
end
|
116
|
-
|
118
|
+
|
119
|
+
# API
|
120
|
+
api :resize_region # handles regions resize
|
117
121
|
def resize_region(params)
|
118
|
-
persistent_config["#{params["region_name"]}
|
119
|
-
persistent_config["#{params["region_name"]}
|
122
|
+
persistent_config["regions__#{params["region_name"]}__region_config__width"] = params["new_width"].to_i if params["new_width"]
|
123
|
+
persistent_config["regions__#{params["region_name"]}__region_config__height"] = params["new_height"].to_i if params["new_height"]
|
120
124
|
{}
|
121
125
|
end
|
122
126
|
|
123
|
-
protected
|
124
|
-
|
125
|
-
def extend_functions; ""; end
|
126
|
-
def js_extra_events; ""; end
|
127
|
-
|
128
127
|
end
|
129
128
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Netzke
|
2
|
+
# TabPanel-based widget that wraps-up "configuration widgets" that each widget can define
|
3
|
+
# (along) with including the Plugins::ConfigurationTool tool.
|
4
|
+
class ConfigurationPanel < TabPanel
|
5
|
+
api :commit
|
6
|
+
def commit(params)
|
7
|
+
commit_data = ActiveSupport::JSON.decode params[:commit_data]
|
8
|
+
commit_data.each_pair do |k,v|
|
9
|
+
aggregatee_instance(k).commit(v)
|
10
|
+
end
|
11
|
+
{:reload_parent => true, :feedback => (@flash.empty? ? nil : @flash)}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.js_extend_properties
|
15
|
+
{
|
16
|
+
:reload_parent => <<-END_OF_JAVASCRIPT.l,
|
17
|
+
function(){
|
18
|
+
this.getParent().reload();
|
19
|
+
}
|
20
|
+
END_OF_JAVASCRIPT
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Netzke
|
2
|
+
# This module is included into such data-driven widgets as GridPanel, FormPanel, etc. It provides for
|
3
|
+
# flexible pre-configuration of (virtual) attributes.
|
4
|
+
#
|
5
|
+
# TODO: show examples of how to create the helpers
|
6
|
+
module DataAccessor
|
7
|
+
|
8
|
+
# This method should be called from the constructor of the widget. It dynamically includes:
|
9
|
+
# 1) helpers into the data model for this widget; those may contain instance methods used as virtual attributes
|
10
|
+
# 2) generic (used by all "data accessor" widgets) extensions into the data model for this widget
|
11
|
+
def apply_helpers
|
12
|
+
# Generic extensions to the data model
|
13
|
+
if data_class # because some widgets, like FormPanel, may have it optional
|
14
|
+
data_class.send(:include, Netzke::ActiveRecord::DataAccessor) if !data_class.include?(Netzke::ActiveRecord::DataAccessor)
|
15
|
+
|
16
|
+
# Model helpers
|
17
|
+
const_name = "Netzke::Helpers::#{data_class.name}"
|
18
|
+
model_extensions = const_name.constantize rescue nil
|
19
|
+
data_class.send(:include, model_extensions) if model_extensions && !data_class.include?(model_extensions)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns columns that are exposed by the class and the helpers
|
24
|
+
def predefined_columns
|
25
|
+
helper_module = "Netzke::Helpers::#{short_widget_class_name}#{data_class.name}".constantize rescue nil
|
26
|
+
|
27
|
+
data_class_columns = data_class && data_class.column_names.map(&:to_sym) || []
|
28
|
+
|
29
|
+
if helper_module
|
30
|
+
exposed_attributes = helper_module.respond_to?(:exposed_attributes) ? normalize_array_of_columns(helper_module.exposed_attributes) : nil
|
31
|
+
virtual_attributes = helper_module.respond_to?(:virtual_attributes) ? helper_module.virtual_attributes : []
|
32
|
+
excluded_attributes = helper_module.respond_to?(:excluded_attributes) ? helper_module.excluded_attributes : []
|
33
|
+
attributes_config = helper_module.respond_to?(:attributes_config) ? helper_module.attributes_config : {}
|
34
|
+
|
35
|
+
res = exposed_attributes || data_class_columns + virtual_attributes
|
36
|
+
|
37
|
+
res = normalize_columns(res)
|
38
|
+
|
39
|
+
res.reject!{ |c| excluded_attributes.include? c[:name] }
|
40
|
+
|
41
|
+
res.map!{ |c| c.merge!(attributes_config[c[:name]] || {})}
|
42
|
+
else
|
43
|
+
res = normalize_columns(data_class_columns)
|
44
|
+
end
|
45
|
+
|
46
|
+
res
|
47
|
+
end
|
48
|
+
|
49
|
+
# Make sure we have keys as symbols, not strings
|
50
|
+
def normalize_array_of_columns(arry)
|
51
|
+
arry.map do |f|
|
52
|
+
if f.is_a?(Hash)
|
53
|
+
f.symbolize_keys
|
54
|
+
else
|
55
|
+
f.to_sym
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# From symbol to config hash
|
61
|
+
def normalize_column(field)
|
62
|
+
field.is_a?(Symbol) ? {:name => field} : field
|
63
|
+
end
|
64
|
+
|
65
|
+
# From symbols to config hashes
|
66
|
+
def normalize_columns(items)
|
67
|
+
items.map{|c| normalize_column(c)}
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
data/lib/netzke/ext.rb
ADDED
data/lib/netzke/field_model.rb
CHANGED
@@ -1,23 +1,27 @@
|
|
1
1
|
module Netzke
|
2
|
+
# == FieldsConfigurator
|
3
|
+
# Provides dynamic configuring columns/fields for GridPanel and FormPanel.
|
4
|
+
# Configuration parameters:
|
5
|
+
# * <tt>:widget</tt> - widget to configure columns/fields for
|
2
6
|
class FieldsConfigurator < GridPanel
|
3
|
-
|
7
|
+
api :load_defaults
|
4
8
|
|
5
|
-
def self.js_base_class
|
6
|
-
GridPanel
|
7
|
-
end
|
8
|
-
|
9
9
|
def initialize(*args)
|
10
10
|
super
|
11
|
-
|
12
|
-
NetzkeLayoutItem.widget = config[:widget].id_name
|
13
|
-
config[:data_class_name] = "NetzkeLayoutItem"
|
11
|
+
NetzkeAutoColumn.widget = config[:widget]
|
14
12
|
end
|
15
13
|
|
16
|
-
def
|
17
|
-
super.
|
14
|
+
def default_config
|
15
|
+
super.deep_merge({
|
18
16
|
:name => 'columns',
|
19
|
-
:
|
20
|
-
:ext_config => {
|
17
|
+
:data_class_name => "NetzkeAutoColumn",
|
18
|
+
:ext_config => {
|
19
|
+
:header => false,
|
20
|
+
:enable_extended_search => false,
|
21
|
+
:enable_edit_in_form => false,
|
22
|
+
:enable_rows_reordering => GridPanel.config[:rows_reordering_available],
|
23
|
+
:enable_pagination => false
|
24
|
+
},
|
21
25
|
})
|
22
26
|
end
|
23
27
|
|
@@ -27,44 +31,65 @@ module Netzke
|
|
27
31
|
)
|
28
32
|
end
|
29
33
|
|
30
|
-
def
|
31
|
-
|
34
|
+
def independent_config
|
35
|
+
res = super
|
36
|
+
res[:ext_config][:bbar] = %w{ edit apply - defaults }
|
37
|
+
res
|
32
38
|
end
|
33
|
-
|
39
|
+
|
40
|
+
def predefined_columns
|
41
|
+
[{:name => :id}, *config[:widget].class.config_columns]
|
42
|
+
end
|
43
|
+
|
34
44
|
def self.js_extend_properties
|
35
|
-
|
36
|
-
|
45
|
+
{
|
46
|
+
# Disable the 'gear' tool for now
|
47
|
+
:gear => <<-END_OF_JAVASCRIPT.l,
|
48
|
+
function(){
|
49
|
+
this.feedback("You can't configure configurator (yet)");
|
50
|
+
}
|
51
|
+
END_OF_JAVASCRIPT
|
52
|
+
|
53
|
+
# we need to provide this function so that the server-side commit would happen
|
54
|
+
:get_commit_data => <<-END_OF_JAVASCRIPT.l,
|
55
|
+
function(){
|
56
|
+
return null; // because our commit data is already at the server
|
57
|
+
}
|
58
|
+
END_OF_JAVASCRIPT
|
59
|
+
|
60
|
+
:defaults => <<-END_OF_JAVASCRIPT.l,
|
37
61
|
function(){
|
38
62
|
Ext.Msg.confirm('Confirm', 'Are you sure?', function(btn){
|
39
63
|
if (btn == 'yes') {
|
40
|
-
|
41
|
-
url:this.initialConfig.interface.loadDefaults,
|
42
|
-
callback:function(){
|
43
|
-
this.store.reload();
|
44
|
-
},
|
45
|
-
scope:this
|
46
|
-
})
|
64
|
+
this.loadDefaults();
|
47
65
|
}
|
48
66
|
}, this);
|
49
67
|
}
|
50
|
-
|
51
|
-
}
|
68
|
+
END_OF_JAVASCRIPT
|
69
|
+
}
|
52
70
|
end
|
53
71
|
|
54
72
|
def load_defaults(params)
|
55
|
-
|
56
|
-
|
73
|
+
config[:widget].persistent_config[:layout__columns] = config[:widget].default_columns
|
74
|
+
NetzkeAutoColumn.rebuild_table
|
75
|
+
{:load_store_data => get_data, :reconfigure => js_config}
|
76
|
+
end
|
77
|
+
|
78
|
+
def commit(params)
|
79
|
+
defaults_hash = config[:widget].class.config_columns.inject({}){ |r, c| r.merge!(c[:name] => c[:default]) }
|
80
|
+
config[:widget].persistent_config[:layout__columns] = NetzkeAutoColumn.all_columns.map do |c|
|
81
|
+
# reject all keys that are 1) same as defaults, 2) 'position'
|
82
|
+
c.reject!{ |k,v| defaults_hash[k.to_sym].to_s == v.to_s || k == 'position'}
|
83
|
+
c = c["name"] if c.keys.count == 1 # denormalize the column
|
84
|
+
c
|
85
|
+
end
|
57
86
|
{}
|
58
87
|
end
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
NetzkeLayoutItem.widget = id_name
|
64
|
-
res
|
88
|
+
|
89
|
+
# each time that we are loaded into the app, rebuild the table
|
90
|
+
def before_load
|
91
|
+
NetzkeAutoColumn.rebuild_table
|
65
92
|
end
|
66
|
-
|
67
|
-
alias_method_chain :default_db_fields, :widget_change
|
68
|
-
|
93
|
+
|
69
94
|
end
|
70
95
|
end
|