skozlov-netzke-basepack 0.1.1.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/.autotest +1 -0
  2. data/.gitignore +5 -0
  3. data/LICENSE +2 -19
  4. data/README.rdoc +87 -0
  5. data/Rakefile +28 -12
  6. data/TODO.rdoc +7 -0
  7. data/VERSION +1 -0
  8. data/autotest/discover.rb +3 -0
  9. data/init.rb +0 -1
  10. data/javascripts/basepack.js +839 -49
  11. data/lib/app/models/netzke_auto_column.rb +56 -0
  12. data/lib/netzke/accordion_panel.rb +113 -0
  13. data/lib/netzke/active_record/basepack.rb +104 -0
  14. data/lib/netzke/active_record/data_accessor.rb +21 -0
  15. data/lib/netzke/basic_app.rb +325 -0
  16. data/lib/netzke/border_layout_panel.rb +128 -0
  17. data/lib/netzke/configuration_panel.rb +24 -0
  18. data/lib/netzke/data_accessor.rb +71 -0
  19. data/lib/netzke/ext.rb +6 -0
  20. data/lib/netzke/field_model.rb +131 -0
  21. data/lib/netzke/fields_configurator.rb +95 -0
  22. data/lib/netzke/form_panel.rb +214 -0
  23. data/lib/netzke/form_panel_api.rb +74 -0
  24. data/lib/netzke/form_panel_extras/javascripts/xcheckbox.js +82 -0
  25. data/lib/netzke/form_panel_js.rb +129 -0
  26. data/lib/netzke/grid_panel.rb +442 -0
  27. data/lib/netzke/grid_panel_api.rb +352 -0
  28. data/lib/netzke/grid_panel_extras/javascripts/check-column.js +33 -0
  29. data/{javascripts → lib/netzke/grid_panel_extras/javascripts}/filters.js +0 -0
  30. data/lib/netzke/grid_panel_extras/javascripts/rows-dd.js +280 -0
  31. data/lib/netzke/grid_panel_js.rb +721 -0
  32. data/lib/netzke/panel.rb +13 -0
  33. data/lib/netzke/plugins/configuration_tool.rb +121 -0
  34. data/lib/netzke/property_editor.rb +105 -0
  35. data/lib/netzke/property_editor_extras/helper_model.rb +126 -0
  36. data/lib/netzke/search_panel.rb +62 -0
  37. data/lib/netzke/tab_panel.rb +160 -0
  38. data/lib/netzke/table_editor.rb +118 -0
  39. data/lib/netzke/tree_panel.rb +73 -0
  40. data/lib/netzke/wrapper.rb +42 -0
  41. data/lib/netzke-basepack.rb +9 -15
  42. data/netzke-basepack.gemspec +147 -20
  43. data/stylesheets/basepack.css +26 -0
  44. data/test/app_root/app/models/book.rb +1 -1
  45. data/test/app_root/config/environment.rb +1 -0
  46. data/test/app_root/db/migrate/20081222033440_create_genres.rb +1 -0
  47. data/test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb +1 -1
  48. data/test/app_root/db/migrate/20090102223630_create_netzke_layouts.rb +14 -0
  49. data/test/app_root/vendor/plugins/acts_as_list/README +23 -0
  50. data/test/app_root/vendor/plugins/acts_as_list/init.rb +3 -0
  51. data/test/app_root/vendor/plugins/acts_as_list/lib/active_record/acts/list.rb +256 -0
  52. data/test/test_helper.rb +1 -2
  53. data/test/unit/accordion_panel_test.rb +20 -0
  54. data/test/unit/active_record_basepack_test.rb +54 -0
  55. data/test/unit/grid_panel_test.rb +43 -0
  56. data/test/unit/helper_model_test.rb +30 -0
  57. data/test/unit/netzke_basepack_test.rb +4 -0
  58. data/test/unit/tab_panel_test.rb +21 -0
  59. metadata +96 -72
  60. data/CHANGELOG +0 -14
  61. data/Manifest +0 -65
  62. data/README.mdown +0 -18
  63. data/generators/netzke_basepack/USAGE +0 -8
  64. data/generators/netzke_basepack/netzke_basepack_generator.rb +0 -8
  65. data/generators/netzke_basepack/netzke_grid_generator.rb +0 -7
  66. data/generators/netzke_basepack/templates/create_netzke_grid_columns.rb +0 -21
  67. data/lib/app/models/netzke_grid_column.rb +0 -23
  68. data/lib/netzke/accordion.rb +0 -11
  69. data/lib/netzke/ar_ext.rb +0 -163
  70. data/lib/netzke/column.rb +0 -43
  71. data/lib/netzke/container.rb +0 -81
  72. data/lib/netzke/grid.rb +0 -120
  73. data/lib/netzke/grid_interface.rb +0 -156
  74. data/lib/netzke/grid_js_builder.rb +0 -276
  75. data/lib/netzke/preference_grid.rb +0 -43
  76. data/lib/netzke/properties_tool.rb +0 -66
  77. data/lib/netzke/property_grid.rb +0 -60
  78. data/test/ar_ext_test.rb +0 -39
  79. data/test/column_test.rb +0 -27
  80. data/test/grid_test.rb +0 -43
  81. 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,6 @@
1
+ module Netzke
2
+ # Ext-related module. Some constants provide meta-information about the Ext.library.
3
+ module Ext
4
+ FORM_FIELD_XTYPES = %w{ textfield numberfield textarea combobox checkbox xdatetime }
5
+ end
6
+ end
@@ -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