netzke-core 0.8.3 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/Gemfile +1 -0
  4. data/README.md +9 -3
  5. data/javascripts/base.js +15 -8
  6. data/javascripts/ext.js +145 -70
  7. data/lib/netzke/base.rb +33 -10
  8. data/lib/netzke/core.rb +1 -0
  9. data/lib/netzke/core/action_config.rb +3 -3
  10. data/lib/netzke/core/actions.rb +34 -2
  11. data/lib/netzke/core/component_config.rb +3 -2
  12. data/lib/netzke/core/composition.rb +19 -36
  13. data/lib/netzke/core/configuration.rb +1 -3
  14. data/lib/netzke/core/dsl_config_base.rb +9 -0
  15. data/lib/netzke/core/dsl_support.rb +6 -6
  16. data/lib/netzke/core/javascript.rb +11 -5
  17. data/lib/netzke/core/railz/controller_extensions.rb +56 -28
  18. data/lib/netzke/core/services.rb +20 -6
  19. data/lib/netzke/core/version.rb +1 -1
  20. data/test/core_test_app/app/components/actions.rb +2 -0
  21. data/test/core_test_app/app/components/composition.rb +1 -0
  22. data/test/core_test_app/app/components/dynamic_loading.rb +7 -11
  23. data/test/core_test_app/app/components/dynamic_loading/javascripts/dynamic_loading.js +1 -1
  24. data/test/core_test_app/app/components/endpoints.rb +15 -1
  25. data/test/core_test_app/app/components/endpoints/javascripts/endpoints.js +6 -2
  26. data/test/core_test_app/app/components/hello_user.rb +12 -0
  27. data/test/core_test_app/app/components/hello_world/javascripts/hello_world.js +1 -1
  28. data/test/core_test_app/app/components/multi_instance_loading.rb +18 -0
  29. data/test/core_test_app/app/components/multi_instance_loading/javascripts/multi_instance_loading.js +18 -0
  30. data/test/core_test_app/app/components/persistence.rb +1 -1
  31. data/test/core_test_app/app/components/session_expiration.rb +21 -0
  32. data/test/core_test_app/app/components/simple_component.rb +1 -1
  33. data/test/core_test_app/config/initializers/javascripts/session_expiration.js +6 -0
  34. data/test/core_test_app/config/initializers/netzke.rb +3 -1
  35. data/test/core_test_app/log/development.log +46574 -0
  36. data/test/core_test_app/log/test.log +67624 -0
  37. data/test/core_test_app/tmp/cache/assets/C92/5A0/sprockets%2F39e75754782ee12179bf35c9a0971d80 +0 -0
  38. data/test/core_test_app/tmp/cache/assets/C9F/750/sprockets%2F20ce3d64040a5d3a0a8883bd60754356 +0 -0
  39. data/test/core_test_app/tmp/cache/assets/CC4/C00/sprockets%2Fc615df52887d8c2e67e8413576a419c5 +0 -0
  40. data/test/core_test_app/tmp/cache/assets/D0E/870/sprockets%2Fa593bf4fac106add88c9434141a49663 +0 -0
  41. data/test/core_test_app/tmp/cache/assets/D14/8E0/sprockets%2F20748e8d1d7d090d122904a9fe6f18fc +0 -0
  42. data/test/core_test_app/tmp/cache/assets/D3E/DA0/sprockets%2Fa175f1ac5996544b908ba3ba3f64c4f3 +0 -0
  43. data/test/core_test_app/tmp/cache/assets/D43/C00/sprockets%2F7bc60c758776356d615ab5edff201ee2 +0 -0
  44. data/test/core_test_app/tmp/cache/assets/D98/9C0/sprockets%2F18b80e8fe200aebc522e561a867ea6fb +0 -0
  45. data/test/core_test_app/tmp/cache/assets/DB0/6E0/sprockets%2F03e33f5a4779eeb48bcfc86ee717fb55 +0 -0
  46. metadata +13 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ece4a46f4a0c3492187c9ae655f1eeca26dfdd55
4
- data.tar.gz: 7cd2bbee3fc83355f8d3f043706d5849646a093d
3
+ metadata.gz: 55fca10ef68267045dcd10e37b97ae453c7ec861
4
+ data.tar.gz: bf701fb44bcb1d3ce8eeb588d605506037c2ad7d
5
5
  SHA512:
6
- metadata.gz: 4011ff3d2e6a8990b4a52f354eb8dea35b5bcc45d88870deb240d883835ed0796268fe540fdaec46ad5587934864165a8da7ef7dc655f47d32d635ba35c70671
7
- data.tar.gz: 0acff09f2bd2eadfec95b50a337067234ec62cd6b453f16432edb4ef17c11218143ddc8c4e081cbeb30b7a75950e976a9b560027173f27f24c85f4ec2db31171
6
+ metadata.gz: a8ab0114b06c034a7f2916b529fcfd2d6812573b880676e05de202d8bf5bc8e5feffee6619f21c402cff5415ac12293d39026d2aaa6e178787722d19b06547d8
7
+ data.tar.gz: 3116eebeb560d37dbadafdc12c2694d6c76c9b58f12015770ddea379621dd26e5308e28a0813f646ff7fb0f9614f96a19024fa6cf87ea77d681249226da80c8c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # v0.8.4 - 2013-05-22
2
+ * bug fix
3
+ * Re-enable session expiration detection
4
+ * Do not crash on a rare situation when an endpoint is being called on an non-existing child component
5
+ * improvements
6
+ * Add `serverexception` event on `Netzke.directProvider`, subscribe to it to handle server exceptions
7
+ * Endpoint calls will now pass Ext.direct.Exception to the provided callback function in case of server exception
8
+ * A component will clean-up the loading mask when a server exception occurs during dynamic component loading
9
+ * `netzkeFeedback` now shows multiple messages in a single slide banner
10
+ * Implement multi-instance child component loading with different configuration (see MultiInstanceLoading in the test app)
11
+
1
12
  # v0.8.3 - 2013-03-22
2
13
  * support Rails 3.2.13
3
14
 
data/Gemfile CHANGED
@@ -6,6 +6,7 @@ gem 'haml'
6
6
 
7
7
  group :test do
8
8
  gem 'capybara'
9
+ gem 'selenium-webdriver'
9
10
  gem 'database_cleaner'
10
11
  gem 'rspec-rails'
11
12
  gem 'pry-rails'
data/README.md CHANGED
@@ -8,7 +8,7 @@ Some knowledge of Sencha Ext JS will be needed in order to fully understand this
8
8
 
9
9
  ## Rationale
10
10
 
11
- [Sencha Ext JS]("http://www.sencha.com/products/extjs") is a powerful front-end framework, which is used for crafting web-apps that give the end user experience similar to that of a desktop application. It has an extensive set of widgets ('components'), and leverages a modular approach to its fullest: a developer can extend components (using Ext JS's own [class system]("http://docs.sencha.com/ext-js/4-1/#!/guide/class_system")), nest components using many powerful layouts, dynamically create and destroy them. The architecture of Ext JS is well-thought and very complete.
11
+ [Sencha Ext JS]("http://www.sencha.com/products/extjs") is a powerful front-end framework, which is used for crafting web-apps that give the end user experience similar to that of a desktop application. It has an extensive set of widgets ('components'), and leverages a modular approach to its fullest: a developer can extend components (using Ext JS's own [class system]("http://docs.sencha.com/ext-js/4-1/#!/guide/class_system")), nest components using many powerful layouts, dynamically create and destroy them. The architecture of Ext JS is well thought out and very complete.
12
12
 
13
13
  However, with Ext JS being server-agnostic, it is not always a trivial task for a developer to bind Ext JS components to the server-side data *and* application business logic, especially in complex applications. Netzke as the solution that allows you to extend the modular approach to the server side.
14
14
 
@@ -25,11 +25,11 @@ Netzke Core takes the burden of implementing the following key aspects of the fr
25
25
 
26
26
  ...and more.
27
27
 
28
- All this extremely facilitates building fast, low-traffic, robust, and highly maintainable applications. As a result, your code scales much better in the sense of complexity, compared to using conventional MVC, where developers are pretty much limited with programming techniques they can apply.
28
+ All this extremely facilitates building fast, low-traffic, robust, and highly maintainable applications. As a result, your code scales much better in the sense of complexity, compared to using conventional MVC, where developers are pretty much limited with the programming techniques that they can apply.
29
29
 
30
30
  ## HelloWorld component
31
31
 
32
- *This component is distributed as a part of the test application, see `test/core_test_app/components`.*
32
+ *This component is distributed as a part of the test application, see `test/core_test_app/components/hello_world.rb`.*
33
33
 
34
34
  Ext JS files are not distributed with Netzke, so, make sure that they are located in (or sym-linked as) `YOUR_APP/public/extjs`.
35
35
 
@@ -365,6 +365,12 @@ This assumes that the Ext JS library is located/symlinked in `test/core_test_app
365
365
 
366
366
  $ EXTJS_SRC=cdn rake
367
367
 
368
+ ## Contributions and support
369
+
370
+ Help developing Netzke by submitting a pull request when you think others can benefit from it.
371
+
372
+ If you feel particularily generous, you can donate a couple of bucks a week at [GitTip](https://www.gittip.com/nomadcoder/).
373
+
368
374
  ## Useful links
369
375
 
370
376
  * [Project website](http://netzke.org)
data/javascripts/base.js CHANGED
@@ -47,10 +47,6 @@ Netzke.isLoading=function () {
47
47
  // xtypes of cached Netzke classes
48
48
  Netzke.cache = [];
49
49
 
50
- Netzke.componentNotInSessionHandler = function() {
51
- throw "Netzke: component not in Rails session. Define Netzke.componentNotInSessionHandler to handle this.";
52
- };
53
-
54
50
  Ext.define("Netzke.classes.Core.Mixin", {
55
51
  isNetzke: true, // to distinguish Netzke components from regular Ext components
56
52
 
@@ -111,6 +107,8 @@ Ext.define("Netzke.classes.Core.Mixin", {
111
107
  } else {
112
108
  for (var instr in instructions) {
113
109
  var args = instructions[instr];
110
+ if(args instanceof Object && Ext.isEmpty(args))
111
+ args = [];
114
112
 
115
113
  if (Ext.isFunction(this[instr])) {
116
114
  // Executing the method.
@@ -120,7 +118,7 @@ Ext.define("Netzke.classes.Core.Mixin", {
120
118
  if (childComponent) {
121
119
  childComponent.netzkeBulkExecute(args);
122
120
  } else if (Ext.isArray(args)) { // only consider those calls that have arguments wrapped in an array; the only (probably) case when they are not, is with 'success' property set to true in a non-ajax form submit - silently ignore that
123
- throw "Netzke: Unknown method or child component '" + instr +"' in component '" + this.id + "'"
121
+ throw "Netzke: Unknown method or child component '" + instr + "' in component '" + this.id + "'"
124
122
  }
125
123
  }
126
124
  }
@@ -135,11 +133,20 @@ Ext.define("Netzke.classes.Core.Mixin", {
135
133
  },
136
134
 
137
135
  /**
138
- * When an endpoint call is issued while the session has expired, this method is called. Override it to do whatever is appropriate.
136
+ * This method gets called by the server when the component to which an endpoint call was directed to, is not in the session anymore.
139
137
  * @private
140
138
  */
141
- netzkeComponentNotInSession: function() {
142
- Netzke.componentNotInSessionHandler();
139
+ netzkeSessionExpired: function() {
140
+ this.netzkeSessionIsExpired = true;
141
+ this.onNetzkeSessionExpired();
142
+ },
143
+
144
+ /**
145
+ * Override this method to handle session expiration. E.g. you may want to inform the user that they will be redirected to the login page.
146
+ * @private
147
+ */
148
+ onNetzkeSessionExpired: function() {
149
+ Netzke.warning("Component not in session. Override `onNetzkeSessionExpired` to handle this.");
143
150
  },
144
151
 
145
152
  /**
data/javascripts/ext.js CHANGED
@@ -56,22 +56,37 @@ Ext.define('Netzke.FeedbackGhost', {
56
56
  Ext.define('Netzke.classes.NetzkeRemotingProvider', {
57
57
  extend: 'Ext.direct.RemotingProvider',
58
58
 
59
+ initComponent: function() {
60
+ this.callParent();
61
+ this.addEvent('serverexception'); // because 'exception' is reserved by Ext JS (but never used!)
62
+ },
63
+
64
+ listeners: {
65
+ // work-around the fact that 'exception' is never thrown by Ext JS
66
+ data: function(self, e) {
67
+ if (Ext.getClass(e) == Ext.direct.ExceptionEvent) {
68
+ this.fireEvent('serverexception', e);
69
+ }
70
+ }
71
+ },
72
+
59
73
  getCallData: function(t){
60
74
  return {
61
- act: t.action, // rails doesn't really support having a parameter named "action"
62
- method: t.method,
75
+ path: t.action,
76
+ endpoint: t.method,
63
77
  data: t.data,
64
- type: 'rpc',
65
78
  tid: t.id
66
79
  }
67
80
  },
68
81
 
69
- addAction: function(action, methods) {
70
- var cls = this.namespace[action] || (this.namespace[action] = {});
71
- for(var i = 0, len = methods.length; i < len; i++){
72
- method = Ext.create('Ext.direct.RemotingMethod', methods[i]);
73
- cls[method.name] = this.createHandler(action, method);
74
- }
82
+ addEndpointsForComponent: function(componentPath, endpoints) {
83
+ var cls = this.namespace[componentPath] || (this.namespace[componentPath] = {});
84
+
85
+ Ext.Array.each(endpoints, function(ep) {
86
+ var methodName = ep.camelize(true),
87
+ method = Ext.create('Ext.direct.RemotingMethod', {name: methodName, len: 1, blah: 666});
88
+ cls[methodName] = this.createHandler(componentPath, method);
89
+ }, this);
75
90
  },
76
91
 
77
92
  // HACK: Ext JS 4.0.0 retry mechanism is broken
@@ -84,11 +99,25 @@ Ext.define('Netzke.classes.NetzkeRemotingProvider', {
84
99
  }
85
100
  });
86
101
 
102
+ Netzke.directProvider = new Netzke.classes.NetzkeRemotingProvider({
103
+ type: "remoting", // create a Ext.direct.RemotingProvider
104
+ url: Netzke.ControllerUrl + "direct/", // url to connect to the Ext.Direct server-side router.
105
+ namespace: "Netzke.providers", // Netzke.providers will have a key per Netzke component, each mapped to a hash with a RemotingMethod per endpoint
106
+ actions: {},
107
+ maxRetries: Netzke.core.directMaxRetries,
108
+ enableBuffer: true, // buffer/batch requests within 10ms timeframe
109
+ timeout: 30000 // 30s timeout per request
110
+ });
111
+
112
+ Ext.Direct.addProvider(Netzke.directProvider);
113
+
87
114
  // Override Ext.Component's constructor to enable Netzke features
88
115
  Ext.define(null, {
89
116
  override: 'Ext.Component',
90
117
  constructor: function(config) {
91
118
  if (this.isNetzke) {
119
+ // component loading index
120
+ this.netzkeLoadingIndex = 0;
92
121
 
93
122
  this.netzkeComponents = config.netzkeComponents;
94
123
  this.passedConfig = config;
@@ -116,18 +145,6 @@ Ext.define(null, {
116
145
  }
117
146
  });
118
147
 
119
- Netzke.directProvider = new Netzke.classes.NetzkeRemotingProvider({
120
- type: "remoting", // create a Ext.direct.RemotingProvider
121
- url: Netzke.ControllerUrl + "direct/", // url to connect to the Ext.Direct server-side router.
122
- namespace: "Netzke.providers", // namespace to create the Remoting Provider in
123
- actions: {},
124
- maxRetries: Netzke.core.directMaxRetries,
125
- enableBuffer: true, // buffer/batch requests within 10ms timeframe
126
- timeout: 30000 // 30s timeout per request
127
- });
128
-
129
- Ext.Direct.addProvider(Netzke.directProvider);
130
-
131
148
  // Methods/properties that each and every Netzke component will have
132
149
  Ext.define(null, {
133
150
  override: 'Netzke.classes.Core.Mixin',
@@ -159,34 +176,70 @@ Ext.define(null, {
159
176
  netzkeProcessEndpoints: function(config){
160
177
  var endpoints = config.endpoints || [];
161
178
  endpoints.push('deliver_component'); // all Netzke components get this endpoint
162
- var directActions = [];
179
+
180
+ Netzke.directProvider.addEndpointsForComponent(config.path, endpoints);
181
+
163
182
  var that = this;
164
183
 
165
- Ext.each(endpoints, function(intp){
166
- directActions.push({"name":intp.camelize(true), "len":1});
167
- this[intp.camelize(true)] = function(arg, callback, scope) {
184
+ Ext.each(endpoints, function(ep){
185
+ var methodName = ep.camelize(true);
186
+
187
+ /* add endpoint method to `this` */
188
+ this[methodName] = function(args, callback, scope) {
168
189
  Netzke.runningRequests++;
169
190
 
170
191
  scope = scope || that;
171
- Netzke.providers[config.id][intp.camelize(true)].call(scope, arg, function(result, remotingEvent) {
172
- if(remotingEvent.message) {
173
- console.error("RPC event indicates an error: ", remotingEvent);
174
- throw new Error(remotingEvent.message);
192
+
193
+ var cfgs = this.buildParentClientConfigs();
194
+ var remotingArgs = {args: args, configs: cfgs};
195
+
196
+ Netzke.providers[config.path][methodName].call(scope, remotingArgs, function(result, e) {
197
+ var callbackParam = e;
198
+
199
+ if (Ext.getClass(e) == Ext.direct.RemotingEvent) { // means we didn't get an exception
200
+ that.netzkeBulkExecute(result); // invoke the endpoint result on the calling component
201
+ callbackParam = that.latestResult;
175
202
  }
176
- that.netzkeBulkExecute(result); // invoke the endpoint result on the calling component
177
- if(typeof callback == "function") {
178
- callback.call(scope, that.latestResult); // invoke the callback on the provided scope, or on the calling component if no scope set. Pass latestResult to callback
203
+
204
+ if (typeof callback == "function" && !scope.netzkeSessionIsExpired) {
205
+ callback.call(scope, callbackParam); // invoke the callback on the provided scope, or on the calling component if no scope set. Pass latestResult to callback in case of success, or the Ext.direct.ExceptionEvent otherwise
179
206
  }
207
+
180
208
  Netzke.runningRequests--;
181
209
  });
182
210
  }
183
211
  }, this);
184
212
 
185
- Netzke.directProvider.addAction(config.id, directActions);
186
-
187
213
  delete config.endpoints;
188
214
  },
189
215
 
216
+ /**
217
+ * Array of client configs for each parent down the tree
218
+ * @private
219
+ */
220
+ buildParentClientConfigs: function() {
221
+ if (!this._parentClientConfig) {
222
+ this._parentClientConfig = [];
223
+ var parent = this;
224
+ while (parent) {
225
+ var cfg = parent.clientConfig || {};
226
+ cfg.id = parent.id;
227
+ this._parentClientConfig.unshift(cfg);
228
+ parent = parent.netzkeGetParentComponent();
229
+ }
230
+ }
231
+
232
+ return this._parentClientConfig;
233
+ },
234
+
235
+ /**
236
+ * @private
237
+ * Handles endpoint exceptions. Ext.direct.ExceptionEvent gets passed as parameter. Override to handle server side exceptions.
238
+ */
239
+ onDirectException: function(e) {
240
+ Netzke.warning("Server error. Override onDirectException to handle this.");
241
+ },
242
+
190
243
  /**
191
244
  * @private
192
245
  */
@@ -232,6 +285,7 @@ Ext.define(null, {
232
285
  * @param {Object} config Can contain the following keys:
233
286
  * 'container' - if specified, the instance (or id) of a panel with the 'fit' layout where the loaded component will be added to; the previously existing component will be destroyed
234
287
  * 'append' - if set to +true+, do not clear the container before adding the loaded component
288
+ * 'clone' - if set to +true+, allows loading multiple instances of the same child component
235
289
  * 'callback' - function that gets called after the component is loaded; it receives the component's instance as parameter
236
290
  * 'configOnly' - if set to +true+, do not instantiate the component, instead pass its config to the callback function
237
291
  * 'params' - object passed to the endpoint, may be useful for extra configuration
@@ -254,6 +308,7 @@ Ext.define(null, {
254
308
  netzkeLoadComponent: function(){
255
309
  var params;
256
310
 
311
+ // support 2 different signatures
257
312
  if (Ext.isString(arguments[0])) {
258
313
  params = arguments[1] || {};
259
314
  params.name = arguments[0];
@@ -264,14 +319,26 @@ Ext.define(null, {
264
319
  if (params.container == undefined) params.container = this;
265
320
  params.name = params.name.underscore();
266
321
 
267
- // params that will be provided for the server API call (deliver_component); all what's passed in params.params is merged in. This way we exclude from sending along such things as :scope, :callback, etc.
322
+ /* params that will be provided for the server API call (deliver_component); all what's passed in params.params is
323
+ * merged in. This way we exclude from sending along such things as :scope and :callback */
268
324
  var serverParams = params.params || {};
269
- serverParams.name = params.name;
325
+ serverParams["name"] = params.name;
326
+ serverParams["client_config"] = params.clientConfig;
327
+
328
+ // by which the loaded component will be referred in +netzkeComponentDelivered+
329
+ var itemId = params.name;
330
+
331
+ // multi-instance loading
332
+ if (params.clone) {
333
+ serverParams["index"] = this.netzkeLoadingIndex;
334
+ itemId += this.netzkeLoadingIndex; // << index
335
+ this.netzkeLoadingIndex++;
336
+ }
270
337
 
271
338
  // coma-separated list of xtypes of already loaded classes
272
- serverParams.cache = Netzke.cache.join();
339
+ serverParams["cache"] = Netzke.cache.join();
273
340
 
274
- var storedConfig = this.componentsBeingLoaded[params.name] = params;
341
+ var storedConfig = this.componentsBeingLoaded[itemId] = params;
275
342
 
276
343
  // Remember where the loaded component should be inserted into
277
344
  var containerCmp = params.container && Ext.isString(params.container) ? Ext.getCmp(params.container) : params.container;
@@ -284,8 +351,12 @@ Ext.define(null, {
284
351
  storedConfig.loadMaskCmp.show();
285
352
  }
286
353
 
287
- // do the remote API call
288
- this.deliverComponent(serverParams);
354
+ // Call the endpoint
355
+ this.deliverComponent(serverParams, function(e) {
356
+ if (Ext.getClass(e) == Ext.direct.ExceptionEvent) {
357
+ this.netzkeUndoLoadingComponent(params.name);
358
+ }
359
+ }, this);
289
360
  },
290
361
 
291
362
  /**
@@ -293,15 +364,8 @@ Ext.define(null, {
293
364
  * @private
294
365
  */
295
366
  netzkeComponentDelivered: function(config){
296
- // retrieve the loading config for this component
297
- var storedConfig = this.componentsBeingLoaded[config.name] || {};
298
- var callbackParam;
299
- delete this.componentsBeingLoaded[config.name];
300
-
301
- if (storedConfig.loadMaskCmp) {
302
- storedConfig.loadMaskCmp.hide();
303
- storedConfig.loadMaskCmp.destroy();
304
- }
367
+ var storedConfig = this.netzkeUndoLoadingComponent(config.itemId),
368
+ callbackParam;
305
369
 
306
370
  if (storedConfig.configOnly) {
307
371
  callbackParam = config;
@@ -329,12 +393,28 @@ Ext.define(null, {
329
393
  }
330
394
  },
331
395
 
396
+ /**
397
+ * Destroys the loading mask and removes the component from componentsBeingLoaded
398
+ * @private
399
+ */
400
+ netzkeUndoLoadingComponent: function(itemId) {
401
+ var storedConfig = this.componentsBeingLoaded[itemId] || {};
402
+ delete this.componentsBeingLoaded[itemId];
403
+
404
+ if (storedConfig.loadMaskCmp) {
405
+ storedConfig.loadMaskCmp.hide();
406
+ storedConfig.loadMaskCmp.destroy();
407
+ }
408
+
409
+ return storedConfig;
410
+ },
411
+
332
412
  /**
333
413
  * @private
334
414
  */
335
415
  netzkeComponentDeliveryFailed: function(params) {
336
- var storedConfig = this.componentsBeingLoaded[params.componentName] || {};
337
- delete this.componentsBeingLoaded[params.componentName];
416
+ var storedConfig = this.componentsBeingLoaded[params.itemId] || {};
417
+ delete this.componentsBeingLoaded[params.itemId];
338
418
 
339
419
  if (storedConfig.loadMaskCmp) {
340
420
  storedConfig.loadMaskCmp.hide();
@@ -377,7 +457,8 @@ Ext.define(null, {
377
457
  */
378
458
  netzkeInstantiateComponent: function(name) {
379
459
  name = name.camelize(true);
380
- return Ext.createByAlias(this.netzkeComponents[name].alias, this.netzkeComponents[name])
460
+ var cfg = this.netzkeComponents[name];
461
+ return Ext.createByAlias(this.netzkeComponents[name].alias, cfg)
381
462
  },
382
463
 
383
464
  /**
@@ -399,27 +480,23 @@ Ext.define(null, {
399
480
 
400
481
  /**
401
482
  * Provides a visual feedback. TODO: refactor
483
+ * msg can be a string, an array of strings, an object in form {msg: 'Message'}, or an array of such objects.
402
484
  */
403
485
  netzkeFeedback: function(msg, options){
404
486
  if (this.initialConfig && this.initialConfig.quiet) return false;
405
487
 
406
488
  options = options || {};
407
489
 
408
- if (this.feedbackGhost) {
409
- this.feedbackGhost.showFeedback(msg, {delay: options.delay});
410
- } else {
411
- // there's no application to show the feedback - so, we do it ourselves
412
- if (typeof msg == 'string'){
413
- alert(msg);
414
- } else {
415
- var compoundResponse = "";
416
- Ext.each(msg, function(m){
417
- compoundResponse += m.msg + "\n"
418
- });
419
- if (compoundResponse != "") {
420
- alert(compoundResponse);
421
- }
422
- }
490
+ if (typeof msg == 'string'){ msg = [msg]; }
491
+
492
+ var feedback = "";
493
+
494
+ Ext.each(msg, function(m){
495
+ feedback += m.msg || m + "<br/>"
496
+ });
497
+
498
+ if (feedback != "") {
499
+ this.feedbackGhost.showFeedback(feedback, {delay: options.delay});
423
500
  }
424
501
  },
425
502
 
@@ -465,7 +542,5 @@ Ext.define(null, {
465
542
  }, this);
466
543
  delete config.netzkePlugins;
467
544
  }
468
- },
469
-
470
- // netzkeOnComponentLoad: Ext.emptyFn // gets overridden
545
+ }
471
546
  });