skozlov-netzke-core 0.1.0.2 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +108 -0
- data/LICENSE +2 -19
- data/Manifest +50 -0
- data/README.rdoc +12 -0
- data/Rakefile +2 -3
- data/TODO +2 -0
- data/autotest/discover.rb +3 -0
- data/generators/netzke_core/netzke_core_generator.rb +6 -6
- data/generators/netzke_core/templates/create_netzke_preferences.rb +2 -2
- data/javascripts/core.js +474 -111
- data/lib/app/controllers/netzke_controller.rb +76 -0
- data/lib/app/models/netzke_preference.rb +128 -39
- data/lib/netzke-core.rb +23 -9
- data/lib/netzke/action_view_ext.rb +26 -0
- data/lib/netzke/base.rb +440 -102
- data/lib/netzke/base_js.rb +258 -0
- data/lib/netzke/controller_extensions.rb +80 -29
- data/lib/netzke/core_ext.rb +72 -21
- data/lib/netzke/feedback_ghost.rb +43 -0
- data/lib/netzke/routing.rb +9 -0
- data/netzke-core.gemspec +10 -11
- data/stylesheets/core.css +12 -0
- data/test/app_root/app/controllers/{application.rb → application_controller.rb} +0 -0
- data/test/app_root/app/models/role.rb +3 -0
- data/test/app_root/app/models/user.rb +3 -0
- data/test/app_root/config/boot.rb +2 -1
- data/test/app_root/config/database.yml +10 -0
- data/test/app_root/config/environment.rb +1 -0
- data/test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb +18 -0
- data/test/app_root/db/migrate/20090423214303_create_roles.rb +11 -0
- data/test/app_root/db/migrate/20090423222114_create_users.rb +12 -0
- data/test/app_root/lib/console_with_fixtures.rb +4 -0
- data/test/app_root/script/console +1 -0
- data/test/fixtures/roles.yml +7 -0
- data/test/fixtures/users.yml +9 -0
- data/test/test_helper.rb +3 -2
- data/test/unit/core_ext_test.rb +66 -0
- data/test/unit/netzke_core_test.rb +167 -0
- data/test/unit/netzke_preference_test.rb +103 -0
- metadata +45 -30
- data/README.mdown +0 -11
- data/generators/netzke_core/templates/create_netzke_layouts.rb +0 -14
- data/generators/netzke_core/templates/netzke.html.erb +0 -10
- data/lib/app/models/netzke_layout.rb +0 -75
- data/lib/netzke/js_class_builder.rb +0 -114
- data/lib/vendor/facets/hash/recursive_merge.rb +0 -28
- data/test/core_ext_test.rb +0 -35
- data/test/netzke_core_test.rb +0 -136
data/CHANGELOG
CHANGED
@@ -1,3 +1,111 @@
|
|
1
|
+
v0.4.1
|
2
|
+
2009-09-06
|
3
|
+
Version bumb to force github rebuild the gem (Manifest is now included)
|
4
|
+
|
5
|
+
v0.4.0
|
6
|
+
2009-09-05
|
7
|
+
Major refactoring.
|
8
|
+
|
9
|
+
v0.3.2
|
10
|
+
2009-06-05
|
11
|
+
Netzke doesn't overwrite session[:user] anymore to not cause authentication-related problems.
|
12
|
+
|
13
|
+
v0.3.1
|
14
|
+
2009-05-07
|
15
|
+
Fix: persistent_config_manager can now be set to nil, and it will work fine
|
16
|
+
|
17
|
+
v0.3.0
|
18
|
+
2009-05-07
|
19
|
+
Refactor: got rid of NetzkeLayout model, now all layouts are stored in netzke_preferences
|
20
|
+
New: persistent_config now has a method for_widget that accepts a block
|
21
|
+
autotest compatibility
|
22
|
+
New: String#to_b converts a string to true/false
|
23
|
+
New: Netzke::Base.session introduced for session data
|
24
|
+
New: weak_children_config and strong_children_config can now be declared by a widget, which specifies weak and strong configuration that every child of this widget will receive (e.g. display/hide configuration tool)
|
25
|
+
Fix: (degradation) flash message is now shown again in case of erroneous attempt to load a widget
|
26
|
+
New: widgets now can check session[:netzke_just_logged_in] and session[:netzke_just_logged_out] automatically set by Netzke after login/logout
|
27
|
+
|
28
|
+
v0.2.11
|
29
|
+
Introduction of getOwnerWidget()-method to Ext.Component. It provides the Netzke widget this Component belongs to.
|
30
|
+
|
31
|
+
v0.2.10
|
32
|
+
Removed dependency on 'json' gem.
|
33
|
+
Rails v2.3.2 compatibility.
|
34
|
+
|
35
|
+
v0.2.9
|
36
|
+
Actions, toolbars and tools reworked for easier configuration.
|
37
|
+
Menus introduced (based on actions).
|
38
|
+
Significant code clean-up.
|
39
|
+
Bug fix (nasty one): Ext.widgetMixIn was getting messed up along with dynamic widget loading.
|
40
|
+
Must work in IE now.
|
41
|
+
|
42
|
+
v0.2.8
|
43
|
+
Support for extra javascripts and stylesheets per widget.
|
44
|
+
|
45
|
+
v0.2.7
|
46
|
+
QuickTips get initialized now, as otherwise Ext 2.2.1 doesn't properly destroy() BoxComponents for me.
|
47
|
+
|
48
|
+
v0.2.6
|
49
|
+
FeedackGhost is now capable of displaying multiple flash messages.
|
50
|
+
Dependencies slightly refactored.
|
51
|
+
An informative exception added to Base#aggregatee_instance.
|
52
|
+
JS-level inheritance enabled.
|
53
|
+
Work-around for the problem with Ext 2.2.1 in loadWidget.
|
54
|
+
Events "<action_id>click" added to the widgets along with the actions.
|
55
|
+
aggregatee_missing method added to Netzke::Base - called when a non-existing aggregate of a widget is tried to be invoked
|
56
|
+
Code readability improvements.
|
57
|
+
|
58
|
+
v0.2.5
|
59
|
+
Minor code restructuring.
|
60
|
+
|
61
|
+
v0.2.4
|
62
|
+
Some minor improvements.
|
63
|
+
|
64
|
+
v0.2.3
|
65
|
+
FeedbackGhost will show the feedback on the top of the screen independent of the page scrolling.
|
66
|
+
Ext.Panel#loadWidget will accept null as url to delete the currently loaded widget
|
67
|
+
Bug fix: persistent_config works again
|
68
|
+
|
69
|
+
v0.2.2
|
70
|
+
js_ext_config instance method added for overwriting
|
71
|
+
Multiuser support
|
72
|
+
Using Rails.logger for logging
|
73
|
+
"config"-class method for every class inheriting Netzke::Base - for class-level configurations
|
74
|
+
|
75
|
+
v0.2.1
|
76
|
+
Fixed the path to ext-base-min.js for production mode.
|
77
|
+
Also works in Safari now.
|
78
|
+
|
79
|
+
v0.2.0
|
80
|
+
* Some re-factoring and redesign. Now simple compound widgets can be created on the fly in the controller
|
81
|
+
* Added ext_widget[:quiet] configuration option to suppress widget's feedback
|
82
|
+
* Support for extra CSS sources, similar to JS
|
83
|
+
* NETZKE_BOOT_CONFIG introduced to specify which Netzke functionality should be disabled to reduce the size of /netzke/netzke.[js|css]
|
84
|
+
* FeedbackGhost widget added - invisible widget providing feedback to the user
|
85
|
+
* netzke_widget controller class-method renamed into netzke
|
86
|
+
* JS-comments now get stripped also from the extra files that get included in the netzke-* gems.
|
87
|
+
* Permissions joined js_config
|
88
|
+
* Bug fixes
|
89
|
+
|
90
|
+
v0.1.4
|
91
|
+
Helpers added to facilitate ExtJS/netzke.js inclusion
|
92
|
+
The route defined for netzke_controller
|
93
|
+
netzke.html.erb-layout is not needed anymore, so not produced by the generator
|
94
|
+
Now compliant with Rails' forgery protection
|
95
|
+
|
96
|
+
v0.1.3
|
97
|
+
Generators fixed
|
98
|
+
|
99
|
+
v0.1.2
|
100
|
+
Fixed the bug with <widget>_class_definition returning empty string on sequential loading.
|
101
|
+
|
102
|
+
v0.1.1.1
|
103
|
+
Meta: moving from GitHub to RubyForge
|
104
|
+
|
105
|
+
v0.1.1
|
106
|
+
Inter-widget dependencies code reworked
|
107
|
+
JS-class code generation code slightly reworked
|
108
|
+
|
1
109
|
v0.1.0.2
|
2
110
|
Meta: fix outdated Manifest
|
3
111
|
|
data/LICENSE
CHANGED
@@ -1,20 +1,3 @@
|
|
1
|
-
Copyright (c) 2008 Sergei Kozlov
|
1
|
+
Copyright (c) 2008-2009 Sergei Kozlov
|
2
2
|
|
3
|
-
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
3
|
+
GNU GPL license v3
|
data/Manifest
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
CHANGELOG
|
2
|
+
LICENSE
|
3
|
+
Manifest
|
4
|
+
README.rdoc
|
5
|
+
Rakefile
|
6
|
+
TODO
|
7
|
+
autotest/discover.rb
|
8
|
+
generators/netzke_core/USAGE
|
9
|
+
generators/netzke_core/netzke_core_generator.rb
|
10
|
+
generators/netzke_core/templates/create_netzke_preferences.rb
|
11
|
+
init.rb
|
12
|
+
install.rb
|
13
|
+
javascripts/core.js
|
14
|
+
lib/app/controllers/netzke_controller.rb
|
15
|
+
lib/app/models/netzke_preference.rb
|
16
|
+
lib/netzke-core.rb
|
17
|
+
lib/netzke/action_view_ext.rb
|
18
|
+
lib/netzke/base.rb
|
19
|
+
lib/netzke/base_js.rb
|
20
|
+
lib/netzke/controller_extensions.rb
|
21
|
+
lib/netzke/core_ext.rb
|
22
|
+
lib/netzke/feedback_ghost.rb
|
23
|
+
lib/netzke/routing.rb
|
24
|
+
netzke-core.gemspec
|
25
|
+
stylesheets/core.css
|
26
|
+
tasks/netzke_core_tasks.rake
|
27
|
+
test/app_root/app/controllers/application_controller.rb
|
28
|
+
test/app_root/app/models/role.rb
|
29
|
+
test/app_root/app/models/user.rb
|
30
|
+
test/app_root/config/boot.rb
|
31
|
+
test/app_root/config/database.yml
|
32
|
+
test/app_root/config/environment.rb
|
33
|
+
test/app_root/config/environments/in_memory.rb
|
34
|
+
test/app_root/config/environments/mysql.rb
|
35
|
+
test/app_root/config/environments/postgresql.rb
|
36
|
+
test/app_root/config/environments/sqlite.rb
|
37
|
+
test/app_root/config/environments/sqlite3.rb
|
38
|
+
test/app_root/config/routes.rb
|
39
|
+
test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb
|
40
|
+
test/app_root/db/migrate/20090423214303_create_roles.rb
|
41
|
+
test/app_root/db/migrate/20090423222114_create_users.rb
|
42
|
+
test/app_root/lib/console_with_fixtures.rb
|
43
|
+
test/app_root/script/console
|
44
|
+
test/fixtures/roles.yml
|
45
|
+
test/fixtures/users.yml
|
46
|
+
test/test_helper.rb
|
47
|
+
test/unit/core_ext_test.rb
|
48
|
+
test/unit/netzke_core_test.rb
|
49
|
+
test/unit/netzke_preference_test.rb
|
50
|
+
uninstall.rb
|
data/README.rdoc
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
= netzke-core
|
2
|
+
Create Ext JS + Rails reusable components (widgets) with minimum effort.
|
3
|
+
|
4
|
+
Introduction to Netzke framework: http://github.com/skozlov/netzke/tree/master
|
5
|
+
|
6
|
+
Tutorials: http://blog.writelesscode.com
|
7
|
+
|
8
|
+
Live-demo: http://netzke-demo.writelesscode.com
|
9
|
+
|
10
|
+
Also see netzke-basepack (pre-programmed widgets) project: http://github.com/skozlov/netzke-basepack/tree/master
|
11
|
+
|
12
|
+
Copyright (c) 2009 Sergei Kozlov, released under the MIT license
|
data/Rakefile
CHANGED
@@ -2,10 +2,9 @@ require 'echoe'
|
|
2
2
|
|
3
3
|
Echoe.new("netzke-core") do |p|
|
4
4
|
p.author = "Sergei Kozlov"
|
5
|
-
p.email = "sergei@
|
5
|
+
p.email = "sergei@playcode.nl"
|
6
6
|
p.summary = "Build ExtJS/Rails widgets with minimum effort"
|
7
|
-
p.url = "http://
|
8
|
-
# p.runtime_dependencies = ["searchlogic >=1.6.2"]
|
7
|
+
p.url = "http://playcode.nl"
|
9
8
|
p.development_dependencies = []
|
10
9
|
p.test_pattern = 'test/**/*_test.rb'
|
11
10
|
p.retain_gemspec = true
|
data/TODO
ADDED
@@ -2,12 +2,12 @@
|
|
2
2
|
class NetzkeCoreGenerator < Rails::Generator::Base
|
3
3
|
def manifest
|
4
4
|
record do |m|
|
5
|
-
|
6
|
-
#
|
7
|
-
|
8
|
-
m.
|
9
|
-
#
|
10
|
-
m.
|
5
|
+
# FIXME: how do we avoid getting the same migration timestamps?
|
6
|
+
# Work-around
|
7
|
+
time = Time.now.utc.strftime("%Y%m%d%H%M%S")
|
8
|
+
m.directory 'db/migrate'
|
9
|
+
# m.file 'create_netzke_layouts.rb', "db/migrate/#{time}_create_netzke_layouts.rb"
|
10
|
+
m.file 'create_netzke_preferences.rb', "db/migrate/#{time.to_i+1}_create_netzke_preferences.rb"
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -3,10 +3,10 @@ class CreateNetzkePreferences < ActiveRecord::Migration
|
|
3
3
|
create_table :netzke_preferences do |t|
|
4
4
|
t.string :name
|
5
5
|
t.string :pref_type
|
6
|
-
t.string :value
|
6
|
+
t.string :value, :limit => 65535
|
7
7
|
t.integer :user_id
|
8
8
|
t.integer :role_id
|
9
|
-
t.string :
|
9
|
+
t.string :widget_name
|
10
10
|
|
11
11
|
t.timestamps
|
12
12
|
end
|
data/javascripts/core.js
CHANGED
@@ -1,124 +1,487 @@
|
|
1
|
+
/*
|
2
|
+
This file gets loaded along with the rest of Ext library at the initial load
|
3
|
+
*/
|
4
|
+
|
1
5
|
Ext.BLANK_IMAGE_URL = "/extjs/resources/images/default/s.gif";
|
2
|
-
Ext.
|
6
|
+
Ext.namespace('Ext.netzke'); // namespace for extensions that depend on Ext
|
7
|
+
Ext.namespace('Netzke'); // namespace for extensions that do not depend on Ext
|
8
|
+
Ext.netzke.cache = {};
|
9
|
+
|
10
|
+
Ext.QuickTips.init(); // seems obligatory in Ext v2.2.1, otherwise Ext.Component#destroy() stops working properly
|
11
|
+
|
12
|
+
// To comply with Rails' forgery protection
|
13
|
+
Ext.Ajax.extraParams = {
|
14
|
+
authenticity_token : Ext.authenticityToken
|
15
|
+
};
|
16
|
+
|
17
|
+
// Type detection functions
|
18
|
+
Netzke.isObject = function(o) {
|
19
|
+
return (o != null && typeof o == "object" && o.constructor.toString() == Object.toString());
|
20
|
+
}
|
21
|
+
|
22
|
+
// Some Ruby-ish String extensions
|
23
|
+
// from http://code.google.com/p/inflection-js/
|
24
|
+
String.prototype.camelize=function(lowFirstLetter)
|
25
|
+
{
|
26
|
+
var str=this.toLowerCase();
|
27
|
+
var str_path=str.split('/');
|
28
|
+
for(var i=0;i<str_path.length;i++)
|
29
|
+
{
|
30
|
+
var str_arr=str_path[i].split('_');
|
31
|
+
var initX=((lowFirstLetter&&i+1==str_path.length)?(1):(0));
|
32
|
+
for(var x=initX;x<str_arr.length;x++)
|
33
|
+
str_arr[x]=str_arr[x].charAt(0).toUpperCase()+str_arr[x].substring(1);
|
34
|
+
str_path[i]=str_arr.join('');
|
35
|
+
}
|
36
|
+
str=str_path.join('::');
|
37
|
+
return str;
|
38
|
+
};
|
3
39
|
|
4
|
-
|
40
|
+
String.prototype.capitalize=function()
|
41
|
+
{
|
42
|
+
var str=this.toLowerCase();
|
43
|
+
str=str.substring(0,1).toUpperCase()+str.substring(1);
|
44
|
+
return str;
|
45
|
+
};
|
5
46
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
47
|
+
String.prototype.humanize=function(lowFirstLetter)
|
48
|
+
{
|
49
|
+
var str=this.toLowerCase();
|
50
|
+
str=str.replace(new RegExp('_id','g'),'');
|
51
|
+
str=str.replace(new RegExp('_','g'),' ');
|
52
|
+
if(!lowFirstLetter)str=str.capitalize();
|
53
|
+
return str;
|
11
54
|
};
|
12
55
|
|
13
|
-
//
|
56
|
+
// Implementation of totalProperty, successProperty and root configuration options for ArrayReader
|
14
57
|
Ext.data.ArrayReader = Ext.extend(Ext.data.JsonReader, {
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
records[records.length] = record;
|
35
|
-
}
|
36
|
-
return {
|
37
|
-
records : records,
|
38
|
-
totalRecords : totalRecords,
|
39
|
-
success : success
|
40
|
-
};
|
58
|
+
readRecords : function(o){
|
59
|
+
var sid = this.meta ? this.meta.id : null;
|
60
|
+
var recordType = this.recordType, fields = recordType.prototype.fields;
|
61
|
+
var records = [];
|
62
|
+
var root = o[this.meta.root] || o, totalRecords = o[this.meta.totalProperty], success = o[this.meta.successProperty];
|
63
|
+
for(var i = 0; i < root.length; i++){
|
64
|
+
var n = root[i];
|
65
|
+
var values = {};
|
66
|
+
var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
|
67
|
+
for(var j = 0, jlen = fields.length; j < jlen; j++){
|
68
|
+
var f = fields.items[j];
|
69
|
+
var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
|
70
|
+
var v = n[k] !== undefined ? n[k] : f.defaultValue;
|
71
|
+
v = f.convert(v, n);
|
72
|
+
values[f.name] = v;
|
73
|
+
}
|
74
|
+
var record = new recordType(values, id);
|
75
|
+
record.json = n;
|
76
|
+
records[records.length] = record;
|
41
77
|
}
|
78
|
+
return {
|
79
|
+
records : records,
|
80
|
+
totalRecords : totalRecords,
|
81
|
+
success : success
|
82
|
+
};
|
83
|
+
}
|
42
84
|
});
|
43
85
|
|
44
|
-
//
|
86
|
+
// Properties/methods common to all widget classes
|
45
87
|
Ext.widgetMixIn = {
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
88
|
+
height: 400,
|
89
|
+
width: 800,
|
90
|
+
border: false,
|
91
|
+
is_netzke: true, // to distinguish Netzke components from regular Ext components
|
92
|
+
|
93
|
+
/*
|
94
|
+
Loads aggregatee into a container. Sends the widgets cache info to the server.
|
95
|
+
*/
|
96
|
+
loadAggregatee: function(params){
|
97
|
+
// build the cached widget list
|
98
|
+
var cachedWidgetNames = [];
|
99
|
+
for (name in Ext.netzke.cache) {
|
100
|
+
cachedWidgetNames.push(name);
|
101
|
+
}
|
102
|
+
|
103
|
+
params.cache = Ext.encode(cachedWidgetNames);
|
104
|
+
|
105
|
+
// remember the passed callback
|
106
|
+
if (params.callback) {
|
107
|
+
this.callbackHash[params.id] = params.callback;
|
108
|
+
delete params.callback;
|
109
|
+
delete params.scope;
|
110
|
+
}
|
111
|
+
|
112
|
+
// visually disable the container while the widget is being loaded
|
113
|
+
// Ext.getCmp(params.container).disable();
|
114
|
+
Ext.getCmp(params.container).removeChild(); // simply cleanup the area, which speaks for itself
|
115
|
+
|
116
|
+
// remote api call
|
117
|
+
this.loadAggregateeWithCache(params);
|
118
|
+
},
|
119
|
+
|
120
|
+
/*
|
121
|
+
Called by the server as callback about loaded widget
|
122
|
+
*/
|
123
|
+
widgetLoaded : function(params){
|
124
|
+
if (this.fireEvent('widgetload')) {
|
125
|
+
// Enable the container after the widget is succesfully loaded
|
126
|
+
// this.getChildWidget(params.id).ownerCt.enable();
|
127
|
+
|
128
|
+
// provide the callback to that widget that was loading the child, passing the child itself
|
129
|
+
if (this.callbackHash[params.id]) {
|
130
|
+
this.callbackHash[params.id].call(params.scope || this, this.getChildWidget(params.id));
|
131
|
+
delete this.callbackHash[params.id];
|
132
|
+
}
|
133
|
+
}
|
134
|
+
},
|
135
|
+
|
136
|
+
/*
|
137
|
+
Returns the parent widget
|
138
|
+
*/
|
139
|
+
getParent: function(){
|
140
|
+
// simply cutting the last part of the id: some_parent__a_kid__a_great_kid => some_parent__a_kid
|
141
|
+
var idSplit = this.id.split("__");
|
142
|
+
idSplit.pop();
|
143
|
+
var parentId = idSplit.join("__");
|
144
|
+
|
145
|
+
return parentId === "" ? null : Ext.getCmp(parentId);
|
146
|
+
},
|
147
|
+
|
148
|
+
/*
|
149
|
+
Reloads current widget (calls the parent to reload it as its aggregatee)
|
150
|
+
*/
|
151
|
+
reload : function(){
|
152
|
+
var parent = this.getParent();
|
153
|
+
if (parent) {
|
154
|
+
parent.loadAggregatee({id:this.localId(parent), container:this.ownerCt.id});
|
155
|
+
} else {
|
156
|
+
window.location.reload();
|
157
|
+
}
|
158
|
+
},
|
159
|
+
|
160
|
+
/*
|
161
|
+
Gets id in the context of provided parent.
|
162
|
+
For example, the widgets "properties", being a child of "books" has global id "books__properties",
|
163
|
+
which *is* its widegt's real id. This methods, with the instance of "books" passed as parameter,
|
164
|
+
returns "properties".
|
165
|
+
*/
|
166
|
+
localId : function(parent){
|
167
|
+
return this.id.replace(parent.id + "__", "");
|
168
|
+
},
|
169
|
+
|
170
|
+
/*
|
171
|
+
Instantiates and inserts a widget into a container with layout 'fit'.
|
172
|
+
Arg: an JS object with the following keys:
|
173
|
+
- id: id of the receiving container
|
174
|
+
- config: configuration of the widget to be instantiated and inserted into the container
|
175
|
+
*/
|
176
|
+
renderWidgetInContainer : function(params){
|
177
|
+
var cont = Ext.getCmp(params.container);
|
178
|
+
cont.instantiateChild(params.config);
|
179
|
+
},
|
180
|
+
|
181
|
+
/*
|
182
|
+
Reconfigures the widget
|
183
|
+
*/
|
184
|
+
reconfigure: function(config){
|
185
|
+
this.ownerCt.instantiateChild(config)
|
186
|
+
},
|
187
|
+
|
188
|
+
/*
|
189
|
+
Evaluates CSS
|
190
|
+
*/
|
191
|
+
css : function(code){
|
192
|
+
var linkTag = document.createElement('style');
|
193
|
+
linkTag.type = 'text/css';
|
194
|
+
linkTag.innerHTML = code;
|
195
|
+
document.body.appendChild(linkTag);
|
196
|
+
},
|
197
|
+
|
198
|
+
/*
|
199
|
+
Evaluates JS
|
200
|
+
*/
|
201
|
+
js : function(code){
|
202
|
+
eval(code);
|
203
|
+
},
|
204
|
+
|
205
|
+
/*
|
206
|
+
Executes a bunch of methods. This method is called almost every time a communication to the server takes place.
|
207
|
+
Thus the server side of a widget can provide any set of commands to its client side.
|
208
|
+
Args:
|
209
|
+
- instructions: array of methods, in the order of execution.
|
210
|
+
Each item is an object in one of the following 2 formats:
|
211
|
+
1) {method1:args1, method2:args2}, where methodN is a name of a public method of this widget; these methods are called in no particular order
|
212
|
+
2) {widget:widget_id, methods:arrayOfMethods}, used for recursive call to bulkExecute on some child widget
|
213
|
+
|
214
|
+
Example:
|
215
|
+
- [
|
216
|
+
// the same as this.feedback("Your order is accepted")
|
217
|
+
{feedback: "You order is accepted"},
|
218
|
+
|
219
|
+
// the same as this.getChildWidget('users').bulkExecute([{setTitle:'Suprise!'}, {setDisabled:true}])
|
220
|
+
{widget:'users', methods:[{setTitle:'Suprise!'}, {setDisabled:true}] },
|
221
|
+
|
222
|
+
// ... etc:
|
223
|
+
{updateStore:{records:[[1, 'Name1'],[2, 'Name2']], total:10}},
|
224
|
+
{setColums:[{},{}]},
|
225
|
+
{setMenus:[{},{}]},
|
226
|
+
...
|
227
|
+
]
|
228
|
+
*/
|
229
|
+
bulkExecute : function(instructions){
|
230
|
+
if (Ext.isArray(instructions)) {
|
231
|
+
Ext.each(instructions, function(instruction){ this.bulkExecute(instruction)}, this);
|
232
|
+
} else {
|
233
|
+
for (var instr in instructions) {
|
234
|
+
if (this[instr]) {
|
235
|
+
this[instr].apply(this, [instructions[instr]]);
|
236
|
+
} else {
|
237
|
+
var childWidget = this.getChildWidget(instr);
|
238
|
+
if (childWidget) {
|
239
|
+
childWidget.bulkExecute(instructions[instr]);
|
240
|
+
} else {
|
241
|
+
throw "Unknown method or child widget '" + instr +"' in widget '" + this.id + "'"
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
}
|
246
|
+
},
|
247
|
+
|
248
|
+
// Get the child widget
|
249
|
+
getChildWidget : function(id){
|
250
|
+
return id === 'parent' ? this.getParent() : Ext.getCmp(this.id+"__"+id);
|
251
|
+
},
|
252
|
+
|
253
|
+
// Common handler for actions
|
254
|
+
actionHandler : function(action){
|
255
|
+
// If firing corresponding event doesn't return false, call the handler
|
256
|
+
if (this.fireEvent(action.name+'click', action)) {
|
257
|
+
this[(action.fn || action.name)](action);
|
258
|
+
}
|
259
|
+
},
|
260
|
+
|
261
|
+
// Common handler for tools
|
262
|
+
toolActionHandler : function(tool){
|
263
|
+
// If firing corresponding event doesn't return false, call the handler
|
264
|
+
if (this.fireEvent(tool.id+'click')) {
|
265
|
+
this[tool]();
|
266
|
+
}
|
267
|
+
},
|
268
|
+
|
269
|
+
// Does the call to the server and processes the response
|
270
|
+
callServer : function(intp, params, callback, scope){
|
271
|
+
if (!params) params = {};
|
272
|
+
Ext.Ajax.request({
|
273
|
+
params : params,
|
274
|
+
url : this.id + "__" + intp,
|
275
|
+
callback : function(options, success, response){
|
276
|
+
if (success) {
|
277
|
+
// execute commands from server
|
278
|
+
this.bulkExecute(Ext.decode(response.responseText));
|
279
|
+
|
280
|
+
// provade callback if needed
|
281
|
+
if (typeof callback == 'function') {
|
282
|
+
if (!scope) scope = this;
|
283
|
+
callback.apply(scope);
|
284
|
+
}
|
285
|
+
}
|
286
|
+
},
|
287
|
+
scope : this
|
288
|
+
});
|
289
|
+
},
|
290
|
+
|
291
|
+
/* Parse the bbar and tbar (both Arrays), replacing the strings with the corresponding methods. For example:
|
292
|
+
replaceStringsWithActions( ['add', {text:'Menu', menu:['edit', 'delete']}] )
|
293
|
+
=> [scope.actions['add'], {text:'Menu', menu:[scope.actions['edit'], scope.actions['delete']]}]
|
294
|
+
*/
|
295
|
+
normalizeMenuItems: function(arry, scope){
|
296
|
+
var res = []; // new array
|
297
|
+
Ext.each(arry, function(o){
|
298
|
+
if (typeof o === "string") {
|
299
|
+
var camelized = o.camelize(true);
|
300
|
+
if (scope.actions[camelized]){
|
301
|
+
res.push(scope.actions[camelized]);
|
302
|
+
} else {
|
303
|
+
// if there's no action with this name, maybe it's a separator or something
|
304
|
+
res.push(o);
|
305
|
+
}
|
306
|
+
} else if (Netzke.isObject(o)) {
|
307
|
+
// look inside the objects...
|
308
|
+
for (var key in o) {
|
309
|
+
if (Ext.isArray(o[key])) {
|
310
|
+
// ... and recursively process inner arrays found
|
311
|
+
o[key] = this.normalizeMenuItems(o[key], scope);
|
312
|
+
}
|
313
|
+
}
|
314
|
+
res.push(o);
|
315
|
+
}
|
316
|
+
}, this);
|
317
|
+
return res;
|
318
|
+
},
|
319
|
+
|
320
|
+
|
321
|
+
// Every Netzke widget
|
322
|
+
commonBeforeConstructor : function(config){
|
323
|
+
this.actions = {};
|
324
|
+
|
325
|
+
// Generate methods for api points
|
326
|
+
if (!config.api) { config.api = []; }
|
327
|
+
config.api.push('load_aggregatee_with_cache'); // all netzke widgets get this API
|
328
|
+
Ext.each(config.api, function(intp){
|
329
|
+
this[intp.camelize(true)] = function(args, callback, scope){ this.callServer(intp, args, callback, scope); }
|
330
|
+
}, this);
|
331
|
+
|
332
|
+
// Create Ext.Actions based on config.actions
|
333
|
+
if (config.actions) {
|
334
|
+
this.testActions = {};
|
335
|
+
for (var name in config.actions) {
|
336
|
+
// Create an event for each action (so that higher-level widgets could interfere)
|
337
|
+
this.addEvents(name+'click');
|
338
|
+
|
339
|
+
// Configure the action
|
340
|
+
var actionConfig = config.actions[name];
|
341
|
+
actionConfig.handler = this.actionHandler.createDelegate(this);
|
342
|
+
actionConfig.name = name;
|
343
|
+
this.actions[name] = new Ext.Action(actionConfig);
|
344
|
+
}
|
345
|
+
|
346
|
+
config.bbar = config.bbar && this.normalizeMenuItems(config.bbar, this);
|
347
|
+
config.tbar = config.tbar && this.normalizeMenuItems(config.tbar, this);
|
348
|
+
config.menu = config.menu && this.normalizeMenuItems(config.menu, this);
|
349
|
+
config.contextMenu = config.contextMenu && this.normalizeMenuItems(config.contextMenu, this);
|
350
|
+
|
351
|
+
// TODO: need to rethink this action related stuff
|
352
|
+
config.actions = this.actions;
|
353
|
+
|
354
|
+
}
|
355
|
+
|
356
|
+
// Normalize tools
|
357
|
+
if (config.tools) {
|
358
|
+
var normTools = [];
|
359
|
+
Ext.each(config.tools, function(tool){
|
360
|
+
// Create an event for each action (so that higher-level widgets could interfere)
|
361
|
+
this.addEvents(tool.id+'click');
|
362
|
+
|
363
|
+
var handler = this.toolActionHandler.createDelegate(this, [tool]);
|
364
|
+
normTools.push({id : tool, handler : handler, scope : this});
|
365
|
+
}, this);
|
366
|
+
config.tools = normTools;
|
367
|
+
}
|
368
|
+
|
369
|
+
// Set title
|
370
|
+
if (!config.title) config.title = config.id.humanize();
|
371
|
+
},
|
372
|
+
|
373
|
+
// At this moment component is fully initializied
|
374
|
+
commonAfterConstructor : function(config){
|
375
|
+
// From everywhere accessible FeedbackGhost
|
376
|
+
this.feedbackGhost = Ext.getCmp('feedback_ghost');
|
377
|
+
|
378
|
+
// Add the menus
|
379
|
+
if (this.initialConfig.menu) {this.addMenu(this.initialConfig.menu, this);}
|
380
|
+
|
381
|
+
// generic events
|
382
|
+
this.addEvents(
|
383
|
+
'widgetload' // fired when a child is dynamically loaded
|
384
|
+
);
|
385
|
+
|
386
|
+
// Cleaning up on destroy
|
387
|
+
this.on('beforedestroy', function(){
|
388
|
+
this.cleanUpMenu();
|
389
|
+
}, this);
|
390
|
+
|
391
|
+
this.callbackHash = {};
|
392
|
+
|
393
|
+
if (this.afterConstructor) this.afterConstructor(config);
|
394
|
+
},
|
395
|
+
|
396
|
+
feedback:function(msg){
|
397
|
+
if (this.initialConfig && this.initialConfig.quiet) {
|
398
|
+
return false;
|
399
|
+
}
|
400
|
+
|
401
|
+
if (this.feedbackGhost) {
|
402
|
+
this.feedbackGhost.showFeedback(msg);
|
403
|
+
} else {
|
404
|
+
// there's no application to show the feedback - so, we do it ourselves
|
405
|
+
if (typeof msg == 'string'){
|
406
|
+
alert(msg);
|
407
|
+
} else {
|
408
|
+
var compoundResponse = "";
|
409
|
+
Ext.each(msg, function(m){
|
74
410
|
compoundResponse += m.msg + "\n"
|
75
|
-
})
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
411
|
+
});
|
412
|
+
if (compoundResponse != "") {
|
413
|
+
alert(compoundResponse);
|
414
|
+
}
|
415
|
+
}
|
416
|
+
}
|
417
|
+
},
|
418
|
+
|
419
|
+
addMenu : function(menu, owner){
|
420
|
+
if (!owner) {
|
421
|
+
owner = this;
|
422
|
+
}
|
423
|
+
|
424
|
+
if (!!this.hostMenu) {
|
425
|
+
this.hostMenu(menu, owner);
|
426
|
+
} else {
|
427
|
+
if (this.ownerWidget) {
|
428
|
+
this.ownerWidget.addMenu(menu, owner);
|
429
|
+
}
|
430
|
+
}
|
431
|
+
},
|
432
|
+
|
433
|
+
cleanUpMenu : function(owner){
|
434
|
+
if (!owner) {
|
435
|
+
owner = this;
|
436
|
+
}
|
437
|
+
|
438
|
+
if (!!this.unhostMenu) {
|
439
|
+
this.unhostMenu(owner);
|
440
|
+
} else {
|
441
|
+
if (this.ownerWidget) {
|
442
|
+
this.ownerWidget.cleanUpMenu(owner);
|
443
|
+
}
|
444
|
+
}
|
445
|
+
},
|
446
|
+
|
447
|
+
onWidgetLoad:Ext.emptyFn // gets overridden
|
88
448
|
};
|
89
449
|
|
90
|
-
//
|
91
|
-
Ext.override(Ext.
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
450
|
+
// Netzke extensions for Ext.Container
|
451
|
+
Ext.override(Ext.Container, {
|
452
|
+
/**
|
453
|
+
Get Netzke widget that this Ext.Container is part of (*not* the parent widget, for which call getParent)
|
454
|
+
It searches up the Ext.Container hierarchy until it finds a Container that has isNetzke property set to true
|
455
|
+
(or until it reaches the top).
|
456
|
+
*/
|
457
|
+
getOwnerWidget : function(){
|
458
|
+
if (this.initialConfig.isNetzke) {
|
459
|
+
return this;
|
460
|
+
} else {
|
461
|
+
if (this.ownerCt){
|
462
|
+
return this.ownerCt.getOwnerWidget()
|
463
|
+
} else {
|
464
|
+
return null
|
465
|
+
}
|
466
|
+
}
|
467
|
+
},
|
468
|
+
|
469
|
+
// Get the widget that we are hosting
|
470
|
+
getWidget: function(){
|
471
|
+
return this.items ? this.items.get(0) : null; // need this check in case when the container is not yet rendered, like an inactive tab in the TabPanel
|
472
|
+
},
|
473
|
+
|
474
|
+
removeChild : function(){
|
475
|
+
this.remove(this.getWidget());
|
476
|
+
},
|
477
|
+
|
478
|
+
instantiateChild : function(config){
|
479
|
+
this.remove(this.getWidget()); // first delete previous widget
|
480
|
+
|
481
|
+
if (!config) return false; // simply remove current widget if null is passed
|
482
|
+
|
483
|
+
var instance = new Ext.netzke.cache[config.widgetClassName](config);
|
484
|
+
this.add(instance);
|
485
|
+
this.doLayout();
|
486
|
+
}
|
487
|
+
});
|