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.
- data/.autotest +1 -0
- data/.gitignore +6 -0
- data/{CHANGELOG → CHANGELOG.rdoc} +26 -0
- data/README.rdoc +11 -11
- data/Rakefile +37 -11
- data/TODO.rdoc +8 -0
- data/VERSION +1 -0
- data/javascripts/basepack.js +71 -28
- data/lib/app/models/netzke_auto_column.rb +56 -0
- data/lib/netzke-basepack.rb +5 -3
- data/lib/netzke/accordion_panel.rb +69 -67
- data/lib/netzke/active_record/basepack.rb +104 -0
- data/lib/netzke/active_record/data_accessor.rb +33 -0
- data/lib/netzke/basic_app.rb +233 -124
- data/lib/netzke/border_layout_panel.rb +97 -98
- data/lib/netzke/configuration_panel.rb +24 -0
- data/lib/netzke/data_accessor.rb +71 -0
- data/lib/netzke/ext.rb +6 -0
- data/lib/netzke/field_model.rb +1 -1
- data/lib/netzke/fields_configurator.rb +62 -37
- data/lib/netzke/form_panel.rb +161 -51
- data/lib/netzke/form_panel_api.rb +74 -0
- data/lib/netzke/form_panel_js.rb +129 -0
- data/lib/netzke/grid_panel.rb +385 -80
- data/lib/netzke/grid_panel_api.rb +352 -0
- data/lib/netzke/grid_panel_extras/javascripts/rows-dd.js +280 -0
- data/lib/netzke/grid_panel_js.rb +721 -0
- data/lib/netzke/masquerade_selector.rb +53 -0
- data/lib/netzke/panel.rb +9 -0
- data/lib/netzke/plugins/configuration_tool.rb +121 -0
- data/lib/netzke/property_editor.rb +95 -7
- data/lib/netzke/property_editor_extras/helper_model.rb +55 -34
- data/lib/netzke/search_panel.rb +62 -0
- data/lib/netzke/tab_panel.rb +97 -37
- data/lib/netzke/table_editor.rb +49 -44
- data/lib/netzke/tree_panel.rb +15 -16
- data/lib/netzke/wrapper.rb +29 -5
- data/netzke-basepack.gemspec +151 -19
- data/stylesheets/basepack.css +5 -0
- data/test/app_root/app/models/book.rb +1 -1
- data/test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb +1 -1
- data/test/unit/accordion_panel_test.rb +1 -2
- data/test/unit/active_record_basepack_test.rb +54 -0
- data/test/unit/grid_panel_test.rb +8 -12
- data/test/unit/helper_model_test.rb +30 -0
- metadata +69 -78
- data/Manifest +0 -86
- data/TODO +0 -3
- data/lib/app/models/netzke_hash_record.rb +0 -180
- data/lib/app/models/netzke_layout_item.rb +0 -11
- data/lib/netzke/ar_ext.rb +0 -269
- data/lib/netzke/configuration_tool.rb +0 -80
- data/lib/netzke/container.rb +0 -77
- data/lib/netzke/db_fields.rb +0 -44
- data/lib/netzke/fields_configurator_old.rb +0 -62
- data/lib/netzke/form_panel_extras/interface.rb +0 -56
- data/lib/netzke/form_panel_extras/js_builder.rb +0 -134
- data/lib/netzke/grid_panel_extras/interface.rb +0 -206
- data/lib/netzke/grid_panel_extras/js_builder.rb +0 -352
- data/test/unit/ar_ext_test.rb +0 -53
- data/test/unit/netzke_hash_record_test.rb +0 -52
- data/test/unit/netzke_layout_item_test.rb +0 -28
data/.autotest
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'autotest/redgreen'
|
data/.gitignore
ADDED
@@ -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 (
|
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
|
56
|
-
2. books_widget_instance will declare a local
|
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
|
-
|
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
|
87
|
+
Copyright (c) 2008-2009 Sergei Kozlov, released under the MIT license
|
data/Rakefile
CHANGED
@@ -1,14 +1,40 @@
|
|
1
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
13
|
-
|
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
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.5.1
|
data/javascripts/basepack.js
CHANGED
@@ -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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
27
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
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 (
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/netzke-basepack.rb
CHANGED
@@ -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/
|
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
|
-
#
|
8
|
+
# Future features:
|
10
9
|
# * Stores the last active panel in persistent_config
|
11
|
-
#
|
12
10
|
class AccordionPanel < Base
|
13
|
-
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
50
|
-
if (
|
51
|
-
|
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
|
-
|
55
|
-
|
56
|
-
|
50
|
+
|
51
|
+
}
|
52
|
+
END_OF_JAVASCRIPT
|
53
|
+
}
|
57
54
|
end
|
58
|
-
|
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
|
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
|
-
|
82
|
-
:
|
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
|
-
#
|
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
|