skozlov-netzke-core 0.1.0.2 → 0.4.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/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
|
+
});
|