merge filemanager
[tine20] / tine20 / Tinebase / js / widgets / tree / ContextMenu.js
1 /*
2  * Tine 2.0
3  * 
4  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
5  * @author      Philipp Schuele <p.schuele@metaways.de>
6  * @copyright   Copyright (c) 2009 Metaways Infosystems GmbH (http://www.metaways.de)
7  *
8  */
9 Ext.ns('Tine.widgets', 'Tine.widgets.tree');
10
11 /**
12  * returns generic tree context menu with
13  * - create/add
14  * - rename
15  * - delete
16  * - edit grants
17  * 
18  * ctxNode class var is required in calling class
19  */
20 Tine.widgets.tree.ContextMenu = {
21     
22     /**
23      * create new Ext.menu.Menu with actions
24      * 
25      * @param {} config has the node name, actions, etc.
26      * @return {}
27      */
28     getMenu: function(config) {
29         
30         this.config = config;
31                 
32         /****************** create ITEMS array ****************/
33               
34         this.action_add = new Ext.Action({
35             text: String.format(_('Add')),
36             iconCls: 'action_add',
37             handler: this.addNode,
38             requiredGrant: 'addGrant',
39             scope: this.config
40         });
41         
42         this.action_rename = new Ext.Action({
43             text: String.format(_('Rename')),
44             iconCls: 'action_rename',
45             handler: this.renameNode,
46             scope: this.config,
47             requiredGrant: 'editGrant',
48             allowMultiple: false
49         });
50         
51         
52         var i18n = new Locale.Gettext();
53         i18n.textdomain('Tinebase');
54         this.action_delete = new Ext.Action({
55             text: String.format(_('Delete')),
56             iconCls: 'action_delete',
57             handler: this.deleteNode,
58             scope: this.config,
59             requiredGrant: 'deleteGrant',
60             allowMultiple: true
61         });
62         
63         this.action_grants = new Ext.Action({
64             text: _('Manage permissions'),
65             iconCls: 'action_managePermissions',
66             handler: this.managePermissions,
67             requiredGrant: 'editGrant',
68             scope: this.config
69         });
70         
71         this.action_changecolor = new Ext.Action({     
72             text: String.format(_('Set color')),
73             iconCls: 'action_changecolor',
74             requiredGrant: 'deleteGrant',
75             allowMultiple: true,
76             menu: new Ext.menu.ColorMenu({
77                 scope: this,
78                 listeners: {
79                     select: this.changeNodeColor,
80                     scope: this.config
81                 }
82             })                                        
83         });
84         
85         this.action_reload = new Ext.Action({
86             text: String.format(_('Reload')),
87             iconCls: 'x-tbar-loading',
88             handler: this.reloadNode,
89             scope: this.config
90         });
91         
92         this.action_resume = new Ext.Action({
93             text: String.format(_('Resume upload'), config.nodeName),
94             iconCls: 'action_resume',
95             handler: this.onResume,
96             scope: this.config,
97             actionUpdater: this.isResumeEnabled
98         });
99         
100         this.action_pause = new Ext.Action({
101             text: String.format(_('Pause upload'), config.nodeName),
102             iconCls: 'action_pause',
103             handler: this.onPause,
104             actionUpdater: this.isPauseEnabled,
105             scope: this.config
106         });
107         
108         this.action_download = new Ext.Action({
109             text: String.format(_('Download'), config.nodeName),
110             iconCls: 'action_filemanager_save_all',
111             handler: this.downloadFile,
112             actionUpdater: this.isDownloadEnabled,
113             requiredGrant: 'exportGrant',
114             scope: this.config
115         });
116         
117         var items = [];
118         for (var i=0; i < config.actions.length; i++) {
119             switch(config.actions[i]) {
120                 case 'add':
121                     items.push(this.action_add);
122                     break;
123                 case 'delete':                    
124                     items.push(this.action_delete);
125                     break;
126                 case 'rename':
127                     items.push(this.action_rename);
128                     break;
129                 case 'changecolor':
130                     items.push(this.action_changecolor);
131                     break;
132                 case 'grants':
133                     items.push(this.action_grants);
134                     break;
135                 case 'reload':
136                     items.push(this.action_reload);
137                     break;
138                 case 'resume':
139                     items.push(this.action_resume);
140                     break;
141                 case 'pause':
142                     items.push(this.action_pause);
143                     break;
144                 case 'download':
145                     items.push(this.action_download);
146                     break;
147                 default:
148                     // add custom actions
149                     items.push(new Ext.Action(config.actions[i]));
150             }
151         }
152
153              
154         /******************* return menu **********************/
155         
156         return new Ext.menu.Menu({
157             items: items
158         });
159     },
160     
161     /**
162      * create tree node
163      */
164     addNode: function() {
165         Ext.MessageBox.prompt(String.format(_('New {0}'), this.nodeName), String.format(_('Please enter the name of the new {0}:'), this.nodeName), function(_btn, _text) {
166             if( this.scope.ctxNode && _btn == 'ok') {
167                 if (! _text) {
168                     Ext.Msg.alert(String.format(_('No {0} added'), this.nodeName), String.format(_('You have to supply a {0} name!'), this.nodeName));
169                     return;
170                 }
171                 Ext.MessageBox.wait(_('Please wait'), String.format(_('Creating {0}...' ), this.nodeName));
172                 var parentNode = this.scope.ctxNode;
173                 
174                 var params = {
175                     method: this.backend + '.add' + this.backendModel,
176                     name: _text
177                 };
178                 
179                 // TODO try to generalize this and move app specific stuff to app
180                 
181                 if (this.backendModel == 'Node') {
182                     params.application = this.scope.app.appName || this.scope.appName;                            
183                     var filename = parentNode.attributes.nodeRecord.data.path + '/' + _text;
184                     params.filename = filename;
185                     params.type = 'folder';
186                     params.method = this.backend + ".createNode";
187                 }
188                 else if (this.backendModel == 'Container') {
189                     params.application = this.scope.app.appName || this.scope.appName;
190                     params.containerType = Tine.Tinebase.container.path2type(parentNode.attributes.path);
191                 } 
192                 else if (this.backendModel == 'Folder') {
193                     var parentFolder = Tine.Tinebase.appMgr.get('Felamimail').getFolderStore().getById(parentNode.attributes.folder_id);
194                     params.parent = parentFolder.get('globalname');
195                     params.accountId = parentFolder.get('account_id');
196                 }
197                 
198                 Ext.Ajax.request({
199                     params: params,
200                     scope: this,
201                     success: function(result, request){
202                         var nodeData = Ext.util.JSON.decode(result.responseText);
203
204                         // TODO add + icon if it wasn't expandable before
205                         if(nodeData.type == 'folder') {
206                             var nodeData = Ext.util.JSON.decode(result.responseText);
207
208                             var app = Tine.Tinebase.appMgr.get(this.scope.app.appName);
209                             var newNode = app.getMainScreen().getWestPanel().getContainerTreePanel().createTreeNode(nodeData, parentNode);
210                             parentNode.appendChild(newNode);
211                         }
212                         else {
213                             var newNode = this.loader.createNode(nodeData);
214                             parentNode.appendChild(newNode);
215                         }
216                         
217                         parentNode.expand();
218                         this.scope.fireEvent('containeradd', nodeData);
219                         
220                         // TODO: im event auswerten
221                         if (this.backendModel == 'Node') {
222                             this.scope.app.getMainScreen().getCenterPanel().getStore().reload();
223                             if(nodeData.error) {
224                                 Tine.log.debug(nodeData);
225                             }
226                         }
227
228                         Ext.MessageBox.hide();
229                     },
230                     failure: function(result, request) {
231                         var nodeData = Ext.util.JSON.decode(result.responseText);
232                         
233                         var appContext = Tine[this.scope.app.appName];
234                         if(appContext && appContext.handleRequestException) {
235                             appContext.handleRequestException(nodeData.data);
236                         }
237                     }
238                 });
239                 
240             }
241         }, this);
242     },
243     
244     /**
245      * rename tree node
246      */
247     renameNode: function() {
248         if (this.scope.ctxNode) {
249                        
250             var node = this.scope.ctxNode;
251             Ext.MessageBox.show({
252                 title: 'Rename ' + this.nodeName,
253                 msg: String.format(_('Please enter the new name of the {0}:'), this.nodeName),
254                 buttons: Ext.MessageBox.OKCANCEL,
255                 value: node.text,
256                 fn: function(_btn, _text){
257                     if (_btn == 'ok') {
258                         if (! _text) {
259                             Ext.Msg.alert(String.format(_('Not renamed {0}'), this.nodeName), String.format(_('You have to supply a {0} name!'), this.nodeName));
260                             return;
261                         }
262                         Ext.MessageBox.wait(_('Please wait'), String.format(_('Updating {0} "{1}"'), this.nodeName, node.text));
263                         
264                         var params = {
265                             method: this.backend + '.rename' + this.backendModel,
266                             newName: _text
267                         };
268                         
269                         if (this.backendModel == 'Node') {
270                             params.application = this.scope.app.appName || this.scope.appName;                                
271                             var filename = node.attributes.path;
272                             params.sourceFilenames = [filename];
273                             
274                             var targetFilename = "/";
275                             var sourceSplitArray = filename.split("/");
276                             for (var i=1; i<sourceSplitArray.length-1; i++) {
277                                 targetFilename += sourceSplitArray[i] + '/'; 
278                             }
279                             
280                             params.destinationFilenames = [targetFilename + _text];
281                             params.method = this.backend + '.moveNodes';
282                         }
283                         
284                         // TODO try to generalize this
285                         if (this.backendModel == 'Container') {
286                             params.containerId = node.attributes.nodeRecord.data.id;
287                         } else if (this.backendModel == 'Folder') {
288                             var folder = Tine.Tinebase.appMgr.get('Felamimail').getFolderStore().getById(node.attributes.folder_id);
289                             params.oldGlobalName = folder.get('globalname');
290                             params.accountId = folder.get('account_id');
291                         }
292                         
293                         Ext.Ajax.request({
294                             params: params,
295                             scope: this,
296                             success: function(_result, _request){
297                                 var nodeData = Ext.util.JSON.decode(_result.responseText);
298                                 node.setText(_text);
299                                 this.scope.fireEvent('containerrename', nodeData);
300                                 Ext.MessageBox.hide();
301                                 
302                                 // TODO: im event auswerten
303                                 if (this.backendModel == 'Node') {
304                                     this.scope.app.getMainScreen().getCenterPanel().getStore().reload();
305                                 }
306                             },
307                             failure: function(result, request) {
308                                 var nodeData = Ext.util.JSON.decode(result.responseText);
309                                 
310                                 var appContext = Tine[this.scope.app.appName];
311                                 if(appContext && appContext.handleRequestException) {
312                                     appContext.handleRequestException(nodeData.data);
313                                 }
314                             }
315                         });
316                     }
317                 },
318                 scope: this,
319                 prompt: true,
320                 icon: Ext.MessageBox.QUESTION
321             });
322         }
323     },
324     
325     /**
326      * delete tree node
327      */
328     deleteNode: function() {
329         
330         if (this.scope.ctxNode) {
331             var node = this.scope.ctxNode;
332             
333             Ext.MessageBox.confirm(_('Confirm'), String.format(_('Do you really want to delete the {0} "{1}"?'), this.nodeName, node.text), function(_btn){
334                 if ( _btn == 'yes') {
335                     Ext.MessageBox.wait(_('Please wait'), String.format(_('Deleting {0} "{1}"' ), this.nodeName , node.text));
336                     
337                     var params = {
338                         method: this.backend + '.delete' + this.backendModel
339                     };
340                     
341                     if (this.backendModel == 'Node') {
342                                            
343                         var filenames = [node.attributes.path];                                              
344                         params.application = this.scope.app.appName || this.scope.appName;    
345                         params.filenames = filenames;
346                         params.method = this.backend + ".deleteNodes";
347                     
348                     } else if (this.backendModel == 'Container') {
349                         params.containerId = node.attributes.container.id;
350                     } else if (this.backendModel == 'Folder') {
351                         var folder = Tine.Tinebase.appMgr.get('Felamimail').getFolderStore().getById(node.attributes.folder_id);
352                         params.folder = folder.get('globalname');
353                         params.accountId = folder.get('account_id');
354                     } else {
355                         // use default json api style
356                         params.ids = [node.id];
357                         params.method = params.method + 's';
358                     }
359                     
360                     Ext.Ajax.request({
361                         params: params,
362                         scope: this,
363                         success: function(_result, _request){
364                               
365                             if(node) {
366                                 if(node.isSelected()) {
367                                     this.scope.getSelectionModel().select(node.parentNode);
368                                     this.scope.fireEvent('click', node.parentNode, Ext.EventObject.setEvent());
369                                 }
370
371                                 node.remove();
372                                 if (this.backendModel == 'Container') {
373                                     this.scope.fireEvent('containerdelete', node.attributes.container);
374                                 } else if (this.backendModel == 'Node') {
375                                     this.scope.fireEvent('containerdelete', node);
376                                 } else {
377                                     this.scope.fireEvent('containerdelete', node.attributes);
378                                 }
379                             }
380                            
381                             
382                             
383                             Ext.MessageBox.hide();
384                         },
385                         failure: function(result, request) {
386                             var nodeData = Ext.util.JSON.decode(result.responseText);
387                             
388                             var appContext = Tine[this.scope.app.appName];
389                             if(appContext && appContext.handleRequestException) {
390                                 appContext.handleRequestException(nodeData.data);
391                             }
392                         }
393                     });
394                 }
395             }, this);
396         }
397     },
398     
399     /**
400      * change tree node color
401      */
402     changeNodeColor: function(cp, color) {
403         if (this.scope.ctxNode) {
404             var node = this.scope.ctxNode;
405             node.getUI().addClass("x-tree-node-loading");
406                 Ext.Ajax.request({
407                     params: {
408                         method: this.backend + '.set' + this.backendModel + 'Color',
409                         containerId: node.attributes.nodeRecord.data.id,
410                         color: '#' + color
411                     },
412                     scope: this,
413                     success: function(_result, _request){
414                         var nodeData = Ext.util.JSON.decode(_result.responseText);
415                         node.getUI().colorNode.setStyle({color: nodeData.color});
416                         node.attributes.nodeRecord.data.color = nodeData.color;
417                         this.scope.fireEvent('containercolorset', nodeData);
418                         node.getUI().removeClass("x-tree-node-loading");
419                     },
420                     failure: function(result, request) {
421                         var nodeData = Ext.util.JSON.decode(result.responseText);
422                         
423                         var appContext = Tine[this.scope.app.appName];
424                         if(appContext && appContext.handleRequestException) {
425                             appContext.handleRequestException(nodeData.data);
426                         }
427                     }
428                 });
429         
430         }
431     },
432     
433     /**
434      * manage permissions
435      * 
436      */
437     managePermissions: function() {
438         console.log(this.scope.ctxNode);
439         if (this.scope.ctxNode) {
440             var node = this.scope.ctxNode;
441             
442             var grantContainer = node.attributes.nodeRecord.data;
443             if(grantContainer.name.id) {
444                 grantContainer = grantContainer.name;
445             }
446             
447             var window = Tine.widgets.container.GrantsDialog.openWindow({
448                 title: String.format(_('Manage Permissions for {0} "{1}"'), this.nodeName, Ext.util.Format.htmlEncode(node.attributes.nodeRecord.data.name)),
449                 containerName: this.nodeName,
450                 grantContainer: grantContainer
451             });
452         }
453     },
454     
455     /**
456      * reload node
457      */
458     reloadNode: function() {
459         if (this.scope.ctxNode) {
460             var tree = this.scope;
461             this.scope.ctxNode.reload(function(node) {
462                 node.expand();
463                 node.select();
464                 // update grid
465                 tree.filterPlugin.onFilterChange();
466             });                    
467         }
468     }
469     
470 };