skozlov-netzke-basepack 0.1.1.2 → 0.5.0
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 +5 -0
- data/LICENSE +2 -19
- data/README.rdoc +87 -0
- data/Rakefile +28 -12
- data/TODO.rdoc +7 -0
- data/VERSION +1 -0
- data/autotest/discover.rb +3 -0
- data/init.rb +0 -1
- data/javascripts/basepack.js +839 -49
- data/lib/app/models/netzke_auto_column.rb +56 -0
- data/lib/netzke/accordion_panel.rb +113 -0
- data/lib/netzke/active_record/basepack.rb +104 -0
- data/lib/netzke/active_record/data_accessor.rb +21 -0
- data/lib/netzke/basic_app.rb +325 -0
- data/lib/netzke/border_layout_panel.rb +128 -0
- 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 +131 -0
- data/lib/netzke/fields_configurator.rb +95 -0
- data/lib/netzke/form_panel.rb +214 -0
- data/lib/netzke/form_panel_api.rb +74 -0
- data/lib/netzke/form_panel_extras/javascripts/xcheckbox.js +82 -0
- data/lib/netzke/form_panel_js.rb +129 -0
- data/lib/netzke/grid_panel.rb +442 -0
- data/lib/netzke/grid_panel_api.rb +352 -0
- data/lib/netzke/grid_panel_extras/javascripts/check-column.js +33 -0
- data/{javascripts → lib/netzke/grid_panel_extras/javascripts}/filters.js +0 -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/panel.rb +13 -0
- data/lib/netzke/plugins/configuration_tool.rb +121 -0
- data/lib/netzke/property_editor.rb +105 -0
- data/lib/netzke/property_editor_extras/helper_model.rb +126 -0
- data/lib/netzke/search_panel.rb +62 -0
- data/lib/netzke/tab_panel.rb +160 -0
- data/lib/netzke/table_editor.rb +118 -0
- data/lib/netzke/tree_panel.rb +73 -0
- data/lib/netzke/wrapper.rb +42 -0
- data/lib/netzke-basepack.rb +9 -15
- data/netzke-basepack.gemspec +147 -20
- data/stylesheets/basepack.css +26 -0
- data/test/app_root/app/models/book.rb +1 -1
- data/test/app_root/config/environment.rb +1 -0
- data/test/app_root/db/migrate/20081222033440_create_genres.rb +1 -0
- data/test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb +1 -1
- data/test/app_root/db/migrate/20090102223630_create_netzke_layouts.rb +14 -0
- data/test/app_root/vendor/plugins/acts_as_list/README +23 -0
- data/test/app_root/vendor/plugins/acts_as_list/init.rb +3 -0
- data/test/app_root/vendor/plugins/acts_as_list/lib/active_record/acts/list.rb +256 -0
- data/test/test_helper.rb +1 -2
- data/test/unit/accordion_panel_test.rb +20 -0
- data/test/unit/active_record_basepack_test.rb +54 -0
- data/test/unit/grid_panel_test.rb +43 -0
- data/test/unit/helper_model_test.rb +30 -0
- data/test/unit/netzke_basepack_test.rb +4 -0
- data/test/unit/tab_panel_test.rb +21 -0
- metadata +96 -72
- data/CHANGELOG +0 -14
- data/Manifest +0 -65
- data/README.mdown +0 -18
- data/generators/netzke_basepack/USAGE +0 -8
- data/generators/netzke_basepack/netzke_basepack_generator.rb +0 -8
- data/generators/netzke_basepack/netzke_grid_generator.rb +0 -7
- data/generators/netzke_basepack/templates/create_netzke_grid_columns.rb +0 -21
- data/lib/app/models/netzke_grid_column.rb +0 -23
- data/lib/netzke/accordion.rb +0 -11
- data/lib/netzke/ar_ext.rb +0 -163
- data/lib/netzke/column.rb +0 -43
- data/lib/netzke/container.rb +0 -81
- data/lib/netzke/grid.rb +0 -120
- data/lib/netzke/grid_interface.rb +0 -156
- data/lib/netzke/grid_js_builder.rb +0 -276
- data/lib/netzke/preference_grid.rb +0 -43
- data/lib/netzke/properties_tool.rb +0 -66
- data/lib/netzke/property_grid.rb +0 -60
- data/test/ar_ext_test.rb +0 -39
- data/test/column_test.rb +0 -27
- data/test/grid_test.rb +0 -43
- data/test/netzke_basepack_test.rb +0 -8
@@ -0,0 +1,128 @@
|
|
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
|
+
# }
|
35
|
+
class BorderLayoutPanel < Base
|
36
|
+
REGIONS = %w(center west east south north).map(&:to_sym)
|
37
|
+
|
38
|
+
# JavaScript part
|
39
|
+
def self.js_extend_properties
|
40
|
+
{
|
41
|
+
:layout => 'border',
|
42
|
+
|
43
|
+
:init_component => <<-END_OF_JAVASCRIPT.l,
|
44
|
+
function(){
|
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
|
+
};
|
61
|
+
}, this);
|
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});
|
68
|
+
}
|
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
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
def initial_aggregatees
|
102
|
+
config[:regions] || {}
|
103
|
+
end
|
104
|
+
|
105
|
+
def region_aggregatees
|
106
|
+
aggregatees.reject{ |k,v| !REGIONS.include?(k) }
|
107
|
+
end
|
108
|
+
|
109
|
+
def js_config
|
110
|
+
regions = {}
|
111
|
+
REGIONS.each do |r|
|
112
|
+
if region_aggr = aggregatees[r]
|
113
|
+
regions.merge!(r => region_aggr[:region_config] || {})
|
114
|
+
end
|
115
|
+
end
|
116
|
+
super.merge(:regions => regions)
|
117
|
+
end
|
118
|
+
|
119
|
+
# API
|
120
|
+
api :resize_region # handles regions resize
|
121
|
+
def resize_region(params)
|
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"]
|
124
|
+
{}
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Netzke
|
2
|
+
# TabPanel-based widget that wraps-up "conifuration 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.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
@@ -0,0 +1,131 @@
|
|
1
|
+
module Netzke
|
2
|
+
class FieldModel < Hash
|
3
|
+
include BasepackActiveRecord
|
4
|
+
|
5
|
+
def self.new_from_hash(hsh)
|
6
|
+
self.new.replace(hsh)
|
7
|
+
end
|
8
|
+
|
9
|
+
# def self.json=(str)
|
10
|
+
# @@data = ActiveSupport::JSON.decode(str)
|
11
|
+
# process_data
|
12
|
+
# end
|
13
|
+
|
14
|
+
def self.widget_name=(w)
|
15
|
+
@@widget_name = w
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.data_storage=(ds)
|
19
|
+
@@storage = ds
|
20
|
+
process_data
|
21
|
+
end
|
22
|
+
|
23
|
+
# def self.data=(data)
|
24
|
+
# @@raw_data = data
|
25
|
+
# process_data
|
26
|
+
# end
|
27
|
+
|
28
|
+
def self.column_names
|
29
|
+
@@data.inject([]){|res, record| (res + record.keys).uniq}
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.columns
|
33
|
+
column_names
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.all(params={})
|
37
|
+
@@data
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.first
|
41
|
+
@@data[0]
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.find(id)
|
45
|
+
@@data[id-1]
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.count(params = {})
|
49
|
+
@@data.size
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.columns_hash
|
53
|
+
@@columns_hash
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.reflect_on_all_associations
|
57
|
+
[]
|
58
|
+
end
|
59
|
+
|
60
|
+
# instance methods
|
61
|
+
def id
|
62
|
+
self[:id] || self["id"]
|
63
|
+
end
|
64
|
+
|
65
|
+
def errors
|
66
|
+
[]
|
67
|
+
end
|
68
|
+
|
69
|
+
def save
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def self.process_data
|
75
|
+
@@columns_hash = {}
|
76
|
+
|
77
|
+
@@data = []
|
78
|
+
|
79
|
+
# convert array of hashes into array of FieldModel instances
|
80
|
+
@@storage.each do |hsh|
|
81
|
+
@@data << new_from_hash(hsh)
|
82
|
+
end
|
83
|
+
|
84
|
+
@@data.each do |record|
|
85
|
+
record.keys.each do |k|
|
86
|
+
|
87
|
+
if @@columns_hash[k.to_s].nil?
|
88
|
+
|
89
|
+
# calculate column type
|
90
|
+
puts record[k].class.to_s
|
91
|
+
column_type = case record[k].class.to_s
|
92
|
+
when "TrueClass"
|
93
|
+
:boolean
|
94
|
+
when "FalseClass"
|
95
|
+
:boolean
|
96
|
+
when "String"
|
97
|
+
:string
|
98
|
+
when "Fixnum"
|
99
|
+
:integer
|
100
|
+
else
|
101
|
+
:string
|
102
|
+
end
|
103
|
+
|
104
|
+
column = {:type => column_type}
|
105
|
+
|
106
|
+
# workaround for the "type" method
|
107
|
+
class << column
|
108
|
+
def type
|
109
|
+
self[:type]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
@@columns_hash[k.to_s] = column
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# # Testing
|
120
|
+
# @@data = [
|
121
|
+
# self.new_from_hash({"id" => 1, "name" => "col1", "column_type" => "text", "read_only" => true}),
|
122
|
+
# self.new_from_hash({"id" => 2, "name" => "col2", "column_type" => "string", "read_only" => false})
|
123
|
+
# ]
|
124
|
+
#
|
125
|
+
# process_data
|
126
|
+
# end testing
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,95 @@
|
|
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
|
6
|
+
class FieldsConfigurator < GridPanel
|
7
|
+
api :load_defaults
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
super
|
11
|
+
NetzkeAutoColumn.widget = config[:widget]
|
12
|
+
end
|
13
|
+
|
14
|
+
def default_config
|
15
|
+
super.deep_merge({
|
16
|
+
:name => 'columns',
|
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
|
+
},
|
25
|
+
})
|
26
|
+
end
|
27
|
+
|
28
|
+
def actions
|
29
|
+
super.merge(
|
30
|
+
:defaults => {:text => 'Restore defaults'}
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def independent_config
|
35
|
+
res = super
|
36
|
+
res[:ext_config][:bbar] = %w{ edit apply - defaults }
|
37
|
+
res
|
38
|
+
end
|
39
|
+
|
40
|
+
def predefined_columns
|
41
|
+
[{:name => :id}, *config[:widget].class.config_columns]
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.js_extend_properties
|
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,
|
61
|
+
function(){
|
62
|
+
Ext.Msg.confirm('Confirm', 'Are you sure?', function(btn){
|
63
|
+
if (btn == 'yes') {
|
64
|
+
this.loadDefaults();
|
65
|
+
}
|
66
|
+
}, this);
|
67
|
+
}
|
68
|
+
END_OF_JAVASCRIPT
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def load_defaults(params)
|
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
|
86
|
+
{}
|
87
|
+
end
|
88
|
+
|
89
|
+
# each time that we are loaded into the app, rebuild the table
|
90
|
+
def before_load
|
91
|
+
NetzkeAutoColumn.rebuild_table
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|