netzke-basepack 0.4.2 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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