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.
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