Bugreport url as constant
[tine20] / tine20 / Tinebase / js / tineInit.js
1 /*
2  * Tine 2.0
3  * 
4  * @package     Tine
5  * @subpackage  Tinebase
6  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
7  * @author      Cornelius Weiss <c.weiss@metaways.de>
8  * @copyright   Copyright (c) 2007-2013 Metaways Infosystems GmbH (http://www.metaways.de)
9  *
10  * TODO         allow to add user defined part to Tine.title
11  */
12
13 /*global Ext, Tine, google, OpenLayers, Locale, */
14
15 /** ------------------------- Ext.ux Initialisation ------------------------ **/
16
17 Ext.ux.Printer.BaseRenderer.prototype.stylesheetPath = 'Tinebase/js/ux/Printer/print.css';
18
19
20 /** ------------------------ Tine 2.0 Initialisation ----------------------- **/
21
22 /**
23  * @class Tine
24  * @singleton
25  */
26 Ext.namespace('Tine', 'Tine.Tinebase', 'Tine.Calendar');
27
28 /**
29  * version of Tine 2.0 javascript client version, gets set a build / release time <br>
30  * <b>Supported Properties:</b>
31  * <table>
32  *   <tr><td><b>buildType</b></td><td> type of build</td></tr>
33  *   <tr><td><b>buildDate</b></td><td> date of build</td></tr>
34  *   <tr><td><b>buildRevision</b></td><td> revision of build</td></tr>
35  *   <tr><td><b>codeName</b></td><td> codename of release</td></tr>
36  *   <tr><td><b>packageString</b></td><td> packageString of release</td></tr>
37  *   <tr><td><b>releaseTime</b></td><td> releaseTime of release</td></tr>
38  * </table>
39  * @type {Object}
40  */
41 Tine.clientVersion = {};
42 Tine.clientVersion.buildType        = 'none';
43 Tine.clientVersion.buildDate        = 'none';
44 Tine.clientVersion.buildRevision    = 'none';
45 Tine.clientVersion.codeName         = 'none';
46 Tine.clientVersion.packageString    = 'none';
47 Tine.clientVersion.releaseTime      = 'none';
48
49 /**
50  * title of app (gets set at build time)
51  * 
52  * @type String
53  */
54 Tine.title = 'Tine 2.0';
55 Tine.weburl = 'https://www.tine20.org/en/the-project/contribute.html';
56 Tine.helpUrl = 'http://www.tine20.org/wiki/index.php/Main_Page';
57 Tine.bugreportUrl = 'https://api.tine20.net/bugreport.php';
58
59 /**
60  * quiet logging in release mode
61  */
62 Ext.LOGLEVEL = Tine.clientVersion.buildType === 'RELEASE' ? 0 : 7;
63 Tine.log = Ext.ux.log;
64
65 Ext.namespace('Tine.Tinebase');
66
67 /**
68  * @class Tine.Tinebase.tineInit
69  * @namespace Tine.Tinebase
70  * @sigleton
71  * static tine init functions
72  */
73 Tine.Tinebase.tineInit = {
74     /**
75      * @cfg {String} getAllRegistryDataMethod
76      */
77     getAllRegistryDataMethod: 'Tinebase.getAllRegistryData',
78
79     /**
80      * @cfg {Boolean} stateful
81      */
82     stateful: true,
83
84     /**
85      * @cfg {String} requestUrl
86      */
87     requestUrl: 'index.php',
88     
89     /**
90      * prefix for localStorage keys
91      * @type String
92      */
93     lsPrefix: Tine.Tinebase.common.getUrl('path') + 'Tine',
94     
95     onPreferenceChangeRegistered: false,
96     
97     initWindow: function () {
98         Ext.getBody().on('keydown', function (e) {
99             if (e.ctrlKey && e.getKey() === e.A && ! (e.getTarget('form') || e.getTarget('input') || e.getTarget('textarea'))) {
100                 // disable the native 'select all'
101                 e.preventDefault();
102             } else if (e.getKey() === e.BACKSPACE && ! (e.getTarget('form') || e.getTarget('input') || e.getTarget('textarea'))) {
103                 // disable the native 'history back'
104                 e.preventDefault();
105             } else if (!window.isMainWindow && e.ctrlKey && e.getKey() === e.T) {
106                 // disable the native 'new tab' if in popup window
107                 e.preventDefault();
108             } else if (window.isMainWindow && e.ctrlKey && e.getKey() === e.L) {
109                 // reload on ctrl-l
110                 Tine.Tinebase.common.reload({
111                     clearCache: true
112                 });
113             }
114         });
115         
116         // disable generic drops
117         Ext.getBody().on('dragover', function (e) {
118             e.stopPropagation();
119             e.preventDefault();
120             e.browserEvent.dataTransfer.dropEffect = 'none';
121         }, this);
122     },
123     
124     initDebugConsole: function () {
125         var map = new Ext.KeyMap(Ext.getDoc(), [{
126             key: [122], // F11
127             ctrl: true,
128             fn: Tine.Tinebase.common.showDebugConsole
129         }]);
130     },
131     
132     
133     /**
134      * Each window has exactly one viewport containing a card layout in its lifetime
135      * The default card is a splash screen.
136      * 
137      * defautl wait panel (picture only no string!)
138      */
139     initBootSplash: function () {
140         
141         this.splash = {
142             xtype: 'container',
143             id: 'tine-viewport-waitcycle',
144             border: false,
145             layout: 'fit',
146             width: 16,
147             height: 16,
148             // the content elements come from the initial html so they are displayed fastly
149             contentEl: Ext.select('div[class^=tine-viewport-]')
150         };
151         
152         Tine.Tinebase.viewport = new Ext.Viewport({
153             layout: 'fit',
154             border: false,
155             items: {
156                 xtype: 'container',
157                 id: 'tine-viewport-maincardpanel',
158                 ref: 'tineViewportMaincardpanel',
159                 isWindowMainCardPanel: true,
160                 layout: 'card',
161                 border: false,
162                 activeItem: 0,
163                 items: this.splash
164             }
165         });
166     },
167
168     initLoginPanel: function() {
169         if (window.isMainWindow && ! Tine.loginPanel) {
170             var mainCardPanel = Tine.Tinebase.viewport.tineViewportMaincardpanel;
171             Tine.loginPanel = new Tine.Tinebase.LoginPanel({
172                 defaultUsername: Tine.Tinebase.registry.get('defaultUsername'),
173                 defaultPassword: Tine.Tinebase.registry.get('defaultPassword')
174             });
175             mainCardPanel.add(Tine.loginPanel);
176         }
177         
178         // event firing is unpredictable in IE9/10/11, you'll never know when it comes ...
179         if (! Ext.isNewIE) {
180             Tine.Tinebase.registry.on('replace', function(key, oldValue, newValue) {
181                 if (oldValue && !newValue) {
182                     Tine.log.info('tineInit::initLoginPanel - handle logout in other window');
183                     if (window.isMainWindow) {
184                         Tine.Tinebase.common.reload();
185                     } else {
186                         Ext.ux.PopupWindow.close(window);
187                     }
188                 }
189             }, this, 'currentAccount');
190         }
191     },
192
193     showLoginBox: function(cb, scope) {
194         var mainCardPanel = Tine.Tinebase.viewport.tineViewportMaincardpanel,
195             activeItem = mainCardPanel.layout.activeItem;
196
197         mainCardPanel.layout.setActiveItem(Tine.loginPanel.id);
198         Tine.loginPanel.doLayout();
199         Tine.loginPanel.onLogin = function(response) {
200             mainCardPanel.layout.setActiveItem(activeItem);
201             cb.call(scope||window, response);
202         };
203
204 //        //listen for other windows login?
205 //        Tine.Tinebase.registry.on('replace', function() {
206 //            mainCardPanel.layout.setActiveItem(activeItem);
207 //        }, this, 'currentAccount');
208
209     },
210
211     renderWindow: function () {
212         Tine.log.info('renderWindow::start');
213         
214         var mainCardPanel = Tine.Tinebase.viewport.tineViewportMaincardpanel;
215
216         // check if user is already logged in
217         if (! Tine.Tinebase.registry.get('currentAccount')) {
218             Tine.Tinebase.tineInit.showLoginBox(function(response){
219                 Tine.log.info('tineInit::renderWindow -fetch users registry');
220                 Tine.Tinebase.tineInit.initRegistry(true, function() {
221                     Tine.log.info('tineInit::renderWindow - registry fetched, render main window');
222                     Ext.MessageBox.hide();
223                     Tine.Tinebase.tineInit.initWindowMgr();
224                     Tine.Tinebase.tineInit.renderWindow();
225                 });
226             });
227             
228             return;
229         }
230
231         // experimental deep link
232         if (window.location.hash) {
233             var hash = window.location.hash.replace(/^#+/, ''),
234                 config;
235
236             if (hash.match(/\//)) {
237                 var args = hash.split('/'),
238                     app = Tine.Tinebase.appMgr.get(args.shift()),
239                     method = args.shift();
240
241                 config = app.dispatchRoute(method, args);
242
243             } else {
244                 //http://tine.example.com/#{"name":"TimesheetEditWindow_0","contentPanelConstructor":"Tine.Timetracker.TimesheetEditDialog","recordId":0}
245                 config = Ext.decode(hash);
246             }
247
248             if (window.history && window.history.replaceState) {
249                 window.history.replaceState({}, document.title, Tine.Tinebase.common.getUrl());
250             }
251
252             // what about plugins?
253             Ext.applyIf(config, {
254                 name: window.name,
255                 popup: window
256             });
257
258             window.name = config.name;
259
260             // disable mainWindows per hash for the moment. MainWindow concept needs to be rethought
261             // in the context of window manager rewrite
262             window.isMainWindow = false;
263
264             Ext.ux.PopupWindowMgr.register(new Ext.ux.PopupWindow(config));
265         }
266
267         /**
268          * register MainWindow
269          */
270         else if (window.isMainWindow) {
271             Ext.ux.PopupWindowMgr.register({
272                 name: window.name,
273                 popup: window,
274                 contentPanelConstructor: 'Tine.Tinebase.MainScreenPanel'
275             });
276         }
277
278
279         Tine.log.info('renderWindow::before get window');
280         
281         // fetch window config from WindowMgr
282         var c = Ext.ux.PopupWindowMgr.get(window) || {};
283         
284         // set window title
285         window.document.title = Ext.util.Format.stripTags(c.title ? c.title : window.document.title);
286         
287         Tine.log.info('renderWindow::getCenterPanel');
288         
289         // finally render the window contents in a new card
290         var card = Tine.WindowFactory.getCenterPanel(c);
291         mainCardPanel.add(card);
292         mainCardPanel.layout.setActiveItem(card.id);
293         card.doLayout();
294         
295         window.initializationComplete = true;
296     },
297
298     initAjax: function () {
299         Ext.Ajax.url = Tine.Tinebase.tineInit.requestUrl;
300         Ext.Ajax.method = 'POST';
301         
302         Ext.Ajax.defaultHeaders = {
303             'X-Tine20-Request-Type' : 'JSON'
304         };
305         
306         Ext.Ajax.transactions = {};
307
308         Tine.Tinebase.tineInit.jsonKeyCookieProvider = new Ext.ux.util.Cookie();
309
310         /**
311          * inspect all requests done via the ajax singleton
312          * 
313          * - send custom headers
314          * - send json key 
315          * - implicitly transform non jsonrpc requests
316          * 
317          * NOTE: implicitly transformed reqeusts get their callback fn's proxied 
318          *       through generic response inspectors as defined below
319          */
320         Ext.Ajax.on('beforerequest', function (connection, options) {
321
322             var jsonKey = Tine.Tinebase.registry && Tine.Tinebase.registry.get ? Tine.Tinebase.registry.get('jsonKey') : '';
323             if (Tine.Tinebase.tineInit.jsonKeyCookieProvider.get('TINE20JSONKEY')) {
324                 var cookieJsonKey = Tine.Tinebase.tineInit.jsonKeyCookieProvider.get('TINE20JSONKEY');
325                 Tine.Tinebase.tineInit.jsonKeyCookieProvider.clear('TINE20JSONKEY');
326                 // NOTE cookie reset is not always working in IE, so we need to check jsonKey again
327                 if (cookieJsonKey && cookieJsonKey != "null") {
328                     jsonKey = cookieJsonKey;
329                     Tine.Tinebase.registry.set('jsonKey', jsonKey);
330                 }
331             }
332
333             options.headers = options.headers || {};
334             options.headers['X-Tine20-JsonKey'] = jsonKey;
335             options.headers['X-Tine20-TransactionId'] = Tine.Tinebase.data.Record.generateUID();
336             
337             options.url = Ext.urlAppend((options.url ? options.url : Tine.Tinebase.tineInit.requestUrl),  'transactionid=' + options.headers['X-Tine20-TransactionId']);
338             
339             // convert non Ext.Direct request to jsonrpc
340             // - convert params
341             // - convert error handling
342             if (options.params && !options.isUpload) {
343                 var params = {};
344                 
345                 var def = Tine.Tinebase.registry.get('serviceMap') ? Tine.Tinebase.registry.get('serviceMap').services[options.params.method] : false;
346                 if (def) {
347                     // sort parms according to def
348                     for (var i = 0, p; i < def.parameters.length; i += 1) {
349                         p = def.parameters[i].name;
350                         params[p] = options.params[p];
351                     }
352                 } else {
353                     for (var param in options.params) {
354                         if (options.params.hasOwnProperty(param) && param !== 'method') {
355                             params[param] = options.params[param];
356                         }
357                     }
358                 }
359                 
360                 options.jsonData = Ext.encode({
361                     jsonrpc: '2.0',
362                     method: options.params.method,
363                     params: params,
364                     id: ++Ext.Direct.TID
365                 });
366                 
367                 options.cbs = {};
368                 options.cbs.success  = options.success  || null;
369                 options.cbs.failure  = options.failure  || null;
370                 options.cbs.callback = options.callback || null;
371                 
372                 options.isImplicitJsonRpc = true;
373                 delete options.params;
374                 delete options.success;
375                 delete options.failure;
376                 delete options.callback;
377             }
378             
379             Ext.Ajax.transactions[options.headers['X-Tine20-TransactionId']] = {
380                 date: new Date(),
381                 json: options.jsonData
382             };
383         });
384         
385         /**
386          * inspect completed responses => staus code == 200
387          * 
388          * - detect resoponse errors (e.g. html from xdebug) and convert to exceptional states
389          * - implicitly transform requests from JSONRPC
390          * 
391          *  NOTE: All programatically catchable exceptions lead to successfull requests
392          *        with the jsonprc protocol. For implicitly converted jsonprc requests we 
393          *        transform error states here and route them to the error methods defined 
394          *        in the request options
395          *        
396          *  NOTE: Illegal json data responses are mapped to error code 530
397          *        Empty resonses (Ext.Decode can't deal with them) are maped to 540
398          *        Memory exhausted to 550
399          */
400         Ext.Ajax.on('requestcomplete', function (connection, response, options) {
401             delete Ext.Ajax.transactions[options.headers['X-Tine20-TransactionId']];
402             
403             // detect resoponse errors (e.g. html from xdebug) and convert into error response
404             if (! options.isUpload && ! response.responseText.match(/^([{\[])|(<\?xml)+/)) {
405                 var exception = {
406                     code: response.responseText !== "" ? 530 : 540,
407                     message: response.responseText !== "" ? 'illegal json data in response' : 'empty response',
408                     traceHTML: response.responseText,
409                     request: options.jsonData,
410                     response: response.responseText
411                 };
412                 
413                 // Fatal error: Allowed memory size of n bytes exhausted (tried to allocate m bytes) 
414                 if (response.responseText.match(/^Fatal error: Allowed memory size of /m)) {
415                     Ext.apply(exception, {
416                         code: 550,
417                         message: response.responseText
418                     });
419                 }
420                 
421                 // encapsulate as jsonrpc response
422                 var requestOptions = Ext.decode(options.jsonData);
423                 response.responseText = Ext.encode({
424                     jsonrpc: requestOptions.jsonrpc,
425                     id: requestOptions.id,
426                     error: {
427                         code: -32000,
428                         message: exception.message,
429                         data: exception
430                     }
431                 });
432             }
433             
434             // strip jsonrpc fragments for non Ext.Direct requests
435             if (options.isImplicitJsonRpc) {
436                 var jsonrpc = Ext.decode(response.responseText);
437                 if (jsonrpc.result) {
438                     response.responseText = Ext.encode(jsonrpc.result);
439                     
440                     if (options.cbs.success) {
441                         options.cbs.success.call(options.scope, response, options);
442                     }
443                     if (options.cbs.callback) {
444                         options.cbs.callback.call(options.scope, options, true, response);
445                     }
446                 } else {
447                     
448                     response.responseText = Ext.encode(jsonrpc.error);
449                     
450                     if (options.cbs.failure) {
451                         options.cbs.failure.call(options.scope, response, options);
452                     } else if (options.cbs.callback) {
453                         options.cbs.callback.call(options.scope, options, false, response);
454                     } else {
455                         var responseData = Ext.decode(response.responseText);
456                             
457                         exception = responseData.data ? responseData.data : responseData;
458                         exception.request = options.jsonData;
459                         exception.response = response.responseText;
460                         
461                         Tine.Tinebase.ExceptionHandler.handleRequestException(exception);
462                     }
463                 }
464             }
465         });
466         
467         /**
468          * inspect request exceptions
469          *  - convert to jsonrpc compatiple exceptional states
470          *  - call generic exception handler if no handler is defined in request options
471          *  
472          * NOTE: Request exceptions are exceptional state from web-server:
473          *       -> status codes != 200 : This kind of exceptions are not part of the jsonrpc protocol
474          *       -> timeouts: status code 520
475          */
476         Ext.Ajax.on('requestexception', function (connection, response, options) {
477             delete Ext.Ajax.transactions[options.headers['X-Tine20-TransactionId']];
478             // map connection errors to errorcode 510 and timeouts to 520
479             var errorCode = response.status > 0 ? response.status :
480                             (response.status === 0 ? 510 : 520);
481                             
482             // convert into error response
483             if (! options.isUpload) {
484                 var exception = {
485                     code: errorCode,
486                     message: 'request exception: ' + response.statusText,
487                     traceHTML: response.responseText,
488                     request: options.jsonData,
489                     requestHeaders: options.headers,
490                     openTransactions: Ext.Ajax.transactions,
491                     response: response.responseText
492                 };
493                 
494                 // encapsulate as jsonrpc response
495                 var requestOptions = Ext.decode(options.jsonData);
496                 response.responseText = Ext.encode({
497                     jsonrpc: requestOptions.jsonrpc,
498                     id: requestOptions.id,
499                     error: {
500                         code: -32000,
501                         message: exception.message,
502                         data: exception
503                     }
504                 });
505             }
506             
507             // NOTE: Tine.data.RecordProxy is implicitRPC atm.
508             if (options.isImplicitJsonRpc) {
509                 var jsonrpc = Ext.decode(response.responseText);
510                 
511                 response.responseText = Ext.encode(jsonrpc.error);
512                     
513                 if (options.cbs.failure) {
514                     options.cbs.failure.call(options.scope, response, options);
515                 } else if (options.cbs.callback) {
516                     options.cbs.callback.call(options.scope, options, false, response);
517                 } else {
518                     var responseData = Ext.decode(response.responseText);
519                     
520                     exception = responseData.data ? responseData.data : responseData;
521                     
522                     Tine.Tinebase.ExceptionHandler.handleRequestException(exception);
523                 }
524                 
525             } else if (! options.failure && ! options.callback) {
526                 Tine.Tinebase.ExceptionHandler.handleRequestException(exception);
527             }
528         });
529     },
530
531     /**
532      * init registry
533      *
534      * @param {Boolean} forceReload
535      * @param {Function} cb
536      * @param {Object} scope
537      */
538     initRegistry: function (forceReload, cb, scope) {
539         Tine.Tinebase.registry = store.namespace(Tine.Tinebase.tineInit.lsPrefix + '.' + 'Tinebase.registry');
540
541         var version = Tine.Tinebase.registry.get('version'),
542             userApplications = Tine.Tinebase.registry.get('userApplications') || [];
543
544         var reloadNeeded =
545                !version
546             || !userApplications
547             || userApplications.length < 2;
548
549         if (forceReload || reloadNeeded) {
550             Tine.Tinebase.tineInit.clearRegistry();
551
552             Ext.Ajax.request({
553                 timeout: 120000, // 2 minutes
554                 params: {
555                     method: Tine.Tinebase.tineInit.getAllRegistryDataMethod
556                 },
557                 failure: function () {
558                     // if registry could not be loaded, this is mostly due to missconfiguaration
559                     // don't send error reports for that!
560                     Tine.Tinebase.ExceptionHandler.handleRequestException({
561                         code: 503
562                     });
563                 },
564                 success: function (response, request) {
565                     var registryData = Ext.util.JSON.decode(response.responseText);
566                     for (var app in registryData) {
567                         if (registryData.hasOwnProperty(app)) {
568                             var appData = registryData[app];
569                             if (Tine[app]) {
570                                 Tine[app].registry = store.namespace(Tine.Tinebase.tineInit.lsPrefix + '.' + app + '.registry');
571
572                                 for (var key in appData) {
573                                     if (appData.hasOwnProperty(key)) {
574                                         if (key === 'preferences') {
575                                             Tine[app].preferences = store.namespace(Tine.Tinebase.tineInit.lsPrefix + '.' + app + '.preferences');
576                                             for (var pref in appData[key]) {
577                                                 if (appData[key].hasOwnProperty(pref)) {
578                                                     Tine[app].preferences.set(pref, appData[key][pref]);
579                                                 }
580                                             }
581
582                                         } else {
583                                             Tine[app].registry.set(key, appData[key]);
584                                         }
585                                     }
586                                 }
587                             }
588                         }
589                     }
590
591                     Tine.Tinebase.tineInit.onRegistryLoad();
592
593                     cb.call(scope);
594                 }
595             });
596         } else {
597             for (var app,i=0;i<userApplications.length;i++) {
598                 app = userApplications[i].name;
599                 if (Tine[app]) {
600                   Tine[app].registry = store.namespace(Tine.Tinebase.tineInit.lsPrefix + '.' + app + '.registry');
601                   Tine[app].preferences = store.namespace(Tine.Tinebase.tineInit.lsPrefix + '.' + app + '.preferences');
602                 }
603             }
604
605             Tine.Tinebase.tineInit.onRegistryLoad();
606             cb.call(scope);
607         }
608
609
610     },
611
612     /**
613      * apply registry data
614      */
615     onRegistryLoad: function() {
616         if (! Tine.Tinebase.tineInit.onPreferenceChangeRegistered 
617             && Tine.Tinebase.registry.get('preferences')
618             && Tine.Tinebase.registry.get('currentAccount')
619             && ! Ext.isNewIE
620         ) {
621             Tine.log.info('tineInit::onRegistryLoad - register onPreferenceChange handler');
622             Tine.Tinebase.preferences.on('replace', Tine.Tinebase.tineInit.onPreferenceChange);
623             Tine.Tinebase.tineInit.onPreferenceChangeRegistered = true;
624         }
625
626         Tine.helpUrl = Tine.Tinebase.registry.get('helpUrl') || Tine.helpUrl;
627
628         Ext.override(Ext.ux.file.Upload, {
629             maxFileUploadSize: Tine.Tinebase.registry.get('maxFileUploadSize'),
630             maxPostSize: Tine.Tinebase.registry.get('maxPostSize')
631         });
632
633         Tine.Tinebase.tineInit.initExtDirect();
634
635         Tine.Tinebase.tineInit.initState();
636
637         if (Tine.Tinebase.registry.get('currentAccount')) {
638             Tine.Tinebase.tineInit.initAppMgr();
639         }
640
641         Tine.Tinebase.tineInit.initUploadMgr();
642
643         Tine.Tinebase.tineInit.initLoginPanel();
644     },
645
646     /**
647      * remove all registry data
648      */
649     clearRegistry: function() {
650         Tine.log.info('tineInit::clearRegistry');
651         store.namespace(Tine.Tinebase.tineInit.lsPrefix).clearAll();
652     },
653
654     /**
655      * executed when a value in Tinebase registry/preferences changed
656      *
657      * @param {string} key
658      * @param {value} oldValue
659      * @param {value} newValue
660      */
661     onPreferenceChange: function (key, oldValue, newValue) {
662         if (Tine.Tinebase.tineInit.isReloading) {
663             return;
664         }
665         
666         switch (key) {
667             case 'windowtype':
668             case 'confirmLogout':
669             case 'timezone':
670             case 'locale':
671                 Tine.log.info('tineInit::onPreferenceChange - reload mainscreen');
672                 Tine.Tinebase.common.reload({
673                     clearCache: key == 'locale'
674                 });
675
676                 break;
677         }
678     },
679     
680     /**
681      * initialise window and windowMgr (only popup atm.)
682      */
683     initWindowMgr: function () {
684         /**
685          * initialise window types
686          */
687         var windowType = 'Browser';
688         Ext.ux.PopupWindow.prototype.url = 'index.php';
689
690         if (Tine.Tinebase.registry && Tine.Tinebase.registry.get('preferences')) {
691             // update window factory window type (required after login)
692             windowType = Tine.Tinebase.registry.get('preferences').get('windowtype');
693             if (! windowType) {
694                 windowType = 'Browser';
695             }
696         }
697
698         Tine.WindowFactory = new Ext.ux.WindowFactory({
699             windowType: windowType
700         });
701
702         // init ApplicationStarter on Ext window once
703         if (windowType == 'Ext') {
704             Tine.Tinebase.ApplicationStarter.init();
705         }
706     },
707     /**
708      * initialise state provider
709      */
710     initState: function () {
711         if (Tine.Tinebase.tineInit.stateful === true) {
712             if (window.isMainWindow || Ext.isIE) {
713                 // NOTE: IE is as always pain in the ass! cross window issues prohibit serialisation of state objects
714                 Ext.state.Manager.setProvider(new Tine.Tinebase.StateProvider());
715             } else {
716                 var mainWindow = Ext.ux.PopupWindowMgr.getMainWindow();
717                 Ext.state.Manager = mainWindow.Ext.state.Manager;
718             }
719         }
720     },
721     
722     /**
723      * add provider to Ext.Direct based on Tine servicemap
724      */
725     initExtDirect: function () {
726         var sam = Tine.Tinebase.registry.get('serviceMap');
727         
728         Ext.Direct.addProvider(Ext.apply(sam, {
729             'type'     : 'jsonrpcprovider',
730             'namespace': 'Tine',
731             'url'      : sam.target
732         }));
733     },
734     
735     /**
736      * init external libraries
737      */
738     initLibs: function () {
739         if (OpenLayers) {
740             // fix OpenLayers script location to find images/themes/...
741             OpenLayers._getScriptLocation = function () {
742                 return 'library/OpenLayers/';
743             };
744         }
745     },
746     
747     /**
748      * initialise application manager
749      */
750     initAppMgr: function () {
751         if (! Ext.isIE9 && ! Ext.isIE && ! window.isMainWindow) {
752             // return app from main window for non-IE browsers
753             Tine.Tinebase.appMgr = Ext.ux.PopupWindowMgr.getMainWindow().Tine.Tinebase.appMgr;
754         } else {
755             Tine.Tinebase.appMgr = new Tine.Tinebase.AppManager();
756         }
757     },
758     
759     /**
760      * initialise upload manager
761      */
762     initUploadMgr: function () {
763         Tine.Tinebase.uploadManager = new Ext.ux.file.UploadManager();
764     },
765     
766     /**
767      * config locales
768      */
769     initLocale: function () {
770         //Locale.setlocale(Locale.LC_ALL, '');
771         Tine.Tinebase.translation = new Locale.Gettext();
772         Tine.Tinebase.translation.textdomain('Tinebase');
773         window._ = function (msgid) {
774             return Tine.Tinebase.translation.dgettext('Tinebase', msgid);
775         };
776         Tine.Tinebase.prototypeTranslation();
777     }
778 };
779
780 Ext.onReady(function () {
781     Tine.Tinebase.tineInit.initWindow();
782     Tine.Tinebase.tineInit.initDebugConsole();
783     Tine.Tinebase.tineInit.initBootSplash();
784     Tine.Tinebase.tineInit.initLocale();
785     Tine.Tinebase.tineInit.initAjax();
786     Tine.Tinebase.tineInit.initLibs();
787
788     Tine.Tinebase.tineInit.initRegistry(false, function() {
789         Tine.Tinebase.tineInit.initWindowMgr();
790         Tine.Tinebase.tineInit.renderWindow();
791     });
792 });