netzke-basepack 0.4.2 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|