netzke-core 0.12.3 → 1.0.0.0.pre

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.
Files changed (41) hide show
  1. data/CHANGELOG.md +65 -607
  2. data/Gemfile +1 -1
  3. data/LICENSE +2 -6
  4. data/README.md +77 -145
  5. data/javascripts/base.js +582 -96
  6. data/javascripts/core.js +62 -0
  7. data/javascripts/notifications.js +43 -0
  8. data/javascripts/remoting_provider.js +29 -0
  9. data/javascripts/routing.js +63 -0
  10. data/lib/netzke/base.rb +16 -83
  11. data/lib/netzke/core/action_config.rb +1 -5
  12. data/lib/netzke/core/actions.rb +59 -21
  13. data/lib/netzke/core/{client_class.rb → client_class_config.rb} +81 -73
  14. data/lib/netzke/core/client_code.rb +157 -0
  15. data/lib/netzke/core/component_config.rb +2 -2
  16. data/lib/netzke/core/composition.rb +85 -65
  17. data/lib/netzke/core/configuration.rb +26 -14
  18. data/lib/netzke/core/core_i18n.rb +17 -0
  19. data/lib/netzke/core/css_config.rb +6 -6
  20. data/lib/netzke/core/dynamic_assets.rb +17 -24
  21. data/lib/netzke/core/embedding.rb +2 -2
  22. data/lib/netzke/core/endpoint_response.rb +8 -2
  23. data/lib/netzke/core/inheritance.rb +33 -0
  24. data/lib/netzke/core/plugins.rb +1 -4
  25. data/lib/netzke/core/railz/action_view_ext.rb +1 -1
  26. data/lib/netzke/core/railz/controller_extensions.rb +21 -15
  27. data/lib/netzke/core/services.rb +61 -48
  28. data/lib/netzke/core/session.rb +0 -2
  29. data/lib/netzke/core/state.rb +11 -9
  30. data/lib/netzke/core/stylesheets.rb +3 -3
  31. data/lib/netzke/core/version.rb +1 -1
  32. data/lib/netzke/core.rb +3 -3
  33. data/lib/netzke/plugin.rb +2 -6
  34. data/stylesheets/core.css +2 -2
  35. metadata +11 -10
  36. data/TODO.md +0 -9
  37. data/javascripts/ext.js +0 -518
  38. data/lib/netzke/core/config_to_dsl_delegator.rb +0 -62
  39. data/lib/netzke/core/dsl_support.rb +0 -70
  40. data/lib/netzke/core/html.rb +0 -29
  41. data/lib/netzke/core/javascript.rb +0 -123
data/javascripts/base.js CHANGED
@@ -1,58 +1,78 @@
1
1
  /**
2
- This file gets loaded along with the rest of Ext library at the initial load. It is common for both Ext JS and Touch; Ext JS-specific stuff is in ext.js.
3
-
4
- At this time the following constants have been set by Rails:
5
-
6
- Netzke.RelativeUrlRoot - set to ActionController::Base.config.relative_url_root
7
- Netzke.RelativeExtUrl - URL to ext files
8
- Netzke.ControllerUrl - NetzkeController URL
9
- */
10
-
11
- // Initial stuff
12
- Netzke.classNamespace = 'Netzke.classes'; // TODO: pass from Ruby
13
- Ext.ns('Ext.netzke'); // namespace for extensions that depend on Ext
14
- Ext.ns('Netzke.page'); // namespace for all component instances on the page
15
- Ext.ns(Netzke.classNamespace); // namespace for all component classes
16
- Ext.ns('Netzke.classes.Core'); // namespace for Core mixins
17
-
18
- Netzke.deprecationWarning = function(msg){
19
- if (typeof console == 'undefined') {
20
- // no console defined
21
- } else {
22
- console.info("Netzke: " + msg);
23
- }
24
- };
2
+ * Client-side code for [Netzke::Base](http://www.rubydoc.info/github/netzke/netzke-core/Netzke/Base)
3
+ * @class Netzke.Base
4
+ */
5
+ Ext.define("Netzke.Base", {
6
+ extend: 'Ext.Mixin',
25
7
 
26
- Netzke.warning = Netzke.deprecationWarning;
8
+ mixinConfig: {
9
+ before: {
10
+ constructor: 'netzkeBeforeConstructor',
11
+ initComponent: 'netzkeBeforeInitComponent'
12
+ },
27
13
 
28
- Netzke.exception = function(msg) {
29
- throw("Netzke: " + msg);
30
- };
14
+ after: {
15
+ constructor: 'netzkeAfterConstructor',
16
+ initComponent: 'netzkeAfterInitComponent'
17
+ }
18
+ },
31
19
 
32
- // Used in testing
33
- if( Netzke.nLoadingFixRequests == undefined ){
34
- Netzke.nLoadingFixRequests=0;
35
- Ext.Ajax.on('beforerequest', function(conn,opt) { Netzke.nLoadingFixRequests+=1; });
36
- Ext.Ajax.on('requestcomplete', function(conn,opt) { Netzke.nLoadingFixRequests-=1; });
37
- Ext.Ajax.on('requestexception', function(conn,opt) { Netzke.nLoadingFixRequests-=1; });
38
- Netzke.ajaxIsLoading = function() { return Netzke.nLoadingFixRequests > 0; };
39
- }
20
+ /**
21
+ * This is `true` for all Netzke components.
22
+ * @property isNetzke
23
+ * @type boolean
24
+ */
25
+ isNetzke: true,
40
26
 
41
- // Used in testing, too
42
- Netzke.runningRequests = 0;
43
- Netzke.isLoading=function () {
44
- return Netzke.runningRequests != 0;
45
- }
27
+ /**
28
+ * Override this property globally if you to use a custom notifier class.
29
+ * @property netzkeNotifier
30
+ * @type Netzke.Notifier
31
+ */
32
+ netzkeNotifier: Ext.create('Netzke.Notifier'),
46
33
 
47
- // xtypes of cached Netzke classes
48
- Netzke.cache = [];
34
+ /**
35
+ * Called before constructor. Implements all kinds of Netzke component initializations. Override as needed.
36
+ * @method netzkeBeforeConstructor
37
+ * @param config {Object} Passed configuration
38
+ */
39
+ netzkeBeforeConstructor: function(config){
40
+ this.server = {}; // namespace for endpoint functions
41
+ this.netzkeComponents = config.netzkeComponents;
42
+ this.passedConfig = config;
43
+ this.netzkeProcessEndpoints(config);
44
+ this.netzkeProcessPlugins(config);
45
+ this.netzkeNormalizeActions(config);
46
+ this.netzkeNormalizeConfig(config);
47
+ this.serverConfig = config.clientConfig || {};
48
+ },
49
49
 
50
- Ext.define("Netzke.classes.Core.Mixin", {
51
- isNetzke: true, // to distinguish Netzke components from regular Ext components
50
+ /**
51
+ * Called after constructor. Override as needed.
52
+ * @method netzkeAfterConstructor
53
+ * @param config {Object} Passed configuration
54
+ */
55
+ netzkeAfterConstructor: function(config){
56
+ },
52
57
 
53
58
  /**
54
- * Evaluates CSS
55
- * @private
59
+ * Called before `initComponent`. Override as needed.
60
+ * @method netzkeBeforeInitComponent
61
+ */
62
+ netzkeBeforeInitComponent: function(){
63
+ },
64
+
65
+ /**
66
+ * Called after `initComponent`. Override as needed.
67
+ * @method netzkeAfterInitComponent
68
+ */
69
+ netzkeAfterInitComponent: function(){
70
+ },
71
+
72
+ /**
73
+ * Evaluates CSS passed from the server.
74
+ * @method netzkeEvalCss
75
+ * @param code {String} CSS code
56
76
  */
57
77
  netzkeEvalCss : function(code){
58
78
  var head = Ext.fly(document.getElementsByTagName('head')[0]);
@@ -64,42 +84,36 @@ Ext.define("Netzke.classes.Core.Mixin", {
64
84
  },
65
85
 
66
86
  /**
67
- * Evaluates JS
68
- * @private
87
+ * Evaluates Javascript passed from the server.
88
+ * @method netzkeEvalJs
89
+ * @param code {String} Javascript code
69
90
  */
70
91
  netzkeEvalJs : function(code){
71
92
  eval(code);
72
93
  },
73
94
 
74
- /**
75
- * Gets id in the context of provided parent.
76
- * For example, the components "properties", being a child of "books" has global id "books__properties", which *is* its component's real id. This methods, with the instance of "books" passed as parameter, returns "properties".
77
- * @private
78
- */
79
- netzkeLocalId : function(parent){
80
- return this.id.replace(parent.id + "__", "");
81
- },
82
-
83
- /**
84
- Executes a bunch of methods. This method is called almost every time a communication to the server takes place.
85
- Thus the server side of a component can provide any set of commands to its client side.
86
- Args:
87
- - instructions: can be
88
- 1) a hash of instructions, where the key is the method name, and value - the argument that method will be called with (thus, these methods are expected to *only* receive 1 argument). In this case, the methods will be executed in no particular order.
89
- 2) an array of hashes of instructions. They will be executed in order.
90
- Arrays and hashes may be nested at will.
91
- If the key in the instructions hash refers to a child Netzke component, netzkeBulkExecute will be called on that component with the value passed as the argument.
95
+ /**
96
+ * Executes a bunch of methods. This method is called almost every time a communication to the server takes place.
97
+ * Thus the server side of a component can provide any set of commands to its client side.
98
+ *
99
+ * @method netzkeBulkExecute
100
+ *
101
+ * @param {Array|Object} instructions
102
+ * 1) a hash of instructions, where the key is the method name, and value - the argument that method will be called with (thus, these methods are expected to *only* receive 1 argument). In this case, the methods will be executed in no particular order.
103
+ * 2) an array of hashes of instructions. They will be executed in order.
104
+ * Arrays and hashes may be nested at will.
105
+ * If the key in the instructions hash refers to a child Netzke component, netzkeBulkExecute will be called on that component with the value passed as the argument.
92
106
 
93
- Examples of the arguments:
94
- // same as this.feedback("Your order is accepted");
95
- {feedback: "You order is accepted"}
107
+ * @example
108
+ *
109
+ * // executes as this.feedback("Your order is accepted");
110
+ * {feedback: "You order is accepted"}
96
111
 
97
- // same as: this.setTitle('Suprise!'); this.setDisabled(true);
98
- [{setTitle:'Suprise!'}, {setDisabled:true}]
112
+ * // executes as: this.setTitle('Suprise!'); this.setDisabled(true);
113
+ * [{setTitle:'Suprise!'}, {setDisabled:true}]
99
114
 
100
- // the same as this.netzkeGetComponent('users').netzkeBulkExecute([{setTitle:'Suprise!'}, {setDisabled:true}]);
101
- {users: [{setTitle:'Suprise!'}, {setDisabled:true}] }
102
- @private
115
+ * // executes as: this.netzkeGetComponent('users').netzkeBulkExecute([{setTitle:'Suprise!'}, {setDisabled:true}]);
116
+ * {users: [{setTitle:'Suprise!'}, {setDisabled:true}] }
103
117
  */
104
118
  netzkeBulkExecute : function(instructions){
105
119
  if (Ext.isArray(instructions)) {
@@ -118,7 +132,7 @@ Ext.define("Netzke.classes.Core.Mixin", {
118
132
  if (childComponent) {
119
133
  childComponent.netzkeBulkExecute(args);
120
134
  } 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
121
- throw "Netzke: Unknown method or child component '" + instr + "' in component '" + this.id + "'"
135
+ throw "Netzke: Unknown method or child component '" + instr + "' in component '" + this.path + "'"
122
136
  }
123
137
  }
124
138
  }
@@ -126,6 +140,9 @@ Ext.define("Netzke.classes.Core.Mixin", {
126
140
  },
127
141
 
128
142
  /**
143
+ * Called by the server side to set the return value of an endpoint call; to be reworked.
144
+ * @method netzkeSetResult
145
+ * @param result {Any}
129
146
  * @private
130
147
  */
131
148
  netzkeSetResult: function(result) {
@@ -133,31 +150,37 @@ Ext.define("Netzke.classes.Core.Mixin", {
133
150
  },
134
151
 
135
152
  /**
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.
153
+ * Called by the server when the component to which an endpoint call was directed to, is not in the session anymore.
154
+ * @method netzkeSessionExpired
137
155
  * @private
138
156
  */
139
- netzkeSessionExpired: function() {
157
+ netzkeOnSessionExpired: function() {
140
158
  this.netzkeSessionIsExpired = true;
141
- this.onNetzkeSessionExpired();
159
+ this.netzkeOnSessionExpired();
142
160
  },
143
161
 
144
162
  /**
145
163
  * 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.
164
+ * @method onSessionExpired
146
165
  * @private
147
166
  */
148
- onNetzkeSessionExpired: function() {
149
- Netzke.warning("Component not in session. Override `onNetzkeSessionExpired` to handle this.");
167
+ netzkeOnSessionExpired: function() {
168
+ Netzke.warning("Component not in session. Override `netzkeOnSessionExpired` to handle this.");
150
169
  },
151
170
 
152
171
  /**
153
- * Returns a URL for old-fashion requests (used at multi-part form non-AJAX submissions)
154
- * @private
172
+ * Returns a URL for old-fashion requests (used at multi-part form non-AJAX submissions).
173
+ * @method netzkeEndpointUrl
174
+ * @param endpoint {String}
155
175
  */
156
176
  netzkeEndpointUrl: function(endpoint){
157
177
  return Netzke.ControllerUrl + "dispatcher?address=" + this.id + "__" + endpoint;
158
178
  },
159
179
 
160
180
  /**
181
+ * Processes items.
182
+ * @method netzkeNormalizeConfigArray
183
+ * @param items {Array} Items
161
184
  * @private
162
185
  */
163
186
  netzkeNormalizeConfigArray: function(items){
@@ -166,19 +189,9 @@ Ext.define("Netzke.classes.Core.Mixin", {
166
189
  Ext.each(items, function(item, i){
167
190
  cfg = item;
168
191
 
169
- // potentially, referencing a component or action with a string
170
- if (Ext.isString(item)) {
171
- ref = item.camelize(true);
172
- if ((this.netzkeComponents || {})[ref]) cfg = {netzkeComponent: ref};
173
- else if ((this.actions || {})[ref]) cfg = {netzkeAction: ref};
174
- }
175
-
176
- if (cfg.netzkeAction) {
177
- // replace with action instance
178
- actName = cfg.netzkeAction.camelize(true);
179
- if (!this.actions[actName]) throw "Netzke: unknown action " + cfg.netzkeAction;
180
- items[i] = this.actions[actName];
181
- delete(item);
192
+ if (cfg.action) {
193
+ if (!this.actions[cfg.action]) throw "Netzke: unknown action " + cfg.action;
194
+ items[i] = this.actions[cfg.action];
182
195
 
183
196
  } else if (cfg.netzkeComponent) {
184
197
  // replace with component config
@@ -187,7 +200,6 @@ Ext.define("Netzke.classes.Core.Mixin", {
187
200
  if (!cmpCfg) throw "Netzke: unknown component " + cmpName;
188
201
  cmpCfg.netzkeParent = this;
189
202
  items[i] = Ext.apply(cmpCfg, cfg);
190
- delete(item);
191
203
 
192
204
  } else if (Ext.isString(cfg) && Ext.isFunction(this[cfg.camelize(true)+"Config"])) { // replace with config referred to on the Ruby side as a symbol
193
205
  // pre-built config
@@ -202,5 +214,479 @@ Ext.define("Netzke.classes.Core.Mixin", {
202
214
  }
203
215
  }
204
216
  }, this);
217
+ },
218
+
219
+ /**
220
+ * Runs through initial config options and does the following:
221
+ *
222
+ * * detects component placeholders and replaces them with full component config found in `netzkeComponents`
223
+ * * detects action placeholders and replaces them with instances of Ext actions found in `this.actions`
224
+ *
225
+ * @method netzkeNormalizeConfig
226
+ * @param config {Object}
227
+ */
228
+ netzkeNormalizeConfig: function(config) {
229
+ for (key in config) {
230
+ if (Ext.isArray(config[key])) this.netzkeNormalizeConfigArray(config[key]);
231
+ }
232
+ },
233
+
234
+ /**
235
+ * Dynamically creates methods for endpoints, so that we could later call them like: this.myEndpointMethod()
236
+ * @method netzkeProcessEndpoints
237
+ * @param config {Object}
238
+ */
239
+ netzkeProcessEndpoints: function(config){
240
+ var endpoints = config.endpoints || [], that = this;
241
+
242
+ Ext.each(endpoints, function(methodName){
243
+ Netzke.directProvider.addRemotingMethodToComponent(config, methodName);
244
+
245
+ // define endpoint function
246
+ this.server[methodName] = function(){
247
+ var args = Array.prototype.slice.call(arguments), callback, serverConfigs, scope = that;
248
+
249
+ if (Ext.isFunction(args[args.length - 2])) {
250
+ scope = args.pop();
251
+ callback = args.pop();
252
+ }
253
+
254
+ if (Ext.isFunction(args[args.length - 1])) {
255
+ callback = args.pop();
256
+ }
257
+
258
+ var cfgs = that.netzkeBuildParentConfigs();
259
+ var remotingArgs = {args: args, configs: cfgs};
260
+
261
+ // call Direct function
262
+ that.netzkeGetDirectFunction(methodName).call(scope, remotingArgs, function(response, event) {
263
+ that.netzkeProcessDirectResponse(response, event, callback, scope);
264
+ }, that);
265
+ }
266
+ }, this);
267
+ },
268
+
269
+ /**
270
+ * TODO
271
+ * @method netzkeProcessDirectResponse
272
+ * @param response {Object}
273
+ * @param event {Object}
274
+ * @param callback {Function}
275
+ * @param scope {Object}
276
+ */
277
+ netzkeProcessDirectResponse: function(response, event, callback, scope){
278
+ var callbackParams,
279
+ result; // endpoint response
280
+
281
+ // no server exception?
282
+ if (Ext.getClass(event) == Ext.direct.RemotingEvent) {
283
+
284
+ // process response and get endpoint return value
285
+ this.netzkeBulkExecute(response);
286
+ result = this.latestResult;
287
+
288
+ // endpoint returns an error?
289
+ if (result && result.error) {
290
+ this.netzkeHandleEndpointError(callback, result);
291
+ // no error
292
+ } else {
293
+ if (callback) callback.apply(scope, [result, true]) != false
294
+ }
295
+
296
+ // got Direct exception?
297
+ } else {
298
+ this.netzkeHandleDirectError(callback, event);
299
+ }
300
+ },
301
+
302
+ /**
303
+ * TODO
304
+ * @method netzkeHandleEndpointError
305
+ */
306
+ netzkeHandleEndpointError: function(callback, result){
307
+ var shouldFireGlobalEvent = true;
308
+
309
+ if (callback) {
310
+ shouldFireGlobalEvent = callback.apply(this, [result.error, false]) != false;
311
+ }
312
+
313
+ if (shouldFireGlobalEvent) {
314
+ Netzke.GlobalEvents.fireEvent('endpointexception', result.error);
315
+ }
316
+ },
317
+
318
+ /**
319
+ * TODO
320
+ * @method netzkeHandleDirectError
321
+ * @param callback {Function}
322
+ * @param event {Object}
323
+ */
324
+ netzkeHandleDirectError: function(callback, event){
325
+ var shouldFireGlobalEvent = true;
326
+
327
+ callbackParams = event;
328
+ callbackParams.type = 'DIRECT_EXCEPTION';
329
+
330
+ // First invoke the callback, and if that allows, call generic exception handler
331
+ if (callback) {
332
+ shouldFireGlobalEvent = callback.apply(this, [callbackParams, false]) != false;
333
+ }
334
+ if (shouldFireGlobalEvent) {
335
+ Netzke.GlobalEvents.fireEvent('endpointexception', callbackParams);
336
+ }
337
+ },
338
+
339
+ /**
340
+ * Returns direct function by endpoint name and optional component's config (if not provided, component's instance
341
+ * will be used instead)
342
+ * @method netzkeGetDirectFunction
343
+ * @param methodName {String}
344
+ * @param {Object} [config]
345
+ */
346
+ netzkeGetDirectFunction: function(methodName, config) {
347
+ config = config || this;
348
+ return Netzke.remotingMethods[config.id][methodName];
349
+ },
350
+
351
+ /**
352
+ * Reversed array of server configs for each parent component up the tree
353
+ * @method netzkeBuildParentConfigs
354
+ */
355
+ netzkeBuildParentConfigs: function() {
356
+ var res = [],
357
+ parent = this;
358
+ while (parent) {
359
+ var cfg = Ext.clone(parent.serverConfig);
360
+ res.unshift(cfg);
361
+ parent = parent.netzkeGetParentComponent();
362
+ }
363
+ return res;
364
+ },
365
+
366
+ /**
367
+ * Replaces actions configs with Ext.Action instances, assigning default handler to them
368
+ * @method netzkeNormalizeActions
369
+ * @param config {Object}
370
+ */
371
+ netzkeNormalizeActions : function(config){
372
+ var normActions = {};
373
+ for (var name in config.actions) {
374
+ // Configure the action
375
+ var actionConfig = Ext.apply({}, config.actions[name]); // do not modify original this.actions
376
+ actionConfig.customHandler = actionConfig.handler;
377
+ actionConfig.handler = Ext.Function.bind(this.netzkeActionHandler, this); // handler common for all actions
378
+ actionConfig.name = name;
379
+
380
+ // instantiate Ext.Action
381
+ normActions[name] = new Ext.Action(actionConfig);
382
+ }
383
+ this.actions = normActions;
384
+ delete(config.actions);
385
+ },
386
+
387
+ /**
388
+ * Dynamically loads child Netzke component
389
+ * @method netzkeLoadComponent
390
+ * @param {String} name Component name as declared in the Ruby class with `component` DSL
391
+ * @param {Object} [options] May contain the following optional keys:
392
+ * * **container** {Ext.container.Container|Integer}
393
+ *
394
+ * The instance (or id) of a container with the "fit" layout where the loaded component will be added to; the previously existing component will be destroyed
395
+ *
396
+ * * **append** {Boolean}
397
+ *
398
+ * If set to `true`, do not clear the container before adding the loaded component
399
+ *
400
+ * * **configOnly** {Boolean}
401
+ *
402
+ * If set to `true`, do not instantiate/insert the component, instead pass its config to the callback function
403
+ *
404
+ * * **serverConfig** {Object}
405
+ *
406
+ * Config accessible inside the `component` DSL block as `client_config`; this allows reconfiguring child components by the client-side code
407
+ *
408
+ * * **callback** {Function}
409
+ *
410
+ * Function that gets called after the component is loaded; it receives the component's instance (or component config if `configOnly` is set) as parameter; if the function returns `false`, the loaded component will not be automatically inserted or (in case of window) shown.
411
+ *
412
+ * * **scope** {Object}
413
+ *
414
+ * Scope for the callback; defaults to the instance of the component.
415
+ *
416
+ * @example
417
+ *
418
+ * Loads 'info' and adds it to `this` container, removing anything from it first:
419
+ *
420
+ * this.netzkeLoadComponent('info');
421
+ *
422
+ * Loads 'info' and adds it to `win` container, envoking a callback in `this` scope, passing it an instance of 'info':
423
+ *
424
+ * this.netzkeLoadComponent('info', { container: win, callback: function(instance){} });
425
+ *
426
+ * Loads configuration for the 'info' component, envoking a callback in `this` scope, passing it the loaded config for 'info'.
427
+ *
428
+ * this.netzkeLoadComponent('info', { configOnly: true, callback: function(config){} });
429
+ *
430
+ * Loads two 'info' instances in different containers and with different configurations:
431
+ *
432
+ * this.netzkeLoadComponent('info', {
433
+ * container: 'tab1',
434
+ * serverConfig: { user: 'john' } // on the server: client_config[:user] == 'john'
435
+ * });
436
+ *
437
+ * this.netzkeLoadComponent('info', {
438
+ * container: 'tab2',
439
+ * serverConfig: { user: 'bill' } // on the server: client_config[:user] == 'bill'
440
+ * });
441
+ */
442
+ netzkeLoadComponent: function(name, options){
443
+ var container, serverParams, containerEl;
444
+ options = options || {};
445
+
446
+ container = this.netzkeChooseContainer(options);
447
+ serverParams = this.netzkeBuildServerLoadingParams(name, options);
448
+
449
+ this.netzkeShowLoadingMask(container);
450
+
451
+ // Call the endpoint
452
+ this.server.deliverComponent(serverParams, function(result, success) {
453
+ this.netzkeHideLoadingMask(container);
454
+
455
+ if (success) {
456
+ this.netzkeHandleLoadingResponse(container, result, options);
457
+ } else {
458
+ this.netzkeHandleLoadingError(result);
459
+ }
460
+ });
461
+ },
462
+
463
+ /**
464
+ * Handles loading error
465
+ * @method netzkeHandleLoadingError
466
+ */
467
+ netzkeHandleLoadingError: function(error){
468
+ this.netzkeNotify(error);
469
+ },
470
+
471
+ /**
472
+ * TODO
473
+ * @method netzkeBuildServerLoadingParams
474
+ */
475
+ netzkeBuildServerLoadingParams: function(name, params) {
476
+ return Ext.apply(params.serverParams || {}, {
477
+ name: name,
478
+ client_config: params.serverConfig,
479
+ item_id: params.itemId || name, // TODO: make optional
480
+ cache: Netzke.cache.join() // coma-separated list of xtypes of already loaded classes
481
+ });
482
+ },
483
+
484
+ /**
485
+ * Decides, based on params passed to `netzkeLoadComponent`, what container the component should be loaded into.
486
+ * @method netzkeChooseContainer
487
+ * @param params Object
488
+ */
489
+ netzkeChooseContainer: function(params) {
490
+ if (!params.container) return this;
491
+ return Ext.isString(params.container) ? Ext.getCmp(params.container) : params.container;
492
+ },
493
+
494
+ /**
495
+ * Handles regular server response (may include error)
496
+ * @method netzkeHandleLoadingResponse
497
+ */
498
+ netzkeHandleLoadingResponse: function(container, result, params){
499
+ if (result.error) {
500
+ this.netzkeNotify(result.error);
501
+ } else {
502
+ this.netzkeProcessDeliveredComponent(container, result, params);
503
+ }
504
+ },
505
+
506
+ /**
507
+ * Processes delivered component
508
+ * @method netzkeProcessDeliveredComponent
509
+ */
510
+ netzkeProcessDeliveredComponent: function(container, result, params){
511
+ var config = result.config, instance, doNotInsert, currentInstance;
512
+ config.netzkeParent = this;
513
+
514
+ this.netzkeEvalJs(result.js);
515
+ this.netzkeEvalCss(result.css);
516
+
517
+ if (params.configOnly) {
518
+ if (params.callback) params.callback.apply((params.scope || this), [config, params]);
519
+ } else {
520
+ // we must destroy eventual existing component with the same ID
521
+ currentInstance = Ext.getCmp(config.id);
522
+ if (currentInstance) currentInstance.destroy();
523
+
524
+ instance = Ext.create(config);
525
+
526
+ if (params.callback) {
527
+ doNotInsert = params.callback.apply((params.scope || this), [instance, params]) == false;
528
+ }
529
+
530
+ if (doNotInsert) return;
531
+
532
+ if (instance.isFloating()) { // windows are not containable
533
+ instance.show();
534
+ } else {
535
+ if (params.replace) {
536
+ this.netzkeReplaceChild(params.replace, instance)
537
+ } else {
538
+ if (!params.append) container.removeAll();
539
+ container.add(instance);
540
+ }
541
+ }
542
+ }
543
+ },
544
+
545
+ /**
546
+ * Masks container in which a child component is being loaded
547
+ * @method netzkeShowLoadingMask
548
+ */
549
+ netzkeShowLoadingMask: function(container){
550
+ if (container.rendered) container.mask();
551
+ },
552
+
553
+ /**
554
+ * Unmasks loading container
555
+ * @method netzkeHideLoadingMask
556
+ */
557
+ netzkeHideLoadingMask: function(container){
558
+ if (container.rendered) container.unmask();
559
+ },
560
+
561
+ /**
562
+ * Returns parent Netzke component
563
+ * @method netzkeGetParentComponent
564
+ */
565
+ netzkeGetParentComponent: function(){
566
+ return this.netzkeParent;
567
+ },
568
+
569
+ /**
570
+ * Reloads itself by instructing the parent to call `netzkeLoadComponent`.
571
+ * Note: in order for this to work, the component must be nested in a container with the 'fit' layout.
572
+ * @method netzkeReload
573
+ */
574
+ netzkeReload: function(){
575
+ var parent = this.netzkeGetParentComponent();
576
+
577
+ if (parent) {
578
+ parent.netzkeReloadChild(this);
579
+ } else {
580
+ window.location.reload();
581
+ }
582
+ },
583
+
584
+ /**
585
+ * Given child component and new serverConfig, reloads the component
586
+ * @method netzkeReloadChild
587
+ * @param child Netzke.Base
588
+ * @param serverConfig Object
589
+ */
590
+ netzkeReloadChild: function(child, serverConfig){
591
+ this.netzkeLoadComponent(child.name, {
592
+ configOnly: true,
593
+ serverConfig: serverConfig,
594
+ callback: function(cfg) {
595
+ this.netzkeReplaceChild(child, cfg);
596
+ }
597
+ });
598
+ },
599
+
600
+ /**
601
+ * Replaces given (Netzke or Ext JS) component and new config, replaces former with latter, by instructing the parent
602
+ * component to re-insert the component at the same index. Override if you need something more fancy (e.g. active tab
603
+ * when it gets re-inserted)
604
+ * @method netzkeReplaceChild
605
+ * @param child {Netzke.Base}
606
+ * @param config {Obect}
607
+ */
608
+ netzkeReplaceChild: function(child, config){
609
+ var parent = child.up();
610
+ if (!parent) return;
611
+ var index = parent.items.indexOf(child);
612
+ Ext.suspendLayouts();
613
+ parent.remove(child);
614
+ var res = parent.insert(index, config);
615
+ Ext.resumeLayouts(true);
616
+ return res;
617
+ },
618
+
619
+ /**
620
+ * Instantiates and returns a Netzke component by its name.
621
+ * @method netzkeInstantiateComponent
622
+ * @param name {String} Child component's name/itemId
623
+ */
624
+ netzkeInstantiateComponent: function(name) {
625
+ name = name.camelize(true);
626
+ var cfg = this.netzkeComponents[name];
627
+ return Ext.createByAlias(this.netzkeComponents[name].alias, cfg)
628
+ },
629
+
630
+ /**
631
+ * Returns *instantiated* child component by its relative path
632
+ * @method netzkeGetComponent
633
+ * @param path {String} Component path, which may contain the 'parent' for walking up the hierarchy, e.g.
634
+ * `parent__sibling`. If this is empty, the method will return `this`.
635
+ */
636
+ netzkeGetComponent: function(path){
637
+ if (path === "") {return this};
638
+ path = path.underscore();
639
+ var split = path.split("__"), res;
640
+ if (split[0] === 'parent') {
641
+ split.shift();
642
+ var childInParentScope = split.join("__");
643
+ res = this.netzkeGetParentComponent().netzkeGetComponent(childInParentScope);
644
+ } else {
645
+ res = Ext.getCmp(this.id+"__"+path);
646
+ }
647
+ return res;
648
+ },
649
+
650
+ /**
651
+ * Triggers a notification unless `quiet` config option is `true`.
652
+ * @method netzkeNotify
653
+ * @param {String} msg Notification body
654
+ * @param {Object} options Notification options (such as `title`, `delay`)
655
+ */
656
+ netzkeNotify: function(msg, options){
657
+ if (this.quiet !== true) this.netzkeNotifier.msg(msg, options);
658
+ },
659
+
660
+ /**
661
+ * Common handler for all netzke's actions.
662
+ * @method netzkeActionHandler
663
+ * @param {Ext.Component} comp Component that triggered the action (e.g. button or menu item)
664
+ */
665
+ netzkeActionHandler: function(comp){
666
+ var actionName = comp.name;
667
+ // If firing corresponding event doesn't return false, call the handler
668
+ if (this.fireEvent(actionName+'click', comp)) {
669
+ var action = this.actions[actionName];
670
+ var customHandler = action.initialConfig.customHandler;
671
+ var methodName = (customHandler && customHandler.camelize(true)) || "netzkeOn" + actionName.camelize();
672
+ if (!this[methodName]) {throw "Netzke: handler '" + methodName + "' is undefined in '" + this.id + "'";}
673
+
674
+ // call the handler passing it the triggering component
675
+ this[methodName](comp);
676
+ }
677
+ },
678
+
679
+ /**
680
+ * TODO
681
+ * @method netzkeProcessPlugins
682
+ */
683
+ netzkeProcessPlugins: function(config) {
684
+ if (config.netzkePlugins) {
685
+ if (!this.plugins) this.plugins = [];
686
+ Ext.each(config.netzkePlugins, function(p){
687
+ this.plugins.push(this.netzkeInstantiateComponent(p));
688
+ }, this);
689
+ delete config.netzkePlugins;
690
+ }
205
691
  }
206
692
  });