netzke-basepack 0.2.0.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ v0.2.2
2
+ Meta: updated netzke-core version (dependency)
3
+
4
+ v0.2.1
5
+ Regression: BorderLayoutPanel now restores the region sizes from the database
6
+
1
7
  v0.2.0.1
2
8
  Meta: updated netzke-core version (dependency)
3
9
 
data/Manifest CHANGED
@@ -1,19 +1,23 @@
1
1
  CHANGELOG
2
2
  css/basepack.css
3
3
  generators/netzke_basepack/netzke_basepack_generator.rb
4
- generators/netzke_basepack/netzke_grid_panel_generator.rb
5
- generators/netzke_basepack/templates/create_netzke_grid_panel_columns.rb
6
4
  generators/netzke_basepack/USAGE
5
+ generators/netzke_form_panel/netzke_form_panel_generator.rb
6
+ generators/netzke_form_panel/templates/create_netzke_form_panel_fields.rb
7
+ generators/netzke_grid_panel/netzke_grid_panel_generator.rb
8
+ generators/netzke_grid_panel/templates/create_netzke_grid_panel_columns.rb
7
9
  init.rb
8
10
  install.rb
9
11
  javascripts/basepack.js
10
12
  javascripts/filters.js
13
+ lib/app/models/netzke_form_panel_field.rb
11
14
  lib/app/models/netzke_grid_panel_column.rb
12
15
  lib/netzke/accordion_panel.rb
13
16
  lib/netzke/ar_ext.rb
14
17
  lib/netzke/border_layout_panel.rb
15
18
  lib/netzke/column.rb
16
19
  lib/netzke/container.rb
20
+ lib/netzke/form_panel.rb
17
21
  lib/netzke/grid_panel.rb
18
22
  lib/netzke/grid_panel_interface.rb
19
23
  lib/netzke/grid_panel_js_builder.rb
@@ -26,7 +30,7 @@ lib/netzke-basepack.rb
26
30
  LICENSE
27
31
  Manifest
28
32
  Rakefile
29
- README.mdown
33
+ README.rdoc
30
34
  tasks/netzke_basepack_tasks.rake
31
35
  test/app_root/app/controllers/application.rb
32
36
  test/app_root/app/models/book.rb
@@ -51,7 +55,12 @@ test/app_root/db/migrate/20081223024935_create_categories.rb
51
55
  test/app_root/db/migrate/20081223025635_create_countries.rb
52
56
  test/app_root/db/migrate/20081223025653_create_continents.rb
53
57
  test/app_root/db/migrate/20081223025732_create_cities.rb
58
+ test/app_root/db/migrate/20090102223630_create_netzke_layouts.rb
59
+ test/app_root/db/migrate/20090102223811_create_netzke_grid_panel_columns.rb
54
60
  test/app_root/script/console
61
+ test/app_root/vendor/plugins/acts_as_list/init.rb
62
+ test/app_root/vendor/plugins/acts_as_list/lib/active_record/acts/list.rb
63
+ test/app_root/vendor/plugins/acts_as_list/README
55
64
  test/ar_ext_test.rb
56
65
  test/border_layout_panel_test.rb
57
66
  test/column_test.rb
data/README.rdoc ADDED
@@ -0,0 +1,87 @@
1
+ = netzke-basepack
2
+ A pack of basic Rails/Ext JS widgets, as a part of Netzke framework. Live demo/tutorials on http://blog.writelesscode.com
3
+
4
+ Note that if you would like to modify this code or experiment with it, you may be better off cloning this project into your app's vendor/plugin directory - it will then behave as a Rails plugin.
5
+
6
+ = Prerequisites
7
+ 1. Rails >= 2.2
8
+ 2. Ext JS >= 2.0: its root *must* be accessible as RAILS_ROOT/public/extjs. You may symlink your Ext JS library here like this (from your app folder):
9
+ cd public && ln -s ~/Developer/extjs/ext-2.2 extjs
10
+
11
+ 3. acts_as_list plugin must be installed:
12
+ ./script/plugin install git://github.com/rails/acts_as_list.git
13
+
14
+ = Installation
15
+ Install the gem:
16
+ gem install netzke-basepack
17
+
18
+ Include it into environment.rb:
19
+ config.gem "netzke-basepack"
20
+
21
+ Include mapping for Netzke controller providing *.js and *.css (in routes.rb):
22
+ map.netzke
23
+
24
+ = Usage
25
+ First, run the generators to have the necessary migrations:
26
+ ./script/generate netzke_core
27
+ ./script/generate netzke_grid_panel
28
+
29
+ Do the migrations:
30
+ rake db:migrate
31
+
32
+ The following example will provide you with a grid-based scaffold for ActiveRecord-model called Book. You may generate it like this:
33
+ ./script/generate model Book title:string amount:integer
34
+ (don't forget to run the migrations after it)
35
+
36
+ In the controller declare the widget:
37
+
38
+ class WelcomeController < ApplicationController
39
+ netzke :books, :widget_class_name => 'GridPanel', :data_class_name => 'Book'
40
+ end
41
+
42
+ After a widget is declared in the controller, it can be accessed in 3 different ways: 1) loaded by means of an automatically created controller action which will produce a basic HTML-page with the widget (handy for testing), 2) embedded directly into a view (by means of helpers), 3) dynamically loaded by other widgets (usually by the widget of class 'Application', if you want a desktop-like, AJAX-driven web-app).
43
+
44
+ == Using automatically created controller action
45
+ Without writing any more code, you can access the widget by http://localhost:3000/welcome/books_test. That is to say, you simply append _test to your widget's name (as declared in the controller) to get the action name.
46
+
47
+ == Embedding a widget into a view
48
+ netzke-core plugin provides the following 2 helpers to put inside your head-tag (use it in your layout):
49
+
50
+ 1. netzke_js_include - to include extjs and netzke javascript files
51
+ 2. netzke_css_include - to include the css. This one can take a parameter to specify a color schema you wish for Ext JS, e.g.: netzke_css_include(:gray)
52
+
53
+ Declaring a widget in the controller provides you with a couple of helpers that can be used in the view:
54
+
55
+ 1. books_class_definition will contain the javascript code defining the code for the JS class.
56
+ 2. books_widget_instance will declare a local javascript variable called book.
57
+
58
+ Use these helpers inside of the script-tag like the following (in the view):
59
+
60
+ <script type="text/javascript" charset="utf-8">
61
+ <%= books_class_definition %>
62
+ Ext.onReady(function(){
63
+ <%= books_widget_instance %>
64
+ books.render("books");
65
+ })
66
+ </script>
67
+ <div id="books">the widget will be rendered in this div</div>
68
+
69
+ If your layout already calls yield :javascripts wrapped in the <script>-tag, you can have all javascript-code in one place on the page:
70
+
71
+ <% content_for :javascripts do %>
72
+ <%= books_class_definition %>
73
+ Ext.onReady(function(){
74
+ <%= books_widget_instance %>
75
+ books.render("books");
76
+ })
77
+ <% end %>
78
+ <p>... your page content here ...</p>
79
+ <div id="books">the widget will be rendered in this div</div>
80
+
81
+ == Dynamic loading of widgets
82
+ TODO: this part will be covered later
83
+
84
+ = Credentials
85
+ Testing done with the help of http://github.com/pluginaweek/plugin_test_helper
86
+
87
+ Copyright (c) 2009 Sergei Kozlov, released under the MIT license
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ Echoe.new("netzke-basepack") do |p|
5
5
  p.email = "sergei@writelesscode.com"
6
6
  p.summary = "Base Netzke widgets - grid, form, tree, and more"
7
7
  p.url = "http://writelesscode.com"
8
- p.runtime_dependencies = ["searchlogic >=1.6.2", "netzke-core >= 0.2.1"]
8
+ p.runtime_dependencies = ["searchlogic >=1.6.2", "netzke-core >= 0.2.2"]
9
9
  p.development_dependencies = []
10
10
  p.test_pattern = 'test/**/*_test.rb'
11
11
 
@@ -0,0 +1,7 @@
1
+ class NetzkeFormPanelGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.migration_template 'create_netzke_form_panel_fields.rb', "db/migrate", {:migration_file_name => "create_netzke_form_panel_fields"}
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ class CreateNetzkeFormPanelFields < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :netzke_form_panel_fields do |t|
4
+ t.string :name
5
+ t.string :label
6
+ t.boolean :read_only
7
+ t.integer :position
8
+ t.boolean :hidden
9
+ t.integer :width
10
+ t.integer :height
11
+ t.string :editor, :limit => 32
12
+
13
+ t.integer :layout_id
14
+
15
+ t.timestamps
16
+ end
17
+ end
18
+
19
+ def self.down
20
+ drop_table :netzke_form_panel_fields
21
+ end
22
+ end
@@ -49,4 +49,34 @@ Ext.netzke.filterMap = {
49
49
  checkbox:'Boolean',
50
50
  combo_box:'String',
51
51
  date:'Date'
52
- }
52
+ }
53
+
54
+ Ext.data.RecordArrayReader = Ext.extend(Ext.data.JsonReader, {
55
+ /**
56
+ * Create a data block containing Ext.data.Records from an Array.
57
+ * @param {Object} o An Array of row objects which represents the dataset.
58
+ * @return {Object} data A data block which is used by an Ext.data.Store object as
59
+ * a cache of Ext.data.Records.
60
+ */
61
+ readRecord : function(o){
62
+ var sid = this.meta ? this.meta.id : null;
63
+ var recordType = this.recordType, fields = recordType.prototype.fields;
64
+ var records = [];
65
+ var root = o;
66
+ // for(var i = 0; i < root.length; i++){
67
+ var n = root;
68
+ var values = {};
69
+ var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
70
+ for(var j = 0, jlen = fields.length; j < jlen; j++){
71
+ var f = fields.items[j];
72
+ var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
73
+ var v = n[k] !== undefined ? n[k] : f.defaultValue;
74
+ v = f.convert(v, n);
75
+ values[f.name] = v;
76
+ }
77
+ var record = new recordType(values, id);
78
+ record.json = n;
79
+ // }
80
+ return record;
81
+ }
82
+ });
@@ -0,0 +1,18 @@
1
+ class NetzkeFormPanelField < ActiveRecord::Base
2
+ belongs_to :layout, :class_name => "NetzkeLayout"
3
+
4
+ acts_as_list :scope => :layout
5
+
6
+ def self.create_layout_for_widget(widget)
7
+ layout = NetzkeLayout.create(:widget_name => widget.id_name, :items_class => self.name, :user_id => NetzkeLayout.user_id)
8
+
9
+ columns = Netzke::Column.default_fields_for_widget(widget)
10
+
11
+ for c in columns
12
+ config_for_create = c.merge(:layout_id => layout.id).stringify_values!
13
+ create(config_for_create)
14
+ end
15
+
16
+ layout
17
+ end
18
+ end
@@ -3,14 +3,8 @@ class NetzkeGridPanelColumn < ActiveRecord::Base
3
3
 
4
4
  acts_as_list :scope => :layout
5
5
 
6
- # old?
7
- # def self.create_with_defaults(column_config, klass)
8
- # create(klass.default_column_config(column_config).stringify_values!)
9
- # end
10
-
11
6
  def self.create_layout_for_widget(widget)
12
- layout = NetzkeLayout.create(:widget_name => widget.id_name, :items_class => self.name, :user_id => NetzkeLayout.user_id)
13
-
7
+ layout = NetzkeLayout.create_with_user(:widget_name => widget.id_name, :items_class => self.name)
14
8
  columns = Netzke::Column.default_columns_for_widget(widget)
15
9
 
16
10
  for c in columns
data/lib/netzke/ar_ext.rb CHANGED
@@ -49,7 +49,24 @@ module Netzke
49
49
  end
50
50
  end
51
51
 
52
+ def to_array(columns)
53
+ res = []
54
+ for c in columns
55
+ method = c.is_a?(Symbol) ? c : c[:name]
56
+ res << send(method)
57
+ end
58
+ res
59
+ end
60
+
52
61
  module ActiveRecordClassMethods
62
+ # next and previous to id records
63
+ def next(id)
64
+ find(:first, :conditions => ["#{primary_key} > ?", id])
65
+ end
66
+ def previous(id)
67
+ find(:first, :conditions => ["#{primary_key} < ?", id], :order => "#{primary_key} DESC")
68
+ end
69
+
53
70
  # Returns all unique values for a column, filtered by the query
54
71
  def choices_for(column, query = nil)
55
72
  if respond_to?("#{column}_choices", query)
@@ -107,18 +124,8 @@ module Netzke
107
124
  read_inheritable_attribute(:virtual_columns).keys.include?(column)
108
125
  end
109
126
 
110
- #
111
- # Used by Netzke::GridPanel
112
- #
113
-
114
- DEFAULT_COLUMN_WIDTH = 100
115
-
116
- # Returns default column config understood by Netzke::GridPanel
117
- # Argument: column name (as Symbol) or column config
118
- def default_column_config(config)
119
- config = config.dup
120
- # config = config.dup # to not touch the original config
121
- config = {:name => config} if config.is_a?(Symbol) # if got a column name
127
+ def default_dbfield_config(config, mode = :grid)
128
+ config = config.is_a?(Symbol) ? {:name => config} : config.dup
122
129
 
123
130
  # detect ActiveRecord column type (if the column is "real") or fall back to :virtual
124
131
  type = (columns_hash[config[:name].to_s] && columns_hash[config[:name].to_s].type) || :virtual
@@ -128,9 +135,12 @@ module Netzke
128
135
  :label => config[:label] || config[:name].to_s.gsub('__', '_').humanize,
129
136
  :read_only => config[:name] == :id, # make "id" column read-only by default
130
137
  :hidden => config[:name] == :id, # hide "id" column by default
131
- :width => DEFAULT_COLUMN_WIDTH,
138
+ :width => mode == :grid ? DEFAULT_COLUMN_WIDTH : DEFAULT_FIELD_WIDTH,
132
139
  :editor => ext_editor(type)
133
140
  }
141
+
142
+ # for forms fields also set up the height
143
+ res.merge!(:height => DEFAULT_FIELD_HEIGHT) if mode == :form
134
144
 
135
145
  # detect :assoc__method
136
146
  if config[:name].to_s.index('__')
@@ -157,13 +167,38 @@ module Netzke
157
167
  end
158
168
 
159
169
  #
160
- # Used by Netzke::Form
170
+ # Used by Netzke::GridPanel
171
+ #
172
+
173
+ DEFAULT_COLUMN_WIDTH = 100
174
+
175
+ # Returns default column config understood by Netzke::GridPanel
176
+ # Argument: column name (as Symbol) or column config
177
+ def default_column_config(config)
178
+ default_dbfield_config(config, :grid)
179
+ end
180
+
181
+ #
182
+ # Used by Netzke::FormPanel
161
183
  #
162
184
 
163
185
  DEFAULT_FIELD_WIDTH = 100
164
- DEFAULT_FIELD_HEIGHT = 50
186
+ DEFAULT_FIELD_HEIGHT = nil
165
187
  def default_field_config(config)
166
- # TODO
188
+ # default_dbfield_config(config, :form)
189
+ config = config.is_a?(Symbol) ? {:name => config} : config.dup
190
+
191
+ # detect ActiveRecord column type (if the column is "real") or fall back to :virtual
192
+ type = (columns_hash[config[:name].to_s] && columns_hash[config[:name].to_s].type) || :virtual
193
+
194
+ res = {
195
+ :name => config[:name].to_s || "unnamed",
196
+ :field_label => config[:field_label] || config[:name].to_s.gsub('__', '_').humanize,
197
+ :disabled => config[:name] == :id, # make "id" column disabled by default
198
+ # :hidden => config[:name] == :id, # hide "id" column by default
199
+ :xtype => XTYPE_MAP[type]
200
+ }
201
+
167
202
  end
168
203
 
169
204
  private
@@ -176,6 +211,14 @@ module Netzke
176
211
  :string => :text_field
177
212
  }
178
213
 
214
+ XTYPE_MAP = {
215
+ :integer => :numberfield,
216
+ :boolean => :textfield,
217
+ :date => :datefield,
218
+ :datetime => :datefield,
219
+ :string => :textfield
220
+ }
221
+
179
222
  def ext_editor(type)
180
223
  TYPE_EDITOR_MAP[type] || :text_field # fall back to :text_field
181
224
  end
@@ -20,7 +20,7 @@ module Netzke
20
20
  Ext.each(['center', 'west', 'east', 'south', 'north'], function(r){
21
21
  var configName = r+'Config';
22
22
  if (config[configName]){
23
- var regionConfig = config[configName].regionConfig || {};
23
+ var regionConfig = config.regions[r] || {};
24
24
  regionConfig.layout = 'fit';
25
25
  regionConfig.region = r;
26
26
  regionConfig.items = [new Ext.componentCache[config[configName].widgetClassName](config[configName])]
@@ -75,39 +75,28 @@ module Netzke
75
75
  config[:regions] || {}
76
76
  end
77
77
 
78
- # def items
79
- # res = []
80
- # config[:regions].each_pair do |k,v|
81
- # width = v.delete(:width)
82
- # height = v.delete(:height)
83
- # split = v[:split].nil? ? true : v.delete(:split) # split is by default true
84
- # region_config = {
85
- # :region => k,
86
- # :width => @pref["#{k}_width"] || width || 100,
87
- # :height => @pref["#{k}_height"] || height || 100,
88
- # :split => split,
89
- # :layout => v.delete(:layout) || 'fit',
90
- # :id => @id_name + "_#{k}_region"
91
- # }
92
- # region_widget_instance = "Netzke::#{v[:widget_class_name]}".constantize.new(v.merge(:name => "#{id_name}__#{k}"))
93
- # region_config.merge!(v)
94
- # region_config[:items] = ["new Ext.componentCache['#{v[:widget_class_name]}'](#{region_widget_instance.js_config.to_js})".l]
95
- # res << region_config
96
- # end
97
- # res
98
- # end
99
-
100
78
  def region_aggregatees
101
79
  aggregatees.reject{ |k,v| !REGIONS.include?(k) }
102
80
  end
103
81
 
104
- # def js_config
105
- # super.merge(:regional_config => items)
106
- # end
82
+ def js_config
83
+ regions = {}
84
+ REGIONS.each do |r|
85
+ if region_aggr = aggregatees[r]
86
+ regions.merge!(r => region_aggr[:region_config] || {})
87
+ height = persistent_config["#{r}_height"] ||= regions[r][:height] if regions[r][:height]
88
+ width = persistent_config["#{r}_width"] ||= regions[r][:width] if regions[r][:width]
89
+ regions[r].merge!(:height => height)
90
+ regions[r].merge!(:width => width)
91
+ end
92
+ end
93
+ super.merge(:regions => regions)
94
+ end
107
95
 
108
- def interface_resize_region(params)
109
- @pref["#{params[:region_name]}_width"] = params[:new_width].to_i if params[:new_width]
110
- @pref["#{params[:region_name]}_height"] = params[:new_height].to_i if params[:new_height]
96
+ def resize_region(params)
97
+ persistent_config["#{params[:region_name]}_width"] = params[:new_width].to_i if params[:new_width]
98
+ persistent_config["#{params[:region_name]}_height"] = params[:new_height].to_i if params[:new_height]
99
+ {}
111
100
  end
112
101
 
113
102
  protected