0013074: some context menu entries missing
[tine20] / tine20 / Filemanager / js / FilePicker.js
1 /*
2  * Tine 2.0
3  *
4  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
5  * @author      Michael Spahn <m.spahn@metaways.de>
6  * @copyright   Copyright (c) 2017 Metaways Infosystems GmbH (http://www.metaways.de)
7  */
8 Ext.ns('Tine.Filemanager');
9
10 /**
11  * FilePicker component.
12  *
13  * Standalone file picker for selecting a node or a folder from filemanager.
14  * The filepicker does require the filemanager to be enabled!
15  *
16  * The filepicker offers two events:
17  *  - nodeSelected
18  *  - invalidNodeSelected
19  */
20 Tine.Filemanager.FilePicker = Ext.extend(Ext.Container, {
21     /**
22      * Filemanager app
23      * @private
24      */
25     app: null,
26
27     /**
28      * Layout.
29      * @private
30      */
31     layout: 'fit',
32
33     /**
34      * NodeTreePanel instance
35      * @private
36      */
37     treePanel: null,
38
39     /**
40      * NodeGridPanel instance
41      * @private
42      */
43     gridPanel: null,
44
45     /**
46      * Selected nodes
47      * @private
48      */
49     selection: [],
50
51     /**
52      * Last clicked node
53      * @private
54      */
55     lastClickedNode: null,
56
57     /**
58      * Allow to select one or more node
59      */
60     singleSelect: true,
61
62     /**
63      * A constraint allows to alter the selection behaviour of the picker, for example only allow to select files.
64      *
65      * By default, file and folder are allowed to be selected, the concrete implementation needs to define it's purpose
66      *
67      * Valids constraints:
68      *  - file
69      *  - folder
70      *  - null (take all)
71      */
72     constraint: null,
73
74     /**
75      * Constructor.
76      */
77     initComponent: function () {
78         var model = Tine.Filemanager.Model.Node;
79         this.app = Tine.Tinebase.appMgr.get(model.getMeta('appName'));
80
81         this.treePanel = this.getTreePanel();
82         this.gridPanel = this.getGridPanel();
83
84         this.addEvents(
85             /**
86              * Fires when a file was selected which fulfills all constraints
87              *
88              * @param nodeData selected node data
89              */
90             'nodeSelected',
91             /**
92              * Fires if a node is selected which does not fulfill the provided constraints
93              */
94             'invalidNodeSelected'
95         );
96
97         this.items = [{
98             layout: 'border',
99             border: false,
100             frame: false,
101             items: [{
102                 layout: 'fit',
103                 region: 'west',
104                 frame: false,
105                 width: 200,
106                 border: false,
107                 split: true,
108                 collapsible: true,
109                 header: false,
110                 collapseMode: 'mini',
111                 items: [
112                     this.treePanel
113                 ]
114             }, {
115                 layout: 'fit',
116                 split: true,
117                 frame: false,
118                 region: 'center',
119                 width: 300,
120                 items: [
121                     this.gridPanel
122                 ]
123             }]
124         }];
125
126         Tine.Filemanager.FilePicker.superclass.initComponent.call(this);
127     },
128
129     /**
130      * Updates selected element and triggers an event
131      */
132     updateSelection: function (nodes) {
133         // If selection doesn't fullfil constraint, we don't throw a selectionChange event
134         if (!this.checkConstraint(nodes)) {
135             this.fireEvent('invalidNodeSelected');
136             return false;
137         }
138
139         //  Clear previous selection
140         this.selection = [];
141
142         var me = this;
143         Ext.each(nodes, function (node) {
144             me.selection.push(node.data || node);
145         });
146
147         this.fireEvent('nodeSelected', this.selection);
148     },
149
150     /**
151      * @returns {Tine.Filemanager.NodeTreePanel}
152      */
153     getTreePanel: function () {
154         if (this.treePanel) {
155             return this.treePanel;
156         }
157
158         var me = this;
159         var treePanel = new Tine.Filemanager.NodeTreePanel({
160             height: 200,
161             width: 200,
162             readOnly: true,
163             filterMode: 'filterToolbar'
164         });
165
166         treePanel.getSelectionModel().on('selectionchange', function (selectionModel) {
167             var treeNode = selectionModel.getSelectedNode();
168             me.updateSelection([
169                 treeNode.attributes
170             ]);
171         });
172
173         return treePanel;
174     },
175
176     /**
177      * @returns {*}
178      */
179     getGridPanel: function () {
180         if (this.gridPanel) {
181             return this.gridPanel;
182         }
183
184         var me = this;
185
186         var gridPanel = new Tine.Filemanager.NodeGridPanel({
187             app: me.app,
188             height: 200,
189             width: 200,
190             readOnly: true,
191             enableDD: false,
192             enableDrag: false,
193             treePanel: this.getTreePanel(),
194             hasQuickSearchFilterToolbarPlugin: false,
195             stateIdSuffix: '-FilePicker',
196             plugins: [this.getTreePanel().getFilterPlugin()]
197         });
198
199         gridPanel.getGrid().reconfigure(gridPanel.getStore(), this.getColumnModel());
200         gridPanel.getGrid().getSelectionModel().singleSelect = this.singleSelect;
201         gridPanel.getGrid().getSelectionModel().on('rowselect', function (selModel) {
202             var record = selModel.getSelections();
203             me.updateSelection(record);
204         });
205
206         return gridPanel;
207     },
208
209     /**
210      * Check if selection fits current constraint
211      * @returns {boolean}
212      */
213     checkConstraint: function (nodes) {
214         var me = this;
215         var valid = true;
216
217         Ext.each(nodes, function (node) {
218             if (!me.checkNodeConstraint(node.data || node)) {
219                 valid = false;
220                 return false;
221             }
222         });
223
224         return valid;
225     },
226
227     /**
228      * Checks if a single node matches the constraints
229      *
230      * @param node
231      * @returns {boolean}
232      */
233     checkNodeConstraint: function (node) {
234         // Minimum information to proceed here
235         if (!node.path || !node.id) {
236             return false;
237         }
238
239         // If no constraints apply, skip here
240         if (this.constraint === null) {
241             return true;
242         }
243
244         switch (this.constraint) {
245             case 'file':
246                 if (node.type !== 'file') {
247                     return false;
248                 }
249                 break;
250             case 'folder':
251                 if (node.type !== 'folder') {
252                     return false;
253                 }
254                 break;
255         }
256
257         return true;
258     },
259
260     /**
261      * Customized column model for the grid
262      * @returns {*}
263      */
264     getColumnModel: function () {
265         var columns = [{
266             id: 'name',
267             header: this.app.i18n._("Name"),
268             width: 70,
269             sortable: true,
270             dataIndex: 'name',
271             renderer: Ext.ux.PercentRendererWithName
272         }, {
273             id: 'size',
274             header: this.app.i18n._("Size"),
275             width: 40,
276             sortable: true,
277             dataIndex: 'size',
278             renderer: Tine.Tinebase.common.byteRenderer.createDelegate(this, [2, true], 3)
279         }, {
280             id: 'contenttype',
281             header: this.app.i18n._("Contenttype"),
282             width: 50,
283             sortable: true,
284             dataIndex: 'contenttype',
285             renderer: function (value, metadata, record) {
286
287                 var app = Tine.Tinebase.appMgr.get('Filemanager');
288                 if (record.data.type == 'folder') {
289                     return app.i18n._("Folder");
290                 }
291                 else {
292                     return value;
293                 }
294             }
295         }];
296
297         return new Ext.grid.ColumnModel({
298             defaults: {
299                 sortable: true,
300                 resizable: true
301             },
302             columns: columns
303         });
304     }
305 });