netzke-basepack 0.4.2 → 0.5.1

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 (62) hide show
  1. data/.autotest +1 -0
  2. data/.gitignore +6 -0
  3. data/{CHANGELOG → CHANGELOG.rdoc} +26 -0
  4. data/README.rdoc +11 -11
  5. data/Rakefile +37 -11
  6. data/TODO.rdoc +8 -0
  7. data/VERSION +1 -0
  8. data/javascripts/basepack.js +71 -28
  9. data/lib/app/models/netzke_auto_column.rb +56 -0
  10. data/lib/netzke-basepack.rb +5 -3
  11. data/lib/netzke/accordion_panel.rb +69 -67
  12. data/lib/netzke/active_record/basepack.rb +104 -0
  13. data/lib/netzke/active_record/data_accessor.rb +33 -0
  14. data/lib/netzke/basic_app.rb +233 -124
  15. data/lib/netzke/border_layout_panel.rb +97 -98
  16. data/lib/netzke/configuration_panel.rb +24 -0
  17. data/lib/netzke/data_accessor.rb +71 -0
  18. data/lib/netzke/ext.rb +6 -0
  19. data/lib/netzke/field_model.rb +1 -1
  20. data/lib/netzke/fields_configurator.rb +62 -37
  21. data/lib/netzke/form_panel.rb +161 -51
  22. data/lib/netzke/form_panel_api.rb +74 -0
  23. data/lib/netzke/form_panel_js.rb +129 -0
  24. data/lib/netzke/grid_panel.rb +385 -80
  25. data/lib/netzke/grid_panel_api.rb +352 -0
  26. data/lib/netzke/grid_panel_extras/javascripts/rows-dd.js +280 -0
  27. data/lib/netzke/grid_panel_js.rb +721 -0
  28. data/lib/netzke/masquerade_selector.rb +53 -0
  29. data/lib/netzke/panel.rb +9 -0
  30. data/lib/netzke/plugins/configuration_tool.rb +121 -0
  31. data/lib/netzke/property_editor.rb +95 -7
  32. data/lib/netzke/property_editor_extras/helper_model.rb +55 -34
  33. data/lib/netzke/search_panel.rb +62 -0
  34. data/lib/netzke/tab_panel.rb +97 -37
  35. data/lib/netzke/table_editor.rb +49 -44
  36. data/lib/netzke/tree_panel.rb +15 -16
  37. data/lib/netzke/wrapper.rb +29 -5
  38. data/netzke-basepack.gemspec +151 -19
  39. data/stylesheets/basepack.css +5 -0
  40. data/test/app_root/app/models/book.rb +1 -1
  41. data/test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb +1 -1
  42. data/test/unit/accordion_panel_test.rb +1 -2
  43. data/test/unit/active_record_basepack_test.rb +54 -0
  44. data/test/unit/grid_panel_test.rb +8 -12
  45. data/test/unit/helper_model_test.rb +30 -0
  46. metadata +69 -78
  47. data/Manifest +0 -86
  48. data/TODO +0 -3
  49. data/lib/app/models/netzke_hash_record.rb +0 -180
  50. data/lib/app/models/netzke_layout_item.rb +0 -11
  51. data/lib/netzke/ar_ext.rb +0 -269
  52. data/lib/netzke/configuration_tool.rb +0 -80
  53. data/lib/netzke/container.rb +0 -77
  54. data/lib/netzke/db_fields.rb +0 -44
  55. data/lib/netzke/fields_configurator_old.rb +0 -62
  56. data/lib/netzke/form_panel_extras/interface.rb +0 -56
  57. data/lib/netzke/form_panel_extras/js_builder.rb +0 -134
  58. data/lib/netzke/grid_panel_extras/interface.rb +0 -206
  59. data/lib/netzke/grid_panel_extras/js_builder.rb +0 -352
  60. data/test/unit/ar_ext_test.rb +0 -53
  61. data/test/unit/netzke_hash_record_test.rb +0 -52
  62. data/test/unit/netzke_layout_item_test.rb +0 -28
data/.autotest ADDED
@@ -0,0 +1 @@
1
+ require 'autotest/redgreen'
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ .DS_Store
2
+ *.log
3
+ pkg
4
+ doc
5
+ Manifest
6
+ test/app_root/vendor/plugins/netzke-core
@@ -1,3 +1,29 @@
1
+ v0.5.1 - 2009-09-11
2
+ Fix: crash when FormPanel has no data_class_name specified.
3
+ New: DataAccessor widgets (Form/GridPanel) now let the underlying model know which widget (i.e. which instance) accesses its data. Can be useful in virtual attributes for generating widget-specific HTML.
4
+ Fix: DataAccessor widgets (Form/GridPanel) now don't crash when calculating default columns/fields for the underlying model that has polymorphic columns.
5
+ Fix: TabPanel was sending redundant "tabchange" event to server when initially instantiated.
6
+ Fix: column filters were making GridPanel crash when the column editor was set to "textarea".
7
+ Fix: dongling comma and "delete" object properties caused problems in IE and Safari.
8
+ Fix: a stand-alone TabPanel would not render the active item.
9
+ New: BasicApp: masquerading as "World". In this mode all the "touched" persistent preferences will be overwritten for all roles and users.
10
+ Impr: configuration panel's header now shows the underlying model's name for convenience.
11
+ Fix: MasqueradeSelector widget added.
12
+
13
+ v0.5.0
14
+ 2009-09-06
15
+ Major refactoring and code reorganization.
16
+ Compatibility with netzke-core v0.4.0.
17
+ New: GridPanel now supports adding/editing records in a form and extended configurable search.
18
+ New: GridPanel now can be loaded along with initial data (saves a request to the server).
19
+ New: context menu in GridPanel
20
+ New: "scopes" configuration option added to GridPanel to specify the searchlogic-compatible scope for the data.
21
+ New: "strong_default_attrs" config option added to GridPanel to specify the attributes that will be assigned to each record that is created or modified by the grid.
22
+ Usability: GridPanel's actions now get enabled/disabled according to the current selection.
23
+ Configuration panel for grids and forms now works more consistently.
24
+ New: some smart defaults for column/fields in Grid/FormPanel.
25
+ New: BasicApp supports masquerading and application-wide AJAX activity indicator.
26
+
1
27
  v0.4.2
2
28
  2009-05-07
3
29
  Fix: afterlayout event bind removed completely because of some tricky inconsistent behavior of Ext. BasicApp initializing code put directly into js_after_constructor.
data/README.rdoc CHANGED
@@ -5,7 +5,7 @@ Note that if you would like to modify this code or experiment with it, you may b
5
5
 
6
6
  = Prerequisites
7
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):
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
9
  cd public && ln -s ~/Developer/extjs/ext-2.2 extjs
10
10
 
11
11
  3. acts_as_list plugin must be installed:
@@ -13,10 +13,10 @@ Note that if you would like to modify this code or experiment with it, you may b
13
13
 
14
14
  = Installation
15
15
  Install the gem:
16
- gem install netzke-basepack
16
+ gem install skozlov-netzke-basepack
17
17
 
18
18
  Include it into environment.rb:
19
- config.gem "netzke-basepack"
19
+ config.gem "skozlov-netzke-basepack"
20
20
 
21
21
  Include mapping for Netzke controller providing *.js and *.css (in routes.rb):
22
22
  map.netzke
@@ -24,14 +24,13 @@ Include mapping for Netzke controller providing *.js and *.css (in routes.rb):
24
24
  = Usage
25
25
  First, run the generators to have the necessary migrations:
26
26
  ./script/generate netzke_core
27
- ./script/generate netzke_grid_panel
28
27
 
29
28
  Do the migrations:
30
29
  rake db:migrate
31
30
 
32
31
  The following example will provide you with a grid-based scaffold for ActiveRecord-model called Book. You may generate it like this:
33
32
  ./script/generate model Book title:string amount:integer
34
- (don't forget to run the migrations after it)
33
+ (don't forget to re-run the migrations after it)
35
34
 
36
35
  In the controller declare the widget:
37
36
 
@@ -39,10 +38,10 @@ In the controller declare the widget:
39
38
  netzke :books, :widget_class_name => 'GridPanel', :data_class_name => 'Book'
40
39
  end
41
40
 
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).
41
+ 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).
43
42
 
44
43
  == 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.
44
+ 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.
46
45
 
47
46
  == Embedding a widget into a view
48
47
  netzke-core plugin provides the following 2 helpers to put inside your head-tag (use it in your layout):
@@ -52,8 +51,9 @@ netzke-core plugin provides the following 2 helpers to put inside your head-tag
52
51
 
53
52
  Declaring a widget in the controller provides you with a couple of helpers that can be used in the view:
54
53
 
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.
54
+ 1. books_class_definition will contain the JavaScript code defining the code for the JS class.
55
+ 2. books_widget_instance will declare a local JavaScript variable called 'book'.
56
+ 3. books_widget_render will provide the JavaScript code that calls the "render" method on the variable declared by books_widget_instance.
57
57
 
58
58
  Use these helpers inside of the script-tag like the following (in the view):
59
59
 
@@ -61,7 +61,7 @@ Use these helpers inside of the script-tag like the following (in the view):
61
61
  <%= books_class_definition %>
62
62
  Ext.onReady(function(){
63
63
  <%= books_widget_instance %>
64
- books.render("books");
64
+ <%= books_widget_render %>
65
65
  })
66
66
  </script>
67
67
  <div id="books">the widget will be rendered in this div</div>
@@ -84,4 +84,4 @@ TODO: this part will be covered later
84
84
  = Credentials
85
85
  Testing done with the help of http://github.com/pluginaweek/plugin_test_helper
86
86
 
87
- Copyright (c) 2008-2009 Sergei Kozlov, released under the LGPL 3.0
87
+ Copyright (c) 2008-2009 Sergei Kozlov, released under the MIT license
data/Rakefile CHANGED
@@ -1,14 +1,40 @@
1
- require 'echoe'
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "netzke-basepack"
5
+ gemspec.summary = "Pre-built Netzke widgets for your RIA"
6
+ gemspec.description = "Pre-built Netzke widgets for your RIA"
7
+ gemspec.email = "sergei@playcode.nl"
8
+ gemspec.homepage = "http://github.com/skozlov/netzke-basepack"
9
+ gemspec.rubyforge_project = "netzke-basepack"
10
+ gemspec.authors = ["Sergei Kozlov"]
11
+ gemspec.add_dependency "netzke-core"
12
+ gemspec.add_dependency "searchlogic"
13
+ end
14
+ Jeweler::RubyforgeTasks.new do |rubyforge|
15
+ rubyforge.doc_task = "rdoc"
16
+ end
17
+ rescue LoadError
18
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
19
+ end
20
+
21
+ require 'rake/rdoctask'
22
+ Rake::RDocTask.new do |rdoc|
23
+ if File.exist?('VERSION')
24
+ version = File.read('VERSION')
25
+ else
26
+ version = ""
27
+ end
2
28
 
3
- Echoe.new("netzke-basepack") do |p|
4
- p.author = "Sergei Kozlov"
5
- p.email = "sergei@writelesscode.com"
6
- p.summary = "Base Netzke widgets - grid, form, tree, and more"
7
- p.url = "http://writelesscode.com"
8
- p.runtime_dependencies = ["searchlogic >=1.6.2", "netzke-core >= 0.3.1"]
9
- p.development_dependencies = []
10
- p.test_pattern = 'test/**/*_test.rb'
29
+ rdoc.rdoc_dir = 'rdoc'
30
+ rdoc.title = "netzke-basepack #{version}"
31
+ rdoc.rdoc_files.include('README*')
32
+ rdoc.rdoc_files.include('lib/**/*.rb')
33
+ end
11
34
 
12
- # fixing the problem with lib/*-* files being removed while doing manifest
13
- p.clean_pattern = ["pkg", "doc", 'build/*', '**/coverage', '**/*.o', '**/*.so', '**/*.a', '**/*.log', "{ext,lib}/*.{bundle,so,obj,pdb,lib,def,exp}", "ext/Makefile", "{ext,lib}/**/*.{bundle,so,obj,pdb,lib,def,exp}", "ext/**/Makefile", "pkg", "*.gem", ".config"]
35
+ require 'rake/testtask'
36
+ Rake::TestTask.new(:test) do |test|
37
+ test.libs << 'lib' << 'test'
38
+ test.pattern = 'test/**/*_test.rb'
39
+ test.verbose = true
14
40
  end
data/TODO.rdoc ADDED
@@ -0,0 +1,8 @@
1
+ == Priority
2
+ * Make column/fields configuration fool-proof
3
+ * Introduce three-state checkbox for SearchPanel
4
+ * Add icons to buttons to actions (toolbars/menus)
5
+
6
+ == One day
7
+ * Add status bar to BasicApp
8
+ * Replace xcheckbox with checkbox in FormPanel
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.1
@@ -8,24 +8,28 @@ Ext.reg('passfield', Ext.netzke.PassField);
8
8
 
9
9
  // Combobox that knows to talk to the server side (used in both grids and panels)
10
10
  Ext.netzke.ComboBox = Ext.extend(Ext.form.ComboBox, {
11
- mode : 'remote',
12
11
  displayField : 'id',
13
12
  valueField : 'id',
14
13
  triggerAction : 'all',
15
14
  typeAhead : true,
16
- selectOnFocus : true,
17
15
 
18
16
  initComponent : function(){
19
- var row = Ext.data.Record.create([{name:'id'}]);
20
- // console.info(this.parentWidget);
21
- var store = new Ext.data.Store({
22
- proxy : new Ext.data.HttpProxy({url:this.parentConfig.interface.getCbChoices, jsonData:{column:this.fieldConfig.name}}),
23
- reader : new Ext.data.ArrayReader({root:'data', id:0}, row)
24
- });
17
+ if (this.options) {
18
+ Ext.apply(this, {
19
+ store : this.options,
20
+ mode : "local"
21
+ });
22
+ } else {
23
+ var row = Ext.data.Record.create([{name:'id'}]);
24
+ var store = new Ext.data.Store({
25
+ proxy : new Ext.data.HttpProxy({url:this.parentId+"__get_combobox_options", jsonData:{column:this.name}}),
26
+ reader : new Ext.data.ArrayReader({root:'data', id:0}, row)
27
+ });
25
28
 
26
- Ext.apply(this, {
27
- store : store
28
- });
29
+ Ext.apply(this, {
30
+ store : store
31
+ });
32
+ }
29
33
 
30
34
  Ext.netzke.ComboBox.superclass.initComponent.apply(this, arguments);
31
35
 
@@ -38,38 +42,58 @@ Ext.netzke.ComboBox = Ext.extend(Ext.form.ComboBox, {
38
42
  });
39
43
  }
40
44
  });
45
+
41
46
  Ext.reg('combobox', Ext.netzke.ComboBox);
42
47
 
43
- // TODO: rethink
44
- Ext.netzke.renderer = function(renderer, c, config){
45
- res = null; // null-renderer means "no renderer"
48
+ /*
49
+ Accepts a string which either contains:
50
+ Ext.util.Format method (e.g. 'usMoney'),
51
+ or
52
+ JSON-encoded array, where the first element is Ext.util.Format method (e.g. 'ellipsis'),
53
+ and the rest of the elements - configuration parameters that should be passed to this method besids
54
+ the value to be rendered (e.g. '2');
55
+
56
+ Example of the latter: ["defaultValue", "MyDefaultValue"]
57
+ */
58
+ Ext.netzke.normalizedRenderer = function(config) {
59
+ res = null;
46
60
 
47
- if (renderer){
48
- switch (renderer) {
49
-
50
- // more renderers can be later added like this:
51
- case 'my_renderer':
52
- res = function(value){ return "My renderer: " + value };
53
- break
54
-
55
- // falls back to Ext.util.Format renderers
56
- default:
57
- res = Ext.util.Format[renderer] ? Ext.util.Format[renderer] : function(value){return "Unknown renderer"}
58
- break
61
+ if (config) {
62
+ try{
63
+ config = Ext.decode(config); // it's an array consisting of renderer's name *and* eventual options
64
+ } catch(e) {
65
+ // leave config as is - it's supposed to be the renderer's name
66
+ }
67
+
68
+ if (Ext.isArray(config)) {
69
+ res = function(v){
70
+ var formatMethod = config[0];
71
+ var valueAndOptions = config.slice(1);
72
+ valueAndOptions.unshift(v);
73
+ // call the Format function with the argument *and* configuration
74
+ return Ext.util.Format[formatMethod] ? Ext.util.Format[formatMethod].apply(this, valueAndOptions) : "Unknown renderer";
75
+ }
76
+ } else {
77
+ res = Ext.util.Format[config] ? Ext.util.Format[config] : function(v){return "Unknown renderer"}
59
78
  }
60
79
  }
80
+
81
+ return res;
82
+ };
61
83
 
62
- return res
84
+ Ext.util.Format.mask = function(v){
85
+ return "********";
63
86
  };
64
87
 
65
88
  // Mapping of editor field to grid filters
66
89
  Ext.netzke.filterMap = {
67
90
  numberfield:'Numeric',
68
91
  textfield:'String',
92
+ textarea:'String',
69
93
  xdatetime:'String',
70
94
  checkbox:'Boolean',
71
95
  combobox:'String',
72
- date:'Date'
96
+ datefield:'Date'
73
97
  };
74
98
 
75
99
  Ext.override(Ext.StatusBar, {
@@ -109,6 +133,24 @@ Ext.data.RecordArrayReader = Ext.extend(Ext.data.JsonReader, {
109
133
  }
110
134
  });
111
135
 
136
+ Ext.netzke.JsonField = Ext.extend(Ext.form.TextField, {
137
+ validator: function(value) {
138
+ try{
139
+ var d = Ext.decode(value);
140
+ return true;
141
+ } catch(e) {
142
+ return "Invalid JSON"
143
+ }
144
+ }
145
+
146
+ ,setValue: function(value) {
147
+ this.setRawValue(Ext.encode(value));
148
+ }
149
+
150
+ });
151
+
152
+ Ext.reg('jsonfield', Ext.netzke.JsonField);
153
+
112
154
  /**
113
155
  * @class Ext.ux.form.DateTime
114
156
  * @extends Ext.form.Field
@@ -742,3 +784,4 @@ Ext.ux.form.DateTime = Ext.extend(Ext.form.Field, {
742
784
  Ext.reg('xdatetime', Ext.ux.form.DateTime);
743
785
 
744
786
  // eof
787
+
@@ -0,0 +1,56 @@
1
+ require 'acts_as_list'
2
+ class NetzkeAutoColumn < ActiveRecord::Base
3
+
4
+ acts_as_list
5
+ 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)
46
+
47
+ end
48
+
49
+ def self.widget=(widget)
50
+ @@widget = widget
51
+ if Netzke::Base.session["netzke_auto_column_last_widget"] != @@widget.id_name
52
+ rebuild_table
53
+ Netzke::Base.session["netzke_auto_column_last_widget"] = @@widget.id_name
54
+ end
55
+ end
56
+ end
@@ -1,8 +1,10 @@
1
1
  # External dependencies
2
2
  require 'netzke-core'
3
3
  require 'searchlogic'
4
+ require 'will_paginate'
4
5
 
5
- require 'netzke/ar_ext'
6
+ require 'netzke/active_record/basepack'
7
+ require 'netzke/ext'
6
8
 
7
9
  %w{ models }.each do |dir|
8
10
  path = File.join(File.dirname(__FILE__), 'app', dir)
@@ -11,10 +13,10 @@ require 'netzke/ar_ext'
11
13
  ActiveSupport::Dependencies.load_once_paths.delete(path)
12
14
  end
13
15
 
14
- # Make this plugin reloadable for easier development
16
+ # Make this plugin reloadable at app restart for easier development
15
17
  ActiveSupport::Dependencies.load_once_paths.delete(File.join(File.dirname(__FILE__)))
16
18
 
17
19
  # Include javascript & styles required by all basepack widgets.
18
20
  # These files will get loaded at the initial load of the framework (along with Ext and Netzke-core).
19
21
  Netzke::Base.config[:javascripts] << "#{File.dirname(__FILE__)}/../javascripts/basepack.js"
20
- Netzke::Base.config[:stylesheets] << "#{File.dirname(__FILE__)}/../stylesheets/basepack.css"
22
+ Netzke::Base.config[:stylesheets] << "#{File.dirname(__FILE__)}/../stylesheets/basepack.css"
@@ -1,111 +1,113 @@
1
1
  module Netzke
2
- #
3
- # AccordionPanel
2
+ # == AccordionPanel
4
3
  #
5
- # Features:
4
+ # == Features:
6
5
  # * Dynamically loads widgets for the panels that get expanded for the first time
7
6
  # * Is loaded along with the active widget - saves a request to the server
8
7
  #
9
- # TODO:
8
+ # Future features:
10
9
  # * Stores the last active panel in persistent_config
11
- #
12
10
  class AccordionPanel < Base
13
- #
14
- # JS-class generation
15
- #
16
- module ClassMethods
17
-
18
- def js_default_config
19
- super.merge({
20
- :layout => 'accordion',
21
- :defaults => {:layout => 'fit'}, # Container's items will be of type Panel with layout 'fit' ("fit-panels")
22
- :listeners => {
23
- # every item gets an expand event set, which dynamically loads a widget into this item
24
- :add => {
25
- :fn => <<-JS.l
26
- function(self, comp){
27
- comp.on('expand', this.loadItemWidget, self)
28
- }
29
- JS
30
- }
31
- }
32
- })
33
- end
11
+
12
+ # JavaScript part
13
+ def self.js_extend_properties
14
+ {
15
+ :layout => 'accordion',
16
+ :defaults => {:layout => 'fit'},
17
+ :init_component => <<-END_OF_JAVASCRIPT.l,
18
+ function(){
19
+ Ext.netzke.cache.#{short_widget_class_name}.superclass.initComponent.call(this);
34
20
 
35
- def js_extend_properties
36
- {
37
- # loads widget into the panel if it wasn't loaded yet
38
- :load_item_widget => <<-JS.l,
39
- function(panel) {
40
- if (!panel.getWidget()) panel.loadWidget(this.id + "__" + panel.widget + "__get_widget");
41
- }
42
- JS
43
-
44
- :on_widget_load => <<-JS.l
45
- function(){
46
- // immediately instantiate the active panel
47
- var activePanel = this.findById(this.id + "_active");
21
+ // Set events
22
+ this.items.each(function(i){
23
+ // Set the expand event
24
+ i.on('expand', this.loadItemWidget, this);
48
25
 
49
- var activeItemConfig = this.initialConfig[this.initialConfig.expandedItem+"Config"];
50
- if (activeItemConfig) {
51
- activePanel.add(new Ext.netzke.cache[activeItemConfig.widgetClassName](activeItemConfig));
26
+ // If not collapsed, add the active aggregatee (item) into it
27
+ if (!i.collapsed) {
28
+ var preloadedItemConfig = this[i.widget.camelize(true) + "Config"];
29
+ i.add(new Ext.netzke.cache[preloadedItemConfig.widgetClassName](preloadedItemConfig));
30
+ i.doLayout(); // always needed after adding a component
52
31
  }
32
+ }, this);
33
+ }
34
+ END_OF_JAVASCRIPT
35
+
36
+ # Loads widget into the panel if it wasn't loaded yet
37
+ :load_item_widget => <<-END_OF_JAVASCRIPT.l,
38
+ function(panel) {
39
+ // if (!panel.getWidget()) panel.loadWidget(this.id + "__" + panel.widget + "__get_widget");
40
+ var preloadedItemConfig = this[panel.widget.camelize(true) + "Config"];
41
+
42
+ if (preloadedItemConfig){
43
+ // preloaded widget only needs to be instantiated, as its class and configuration have already been loaded
44
+ panel.add(new Ext.netzke.cache[preloadedItemConfig.widgetClassName](preloadedItemConfig));
45
+ panel.doLayout(); // always needed after adding a component
46
+ } else {
47
+ // load the widget from the server
48
+ this.loadAggregatee({id:panel.widget, container:panel.id});
53
49
  }
54
- JS
55
- }
56
- end
50
+
51
+ }
52
+ END_OF_JAVASCRIPT
53
+ }
57
54
  end
58
- extend ClassMethods
59
-
60
- # some configuration normalization
55
+
56
+ # Some normalization of config
61
57
  def initialize(*args)
62
58
  super
63
59
 
64
60
  seen_active = false
65
-
61
+
66
62
  config[:items].each_with_index do |item, i|
67
63
  # if some items are provided without names, give them generated names
68
64
  item[:name] ||= "item#{i}"
69
-
65
+
70
66
  # remove duplucated :active configuration
71
67
  if item[:active]
72
68
  item[:active] = nil if seen_active
73
- seen_active = true
69
+ seen_active ||= true
74
70
  end
75
71
  end
76
72
  end
73
+
74
+ # Returns items configs
75
+ def items
76
+ @items ||= config[:items]
77
+ end
77
78
 
79
+ # Provides configs for fit panels (which will effectively be accordion panels)
78
80
  def js_config
79
- expanded_widget_config = config[:items].detect{|i| i[:active]}
80
81
  super.merge({
81
- :items => fit_panels,
82
- :expanded_item => expanded_widget_config && expanded_widget_config[:name]
82
+ # these "items" are not related to the "items" of the config, rather these are the items required by the the accordion panel
83
+ :items => fit_panels
83
84
  })
84
85
  end
85
86
 
86
- # the items are late aggregatees, besides the ones that are marked "active"
87
- def initial_aggregatees
88
- res = {}
89
- config[:items].each_with_index do |item, i|
90
- item[:late_aggregation] = !item[:active]
91
- res.merge!(item[:name].to_sym => item)
92
- end
93
- res
94
- end
95
-
96
- # fit-panels - panels of layout 'fit' that will contain the widgets (items)
87
+ # "Fit-panels" - panels of layout 'fit' (effectively the accordion panels) that will contain the widgets ("items")
97
88
  def fit_panels
98
89
  res = []
99
90
  config[:items].each_with_index do |item, i|
100
91
  res << {
101
- :id => item[:active] && id_name + '_active', # to mark the fit-panel which will contain the active widget
102
- :title => item[:title] || (item[:name] && item[:name].humanize),
92
+ # :id => item[:active] && id_name + '_active', # to mark the fit-panel which will contain the active widget
93
+ :title => item[:title] || (item[:name] && item[:name].to_s.humanize),
103
94
  :widget => item[:name], # to know which fit panel will load which widget
104
95
  :collapsed => !(item[:active] || false)
105
96
  }
106
97
  end
107
98
  res
108
99
  end
100
+
101
+ # All items become *late* aggregatees, besides the ones that are marked "active"
102
+ def initial_aggregatees
103
+ res = {}
104
+ config[:items].each_with_index do |item, i|
105
+ item[:late_aggregation] = !item[:active]
106
+ res.merge!(item[:name].to_sym => item)
107
+ end
108
+ res
109
+ end
110
+
109
111
 
110
112
  end
111
113
  end