netzke-basepack 0.5.5.1 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/CHANGELOG.rdoc +16 -1
  2. data/README.rdoc +31 -56
  3. data/Rakefile +2 -2
  4. data/TODO.rdoc +3 -0
  5. data/javascripts/basepack.js +70 -30
  6. data/lib/app/models/netzke_auto_column.rb +1 -53
  7. data/lib/app/models/netzke_auto_field.rb +4 -0
  8. data/lib/app/models/netzke_auto_table.rb +61 -0
  9. data/lib/netzke-basepack.rb +13 -7
  10. data/lib/netzke/active_record/basepack.rb +28 -0
  11. data/lib/netzke/active_record/data_accessor.rb +2 -0
  12. data/lib/netzke/basic_app.rb +3 -4
  13. data/lib/netzke/{basic_app_extras → basic_app}/statusbar_ext.js +0 -0
  14. data/lib/netzke/data_accessor.rb +2 -0
  15. data/lib/netzke/ext.rb +1 -1
  16. data/lib/netzke/fields_configurator.rb +22 -6
  17. data/lib/netzke/form_panel.rb +20 -11
  18. data/lib/netzke/form_panel/form_panel_api.rb +78 -0
  19. data/lib/netzke/form_panel/form_panel_js.rb +143 -0
  20. data/lib/netzke/{form_panel_extras → form_panel}/javascripts/netzkefileupload.js +0 -0
  21. data/lib/netzke/{form_panel_extras → form_panel}/javascripts/xcheckbox.js +0 -0
  22. data/lib/netzke/grid_panel.rb +33 -24
  23. data/lib/netzke/grid_panel/grid_panel_api.rb +358 -0
  24. data/lib/netzke/grid_panel/grid_panel_js.rb +747 -0
  25. data/lib/netzke/{grid_panel_extras → grid_panel}/javascripts/filters.js +0 -0
  26. data/lib/netzke/{grid_panel_extras → grid_panel}/javascripts/rows-dd.js +0 -0
  27. data/lib/netzke/grid_panel/record_form_window.rb +44 -0
  28. data/lib/netzke/panel.rb +1 -3
  29. data/lib/netzke/property_editor.rb +2 -0
  30. data/lib/netzke/{property_editor_extras → property_editor}/helper_model.rb +2 -2
  31. data/lib/netzke/search_panel.rb +3 -3
  32. data/lib/netzke/window.rb +9 -3
  33. data/test/unit/grid_panel_test.rb +0 -2
  34. data/test/unit/helper_model_test.rb +2 -2
  35. metadata +16 -15
  36. data/lib/netzke/field_model.rb +0 -131
  37. data/lib/netzke/form_panel_api.rb +0 -78
  38. data/lib/netzke/form_panel_js.rb +0 -141
  39. data/lib/netzke/grid_panel_api.rb +0 -356
  40. data/lib/netzke/grid_panel_extras/record_form_window.rb +0 -46
  41. data/lib/netzke/grid_panel_js.rb +0 -725
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,18 @@
1
+ = v0.5.6
2
+ * Compatibility with latest netzke-core
3
+ * Compatibility with Ext JS v3.1
4
+ * Impr: Code reorganization
5
+ * Impr: Non-standard primary key support in GridPanel and FormPanel
6
+ * Impr: Search button in GridPanel indicates that records filtering is active
7
+ * Fix: by default, SearchPanel excludes boolean fields for now (until a 3-state checkbox is introduced)
8
+ * Impr: made it possible to create new AR records with assigned associations using double-underscore notation, e.g.: Clerk.new(:boss__last_name => "Aguraijuja ")
9
+ * Impr: specifying an item for Netzke::Window is now optional
10
+ * Fix: xtype field in FieldsConfigurator is now a combobox
11
+ * Fix: FieldsConfigurator was crashing when fired consequently for grid and form
12
+ * Depr: :data_class_name option is deprecated, use :model
13
+ * Impr: "gear" tool is now hidden on FieldsConfigurator
14
+ * Impr: Grid/FormPanel layouts are now not stored into the netzke_preferences table unless the defaults are modified (cleaner table)
15
+
1
16
  = v0.5.5.1 - 2009-11-09
2
17
  * Compatibility with latest netzke-core
3
18
 
@@ -5,7 +20,7 @@
5
20
  * Compatibility with latest netzke-core
6
21
  * Regression: pressing "enter" was not submitting the form (FormPanel)
7
22
  * Regression: "Restore defaults" button was not working in FieldsConfigurator and PropertyEditor
8
- * Fix: excluding columns in FieldConfigurator was causing inconsistent column behavior (move/hide/resize)
23
+ * Fix: excluding columns in FieldsConfigurator was causing inconsistent column behavior (move/hide/resize)
9
24
  * Fix: resolving conflicts with Ext.form.FormPanel's <tt>submit</tt> and <tt>load</tt> methods
10
25
  * New: rudimentary FileUploadField support in FormPanel (it will do a normal, non-AJAX, form submit)
11
26
  * New: Netzke::Window widget, supports persistent moving/resizing.
data/README.rdoc CHANGED
@@ -1,20 +1,30 @@
1
1
  = netzke-basepack
2
2
  A pack of basic Rails/ExtJS widgets as a part of the Netzke framework. Live demo/tutorials on http://blog.writelesscode.com. Introduction to the Netzke framework and the Wiki: http://github.com/skozlov/netzke
3
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
4
  = Prerequisites
7
5
  1. Rails >= 2.2
8
- 2. Ext JS >= 3.0: its root by default must be accessible as RAILS_ROOT/public/extjs. You may symlink your Ext JS library here like this (from your app folder):
6
+ 2. ExtJS = 3.0.3. Its root by default must be accessible as RAILS_ROOT/public/extjs. You may symlink your Ext JS library here like this (from your app folder):
9
7
 
10
- cd public && ln -s ~/Developer/extjs/ext-3.0 extjs
8
+ cd public && ln -s ~/Developer/extjs/ext-3.0.3 extjs
11
9
 
12
- 3. acts_as_list plugin must be installed:
10
+ 3. acts_as_list plugin:
13
11
 
14
12
  ./script/plugin install git://github.com/rails/acts_as_list.git
15
13
 
14
+ 4. netzke-core gem or plugin. Gem:
15
+
16
+ gem install netzke-core
17
+
18
+ Plugin (for the "edge" stuff, recommended):
19
+
20
+ ./script/plugin install git://github.com/skozlov/netzke-core.git
21
+
16
22
  = Installation
17
- The gem is hosted on gemcutter. If you haven't yet enabled gemcutter, run the following:
23
+ For the "edge" stuff, install as plugin (recommended):
24
+
25
+ ./script/plugin install git://github.com/skozlov/netzke-basepack.git
26
+
27
+ Otherwise install as gem. The gem is hosted on gemcutter. If you haven't yet enabled gemcutter, run the following:
18
28
 
19
29
  sudo gem install gemcutter && gem tumble
20
30
 
@@ -22,74 +32,39 @@ Install the gem:
22
32
 
23
33
  gem install netzke-basepack
24
34
 
25
- Include it into environment.rb:
35
+ = Usage
36
+ If using as gem, include it into environment.rb:
26
37
 
27
38
  config.gem "netzke-basepack"
28
39
 
29
- Include mapping for Netzke controller providing *.js and *.css (in routes.rb):
40
+ Include mapping for Netzke controller providing Netzke javascripts and styles (in routes.rb):
30
41
 
31
42
  map.netzke
32
43
 
33
- = Usage
34
- First, run the generators to have the necessary migrations:
44
+ To be able to use persistent on-the-fly configuration of widgets, run netzke-core generators to have the necessary migrations:
35
45
 
36
46
  ./script/generate netzke_core
37
47
 
38
- Do the migrations:
48
+ ... then run the migrations:
39
49
 
40
50
  rake db:migrate
41
51
 
42
- The following example will provide you with a grid-based scaffold for ActiveRecord-model called Book. You may generate it like this:
43
-
44
- ./script/generate model Book title:string amount:integer
45
-
46
- (don't forget to re-run the migrations after it)
47
-
48
- In the controller declare the widget:
49
-
50
- class WelcomeController < ApplicationController
51
- netzke :books, :widget_class_name => 'GridPanel', :data_class_name => 'Book'
52
- end
53
-
54
- 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 (like BasicApp-derived, if you want a desktop-like, AJAX-driven web-app).
52
+ == Embedding widgets into Rails' view
53
+ To enable Netzke widgets in Rails' views, you need to add the following helper into your layout template, inside the "head" tag:
55
54
 
56
- == Using automatically created controller action
57
- 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's name.
55
+ <%= netzke_init %>
56
+
57
+ This will include both ExtJS-related files (JavaScript and styles), and Netzke-related files.
58
58
 
59
- == Embedding a widget into a view
60
- netzke-core plugin provides the following 2 helpers to put inside your head-tag (use it in your layout):
59
+ Now let's embed a widget into a view. The following example will provide you with a grid-based scaffold for ActiveRecord-model called Book. You may generate it like this:
61
60
 
62
- 1. netzke_js_include - to include extjs and netzke javascript files
63
- 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)
64
-
65
- Declaring a widget in the controller provides you with a couple of helpers that can be used in the view:
66
-
67
- 1. books_class_definition will contain the JavaScript code defining the code for the JS class.
68
- 2. books_widget_instance will declare a local JavaScript variable called 'book'.
69
- 3. books_widget_render will provide the JavaScript code that calls the "render" method on the variable declared by books_widget_instance; the widget will be rendered into a div with id "books-div".
61
+ ./script/generate model Book title:string amount:integer
70
62
 
71
- Use these helpers inside of the script-tag like the following (in the view):
72
-
73
- <script type="text/javascript" charset="utf-8">
74
- <%= books_class_definition %>
75
- Ext.onReady(function(){
76
- <%= books_widget_instance %>
77
- <%= books_widget_render %>
78
- })
79
- </script>
80
- <div id="books-div">the widget will be rendered in this div</div>
63
+ (don't forget to re-run the migrations after it)
81
64
 
82
- If your layout already calls yield :javascripts wrapped in the <script>-tag, you can have all javascript-code in one place on the page:
65
+ Now embed a widget into a view like this:
83
66
 
84
- <% content_for :javascripts do %>
85
- <%= books_class_definition %>
86
- Ext.onReady(function(){
87
- <%= books_widget_instance %>
88
- books.render("books");
89
- })
90
- <% end %>
91
- <p>... your page content here ...</p>
92
- <div id="books-div">the widget will be rendered in this div</div>
67
+ <%= netzke :books, :class_name => 'GridPanel', :model => 'Book' %>
93
68
 
94
69
  == Dynamic loading of widgets
95
70
  TODO: this part will be covered later
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  begin
2
2
  require 'jeweler'
3
3
  Jeweler::Tasks.new do |gemspec|
4
- gemspec.version = "0.5.5.1"
4
+ gemspec.version = "0.5.6"
5
5
  gemspec.name = "netzke-basepack"
6
6
  gemspec.summary = "Pre-built Rails + ExtJS widgets for your RIA"
7
7
  gemspec.description = "A set of full-featured extendible Netzke widgets (such as FormPanel, GridPanel, Window, BorderLayoutPanel, etc) which can be used as building block for your RIA"
@@ -9,7 +9,7 @@ begin
9
9
  gemspec.homepage = "http://github.com/skozlov/netzke-basepack"
10
10
  gemspec.rubyforge_project = "netzke-basepack"
11
11
  gemspec.authors = ["Sergei Kozlov"]
12
- gemspec.add_dependency("netzke-core", ">=0.4.5.2")
12
+ gemspec.add_dependency("netzke-core", ">=0.5.0")
13
13
  gemspec.add_dependency("searchlogic", ">=2.0.0")
14
14
  gemspec.add_dependency("will_paginate", ">=2.0.0")
15
15
  end
data/TODO.rdoc CHANGED
@@ -9,5 +9,8 @@
9
9
  == Optimizations
10
10
  * Check persistent_config-related queries (aren't they too many?)
11
11
 
12
+ == Code design
13
+ * Replace <tt>initial_late_aggregatees</tt> method with a set of methods for each aggregatee, so that more logic would be possible at the moment of on-demand aggregatee loading.
14
+
12
15
  == One day
13
16
  * Replace xcheckbox with checkbox in FormPanel
@@ -22,7 +22,7 @@ Ext.netzke.ComboBox = Ext.extend(Ext.form.ComboBox, {
22
22
  } else {
23
23
  var row = Ext.data.Record.create([{name:'id'}]);
24
24
  var store = new Ext.data.Store({
25
- proxy : new Ext.data.HttpProxy({url:this.parentId+"__get_combobox_options", jsonData:{column:this.name}}),
25
+ proxy : new Ext.data.HttpProxy({url: Ext.getCmp(this.parentId).buildApiUrl("get_combobox_options"), jsonData:{column:this.name}}),
26
26
  reader : new Ext.data.ArrayReader({root:'data', id:0}, row)
27
27
  });
28
28
 
@@ -794,35 +794,75 @@ Ext.grid.HeaderDropZone.prototype.onNodeDrop = function(n, dd, e, data){
794
794
  return true;
795
795
  }
796
796
  return false;
797
- }
798
-
799
- // Feedback Ghost
800
- Netzke.FeedbackGhost = function(){};
801
- Ext.apply(Netzke.FeedbackGhost.prototype, {
802
- showFeedback: function(msg){
803
- var createBox = function(s, l){
804
- return ['<div class="msg">',
805
- '<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',
806
- '<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc">', s, '</div></div></div>',
807
- '<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
808
- '</div>'].join('');
809
- }
797
+ };
810
798
 
811
- var showBox = function(msg, lvl){
812
- if (!lvl) {lvl = 'notice'};
813
- var msgCt = Ext.DomHelper.insertFirst(document.body, {'class':'netzke-feedback'}, true);
814
- var m = Ext.DomHelper.append(msgCt, {html:createBox(msg,lvl)}, true);
815
- m.slideIn('t').pause(2).ghost("b", {remove:true});
816
- }
799
+ // Temporary fix for Ext 3.1 resize problem:
800
+ Ext.override(Ext.Panel, {
801
+
802
+ // private
803
+ onResize : function(w, h, rw, rh){
804
+ if(Ext.isDefined(w) || Ext.isDefined(h)){
805
+ if(!this.collapsed){
806
+ // First, set the the Panel's body width.
807
+ // If we have auto-widthed it, get the resulting full offset width so we can size the Toolbars to match
808
+ // The Toolbars must not buffer this resize operation because we need to know their heights.
809
+
810
+ if(Ext.isNumber(w)){
811
+ this.body.setWidth(w = this.adjustBodyWidth(w - this.getFrameWidth()));
812
+ } else if (w == 'auto') {
813
+ w = this.body.setWidth('auto').dom.offsetWidth;
814
+ } else {
815
+ w = this.body.dom.offsetWidth;
816
+ }
817
817
 
818
- if (typeof msg != 'string') {
819
- var compoundMsg = "";
820
- Ext.each(msg, function(m){
821
- compoundMsg += m.msg + '<br>';
822
- });
823
- if (compoundMsg != "") showBox(compoundMsg, null); // the second parameter will be level
824
- } else {
825
- showBox(msg);
818
+ if(this.tbar){
819
+ this.tbar.setWidth(w);
820
+ if(this.topToolbar){
821
+ this.topToolbar.setSize(w);
822
+ }
823
+ }
824
+ if(this.bbar){
825
+ this.bbar.setWidth(w);
826
+ if(this.bottomToolbar){
827
+ this.bottomToolbar.setSize(w);
828
+ // The bbar does not move on resize without this.
829
+ if (Ext.isIE) {
830
+ this.bbar.setStyle('position', 'static');
831
+ this.bbar.setStyle('position', '');
832
+ }
833
+ }
834
+ }
835
+ if(this.footer){
836
+ this.footer.setWidth(w);
837
+ if(this.fbar){
838
+ this.fbar.setSize(Ext.isIE ? (w - this.footer.getFrameWidth('lr')) : 'auto');
839
+ }
840
+ }
841
+
842
+ // At this point, the Toolbars must be layed out for getFrameHeight to find a result.
843
+ if(Ext.isNumber(h)){
844
+ h = Math.max(0, this.adjustBodyHeight(h - this.getFrameHeight()));
845
+ this.body.setHeight(h);
846
+ }else if(h == 'auto'){
847
+ this.body.setHeight(h);
848
+ }
849
+
850
+ if(this.disabled && this.el._mask){
851
+ this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight());
852
+ }
853
+ }else{
854
+ this.queuedBodySize = {width: w, height: h};
855
+ if(!this.queuedExpand && this.allowQueuedExpand !== false){
856
+ this.queuedExpand = true;
857
+ this.on('expand', function(){
858
+ delete this.queuedExpand;
859
+ this.onResize(this.queuedBodySize.width, this.queuedBodySize.height);
860
+ }, this, {single:true});
861
+ }
862
+ }
863
+ this.onBodyResize(w, h);
864
+ }
865
+ this.syncShadow();
866
+ Ext.Panel.superclass.onResize.call(this, w, h, rw, rh);
826
867
  }
827
- }
828
- });
868
+ });
@@ -1,56 +1,4 @@
1
- require 'acts_as_list'
2
- class NetzkeAutoColumn < ActiveRecord::Base
3
-
1
+ class NetzkeAutoColumn < NetzkeAutoTable
4
2
  acts_as_list
5
3
  default_scope :order => "position"
6
-
7
- # Returns an array of column configuration hashes (without the "id" attribute)
8
- def self.all_columns
9
- self.all.map do |c|
10
- column_hash = c.attributes.reject{ |k,v| k == 'id' }
11
- column_hash.each_pair do |k,v|
12
- # try to detect JSON format
13
- begin
14
- normalized_value = v.is_a?(String) ? ActiveSupport::JSON.decode(v) : v
15
- rescue ActiveSupport::JSON::ParseError
16
- normalized_value = v
17
- end
18
- column_hash[k] = normalized_value
19
- end
20
- column_hash
21
- end
22
- end
23
-
24
- # Build the table with columns for this widget
25
- def self.rebuild_table
26
- connection.drop_table('netzke_auto_columns') if table_exists?
27
-
28
- normalized_config_columns = []
29
-
30
- @@widget.class.config_columns.each do |mc|
31
- column_hash = mc.is_a?(Symbol) ? {:name => mc} : mc
32
- column_hash[:type] ||= :string
33
- normalized_config_columns << column_hash
34
- end
35
-
36
- # create the table with the fields
37
- self.connection.create_table('netzke_auto_columns') do |t|
38
- normalized_config_columns.each do |mc|
39
- t.column mc[:name], mc[:type], :default => mc[:default]
40
- end
41
- t.column :position, :integer
42
- end
43
-
44
- # populate the table with data
45
- NetzkeAutoColumn.create @@widget.normalized_columns.map(&:deebeefy_values) rescue ActiveRecord::UnknownAttributeError
46
-
47
- end
48
-
49
- def self.widget=(widget)
50
- @@widget = widget
51
- if Netzke::Base.session["netzke_auto_column_last_widget"] != @@widget.global_id
52
- rebuild_table
53
- Netzke::Base.session["netzke_auto_column_last_widget"] = @@widget.global_id
54
- end
55
- end
56
4
  end
@@ -0,0 +1,4 @@
1
+ class NetzkeAutoField < NetzkeAutoTable
2
+ acts_as_list
3
+ default_scope :order => "position"
4
+ end
@@ -0,0 +1,61 @@
1
+ require 'acts_as_list'
2
+
3
+ class NetzkeAutoTable < ActiveRecord::Base
4
+
5
+ # Returns an array of column configuration hashes (without the "id" attribute)
6
+ def self.all_columns
7
+ self.all.map do |c|
8
+ column_hash = c.attributes.reject{ |k,v| k == 'id' }
9
+ column_hash.each_pair do |k,v|
10
+ # try to detect JSON format
11
+ begin
12
+ normalized_value = v.is_a?(String) ? ActiveSupport::JSON.decode(v) : v
13
+ rescue ActiveSupport::JSON::ParseError
14
+ normalized_value = v
15
+ end
16
+ column_hash[k] = normalized_value
17
+ end
18
+ column_hash
19
+ end
20
+ end
21
+
22
+ # Build the table with columns for this widget
23
+ def self.rebuild_table
24
+ connection.drop_table(table_name) if table_exists?
25
+
26
+ normalized_config_columns = []
27
+
28
+ widget = read_inheritable_attribute(:widget)
29
+
30
+ widget.class.config_columns.each do |mc|
31
+ column_hash = mc.is_a?(Symbol) ? {:name => mc} : mc
32
+ column_hash[:type] ||= :string
33
+ normalized_config_columns << column_hash
34
+ end
35
+
36
+ # create the table with the fields
37
+ self.connection.create_table(table_name) do |t|
38
+ normalized_config_columns.each do |mc|
39
+ t.column mc[:name], mc[:type], :default => mc[:default]
40
+ end
41
+ t.column :position, :integer
42
+ end
43
+
44
+ # populate the table with data
45
+ create widget.normalized_columns.map(&:deebeefy_values) # rescue ActiveRecord::UnknownAttributeError
46
+
47
+ end
48
+
49
+ def self.table_name
50
+ self.name.tableize
51
+ end
52
+
53
+ def self.widget=(widget)
54
+ write_inheritable_attribute(:widget, widget)
55
+ if Netzke::Base.session["#{table_name}_last_widget"] != widget.global_id
56
+ rebuild_table
57
+ Netzke::Base.session["#{table_name}_last_widget"] = widget.global_id
58
+ end
59
+ end
60
+
61
+ end
@@ -1,11 +1,18 @@
1
1
  # External dependencies
2
+ require 'active_support'
2
3
  require 'netzke-core'
3
- require 'searchlogic'
4
- require 'will_paginate'
5
4
 
6
- require 'netzke/active_record/basepack'
5
+ # ExtJS-related constants
7
6
  require 'netzke/ext'
8
7
 
8
+ # Make widget classes auto-loadable with help of ActiveSupport
9
+ path = File.dirname(__FILE__)
10
+ ActiveSupport::Dependencies.load_paths << path
11
+
12
+ # Make this plugin auto-reloadable for easier development
13
+ ActiveSupport::Dependencies.load_once_paths.delete(path)
14
+
15
+ # Make gem's models auto-loadable
9
16
  %w{ models }.each do |dir|
10
17
  path = File.join(File.dirname(__FILE__), 'app', dir)
11
18
  $LOAD_PATH << path
@@ -13,11 +20,10 @@ require 'netzke/ext'
13
20
  ActiveSupport::Dependencies.load_once_paths.delete(path)
14
21
  end
15
22
 
16
- # Make this plugin reloadable at app restart for easier development
17
- ActiveSupport::Dependencies.load_once_paths.delete(File.join(File.dirname(__FILE__)))
18
-
19
23
  # Include javascript & styles required by all basepack widgets.
20
24
  # These files will get loaded at the initial load of the framework (along with Ext and Netzke-core).
21
25
  Netzke::Base.config[:javascripts] << "#{File.dirname(__FILE__)}/../javascripts/basepack.js"
22
26
  Netzke::Base.config[:stylesheets] << "#{File.dirname(__FILE__)}/../stylesheets/basepack.css"
23
- Netzke::Base.config[:stylesheets] << Netzke::Base.config[:ext_location] + "/examples/form/file-upload.css"
27
+
28
+ # FIXME: doesn't belong here
29
+ Netzke::Base.config[:stylesheets] << Netzke::Base.config[:ext_location] + "/examples/ux/fileuploadfield/css/fileuploadfield.css" if Netzke::Base.config[:ext_location]