netzke-core 0.2.8 → 0.2.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +7 -0
- data/Manifest +2 -1
- data/README.mdown +1 -1
- data/TODO +1 -0
- data/javascripts/core.js +174 -59
- data/lib/app/controllers/netzke_controller.rb +1 -1
- data/lib/app/models/netzke_layout.rb +2 -9
- data/lib/app/models/netzke_preference.rb +10 -12
- data/lib/netzke/base.rb +61 -66
- data/lib/netzke/base_extras/interface.rb +2 -0
- data/lib/netzke/base_extras/js_builder.rb +106 -52
- data/lib/netzke/controller_extensions.rb +1 -1
- data/lib/netzke/core_ext.rb +1 -1
- data/lib/netzke-core.rb +6 -2
- data/netzke-core.gemspec +4 -4
- data/{css → stylesheets}/core.css +4 -0
- data/test/netzke_core_test.rb +2 -2
- metadata +5 -3
data/CHANGELOG
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
v0.2.9
|
2
|
+
Actions, toolbars and tools reworked for easier configuration.
|
3
|
+
Menus introduced (based on actions).
|
4
|
+
Significant code clean-up.
|
5
|
+
Bug fix (nasty one): Ext.widgetMixIn was getting messed up along with dynamic widget loading.
|
6
|
+
Must work in IE now.
|
7
|
+
|
1
8
|
v0.2.8
|
2
9
|
Support for extra javascripts and stylesheets per widget.
|
3
10
|
|
data/Manifest
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
CHANGELOG
|
2
|
-
css/core.css
|
3
2
|
generators/netzke_core/netzke_core_generator.rb
|
4
3
|
generators/netzke_core/templates/create_netzke_layouts.rb
|
5
4
|
generators/netzke_core/templates/create_netzke_preferences.rb
|
@@ -25,6 +24,7 @@ Manifest
|
|
25
24
|
netzke-core.gemspec
|
26
25
|
Rakefile
|
27
26
|
README.mdown
|
27
|
+
stylesheets/core.css
|
28
28
|
tasks/netzke_core_tasks.rake
|
29
29
|
test/app_root/app/controllers/application.rb
|
30
30
|
test/app_root/config/boot.rb
|
@@ -42,4 +42,5 @@ test/core_ext_test.rb
|
|
42
42
|
test/netzke_core_test.rb
|
43
43
|
test/netzke_preference_test.rb
|
44
44
|
test/test_helper.rb
|
45
|
+
TODO
|
45
46
|
uninstall.rb
|
data/README.mdown
CHANGED
@@ -10,4 +10,4 @@ The tutorials: http://blog.writelesscode.com
|
|
10
10
|
|
11
11
|
Also see the netzke-basepack project: http://github.com/skozlov/netzke-basepack/tree/master
|
12
12
|
|
13
|
-
Copyright (c) 2008-2009 Sergei Kozlov, released under
|
13
|
+
Copyright (c) 2008-2009 Sergei Kozlov, released under LGPL 3.0
|
data/javascripts/core.js
CHANGED
@@ -1,8 +1,12 @@
|
|
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
6
|
Ext.namespace('Ext.netzke');
|
3
7
|
Ext.netzke.cache = {};
|
4
8
|
|
5
|
-
Ext.QuickTips.init(); // seems obligatory in Ext v2.2.1, otherwise destroy() stops working properly
|
9
|
+
Ext.QuickTips.init(); // seems obligatory in Ext v2.2.1, otherwise Ext.Component#destroy() stops working properly
|
6
10
|
|
7
11
|
// to comply with Rails' forgery protection
|
8
12
|
Ext.Ajax.extraParams = {
|
@@ -16,7 +20,50 @@ Ext.chainApply = function(objectArray){
|
|
16
20
|
return res;
|
17
21
|
};
|
18
22
|
|
19
|
-
//
|
23
|
+
// Type detection functions
|
24
|
+
function isArray(o) {
|
25
|
+
return (o != null && typeof o == "object" && o.constructor.toString() == Array.toString());
|
26
|
+
}
|
27
|
+
|
28
|
+
function isObject(o) {
|
29
|
+
return (o != null && typeof o == "object" && o.constructor.toString() == Object.toString());
|
30
|
+
}
|
31
|
+
|
32
|
+
// Some Rubyish String extensions
|
33
|
+
// from http://code.google.com/p/inflection-js/
|
34
|
+
String.prototype.camelize=function(lowFirstLetter)
|
35
|
+
{
|
36
|
+
var str=this.toLowerCase();
|
37
|
+
var str_path=str.split('/');
|
38
|
+
for(var i=0;i<str_path.length;i++)
|
39
|
+
{
|
40
|
+
var str_arr=str_path[i].split('_');
|
41
|
+
var initX=((lowFirstLetter&&i+1==str_path.length)?(1):(0));
|
42
|
+
for(var x=initX;x<str_arr.length;x++)
|
43
|
+
str_arr[x]=str_arr[x].charAt(0).toUpperCase()+str_arr[x].substring(1);
|
44
|
+
str_path[i]=str_arr.join('');
|
45
|
+
}
|
46
|
+
str=str_path.join('::');
|
47
|
+
return str;
|
48
|
+
};
|
49
|
+
|
50
|
+
String.prototype.capitalize=function()
|
51
|
+
{
|
52
|
+
var str=this.toLowerCase();
|
53
|
+
str=str.substring(0,1).toUpperCase()+str.substring(1);
|
54
|
+
return str;
|
55
|
+
};
|
56
|
+
|
57
|
+
String.prototype.humanize=function(lowFirstLetter)
|
58
|
+
{
|
59
|
+
var str=this.toLowerCase();
|
60
|
+
str=str.replace(new RegExp('_id','g'),'');
|
61
|
+
str=str.replace(new RegExp('_','g'),' ');
|
62
|
+
if(!lowFirstLetter)str=str.capitalize();
|
63
|
+
return str;
|
64
|
+
};
|
65
|
+
|
66
|
+
// Implementation of totalProperty, successProperty and root configuration options for ArrayReader
|
20
67
|
Ext.data.ArrayReader = Ext.extend(Ext.data.JsonReader, {
|
21
68
|
readRecords : function(o){
|
22
69
|
var sid = this.meta ? this.meta.id : null;
|
@@ -49,68 +96,151 @@ Ext.data.ArrayReader = Ext.extend(Ext.data.JsonReader, {
|
|
49
96
|
|
50
97
|
// Methods common to all widget classes
|
51
98
|
Ext.widgetMixIn = {
|
99
|
+
// Common handler for actions
|
52
100
|
actionHandler : function(action){
|
53
|
-
|
101
|
+
// If firing corresponding event doesn't return false, call the handler
|
102
|
+
if (this.fireEvent(action.name+'click', action)) {
|
103
|
+
this[(action.fn || action.name)](action);
|
104
|
+
}
|
54
105
|
},
|
55
106
|
|
56
|
-
|
57
|
-
|
107
|
+
// Common handler for tools
|
108
|
+
toolActionHandler : function(tool){
|
109
|
+
// If firing corresponding event doesn't return false, call the handler
|
110
|
+
if (this.fireEvent(tool.id+'click')) {
|
111
|
+
this[tool]();
|
112
|
+
}
|
113
|
+
},
|
58
114
|
|
59
|
-
|
60
|
-
|
61
|
-
}, this);
|
115
|
+
beforeConstructor : function(config){
|
116
|
+
this.actions = {};
|
62
117
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
118
|
+
// Create Ext.Actions based on config.actions
|
119
|
+
if (config.actions) {
|
120
|
+
for (var name in config.actions) {
|
121
|
+
// Create an event for each action (so that higher-level widgets could interfere)
|
122
|
+
this.addEvents(name+'click');
|
67
123
|
|
68
|
-
|
69
|
-
|
70
|
-
|
124
|
+
// Configure the action
|
125
|
+
var actionConfig = config.actions[name];
|
126
|
+
actionConfig.handler = this.actionHandler.createDelegate(this);
|
127
|
+
actionConfig.name = name;
|
128
|
+
this.actions[name] = new Ext.Action(actionConfig);
|
129
|
+
}
|
71
130
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
131
|
+
/* Parse the bbar and tbar (both Arrays), replacing the strings with the corresponding methods. For example:
|
132
|
+
replaceStringsWithActions( ['add', {text:'Menu', menu:['edit', 'delete']}] )
|
133
|
+
=> [scope.actions['add'], {text:'Menu', menu:[scope.actions['edit'], scope.actions['delete']]}]
|
134
|
+
*/
|
135
|
+
var replaceStringsWithActions = function(arry, scope){
|
136
|
+
var res = []; // new array
|
137
|
+
Ext.each(arry, function(o){
|
138
|
+
if (typeof o === "string") {
|
139
|
+
var camelized = o.camelize(true);
|
140
|
+
if (scope.actions[camelized]){
|
141
|
+
res.push(scope.actions[camelized]);
|
142
|
+
} else {
|
143
|
+
// if there's no action with this name, maybe it's a separator or something
|
144
|
+
res.push(o);
|
145
|
+
}
|
146
|
+
} else if (isObject(o)) {
|
147
|
+
// look inside the objects...
|
148
|
+
for (var key in o) {
|
149
|
+
if (isArray(o[key])) {
|
150
|
+
// ... and recursively process inner arrays found
|
151
|
+
o[key] = replaceStringsWithActions(o[key], scope);
|
152
|
+
}
|
153
|
+
}
|
154
|
+
res.push(o);
|
155
|
+
}
|
156
|
+
});
|
157
|
+
return res;
|
77
158
|
}
|
159
|
+
config.bbar = config.bbar && replaceStringsWithActions(config.bbar, this);
|
160
|
+
config.tbar = config.tbar && replaceStringsWithActions(config.tbar, this);
|
161
|
+
config.menu = config.menu && replaceStringsWithActions(config.menu, this);
|
162
|
+
|
163
|
+
}
|
164
|
+
|
165
|
+
// Normalize tools
|
166
|
+
if (config.tools) {
|
167
|
+
var normTools = [];
|
168
|
+
Ext.each(config.tools, function(tool){
|
169
|
+
// Create an event for each action (so that higher-level widgets could interfere)
|
170
|
+
this.addEvents(tool.id+'click');
|
171
|
+
|
172
|
+
var handler = this.toolActionHandler.createDelegate(this, [tool]);
|
173
|
+
normTools.push({id : tool, handler : handler, scope : this});
|
174
|
+
}, this);
|
175
|
+
config.tools = normTools;
|
176
|
+
}
|
177
|
+
|
178
|
+
},
|
179
|
+
|
180
|
+
afterConstructor : function(config){
|
181
|
+
this.feedbackGhost = Ext.getCmp('feedback_ghost');
|
182
|
+
|
183
|
+
// cleaning up
|
184
|
+
this.on('beforedestroy', function(){
|
185
|
+
this.cleanUpMenu(this);
|
78
186
|
}, this);
|
79
187
|
|
188
|
+
// After render, add the menus
|
189
|
+
this.on('render', function(){
|
190
|
+
if (this.initialConfig.menu) {this.addMenu(this.initialConfig.menu);}
|
191
|
+
}, this);
|
192
|
+
|
80
193
|
this.on('render', this.onWidgetLoad, this);
|
81
194
|
},
|
82
195
|
|
83
196
|
feedback:function(msg){
|
84
|
-
if (this.initialConfig && this.initialConfig.quiet)
|
85
|
-
|
86
|
-
|
197
|
+
if (this.initialConfig && this.initialConfig.quiet) {
|
198
|
+
return false;
|
199
|
+
}
|
200
|
+
|
201
|
+
if (this.feedbackGhost) {
|
202
|
+
this.feedbackGhost.showFeedback(msg);
|
87
203
|
} else {
|
88
204
|
// there's no application to show the feedback - so, we do it ourselves
|
89
205
|
if (typeof msg == 'string'){
|
90
|
-
alert(msg)
|
206
|
+
alert(msg);
|
91
207
|
} else {
|
92
|
-
var compoundResponse = ""
|
208
|
+
var compoundResponse = "";
|
93
209
|
Ext.each(msg, function(m){
|
94
210
|
compoundResponse += m.msg + "\n"
|
95
|
-
})
|
96
|
-
if (compoundResponse != "")
|
211
|
+
});
|
212
|
+
if (compoundResponse != "") {
|
213
|
+
alert(compoundResponse);
|
214
|
+
}
|
97
215
|
}
|
98
|
-
}
|
216
|
+
}
|
99
217
|
},
|
100
218
|
|
101
|
-
|
102
|
-
if (
|
103
|
-
|
219
|
+
addMenu : function(menu, owner){
|
220
|
+
if (!owner) {
|
221
|
+
owner = this;
|
222
|
+
}
|
223
|
+
|
224
|
+
if (!!this.hostMenu) {
|
225
|
+
this.hostMenu(menu, owner);
|
104
226
|
} else {
|
105
|
-
if (this.
|
106
|
-
this.
|
227
|
+
if (this.parent) {
|
228
|
+
this.parent.addMenu(menu, owner);
|
107
229
|
}
|
108
230
|
}
|
109
231
|
},
|
110
|
-
|
111
|
-
|
112
|
-
if (
|
113
|
-
|
232
|
+
|
233
|
+
cleanUpMenu : function(owner){
|
234
|
+
if (!owner) {
|
235
|
+
owner = this;
|
236
|
+
}
|
237
|
+
|
238
|
+
if (!!this.unhostMenu) {
|
239
|
+
this.unhostMenu(owner);
|
240
|
+
} else {
|
241
|
+
if (this.parent) {
|
242
|
+
this.parent.cleanUpMenu(owner);
|
243
|
+
}
|
114
244
|
}
|
115
245
|
},
|
116
246
|
|
@@ -120,11 +250,13 @@ Ext.widgetMixIn = {
|
|
120
250
|
// Make Panel with layout 'fit' capable to dynamically load widgets
|
121
251
|
Ext.override(Ext.Panel, {
|
122
252
|
getWidget: function(){
|
123
|
-
return this.items.get(0)
|
253
|
+
return this.items.get(0);
|
124
254
|
},
|
125
255
|
|
126
256
|
loadWidget: function(url, params){
|
127
|
-
if (!params)
|
257
|
+
if (!params) {
|
258
|
+
params = {};
|
259
|
+
}
|
128
260
|
|
129
261
|
this.remove(this.getWidget()); // first delete previous widget
|
130
262
|
|
@@ -149,7 +281,7 @@ Ext.override(Ext.Panel, {
|
|
149
281
|
|
150
282
|
// evaluate widget's stylesheets
|
151
283
|
if (responseObj.css){
|
152
|
-
var linkTag = document.createElement('style')
|
284
|
+
var linkTag = document.createElement('style');
|
153
285
|
linkTag.type = 'text/css';
|
154
286
|
linkTag.innerHTML = responseObj.css;
|
155
287
|
document.body.appendChild(linkTag);
|
@@ -160,14 +292,14 @@ Ext.override(Ext.Panel, {
|
|
160
292
|
eval(responseObj.js);
|
161
293
|
}
|
162
294
|
|
163
|
-
responseObj.config.parent = this // we might want to know the parent panel in advance (e.g. to know its size)
|
295
|
+
responseObj.config.parent = this.ownerCt; // we might want to know the parent panel in advance (e.g. to know its size)
|
164
296
|
var instance = new Ext.netzke.cache[responseObj.config.widgetClassName](responseObj.config)
|
165
297
|
|
166
298
|
this.add(instance);
|
167
299
|
this.doLayout();
|
168
300
|
} else {
|
169
301
|
// we didn't get normal response - desplay the flash with eventual errors
|
170
|
-
this.ownerCt.feedback(responseObj.flash)
|
302
|
+
this.ownerCt.feedback(responseObj.flash);
|
171
303
|
}
|
172
304
|
|
173
305
|
// reenable the panel
|
@@ -178,20 +310,3 @@ Ext.override(Ext.Panel, {
|
|
178
310
|
}
|
179
311
|
});
|
180
312
|
|
181
|
-
// Some Rubyish String extensions
|
182
|
-
// from http://code.google.com/p/inflection-js/
|
183
|
-
String.prototype.capitalize=function()
|
184
|
-
{
|
185
|
-
var str=this.toLowerCase();
|
186
|
-
str=str.substring(0,1).toUpperCase()+str.substring(1);
|
187
|
-
return str;
|
188
|
-
};
|
189
|
-
|
190
|
-
String.prototype.humanize=function(lowFirstLetter)
|
191
|
-
{
|
192
|
-
var str=this.toLowerCase();
|
193
|
-
str=str.replace(new RegExp('_id','g'),'');
|
194
|
-
str=str.replace(new RegExp('_','g'),' ');
|
195
|
-
if(!lowFirstLetter)str=str.capitalize();
|
196
|
-
return str;
|
197
|
-
};
|
@@ -1,16 +1,9 @@
|
|
1
1
|
class NetzkeLayout < ActiveRecord::Base
|
2
2
|
EXT_UNRELATED_ATTRIBUTES = %w{ id layout_id position created_at updated_at }
|
3
|
+
|
3
4
|
# Multi user support
|
4
|
-
def self.user
|
5
|
-
@@user ||= nil
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.user=(user)
|
9
|
-
@@user = user
|
10
|
-
end
|
11
|
-
|
12
5
|
def self.user_id
|
13
|
-
user && user.id
|
6
|
+
Netzke::Base.user && Netzke::Base.user.id
|
14
7
|
end
|
15
8
|
|
16
9
|
# normal create, but with a user_id merged-in
|
@@ -6,19 +6,12 @@
|
|
6
6
|
# etc
|
7
7
|
#
|
8
8
|
class NetzkePreference < ActiveRecord::Base
|
9
|
-
|
10
|
-
|
11
|
-
# Multi user support
|
12
|
-
def self.user
|
13
|
-
@@user ||= nil
|
14
|
-
end
|
9
|
+
named_scope :for_current_user, lambda { {:conditions => {:user_id => user_id}} }
|
15
10
|
|
16
|
-
|
17
|
-
@@user = user
|
18
|
-
end
|
11
|
+
ELEMENTARY_CONVERTION_METHODS= {'Fixnum' => 'to_i', 'String' => 'to_s', 'Float' => 'to_f', 'Symbol' => 'to_sym'}
|
19
12
|
|
20
13
|
def self.user_id
|
21
|
-
user && user.id
|
14
|
+
Netzke::Base.user && Netzke::Base.user.id
|
22
15
|
end
|
23
16
|
|
24
17
|
def self.widget_name=(value)
|
@@ -54,14 +47,14 @@ class NetzkePreference < ActiveRecord::Base
|
|
54
47
|
end
|
55
48
|
|
56
49
|
def self.[](pref_name)
|
57
|
-
pref_name = pref_name
|
50
|
+
pref_name = normalize_preference_name(pref_name)
|
58
51
|
conditions = {:name => pref_name, :user_id => user_id, :widget_name => self.widget_name}
|
59
52
|
pref = self.find(:first, :conditions => conditions)
|
60
53
|
pref && pref.normalized_value
|
61
54
|
end
|
62
55
|
|
63
56
|
def self.[]=(pref_name, new_value)
|
64
|
-
pref_name = pref_name
|
57
|
+
pref_name = normalize_preference_name(pref_name)
|
65
58
|
conditions = {:name => pref_name, :user_id => user_id, :widget_name => self.widget_name}
|
66
59
|
pref = self.find(:first, :conditions => conditions)
|
67
60
|
|
@@ -75,4 +68,9 @@ class NetzkePreference < ActiveRecord::Base
|
|
75
68
|
end
|
76
69
|
end
|
77
70
|
|
71
|
+
private
|
72
|
+
def self.normalize_preference_name(name)
|
73
|
+
name.to_s.gsub(".", "__").gsub("/", "__")
|
74
|
+
end
|
75
|
+
|
78
76
|
end
|
data/lib/netzke/base.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
require '
|
1
|
+
require 'netzke/base_extras/js_builder'
|
2
|
+
require 'netzke/base_extras/interface'
|
2
3
|
|
3
4
|
module Netzke
|
4
5
|
#
|
@@ -8,48 +9,38 @@ module Netzke
|
|
8
9
|
# should be aware of this constant.
|
9
10
|
#
|
10
11
|
class Base
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
12
|
+
|
13
|
+
# Class-level Netzke::Base configuration. The defaults also get specified here.
|
14
|
+
def self.config
|
15
|
+
set_default_config({
|
16
|
+
# which javascripts and stylesheets must get included at the initial load (see netzke-core.rb)
|
17
|
+
:javascripts => [],
|
18
|
+
:stylesheets => [],
|
19
|
+
|
20
|
+
:layout_manager => "NetzkeLayout",
|
21
|
+
:persistent_config_manager => "NetzkePreference",
|
22
|
+
|
23
|
+
:ext_location => defined?(RAILS_ROOT) && "#{RAILS_ROOT}/public/extjs"
|
24
|
+
})
|
25
|
+
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
:css => [],
|
30
|
-
:layout_manager => "NetzkeLayout",
|
31
|
-
:persistent_config_manager => "NetzkePreference"
|
32
|
-
})
|
33
|
-
end
|
27
|
+
include Netzke::BaseExtras::JsBuilder
|
28
|
+
include Netzke::BaseExtras::Interface
|
29
|
+
|
30
|
+
module ClassMethods
|
34
31
|
|
32
|
+
# "Netzke::SomeWidget" => "SomeWidget"
|
35
33
|
def short_widget_class_name
|
36
|
-
name.split("::").last
|
34
|
+
self.name.split("::").last
|
37
35
|
end
|
38
36
|
|
37
|
+
# Multi-user support
|
39
38
|
def user
|
40
39
|
@@user ||= nil
|
41
40
|
end
|
42
41
|
|
43
42
|
def user=(user)
|
44
43
|
@@user = user
|
45
|
-
|
46
|
-
# also set up the managers
|
47
|
-
persistent_config_manager_class && persistent_config_manager_class.user = user
|
48
|
-
layout_manager_class && layout_manager_class.user = user
|
49
|
-
end
|
50
|
-
|
51
|
-
def user_has_role?(role)
|
52
|
-
user.login == 'sergei' && role.to_s == 'configurator'
|
53
44
|
end
|
54
45
|
|
55
46
|
#
|
@@ -78,32 +69,6 @@ module Netzke
|
|
78
69
|
read_inheritable_attribute(:interface_points)
|
79
70
|
end
|
80
71
|
|
81
|
-
#
|
82
|
-
# Include extra code from Ext js library (e.g. examples)
|
83
|
-
#
|
84
|
-
def ext_js_include(*args)
|
85
|
-
included_ext_js = read_inheritable_attribute(:included_ext_js) || []
|
86
|
-
args.each {|f| included_ext_js << f}
|
87
|
-
write_inheritable_attribute(:included_ext_js, included_ext_js)
|
88
|
-
end
|
89
|
-
|
90
|
-
# def js_include(*args)
|
91
|
-
# included_js = read_inheritable_attribute(:included_js) || []
|
92
|
-
# args.each {|f| included_js << f}
|
93
|
-
# write_inheritable_attribute(:included_js, included_js)
|
94
|
-
# end
|
95
|
-
|
96
|
-
# include eventual extra modules
|
97
|
-
def include_extras
|
98
|
-
extras_dir = File.join(File.dirname(widget_file), short_widget_class_name.underscore + "_extras")
|
99
|
-
file_list = Dir.glob("#{extras_dir}/*.rb")
|
100
|
-
for file_name in file_list
|
101
|
-
require file_name
|
102
|
-
module_name = "#{self.name}Extras::#{File.basename(file_name, ".rb").classify}"
|
103
|
-
include module_name.constantize
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
72
|
# returns an instance of a widget defined in the config
|
108
73
|
def instance_by_config(config)
|
109
74
|
widget_class = "Netzke::#{config[:widget_class_name]}".constantize
|
@@ -123,7 +88,6 @@ module Netzke
|
|
123
88
|
nil
|
124
89
|
end
|
125
90
|
|
126
|
-
|
127
91
|
private
|
128
92
|
def set_default_config(default_config)
|
129
93
|
@@config ||= {}
|
@@ -134,9 +98,6 @@ module Netzke
|
|
134
98
|
end
|
135
99
|
extend ClassMethods
|
136
100
|
|
137
|
-
# include extra modules
|
138
|
-
include_extras
|
139
|
-
|
140
101
|
attr_accessor :config, :server_confg, :parent, :logger, :id_name, :permissions
|
141
102
|
attr_reader :pref
|
142
103
|
|
@@ -171,9 +132,14 @@ module Netzke
|
|
171
132
|
# persistent_config["window.size"] => 100
|
172
133
|
# This method is user-aware
|
173
134
|
def persistent_config
|
174
|
-
config_klass = self.class.persistent_config_manager_class
|
175
|
-
|
176
|
-
|
135
|
+
config_klass = config[:persistent_config] && self.class.persistent_config_manager_class
|
136
|
+
if config_klass
|
137
|
+
config_klass.widget_name = id_name # pass to the config class our unique name
|
138
|
+
config_klass
|
139
|
+
else
|
140
|
+
# if we can't use presistent config, all the calls to it will always return nil, and the "="-operation will be ignored
|
141
|
+
{}
|
142
|
+
end
|
177
143
|
end
|
178
144
|
|
179
145
|
def initial_config
|
@@ -272,7 +238,11 @@ module Netzke
|
|
272
238
|
|
273
239
|
# ... and then merge it with NetzkePreferences
|
274
240
|
available_permissions.each do |p|
|
275
|
-
|
241
|
+
# if nothing is stored in persistent_config, store the permission from the config; otherwise leave what's there
|
242
|
+
persistent_config["permissions/#{p}"].nil? && persistent_config["permissions/#{p}"] = @permissions[p.to_sym]
|
243
|
+
|
244
|
+
# what's stored in persistent_config has higher priority, so, if there's something there, use that
|
245
|
+
persistent_permisson = persistent_config["permissions/#{p}"]
|
276
246
|
@permissions[p.to_sym] = persistent_permisson unless persistent_permisson.nil?
|
277
247
|
end
|
278
248
|
end
|
@@ -303,5 +273,30 @@ module Netzke
|
|
303
273
|
{:success => false, :flash => @flash}.to_json
|
304
274
|
end
|
305
275
|
|
276
|
+
def tools
|
277
|
+
persistent_config[:tools] ||= config[:tools] == false ? nil : config[:tools]
|
278
|
+
end
|
279
|
+
|
280
|
+
def bbar
|
281
|
+
persistent_config[:bottom_bar] ||= config[:bbar] == false ? nil : config[:bbar]
|
282
|
+
end
|
283
|
+
|
284
|
+
def tbar
|
285
|
+
persistent_config[:top_bar] ||= config[:tbar] == false ? nil : config[:tbar]
|
286
|
+
end
|
287
|
+
|
288
|
+
def menu
|
289
|
+
persistent_config[:menu] ||= config[:menu] == false ? nil : config[:menu]
|
290
|
+
end
|
291
|
+
|
292
|
+
# some convenience for instances
|
293
|
+
def layout_manager_class
|
294
|
+
self.class.layout_manager_class
|
295
|
+
end
|
296
|
+
|
297
|
+
def persistent_config_manager_class
|
298
|
+
self.class.persistent_config_manager_class
|
299
|
+
end
|
300
|
+
|
306
301
|
end
|
307
302
|
end
|
@@ -17,29 +17,35 @@ module Netzke
|
|
17
17
|
# The config that is sent from the server and is used for instantiating a widget
|
18
18
|
def js_config
|
19
19
|
res = {}
|
20
|
+
|
21
|
+
# Unique id of the widget
|
22
|
+
res.merge!(:id => @id_name)
|
20
23
|
|
21
|
-
#
|
24
|
+
# Recursively include configs of all non-late aggregatees, so that the widget can instantiate them in
|
25
|
+
# in the browser immediately.
|
22
26
|
aggregatees.each_pair do |aggr_name, aggr_config|
|
23
27
|
next if aggr_config[:late_aggregation]
|
24
28
|
res["#{aggr_name}_config".to_sym] = aggregatee_instance(aggr_name.to_sym).js_config
|
25
29
|
end
|
26
30
|
|
27
|
-
#
|
31
|
+
# Interface
|
28
32
|
interface = self.class.interface_points.inject({}){|h,interfacep| h.merge(interfacep => widget_action(interfacep))}
|
29
33
|
res.merge!(:interface => interface)
|
30
34
|
|
35
|
+
# Widget class name
|
31
36
|
res.merge!(:widget_class_name => short_widget_class_name)
|
32
|
-
|
37
|
+
|
38
|
+
# Include
|
33
39
|
res.merge!(js_ext_config)
|
34
|
-
res.merge!(:id => @id_name)
|
35
40
|
|
36
|
-
#
|
37
|
-
res.merge!(:tools => tools)
|
38
|
-
res.merge!(:actions => actions)
|
39
|
-
res.merge!(:
|
40
|
-
res.merge!(:
|
41
|
+
# Actions, toolbars and menus
|
42
|
+
tools && res.merge!(:tools => tools)
|
43
|
+
actions && res.merge!(:actions => actions)
|
44
|
+
tbar && res.merge!(:tbar => tbar)
|
45
|
+
bbar && res.merge!(:bbar => bbar)
|
46
|
+
menu && res.merge!(:menu => menu)
|
41
47
|
|
42
|
-
#
|
48
|
+
# Permissions
|
43
49
|
res.merge!(:permissions => permissions) unless available_permissions.empty?
|
44
50
|
|
45
51
|
res
|
@@ -69,7 +75,7 @@ module Netzke
|
|
69
75
|
|
70
76
|
# instantiating
|
71
77
|
def js_widget_instance
|
72
|
-
%Q{var #{config[:name].to_js} = new Ext.netzke.cache
|
78
|
+
%Q{var #{config[:name].to_js} = new Ext.netzke.cache.#{short_widget_class_name}(#{js_config.to_js});}
|
73
79
|
end
|
74
80
|
|
75
81
|
# rendering
|
@@ -88,9 +94,10 @@ module Netzke
|
|
88
94
|
|
89
95
|
# widget's actions, tools and toolbars that are loaded at the moment of instantiating a widget
|
90
96
|
def actions; nil; end
|
91
|
-
def tools; nil; end
|
92
97
|
def tbar; nil; end
|
93
98
|
def bbar; nil; end
|
99
|
+
def menu; nil; end
|
100
|
+
def tools; nil; end
|
94
101
|
|
95
102
|
# little helpers
|
96
103
|
def this; "this".l; end
|
@@ -150,50 +157,97 @@ module Netzke
|
|
150
157
|
def js_class
|
151
158
|
if js_inheritance
|
152
159
|
<<-JS
|
153
|
-
Ext.netzke.cache
|
154
|
-
constructor
|
155
|
-
|
156
|
-
|
157
|
-
}, #{js_extend_properties.to_js}]))
|
160
|
+
Ext.netzke.cache.#{short_widget_class_name} = function(config){
|
161
|
+
Ext.netzke.cache.#{short_widget_class_name}.superclass.constructor.call(this, config);
|
162
|
+
};
|
163
|
+
Ext.extend(Ext.netzke.cache.#{short_widget_class_name}, Ext.netzke.cache.#{js_base_class.short_widget_class_name}, Ext.applyIf(#{js_extend_properties.to_js}, Ext.widgetMixIn));
|
158
164
|
|
159
165
|
JS
|
160
166
|
else
|
161
167
|
js_add_menus = "this.addMenus(#{js_menus.to_js});" unless js_menus.empty?
|
162
168
|
<<-JS
|
163
|
-
Ext.netzke.cache
|
164
|
-
|
165
|
-
// comment
|
169
|
+
Ext.netzke.cache.#{short_widget_class_name} = function(config){
|
170
|
+
this.beforeConstructor(config);
|
166
171
|
#{js_before_constructor}
|
167
|
-
Ext.netzke.cache
|
168
|
-
this.
|
172
|
+
Ext.netzke.cache.#{short_widget_class_name}.superclass.constructor.call(this, Ext.apply(#{js_default_config.to_js}, config));
|
173
|
+
this.afterConstructor(config);
|
169
174
|
#{js_after_constructor}
|
170
175
|
#{js_add_menus}
|
171
|
-
|
172
|
-
}, #{js_extend_properties.to_js}
|
176
|
+
};
|
177
|
+
Ext.extend(Ext.netzke.cache.#{short_widget_class_name}, #{js_base_class}, Ext.applyIf(#{js_extend_properties.to_js}, Ext.widgetMixIn));
|
173
178
|
JS
|
174
179
|
end
|
175
180
|
end
|
176
181
|
|
182
|
+
#
|
183
|
+
# Include extra code from Ext js library (e.g. examples)
|
184
|
+
#
|
185
|
+
def ext_js_include(*args)
|
186
|
+
included_ext_js = read_inheritable_attribute(:included_ext_js) || []
|
187
|
+
args.each {|f| included_ext_js << f}
|
188
|
+
write_inheritable_attribute(:included_ext_js, included_ext_js)
|
189
|
+
end
|
190
|
+
|
191
|
+
#
|
192
|
+
# Include extra Javascript code. This code will be loaded along with the widget's class and in front of it.
|
193
|
+
#
|
194
|
+
# Example usage:
|
195
|
+
# js_include "File.dirname(__FILE__)/form_panel_extras/javascripts/xdatetime.js",
|
196
|
+
# :ext_examples => ["grid-filtering/menu/EditableItem.js", "grid-filtering/menu/RangeMenu.js"],
|
197
|
+
# "File.dirname(__FILE__)/form_panel_extras/javascripts/xcheckbox.js"
|
198
|
+
#
|
199
|
+
def js_include(*args)
|
200
|
+
included_js = read_inheritable_attribute(:included_js) || []
|
201
|
+
args.each do |inclusion|
|
202
|
+
if inclusion.is_a?(Hash)
|
203
|
+
# we are signalized a non-default file location (e.g. Ext examples)
|
204
|
+
case inclusion.keys.first
|
205
|
+
when :ext_examples
|
206
|
+
location = Netzke::Base.config[:ext_location] + "/examples/"
|
207
|
+
end
|
208
|
+
files = inclusion.values.first
|
209
|
+
else
|
210
|
+
location = ""
|
211
|
+
files = inclusion
|
212
|
+
end
|
213
|
+
|
214
|
+
files = [files] if files.is_a?(String)
|
215
|
+
|
216
|
+
for f in files
|
217
|
+
included_js << location + f
|
218
|
+
end
|
219
|
+
end
|
220
|
+
write_inheritable_attribute(:included_js, included_js)
|
221
|
+
end
|
222
|
+
|
177
223
|
# returns all extra js-code (as string) required by this widget's class
|
178
224
|
def js_included
|
179
225
|
# from extjs - defined in the widget class with ext_js_include
|
180
|
-
extjs_dir = "#{RAILS_ROOT}/public/extjs" # TODO: make extjs location configurable
|
181
|
-
|
182
|
-
res =
|
183
|
-
|
184
|
-
|
185
|
-
end
|
226
|
+
# extjs_dir = "#{RAILS_ROOT}/public/extjs" # TODO: make extjs location configurable
|
227
|
+
# begin
|
228
|
+
# res = super
|
229
|
+
# rescue
|
230
|
+
# raise self.superclass.to_s
|
231
|
+
# end
|
186
232
|
|
187
|
-
res
|
233
|
+
res = ""
|
188
234
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
for file_name in file_list
|
194
|
-
f = File.new(file_name)
|
195
|
-
res << f.read
|
235
|
+
included_js = read_inheritable_attribute(:included_js) || []
|
236
|
+
res << included_js.inject("") do |r, path|
|
237
|
+
f = File.new(path)
|
238
|
+
r << f.read
|
196
239
|
end
|
240
|
+
|
241
|
+
# res << "\n"
|
242
|
+
#
|
243
|
+
# # from <widget_name>_extras/javascripts - all *.js files found there
|
244
|
+
# js_dir = File.join(File.dirname(widget_file), short_widget_class_name.underscore + "_extras", "javascripts")
|
245
|
+
# file_list = Dir.glob("#{js_dir}/*.js")
|
246
|
+
#
|
247
|
+
# for file_name in file_list
|
248
|
+
# f = File.new(file_name)
|
249
|
+
# res << f.read
|
250
|
+
# end
|
197
251
|
|
198
252
|
res
|
199
253
|
end
|
@@ -214,19 +268,19 @@ JS
|
|
214
268
|
end
|
215
269
|
|
216
270
|
# returns all css code require by this widget's class
|
217
|
-
def css_included
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
end
|
271
|
+
# def css_included
|
272
|
+
# res = ""
|
273
|
+
# # from <widget_name>_extras/stylesheets - all *.css files found there
|
274
|
+
# js_dir = File.join(File.dirname(widget_file), short_widget_class_name.underscore + "_extras", "stylesheets")
|
275
|
+
# file_list = Dir.glob("#{js_dir}/*.css")
|
276
|
+
#
|
277
|
+
# for file_name in file_list
|
278
|
+
# f = File.new(file_name)
|
279
|
+
# res << f.read
|
280
|
+
# end
|
281
|
+
#
|
282
|
+
# res
|
283
|
+
# end
|
230
284
|
|
231
285
|
# all JS code needed for this class including the one from the ancestor widget
|
232
286
|
def css_code(cached_dependencies = [])
|
@@ -235,7 +289,7 @@ JS
|
|
235
289
|
# include the base-class javascript if doing JS inheritance
|
236
290
|
res << js_base_class.css_code << "\n" if js_inheritance && !cached_dependencies.include?(js_base_class.short_widget_class_name)
|
237
291
|
|
238
|
-
res << css_included << "\n"
|
292
|
+
# res << css_included << "\n"
|
239
293
|
|
240
294
|
res
|
241
295
|
end
|
data/lib/netzke/core_ext.rb
CHANGED
@@ -12,7 +12,6 @@ class Hash
|
|
12
12
|
|
13
13
|
# First camelizes the keys, then convert the whole hash to JSON
|
14
14
|
def to_js
|
15
|
-
# self.delete_if{ |k,v| v.nil? } # we don't need to explicitely pass null values to javascript
|
16
15
|
self.recursive_delete_if_nil.convert_keys{|k| k.camelize(:lower)}.to_json
|
17
16
|
end
|
18
17
|
|
@@ -21,6 +20,7 @@ class Hash
|
|
21
20
|
self.each_pair{|k,v| self[k] = v.to_s if v.is_a?(Symbol)}
|
22
21
|
end
|
23
22
|
|
23
|
+
# We don't need to pass null values in JSON, they are null by simply being absent
|
24
24
|
def recursive_delete_if_nil
|
25
25
|
self.inject({}) do |h,(k,v)|
|
26
26
|
if !v.nil?
|
data/lib/netzke-core.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
1
3
|
# NetzkeCore
|
2
4
|
require 'netzke/base'
|
5
|
+
|
3
6
|
require 'netzke/action_view_ext'
|
4
7
|
require 'netzke/controller_extensions'
|
5
8
|
require 'netzke/core_ext'
|
@@ -34,6 +37,7 @@ end
|
|
34
37
|
# Make this plugin auto-reloadable for easier development
|
35
38
|
ActiveSupport::Dependencies.load_once_paths.delete(File.join(File.dirname(__FILE__)))
|
36
39
|
|
37
|
-
# Include javascript & styles
|
40
|
+
# Include javascript & styles required by all Netzke widgets.
|
41
|
+
# These files will get loaded at the initial load of the framework (along with Ext).
|
38
42
|
Netzke::Base.config[:javascripts] << "#{File.dirname(__FILE__)}/../javascripts/core.js"
|
39
|
-
Netzke::Base.config[:
|
43
|
+
Netzke::Base.config[:stylesheets] << "#{File.dirname(__FILE__)}/../stylesheets/core.css"
|
data/netzke-core.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{netzke-core}
|
5
|
-
s.version = "0.2.
|
5
|
+
s.version = "0.2.9"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Sergei Kozlov"]
|
9
|
-
s.date = %q{2009-03-
|
9
|
+
s.date = %q{2009-03-19}
|
10
10
|
s.description = %q{Build ExtJS/Rails widgets with minimum effort}
|
11
11
|
s.email = %q{sergei@writelesscode.com}
|
12
|
-
s.extra_rdoc_files = ["CHANGELOG", "lib/app/controllers/netzke_controller.rb", "lib/app/models/netzke_layout.rb", "lib/app/models/netzke_preference.rb", "lib/netzke/action_view_ext.rb", "lib/netzke/base.rb", "lib/netzke/base_extras/interface.rb", "lib/netzke/base_extras/js_builder.rb", "lib/netzke/controller_extensions.rb", "lib/netzke/core_ext.rb", "lib/netzke/feedback_ghost.rb", "lib/netzke/routing.rb", "lib/netzke-core.rb", "lib/vendor/facets/hash/recursive_merge.rb", "LICENSE", "README.mdown", "tasks/netzke_core_tasks.rake"]
|
13
|
-
s.files = ["CHANGELOG", "
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "lib/app/controllers/netzke_controller.rb", "lib/app/models/netzke_layout.rb", "lib/app/models/netzke_preference.rb", "lib/netzke/action_view_ext.rb", "lib/netzke/base.rb", "lib/netzke/base_extras/interface.rb", "lib/netzke/base_extras/js_builder.rb", "lib/netzke/controller_extensions.rb", "lib/netzke/core_ext.rb", "lib/netzke/feedback_ghost.rb", "lib/netzke/routing.rb", "lib/netzke-core.rb", "lib/vendor/facets/hash/recursive_merge.rb", "LICENSE", "README.mdown", "tasks/netzke_core_tasks.rake", "TODO"]
|
13
|
+
s.files = ["CHANGELOG", "generators/netzke_core/netzke_core_generator.rb", "generators/netzke_core/templates/create_netzke_layouts.rb", "generators/netzke_core/templates/create_netzke_preferences.rb", "generators/netzke_core/USAGE", "init.rb", "install.rb", "javascripts/core.js", "lib/app/controllers/netzke_controller.rb", "lib/app/models/netzke_layout.rb", "lib/app/models/netzke_preference.rb", "lib/netzke/action_view_ext.rb", "lib/netzke/base.rb", "lib/netzke/base_extras/interface.rb", "lib/netzke/base_extras/js_builder.rb", "lib/netzke/controller_extensions.rb", "lib/netzke/core_ext.rb", "lib/netzke/feedback_ghost.rb", "lib/netzke/routing.rb", "lib/netzke-core.rb", "lib/vendor/facets/hash/recursive_merge.rb", "LICENSE", "Manifest", "netzke-core.gemspec", "Rakefile", "README.mdown", "stylesheets/core.css", "tasks/netzke_core_tasks.rake", "test/app_root/app/controllers/application.rb", "test/app_root/config/boot.rb", "test/app_root/config/database.yml", "test/app_root/config/environment.rb", "test/app_root/config/environments/in_memory.rb", "test/app_root/config/environments/mysql.rb", "test/app_root/config/environments/postgresql.rb", "test/app_root/config/environments/sqlite.rb", "test/app_root/config/environments/sqlite3.rb", "test/app_root/config/routes.rb", "test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb", "test/app_root/script/console", "test/core_ext_test.rb", "test/netzke_core_test.rb", "test/netzke_preference_test.rb", "test/test_helper.rb", "TODO", "uninstall.rb"]
|
14
14
|
s.has_rdoc = true
|
15
15
|
s.homepage = %q{http://writelesscode.com}
|
16
16
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Netzke-core", "--main", "README.mdown"]
|
data/test/netzke_core_test.rb
CHANGED
@@ -160,8 +160,8 @@ class NetzkeCoreTest < ActiveSupport::TestCase
|
|
160
160
|
|
161
161
|
test "js inheritance" do
|
162
162
|
widget = JsInheritanceWidget.new
|
163
|
-
assert(widget.js_missing_code.index("Ext.netzke.cache
|
164
|
-
assert(widget.js_missing_code.index("Ext.netzke.cache
|
163
|
+
assert(widget.js_missing_code.index("Ext.netzke.cache.JsInheritanceWidget"))
|
164
|
+
assert(widget.js_missing_code.index("Ext.netzke.cache.Widget"))
|
165
165
|
end
|
166
166
|
# test "multiuser" do
|
167
167
|
# Netzke::Base.current_user = User.new(1)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: netzke-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sergei Kozlov
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-03-
|
12
|
+
date: 2009-03-19 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -37,9 +37,9 @@ extra_rdoc_files:
|
|
37
37
|
- LICENSE
|
38
38
|
- README.mdown
|
39
39
|
- tasks/netzke_core_tasks.rake
|
40
|
+
- TODO
|
40
41
|
files:
|
41
42
|
- CHANGELOG
|
42
|
-
- css/core.css
|
43
43
|
- generators/netzke_core/netzke_core_generator.rb
|
44
44
|
- generators/netzke_core/templates/create_netzke_layouts.rb
|
45
45
|
- generators/netzke_core/templates/create_netzke_preferences.rb
|
@@ -65,6 +65,7 @@ files:
|
|
65
65
|
- netzke-core.gemspec
|
66
66
|
- Rakefile
|
67
67
|
- README.mdown
|
68
|
+
- stylesheets/core.css
|
68
69
|
- tasks/netzke_core_tasks.rake
|
69
70
|
- test/app_root/app/controllers/application.rb
|
70
71
|
- test/app_root/config/boot.rb
|
@@ -82,6 +83,7 @@ files:
|
|
82
83
|
- test/netzke_core_test.rb
|
83
84
|
- test/netzke_preference_test.rb
|
84
85
|
- test/test_helper.rb
|
86
|
+
- TODO
|
85
87
|
- uninstall.rb
|
86
88
|
has_rdoc: true
|
87
89
|
homepage: http://writelesscode.com
|