0013214: allow to set fixed calendars as user preference
[tine20] / tine20 / Tinebase / js / widgets / dialog / PreferencesPanel.js
1 /*
2  * Tine 2.0
3  * 
4  * @package     Tinebase
5  * @subpackage  widgets
6  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
7  * @author      Philipp Schüle <p.schuele@metaways.de>
8  * @copyright   Copyright (c) 2009-2012 Metaways Infosystems GmbH (http://www.metaways.de)
9  *
10  * TODO         add pref description to input fields
11  */
12
13 Ext.ns('Tine.widgets', 'Tine.widgets.dialog');
14
15 /**
16  * preferences card panel
17  * -> this panel is filled with the preferences subpanels containing the pref stores for the apps
18  * 
19  * @namespace   Tine.widgets.dialog
20  * @class       Tine.widgets.dialog.PreferencesCardPanel
21  * @extends     Ext.Panel
22  */
23 Tine.widgets.dialog.PreferencesCardPanel = Ext.extend(Ext.Panel, {
24     
25     //private
26     layout: 'card',
27     border: false,
28     frame: true,
29     labelAlign: 'top',
30     autoScroll: true,
31     defaults: {
32         anchor: '100%'
33     },
34     
35     initComponent: function() {
36         this.title = i18n._('Preferences');
37         Tine.widgets.dialog.PreferencesCardPanel.superclass.initComponent.call(this);
38     }
39 });
40
41 /**
42  * preferences panel with the preference input fields for an application
43  * 
44  * @todo add checkbox type
45  */
46 Tine.widgets.dialog.PreferencesPanel = Ext.extend(Ext.Panel, {
47     
48     /**
49      * the prefs store
50      * @cfg {Ext.data.Store}
51      */
52     prefStore: null,
53     
54     /**
55      * @cfg {String} appName
56      */
57     appName: 'Tinebase',
58
59     /**
60      * @cfg {Boolean} adminMode activated?
61      */
62     adminMode: false,
63     
64     //private
65     layout: 'form',
66     border: true,
67     labelAlign: 'top',
68     autoScroll: true,
69     defaults: {
70         anchor: '95%',
71         labelSeparator: ''
72     },
73     bodyStyle: 'padding:5px',
74     
75     /**
76      * init component
77      * @private
78      */
79     initComponent: function() {
80         
81         this.addEvents(
82             /**
83              * @event change
84              * @param appName
85              * Fired when a value is changed
86              */
87             'change'
88         );
89         
90         if (this.prefStore && this.prefStore.getCount() > 0) {
91             Tine.log.debug('Tine.widgets.dialog.PreferencesPanel::initComponent() -> Adding pref items from store:');
92             Tine.log.debug(this.prefStore);
93             
94             this.items = [];
95             this.prefStore.each(function(pref) {
96                 // check if options available -> use combobox or textfield
97                 var fieldDef = {
98                     fieldLabel: pref.get('label'),
99                     name: pref.get('name'),
100                     value: pref.get('value'),
101                     listeners: {
102                         scope: this,
103                         change: function(field, newValue, oldValue) {
104                             // fire change event
105                             this.fireEvent('change', this.appName);
106                         }
107                     },
108                     prefId: pref.id,
109                     description: pref.get('description')
110                 };
111                 
112                 var options = pref.get('options');
113                 // NOTE: some prefs have no default and only one option (e.g. std email account)
114                 if (options.length > 1 || (options.length == 1 && options[0][0] !== '_default_')) {
115                     if (pref.get('uiconfig') && pref.get('uiconfig').xtype) {
116                         // TODO support admin mode / currently this is personal_only
117                         Ext.apply(fieldDef, {
118                             xtype: pref.get('uiconfig').xtype,
119                             recordClass: Tine[pref.get('uiconfig').appName].Model[pref.get('uiconfig').model],
120                             value: pref.get('value') === '_default_' ? [] : pref.get('value'),
121                         });
122                     } else {
123                         Ext.apply(fieldDef, {
124                             xtype: (this.adminMode ? 'lockCombo' : 'combo'),
125                             store: pref.get('options'),
126                             mode: 'local',
127                             forceSelection: true,
128                             allowBlank: false,
129                             triggerAction: 'all'
130                         });
131                     }
132                 } else {
133                     Ext.apply(fieldDef, {
134                         xtype: (this.adminMode ? 'lockTextfield' : 'textfield'),
135                         defaultValue: (options[0] && options[0][1]) ? options[0][1] : '',
136                         isValid: function() {
137                             // crude hack to guess type (prefs need DTD)
138                             var type = this.defaultValue.match(/\(([0-9]*)\)$/) ? 'int' : 'string',
139                                 value = this.getValue();
140                             
141                             // default is always valid
142                             if (value == '_default_') {
143                                 return true;
144                             }
145                             
146                             if (type == 'int') {
147                                 return !! String(value).match(/^\d+$/);
148                             }
149                             
150                             return true;
151                         },
152                         setValue: function(v) {
153                             v = v == '_default_' ? this.defaultValue : v;
154                             Ext.form.TextField.prototype.setValue.call(this, v);
155                         },
156                         getValue: function() {
157                             var value = Ext.form.TextField.prototype.getValue.call(this);
158                             return value == this.defaultValue ? '_default_' : value;
159                         },
160                         postBlur: function() {
161                             var value = this.getValue();
162                             if (value === '') {
163                                 this.setValue('_default_');
164                             }
165                         }
166                     });
167                 }
168                 
169                 if (this.adminMode) {
170                     // set lock (value forced => hiddenFieldData = '0')
171                     fieldDef.hiddenFieldData = (pref.get('type') == 'forced') ? '0' : '1';
172                     fieldDef.hiddenFieldId = pref.get('name') + '_writable';
173                     // disable personal only fields (not quite sure why we get a string here in personal_only field)
174                     fieldDef.disabled = (pref.get('personal_only') === '1' || pref.get('personal_only') === true);
175                 } else {
176                     fieldDef.disabled = (pref.get('type') == 'forced' || pref.get('locked') == true);
177                 }
178                 
179                 try {
180                     var fieldObj = Ext.ComponentMgr.create(fieldDef);
181                     this.items.push(fieldObj);
182
183                     // ugh a bit ugly
184                     // what does that do??
185                     pref.fieldObj = fieldObj;
186                 } catch (e) {
187                     Tine.log.debug(e);
188                     Tine.log.error('Unable to create preference field "' + pref.get('name') + '". Check definition!');
189                     this.prefStore.remove(pref);
190                 }
191             }, this);
192
193         } else {
194             this.html = '<div class="x-grid-empty">' + i18n._('There are no preferences for this application.') + "</div>";
195         }
196         
197         Ext.QuickTips.init();
198
199         Tine.widgets.dialog.PreferencesPanel.superclass.initComponent.call(this);
200     },
201     
202     /**
203      * afterRender -> adds qtips to all elements
204      * 
205      * @private
206      * 
207      * @todo add qtip to label as well
208      */
209     afterRender: function() {
210         Tine.widgets.dialog.PreferencesPanel.superclass.afterRender.call(this);
211         
212         // NOTE: server side translations have problems with quotes. Preferences with quotes
213         //       in their description don't get translated. Thus we (re) translate them here
214         //       as the js translations are much better
215         var app = Tine.Tinebase.appMgr.get(this.appName),
216             gt  = app ? app.i18n._.createDelegate(app.i18n) : i18n._.createDelegate(i18n);
217         
218         if (this.items && this.items.items) {
219             for (var i=0; i < this.items.items.length; i++) {
220                 var field = this.items.items[i];
221                 Ext.QuickTips.register({
222                     target: field,
223                     dismissDelay: 30000,
224                     title: Ext.util.Format.htmlEncode(gt(field.fieldLabel)),
225                     text: Ext.util.Format.htmlEncode(gt(field.description)),
226                     width: 200
227                 });
228             }
229         }
230     },
231     
232     /**
233      * check validity for all panel items
234      * 
235      * @return {Boolean}
236      */
237     isValid: function() {
238         var isValid = true;
239         
240         if (this.items && this.items.items) {
241             var field;
242             for (var i=0; i < this.items.items.length; i++) {
243                 field = this.items.items[i];
244                 if (! field.isValid()) {
245                     field.markInvalid();
246                     isValid = false;
247                 }
248             }
249         }
250         
251         return isValid;
252     }
253 });