e18f4e5e88ba33c2493f8ef6affa459491a41693
[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.logo = 'images/tine_logo.png';
55 Tine.favicon;
56 Tine.title = 'Tine 2.0 \u263c';
57 Tine.weburl = 'http://www.tine20.com/1/welcome-community/';
58 Tine.helpUrl = 'https://wiki.tine20.org/Main_Page';
59 Tine.bugreportUrl = 'https://api.tine20.net/bugreport.php';
60
61 /**
62  * quiet logging in release mode
63  */
64 Ext.LOGLEVEL = Tine.clientVersion.buildType === 'RELEASE' ? 0 : 7;
65 Tine.log = Ext.ux.log;
66
67 Ext.namespace('Tine.Tinebase');
68
69 /**
70  * @class Tine.Tinebase.tineInit
71  * @namespace Tine.Tinebase
72  * @sigleton
73  * static tine init functions
74  */
75 Tine.Tinebase.tineInit = {
76     /**
77      * @cfg {String} getAllRegistryDataMethod
78      */
79     getAllRegistryDataMethod: 'Tinebase.getAllRegistryData',
80
81     /**
82      * @cfg {Boolean} stateful
83      */
84     stateful: true,
85
86     /**
87      * @cfg {String} jsonKeyCookieId
88      */
89     jsonKeyCookieId: 'TINE20JSONKEY',
90
91     /**
92      * @cfg {String} requestUrl
93      */
94     requestUrl: 'index.php',
95     
96     /**
97      * prefix for localStorage keys
98      * @type String
99      */
100     lsPrefix: Tine.Tinebase.common.getUrl('path') + 'Tine',
101     
102     onPreferenceChangeRegistered: false,
103     
104     initWindow: function () {
105         Ext.getBody().on('keydown', function (e) {
106             if (e.ctrlKey && e.getKey() === e.A && ! (e.getTarget('form') || e.getTarget('input') || e.getTarget('textarea'))) {
107                 // disable the native 'select all'
108                 e.preventDefault();
109             } else if (e.getKey() === e.BACKSPACE && ! (e.getTarget('form') || e.getTarget('input') || e.getTarget('textarea'))) {
110                 // disable the native 'history back'
111                 e.preventDefault();
112             } else if (!window.isMainWindow && e.ctrlKey && e.getKey() === e.T) {
113                 // disable the native 'new tab' if in popup window
114                 e.preventDefault();
115             } else if (window.isMainWindow && e.ctrlKey && (e.getKey() === e.L || e.getKey() === e.DELETE)) {
116                 // reload on ctrl-l
117                 Tine.Tinebase.common.reload({
118                     clearCache: true
119                 });
120             }
121         });
122         
123         // disable generic drops
124         Ext.getBody().on('dragover', function (e) {
125             e.stopPropagation();
126             e.preventDefault();
127             e.browserEvent.dataTransfer.dropEffect = 'none';
128         }, this);
129
130         // generic context menu
131         Ext.getBody().on('contextmenu', function (e) {
132             var target = e.getTarget('a',1 ,true);
133             if (target) {
134                 // allow native context menu for links
135                 return;
136             }
137
138             e.stopPropagation();
139             e.preventDefault();
140
141             Tine.Tinebase.MainContextMenu.showIf(e);
142         }, this);
143
144         // open internal links in same window (use router)
145         Ext.getBody().on('click', function(e) {
146             var target = e.getTarget('a',1 ,true);
147             if (target && target.getAttribute('target') == '_blank') {
148                 var href = String(target.getAttribute('href'));
149                     if (href.match(new RegExp('^' + window.lodash.escapeRegExp(Tine.Tinebase.common.getUrl())))) {
150                         target.set({
151                             href: decodeURI(href),
152                             target: "_self"
153                         });
154                     }
155             }
156         }, this);
157     },
158
159     initPostal: function () {
160         if (! window.postal) {
161             return;
162         }
163
164         var config = postal.fedx.transports.xwindow.configure();
165         postal.fedx.transports.xwindow.configure( {
166             localStoragePrefix: Tine.Tinebase.tineInit.lsPrefix + '.' + config.localStoragePrefix
167         } );
168         postal.instanceId('xwindow-' + _.random(0,1000));
169         postal.configuration.promise.createDeferred = function() {
170             return Promise.defer();
171         };
172         postal.configuration.promise.getPromise = function(dfd) {
173             return dfd.promise;
174         };
175         postal.fedx.addFilter( [
176             { channel: 'thirdparty', topic: '#', direction: 'both' },
177             { channel: 'recordchange', topic: '#', direction: 'both' },
178             { channel: 'messagebus', topic: '#', direction: 'both' }
179             //{ channel: 'postal.request-response', topic: '#', direction: 'both' }
180         ] );
181         postal.fedx.signalReady();
182
183         postal.addWireTap( function( d, e ) {
184             Tine.log.debug( "ID: " + postal.instanceId() + " " + JSON.stringify( e, null, 4 ) );
185         } );
186     },
187     
188     initDebugConsole: function () {
189         var map = new Ext.KeyMap(Ext.getDoc(), [{
190             key: [122], // F11
191             ctrl: true,
192             fn: Tine.Tinebase.common.showDebugConsole
193         }]);
194     },
195
196     /**
197      * Each window has exactly one viewport containing a card layout in its lifetime
198      * The default card is a splash screen.
199      * 
200      * default wait panel (picture only no string!)
201      */
202     initBootSplash: function () {
203         Tine.Tinebase.viewport = new Ext.Viewport({
204             layout: 'fit',
205             border: false,
206             items: {
207                 xtype: 'container',
208                 ref: 'tineViewportMaincardpanel',
209                 isWindowMainCardPanel: true,
210                 layout: 'card',
211                 border: false,
212                 activeItem: 0,
213                 items: [{
214                     xtype: 'container',
215                     border: false,
216                     layout: 'fit',
217                     width: 16,
218                     height: 16,
219                     // the content elements come from the initial html so they are displayed fastly
220                     contentEl: Ext.select('div[class^=tine-viewport-]')
221                 }]
222             }
223         });
224     },
225
226     initLoginPanel: function() {
227         if (window.isMainWindow && ! Tine.loginPanel) {
228             var mainCardPanel = Tine.Tinebase.viewport.tineViewportMaincardpanel;
229             Tine.loginPanel = new Tine.Tinebase.LoginPanel({
230                 defaultUsername: Tine.Tinebase.registry.get('defaultUsername'),
231                 defaultPassword: Tine.Tinebase.registry.get('defaultPassword')
232             });
233             mainCardPanel.add(Tine.loginPanel);
234         }
235     },
236
237     showLoginBox: function(cb, scope) {
238         var mainCardPanel = Tine.Tinebase.viewport.tineViewportMaincardpanel,
239             activeItem = mainCardPanel.layout.activeItem;
240
241         mainCardPanel.layout.setActiveItem(Tine.loginPanel.id);
242         Tine.loginPanel.doLayout();
243         Tine.loginPanel.onLogin = function(response) {
244             mainCardPanel.layout.setActiveItem(activeItem);
245             cb.call(scope||window, response);
246         };
247     },
248
249     renderWindow: function () {
250         Tine.log.info('renderWindow::start');
251
252         // check if user is already logged in
253         if (! Tine.Tinebase.registry.get('currentAccount')) {
254             Tine.Tinebase.tineInit.showLoginBox(function(response){
255                 Tine.log.info('tineInit::renderWindow -fetch users registry');
256                 Tine.Tinebase.tineInit.initRegistry(true, function() {
257                     if (Ext.isWebApp) {
258                         Tine.Tinebase.registry.set('sessionId', response.responseData.sessionId);
259                         Tine.Tinebase.registry.set('usercredentialcache', Tine.Tinebase.tineInit.jsonKeyCookieProvider.get('usercredentialcache'));
260                     }
261                     Tine.log.info('tineInit::renderWindow - registry fetched, render main window');
262                     Ext.MessageBox.hide();
263                     Tine.Tinebase.tineInit.checkClientVersion();
264                     Tine.Tinebase.tineInit.initWindowMgr();
265                     Tine.Tinebase.tineInit.renderWindow();
266                 });
267             });
268             
269             return;
270         } else {
271             var sessionLifeTime = Tine.Tinebase.registry.get('sessionLifeTime') || 86400,
272                 presenceObserver = new Tine.Tinebase.PresenceObserver({
273                     maxAbsenseTime: sessionLifeTime / 60,
274                     absenceCallback: function(lastPresence, po) {
275                         Tine.Tinebase.MainMenu.prototype._doLogout()
276                     }
277                 });
278         }
279
280         Tine.Tinebase.router = new director.Router().init();
281         Tine.Tinebase.router.configure({notfound: function () {
282             var defaultApp = Tine.Tinebase.appMgr.getDefault()
283             Tine.Tinebase.router.setRoute('/' + defaultApp.appName);
284         }});
285
286         var route = Tine.Tinebase.router.getRoute(),
287             winConfig = Ext.ux.PopupWindowMgr.get(window);
288
289         Tine.Tinebase.ApplicationStarter.init();
290         Tine.Tinebase.appMgr.getAll();
291
292         if (winConfig) {
293             var mainCardPanel = Tine.Tinebase.viewport.tineViewportMaincardpanel,
294                 card = Tine.WindowFactory.getCenterPanel(winConfig);
295
296             mainCardPanel.add(card);
297             mainCardPanel.layout.setActiveItem(card.id);
298             card.doLayout();
299         } else {
300             Tine.Tinebase.router.dispatch('on', '/' + route.join('/'));
301         }
302     },
303
304     initAjax: function () {
305         Ext.Ajax.url = Tine.Tinebase.tineInit.requestUrl;
306         Ext.Ajax.method = 'POST';
307         
308         Ext.Ajax.defaultHeaders = {
309             'X-Tine20-Request-Type' : 'JSON'
310         };
311         
312         Ext.Ajax.transactions = {};
313
314         Tine.Tinebase.tineInit.jsonKeyCookieProvider = new Ext.ux.util.Cookie({
315             path: String(Tine.Tinebase.common.getUrl('path')).replace(/\/$/, '')
316         });
317
318         /**
319          * inspect all requests done via the ajax singleton
320          * 
321          * - send custom headers
322          * - send json key 
323          * - implicitly transform non jsonrpc requests
324          * 
325          * NOTE: implicitly transformed reqeusts get their callback fn's proxied 
326          *       through generic response inspectors as defined below
327          */
328         Ext.Ajax.on('beforerequest', function (connection, options) {
329
330             var jsonKey = Tine.Tinebase.registry && Tine.Tinebase.registry.get ? Tine.Tinebase.registry.get('jsonKey') : '',
331                 jsonKeyCookieId = Tine.Tinebase.tineInit.jsonKeyCookieId,
332                 cookieJsonKey = Tine.Tinebase.tineInit.jsonKeyCookieProvider.get(jsonKeyCookieId);
333
334             if (cookieJsonKey) {
335                 Tine.Tinebase.tineInit.jsonKeyCookieProvider.clear(jsonKeyCookieId);
336                 // NOTE cookie reset is not always working in IE, so we need to check jsonKey again
337                 if (cookieJsonKey && cookieJsonKey != "null") {
338                     jsonKey = cookieJsonKey;
339                     Tine.Tinebase.registry.set('jsonKey', jsonKey);
340                 }
341             }
342
343             options.headers = options.headers || {};
344             options.headers['X-Tine20-JsonKey'] = jsonKey;
345             options.headers['X-Tine20-TransactionId'] = Tine.Tinebase.data.Record.generateUID();
346             
347             options.url = Ext.urlAppend((options.url ? options.url : Tine.Tinebase.tineInit.requestUrl),  'transactionid=' + options.headers['X-Tine20-TransactionId']);
348             
349             // convert non Ext.Direct request to jsonrpc
350             // - convert params
351             // - convert error handling
352             if (options.params && !options.isUpload) {
353                 var params = {};
354                 
355                 var def = Tine.Tinebase.registry.get('serviceMap') ? Tine.Tinebase.registry.get('serviceMap').services[options.params.method] : false;
356                 if (def) {
357                     // sort parms according to def
358                     for (var i = 0, p; i < def.parameters.length; i += 1) {
359                         p = def.parameters[i].name;
360                         params[p] = options.params[p];
361                     }
362                 } else {
363                     for (var param in options.params) {
364                         if (options.params.hasOwnProperty(param) && param !== 'method') {
365                             params[param] = options.params[param];
366                         }
367                     }
368                 }
369                 
370                 options.jsonData = Ext.encode({
371                     jsonrpc: '2.0',
372                     method: options.params.method,
373                     params: params,
374                     id: ++Ext.Direct.TID
375                 });
376                 
377                 options.cbs = {};
378                 options.cbs.success  = options.success  || null;
379                 options.cbs.failure  = options.failure  || null;
380                 options.cbs.callback = options.callback || null;
381                 
382                 options.isImplicitJsonRpc = true;
383                 delete options.params;
384                 delete options.success;
385                 delete options.failure;
386                 delete options.callback;
387             }
388             
389             Ext.Ajax.transactions[options.headers['X-Tine20-TransactionId']] = {
390                 date: new Date(),
391                 json: options.jsonData
392             };
393         });
394
395
396         
397         /**
398          * inspect completed responses => staus code == 200
399          * 
400          * - detect resoponse errors (e.g. html from xdebug) and convert to exceptional states
401          * - implicitly transform requests from JSONRPC
402          * 
403          *  NOTE: All programatically catchable exceptions lead to successfull requests
404          *        with the jsonprc protocol. For implicitly converted jsonprc requests we 
405          *        transform error states here and route them to the error methods defined 
406          *        in the request options
407          *        
408          *  NOTE: Illegal json data responses are mapped to error code 530
409          *        Empty resonses (Ext.Decode can't deal with them) are maped to 540
410          *        Memory exhausted to 550
411          */
412         Ext.Ajax.on('requestcomplete', function (connection, response, options) {
413             delete Ext.Ajax.transactions[options.headers['X-Tine20-TransactionId']];
414             
415             // detect resoponse errors (e.g. html from xdebug) and convert into error response
416             if (! options.isUpload && ! response.responseText.match(/^([{\[])|(<\?xml)+/)) {
417                 var exception = {
418                     code: response.responseText !== "" ? 530 : 540,
419                     message: response.responseText !== "" ? 'illegal json data in response' : 'empty response',
420                     traceHTML: response.responseText,
421                     request: options.jsonData,
422                     response: response.responseText
423                 };
424                 
425                 // Fatal error: Allowed memory size of n bytes exhausted (tried to allocate m bytes) 
426                 if (response.responseText.match(/^Fatal error: Allowed memory size of /m)) {
427                     Ext.apply(exception, {
428                         code: 550,
429                         message: response.responseText
430                     });
431                 }
432                 
433                 // encapsulate as jsonrpc response
434                 var requestOptions = Ext.decode(options.jsonData);
435                 response.responseText = Ext.encode({
436                     jsonrpc: requestOptions.jsonrpc,
437                     id: requestOptions.id,
438                     error: {
439                         code: -32000,
440                         message: exception.message,
441                         data: exception
442                     }
443                 });
444             }
445             
446             // strip jsonrpc fragments for non Ext.Direct requests
447             if (options.isImplicitJsonRpc) {
448                 var jsonrpc = Ext.decode(response.responseText);
449                 if (jsonrpc.result) {
450                     response.responseText = Ext.encode(jsonrpc.result);
451                     
452                     if (options.cbs.success) {
453                         options.cbs.success.call(options.scope, response, options);
454                     }
455                     if (options.cbs.callback) {
456                         options.cbs.callback.call(options.scope, options, true, response);
457                     }
458                 } else {
459                     
460                     response.responseText = Ext.encode(jsonrpc.error);
461                     
462                     if (options.cbs.failure) {
463                         options.cbs.failure.call(options.scope, response, options);
464                     } else if (options.cbs.callback) {
465                         options.cbs.callback.call(options.scope, options, false, response);
466                     } else {
467                         var responseData = Ext.decode(response.responseText);
468                             
469                         exception = responseData.data ? responseData.data : responseData;
470                         exception.request = options.jsonData;
471                         exception.response = response.responseText;
472                         
473                         Tine.Tinebase.ExceptionHandler.handleRequestException(exception);
474                     }
475                 }
476             }
477         });
478         
479         /**
480          * inspect request exceptions
481          *  - convert to jsonrpc compatiple exceptional states
482          *  - call generic exception handler if no handler is defined in request options
483          *  
484          * NOTE: Request exceptions are exceptional state from web-server:
485          *       -> status codes != 200 : This kind of exceptions are not part of the jsonrpc protocol
486          *       -> timeouts: status code 520
487          */
488         Ext.Ajax.on('requestexception', function (connection, response, options) {
489             delete Ext.Ajax.transactions[options.headers['X-Tine20-TransactionId']];
490             // map connection errors to errorcode 510 and timeouts to 520
491             var errorCode = response.status > 0 ? response.status :
492                             (response.status === 0 ? 510 : 520);
493                             
494             // convert into error response
495             if (! options.isUpload) {
496                 var exception = {
497                     code: errorCode,
498                     message: 'request exception: ' + response.statusText,
499                     traceHTML: response.responseText,
500                     request: options.jsonData,
501                     requestHeaders: options.headers,
502                     openTransactions: Ext.Ajax.transactions,
503                     response: response.responseText
504                 };
505                 
506                 // encapsulate as jsonrpc response
507                 var requestOptions = Ext.decode(options.jsonData);
508                 response.responseText = Ext.encode({
509                     jsonrpc: requestOptions.jsonrpc,
510                     id: requestOptions.id,
511                     error: {
512                         code: -32000,
513                         message: exception.message,
514                         data: exception
515                     }
516                 });
517             }
518             
519             // NOTE: Tine.data.RecordProxy is implicitRPC atm.
520             if (options.isImplicitJsonRpc) {
521                 var jsonrpc = Ext.decode(response.responseText);
522                 
523                 response.responseText = Ext.encode(jsonrpc.error);
524                     
525                 if (options.cbs.failure) {
526                     options.cbs.failure.call(options.scope, response, options);
527                 } else if (options.cbs.callback) {
528                     options.cbs.callback.call(options.scope, options, false, response);
529                 } else {
530                     var responseData = Ext.decode(response.responseText);
531                     
532                     exception = responseData.data ? responseData.data : responseData;
533                     
534                     Tine.Tinebase.ExceptionHandler.handleRequestException(exception);
535                 }
536                 
537             } else if (! options.failure && ! options.callback) {
538                 Tine.Tinebase.ExceptionHandler.handleRequestException(exception);
539             }
540         });
541     },
542
543     /**
544      * init registry
545      *
546      * @param {Boolean} forceReload
547      * @param {Function} cb
548      * @param {Object} scope
549      */
550     initRegistry: function (forceReload, cb, scope) {
551         Tine.Tinebase.registry = store.namespace(Tine.Tinebase.tineInit.lsPrefix + '.' + 'Tinebase.registry');
552
553         var version = Tine.Tinebase.registry.get('version'),
554             userApplications = Tine.Tinebase.registry.get('userApplications') || [];
555
556         var reloadNeeded =
557                !version
558             || !userApplications
559             || userApplications.length < 2;
560
561         if (forceReload || reloadNeeded) {
562             Tine.Tinebase.tineInit.clearRegistry();
563
564             Ext.Ajax.request({
565                 timeout: 120000, // 2 minutes
566                 params: {
567                     method: Tine.Tinebase.tineInit.getAllRegistryDataMethod
568                 },
569                 failure: function () {
570                     // if registry could not be loaded, this is mostly due to missconfiguaration
571                     // don't send error reports for that!
572                     Tine.Tinebase.ExceptionHandler.handleRequestException({
573                         code: 503
574                     });
575                 },
576                 success: function (response, request) {
577                     var registryData = Ext.util.JSON.decode(response.responseText);
578                     for (var app in registryData) {
579                         if (registryData.hasOwnProperty(app)) {
580                             var appData = registryData[app];
581                             Ext.ns('Tine.' + app);
582                             Tine[app].registry = store.namespace(Tine.Tinebase.tineInit.lsPrefix + '.' + app + '.registry');
583
584                             for (var key in appData) {
585                                 if (appData.hasOwnProperty(key)) {
586                                     if (key === 'preferences') {
587                                         Tine[app].preferences = store.namespace(Tine.Tinebase.tineInit.lsPrefix + '.' + app + '.preferences');
588                                         for (var pref in appData[key]) {
589                                             if (appData[key].hasOwnProperty(pref)) {
590                                                 Tine[app].preferences.set(pref, appData[key][pref]);
591                                             }
592                                         }
593
594                                     } else {
595                                         Tine[app].registry.set(key, appData[key]);
596                                     }
597                                 }
598                             }
599                         }
600                     }
601
602                     Tine.Tinebase.tineInit.onRegistryLoad();
603
604                     cb.call(scope);
605                 }
606             });
607         } else {
608             for (var app,i=0;i<userApplications.length;i++) {
609                 app = userApplications[i].name;
610                 Ext.ns('Tine.' + app);
611                 Tine[app].registry = store.namespace(Tine.Tinebase.tineInit.lsPrefix + '.' + app + '.registry');
612                 Tine[app].preferences = store.namespace(Tine.Tinebase.tineInit.lsPrefix + '.' + app + '.preferences');
613             }
614
615             Tine.Tinebase.tineInit.onRegistryLoad();
616             cb.call(scope);
617         }
618
619
620     },
621
622     /**
623      * apply registry data
624      */
625     onRegistryLoad: function() {
626         if (! Tine.Tinebase.tineInit.onPreferenceChangeRegistered 
627             && Tine.Tinebase.registry.get('preferences')
628             && Tine.Tinebase.registry.get('currentAccount')
629             && ! Ext.isNewIE
630         ) {
631             Tine.log.info('tineInit::onRegistryLoad - register onPreferenceChange handler');
632             Tine.Tinebase.preferences.on('replace', Tine.Tinebase.tineInit.onPreferenceChange);
633             Tine.Tinebase.tineInit.onPreferenceChangeRegistered = true;
634         }
635
636         Tine.helpUrl = Tine.Tinebase.registry.get('helpUrl') || Tine.helpUrl;
637         //Do we have a custom weburl for branding?
638         Tine.weburl = Tine.Tinebase.registry.get('brandingWeburl') ? Tine.Tinebase.registry.get('brandingWeburl') : Tine.weburl;
639         //DO we have a custom title for branding?
640         Tine.title = Tine.Tinebase.registry.get('brandingTitle') ? Tine.Tinebase.registry.get('brandingTitle') : Tine.title;
641         Tine.logo = Tine.Tinebase.registry.get('brandingLogo') ? Tine.Tinebase.registry.get('brandingLogo') : Tine.logo;
642         Tine.favicon = Tine.Tinebase.registry.get('brandingFavicon') ? Tine.Tinebase.registry.get('brandingFavicon') : Tine.favicon;
643
644         if (Ext.isWebApp && Tine.Tinebase.registry.get('sessionId')) {
645             // restore session cookie
646             Tine.Tinebase.tineInit.jsonKeyCookieProvider.set('TINE20SESSID', Tine.Tinebase.registry.get('sessionId'));
647             Tine.Tinebase.tineInit.jsonKeyCookieProvider.set('usercredentialcache', Tine.Tinebase.registry.get('usercredentialcache'));
648         }
649
650         Ext.override(Ext.ux.file.Upload, {
651             maxFileUploadSize: Tine.Tinebase.registry.get('maxFileUploadSize'),
652             maxPostSize: Tine.Tinebase.registry.get('maxPostSize')
653         });
654
655         Tine.Tinebase.tineInit.initExtDirect();
656
657         Tine.Tinebase.tineInit.initState();
658
659         if (Tine.Tinebase.registry.get('currentAccount')) {
660             Tine.Tinebase.tineInit.initAppMgr();
661         }
662
663         Tine.Tinebase.tineInit.initUploadMgr();
664
665         Tine.Tinebase.tineInit.initLoginPanel();
666     },
667
668     /**
669      * check client version and reload on demand
670      */
671     checkClientVersion: function() {
672         var serverHash = Tine.Tinebase.registry.get('version').filesHash,
673             clientHash = Tine.clientVersion.filesHash;
674
675         if (clientHash && clientHash != serverHash) {
676             Ext.MessageBox.show({
677                 buttons: Ext.Msg.OK,
678                 icon: Ext.MessageBox.WARNING,
679                 title: i18n._('Your Client is Outdated'),
680                 msg: i18n._('A new client is available, press OK to get this version'),
681                 fn: function() {
682                     Tine.Tinebase.common.reload({
683                         keepRegistry: false,
684                         clearCache: true
685                     });
686                 }
687             });
688         }
689     },
690
691     /**
692      * remove all registry data
693      */
694     clearRegistry: function() {
695         Tine.log.info('tineInit::clearRegistry');
696         if (Ext.isFunction(store.namespace)) {
697             store.namespace(Tine.Tinebase.tineInit.lsPrefix).clearAll();
698         }
699     },
700
701     /**
702      * executed when a value in Tinebase registry/preferences changed
703      *
704      * @param {string} key
705      * @param {value} oldValue
706      * @param {value} newValue
707      */
708     onPreferenceChange: function (key, oldValue, newValue) {
709         if (Tine.Tinebase.tineInit.isReloading) {
710             return;
711         }
712         
713         switch (key) {
714             case 'windowtype':
715             case 'confirmLogout':
716             case 'timezone':
717             case 'locale':
718                 Tine.log.info('tineInit::onPreferenceChange - reload mainscreen');
719                 Tine.Tinebase.common.reload({
720                     clearCache: key == 'locale'
721                 });
722
723                 break;
724         }
725     },
726     
727     /**
728      * initialise window and windowMgr (only popup atm.)
729      */
730     initWindowMgr: function () {
731         // touch UI support
732         if (Ext.isTouchDevice) {
733             require.ensure(["hammerjs"], function() {
734                 require('hammerjs'); // global by include :-(
735
736                 Ext.apply (Ext.EventObject, {
737                     // NOTE: multipoint gesture events have no xy, so we need to grab it from gesture
738                     getXY: function() {
739                         if (this.browserEvent &&
740                             this.browserEvent.gesture &&
741                             this.browserEvent.gesture.center) {
742                             this.xy = [this.browserEvent.gesture.center.x, this.browserEvent.gesture.center.y];
743                         }
744
745                         return this.xy;
746                     }
747                 });
748
749                 var mc = new Hammer.Manager(Ext.getDoc().dom, {
750                     domEvents: true
751                 });
752
753                 // convert two finger taps into contextmenu clicks
754                 mc.add(new Hammer.Tap({
755                     event: 'contextmenu',
756                     pointers: 2
757                 }));
758                 // convert double taps into double clicks
759                 mc.add(new Hammer.Tap({
760                     event: 'dblclick',
761                     taps: 2
762                 }));
763
764                 Ext.getDoc().on('orientationchange', function() {
765                     // @TODO: iOS safari only?
766                     var metas = document.getElementsByTagName('meta');
767                     for (var i = 0; i < metas.length; i++) {
768                         if (metas[i].name == "viewport") {
769                             metas[i].content = "width=device-width, maximum-scale=1.0";
770                             // NOTE: if we don't release the max scale here, we get wired layout effects
771                             metas[i].content = "width=device-width, maximum-scale=10, user-scalable=no";
772                         }
773                     }
774                     // NOTE: need to hide soft-keybord before relayouting to preserve layout
775                     document.activeElement.blur();
776                     Tine.Tinebase.viewport.doLayout.defer(500, Tine.Tinebase.viewport);
777                 }, this);
778
779                 // NOTE: document scroll only happens when soft keybord is displayed and therefore viewport scrolls.
780                 //       in this case, content might not be accessable
781                 //Ext.getDoc().on('scroll', function() {
782                 //
783                 //}, this);
784
785             }, 'Tinebase/js/hammerjs');
786         }
787
788         // initialise window types
789         var windowType = 'Browser';
790         Ext.ux.PopupWindow.prototype.url = 'index.php';
791         if (Tine.Tinebase.registry && Tine.Tinebase.registry.get('preferences')) {
792             // update window factory window type (required after login)
793             windowType = Tine.Tinebase.registry.get('preferences').get('windowtype');
794             if (! windowType) {
795                 windowType = 'Browser';
796             }
797         }
798         windowType = Ext.isTouchDevice ? 'Ext' : windowType;
799
800         Tine.WindowFactory = new Ext.ux.WindowFactory({
801             windowType: windowType
802         });
803     },
804     /**
805      * initialise state provider
806      */
807     initState: function () {
808         if (Tine.Tinebase.tineInit.stateful === true) {
809             if (window.isMainWindow || Ext.isIE) {
810                 // NOTE: IE is as always pain in the ass! cross window issues prohibit serialisation of state objects
811                 Ext.state.Manager.setProvider(new Tine.Tinebase.StateProvider());
812             } else {
813                 var mainWindow = Ext.ux.PopupWindowMgr.getMainWindow();
814                 Ext.state.Manager = mainWindow.Ext.state.Manager;
815             }
816         }
817     },
818     
819     /**
820      * add provider to Ext.Direct based on Tine servicemap
821      */
822     initExtDirect: function () {
823         var sam = Tine.Tinebase.registry.get('serviceMap');
824         
825         Ext.Direct.addProvider(Ext.apply(sam, {
826             'type'     : 'jsonrpcprovider',
827             'namespace': 'Tine',
828             'url'      : sam.target
829         }));
830     },
831     
832     /**
833      * initialise application manager
834      */
835     initAppMgr: function () {
836         if (! Ext.isIE9 && ! Ext.isIE && ! window.isMainWindow) {
837             // return app from main window for non-IE browsers
838             Tine.Tinebase.appMgr = Ext.ux.PopupWindowMgr.getMainWindow().Tine.Tinebase.appMgr;
839         } else {
840             Tine.Tinebase.appMgr = new Tine.Tinebase.AppManager();
841         }
842     },
843     
844     /**
845      * initialise upload manager
846      */
847     initUploadMgr: function () {
848         Tine.Tinebase.uploadManager = new Ext.ux.file.UploadManager();
849     },
850     
851     /**
852      * config locales
853      */
854     initLocale: function () {
855         //Locale.setlocale(Locale.LC_ALL, '');
856         window.i18n = new Locale.Gettext();
857         window.i18n.textdomain('Tinebase');
858
859         window._ = function (msgid) {
860             Tine.log.warn('_() is deprecated, please use i18n._ instead' + new Error().stack);
861             return window.i18n.dgettext('Tinebase', msgid);
862         };
863
864         Tine.Tinebase.prototypeTranslation();
865     }
866 };
867
868 Ext.onReady(function () {
869     Tine.Tinebase.tineInit.initWindow();
870     Tine.Tinebase.tineInit.initPostal();
871     Tine.Tinebase.tineInit.initDebugConsole();
872     Tine.Tinebase.tineInit.initBootSplash();
873     Tine.Tinebase.tineInit.initLocale();
874     Tine.Tinebase.tineInit.initAjax();
875
876     Tine.Tinebase.tineInit.initRegistry(false, function() {
877         Tine.Tinebase.tineInit.checkClientVersion();
878         Tine.Tinebase.tineInit.initWindowMgr();
879         Tine.Tinebase.tineInit.renderWindow();
880     });
881 });