Merge branch 'MDL-38346_master' of git://github.com/dmonllao/moodle
[moodle.git] / lib / form / filemanager.js
1 // This file is part of Moodle - http://moodle.org/
2 //
3 // Moodle is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // Moodle is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
15 /**
16  *
17  * File Manager UI
18  * =====
19  * this.api, stores the URL to make ajax request
20  * this.currentpath
21  * this.filepicker_options
22  * this.movefile_dialog
23  * this.mkdir_dialog
24  * this.rename_dialog
25  * this.client_id
26  * this.filecount, how many files in this filemanager
27  * this.maxfiles
28  * this.maxbytes
29  * this.areamaxbytes, the maximum size of the area
30  * this.filemanager, contains reference to filemanager Node
31  * this.selectnode, contains referenct to select-file Node
32  * this.selectui, YUI Panel to select the file
33  *
34  * FileManager options:
35  * =====
36  * this.options.currentpath
37  * this.options.itemid
38  */
41 M.form_filemanager = {templates:{}};
43 M.form_filemanager.set_templates = function(Y, templates) {
44     M.form_filemanager.templates = templates;
45 }
47 /**
48  * This fucntion is called for each file picker on page.
49  */
50 M.form_filemanager.init = function(Y, options) {
51     var FileManagerHelper = function(options) {
52         FileManagerHelper.superclass.constructor.apply(this, arguments);
53     };
54     FileManagerHelper.NAME = "FileManager";
55     FileManagerHelper.ATTRS = {
56         options: {},
57         lang: {}
58     };
60     Y.extend(FileManagerHelper, Y.Base, {
61         api: M.cfg.wwwroot+'/repository/draftfiles_ajax.php',
62         menus: {},
63         initializer: function(options) {
64             this.options = options;
65             if (options.mainfile) {
66                 this.enablemainfile = options.mainfile;
67             }
68             this.client_id = options.client_id;
69             this.currentpath = '/';
70             this.maxfiles = options.maxfiles;
71             this.maxbytes = options.maxbytes;
72             this.areamaxbytes = options.areamaxbytes;
73             this.emptycallback = null; // Used by drag and drop upload
75             this.filepicker_options = options.filepicker?options.filepicker:{};
76             this.filepicker_options.client_id = this.client_id;
77             this.filepicker_options.context = options.context;
78             this.filepicker_options.maxfiles = this.maxfiles;
79             this.filepicker_options.maxbytes = this.maxbytes;
80             this.filepicker_options.areamaxbytes = this.areamaxbytes;
81             this.filepicker_options.env = 'filemanager';
82             this.filepicker_options.itemid = options.itemid;
84             if (options.filecount) {
85                 this.filecount = options.filecount;
86             } else {
87                 this.filecount = 0;
88             }
89             // prepare filemanager for drag-and-drop upload
90             this.filemanager = Y.one('#filemanager-'+options.client_id);
91             if (this.filemanager.hasClass('filemanager-container') || !this.filemanager.one('.filemanager-container')) {
92                 this.dndcontainer = this.filemanager;
93             } else  {
94                 this.dndcontainer = this.filemanager.one('.filemanager-container');
95                 if (!this.dndcontainer.get('id')) {
96                     this.dndcontainer.generateID();
97                 }
98             }
99             // save template for one path element and location of path bar
100             if (this.filemanager.one('.fp-path-folder')) {
101                 this.pathnode = this.filemanager.one('.fp-path-folder');
102                 this.pathbar = this.pathnode.get('parentNode');
103                 this.pathbar.removeChild(this.pathnode);
104             }
105             // initialize 'select file' panel
106             this.selectnode = Y.Node.createWithFilesSkin(M.form_filemanager.templates.fileselectlayout);
107             this.selectnode.generateID();
108             this.selectui = new Y.Panel({
109                 srcNode      : this.selectnode,
110                 zIndex       : 7600,
111                 centered     : true,
112                 modal        : true,
113                 close        : true,
114                 render       : true
115             });
116             this.selectui.plug(Y.Plugin.Drag,{handles:['#'+this.selectnode.get('id')+' .yui3-widget-hd']});
117             this.selectui.hide();
118             this.setup_select_file();
119             // setup buttons onclick events
120             this.setup_buttons();
121             // set event handler for lazy loading of thumbnails
122             this.filemanager.one('.fp-content').on(['scroll','resize'], this.content_scrolled, this);
123             // display files
124             this.viewmode = 1; // TODO take from cookies?
125             this.filemanager.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').removeClass('checked')
126             this.filemanager.all('.fp-vb-icons').addClass('checked')
127             this.refresh(this.currentpath); // MDL-31113 get latest list from server
128         },
130         wait: function() {
131            this.filemanager.addClass('fm-updating');
132         },
133         request: function(args, redraw) {
134             var api = this.api + '?action='+args.action;
135             var params = {};
136             var scope = this;
137             if (args['scope']) {
138                 scope = args['scope'];
139             }
140             params['sesskey'] = M.cfg.sesskey;
141             params['client_id'] = this.client_id;
142             params['filepath'] = this.currentpath;
143             params['itemid'] = this.options.itemid?this.options.itemid:0;
144             if (args['params']) {
145                 for (i in args['params']) {
146                     params[i] = args['params'][i];
147                 }
148             }
149             var cfg = {
150                 method: 'POST',
151                 on: {
152                     complete: function(id,o,p) {
153                         if (!o) {
154                             alert('IO FATAL');
155                             return;
156                         }
157                         var data = null;
158                         try {
159                             data = Y.JSON.parse(o.responseText);
160                         } catch(e) {
161                             scope.print_msg(M.str.repository.invalidjson, 'error');
162                             Y.error(M.str.repository.invalidjson+":\n"+o.responseText);
163                             return;
164                         }
165                         if (data && data.tree && scope.set_current_tree) {
166                             scope.set_current_tree(data.tree);
167                         }
168                         args.callback(id,data,p);
169                     }
170                 },
171                 arguments: {
172                     scope: scope
173                 },
174                 headers: {
175                     'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
176                 },
177                 data: build_querystring(params)
178             };
179             if (args.form) {
180                 cfg.form = args.form;
181             }
182             Y.io(api, cfg);
183             if (redraw) {
184                 this.wait();
185             }
186         },
187         filepicker_callback: function(obj) {
188             this.filecount++;
189             this.check_buttons();
190             this.refresh(this.currentpath);
191             if (typeof M.core_formchangechecker != 'undefined') {
192                 M.core_formchangechecker.set_form_changed();
193             }
194         },
195         check_buttons: function() {
196             if (this.filecount>0) {
197                 this.filemanager.removeClass('fm-nofiles');
198             } else {
199                 this.filemanager.addClass('fm-nofiles');
200             }
201             if (this.filecount >= this.maxfiles && this.maxfiles!=-1) {
202                 this.filemanager.addClass('fm-maxfiles');
203             }
204             else {
205                 this.filemanager.removeClass('fm-maxfiles');
206             }
207         },
208         refresh: function(filepath) {
209             var scope = this;
210             this.currentpath = filepath;
211             if (!filepath) {
212                 filepath = this.currentpath;
213             } else {
214                 this.currentpath = filepath;
215             }
216             this.request({
217                 action: 'list',
218                 scope: scope,
219                 params: {'filepath':filepath},
220                 callback: function(id, obj, args) {
221                     scope.filecount = obj.filecount;
222                     scope.options = obj;
223                     scope.lazyloading = {};
224                     scope.check_buttons();
225                     scope.render(obj);
226                 }
227             }, true);
228         },
229         /** displays message in a popup */
230         print_msg: function(msg, type) {
231             var header = M.str.moodle.error;
232             if (type != 'error') {
233                 type = 'info'; // one of only two types excepted
234                 header = M.str.moodle.info;
235             }
236             if (!this.msg_dlg) {
237                 this.msg_dlg_node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.message);
238                 var nodeid = this.msg_dlg_node.generateID();
240                 this.msg_dlg = new Y.Panel({
241                     srcNode      : this.msg_dlg_node,
242                     zIndex       : 8000,
243                     centered     : true,
244                     modal        : true,
245                     visible      : false,
246                     render       : true
247                 });
248                 this.msg_dlg.plug(Y.Plugin.Drag,{handles:['#'+nodeid+' .yui3-widget-hd']});
249                 this.msg_dlg_node.one('.fp-msg-butok').on('click', function(e) {
250                     e.preventDefault();
251                     this.msg_dlg.hide();
252                 }, this);
253             }
255             this.msg_dlg.set('headerContent', header);
256             this.msg_dlg_node.removeClass('fp-msg-info').removeClass('fp-msg-error').addClass('fp-msg-'+type)
257             this.msg_dlg_node.one('.fp-msg-text').setContent(Y.Escape.html(msg));
258             this.msg_dlg.show();
259         },
260         is_disabled: function() {
261             return this.filemanager.ancestor('.fitem.disabled') != null;
262         },
263         setup_buttons: function() {
264             var button_download = this.filemanager.one('.fp-btn-download');
265             var button_create   = this.filemanager.one('.fp-btn-mkdir');
266             var button_addfile  = this.filemanager.one('.fp-btn-add');
268             // setup 'add file' button
269             button_addfile.on('click', this.show_filepicker, this);
271             var dndarrow = this.filemanager.one('.dndupload-arrow');
272             if (dndarrow) {
273                 dndarrow.on('click', this.show_filepicker, this);
274             }
276             // setup 'make a folder' button
277             if (this.options.subdirs) {
278                 button_create.on('click',function(e) {
279                     e.preventDefault();
280                     if (this.is_disabled()) {
281                         return;
282                     }
283                     var scope = this;
284                     // a function used to perform an ajax request
285                     var perform_action = function(e) {
286                         e.preventDefault();
287                         var foldername = Y.one('#fm-newname-'+scope.client_id).get('value');
288                         if (!foldername) {
289                             scope.mkdir_dialog.hide();
290                             return;
291                         }
292                         scope.request({
293                             action:'mkdir',
294                             params: {filepath:scope.currentpath, newdirname:foldername},
295                             callback: function(id, obj, args) {
296                                 var filepath = obj.filepath;
297                                 scope.mkdir_dialog.hide();
298                                 scope.refresh(filepath);
299                                 Y.one('#fm-newname-'+scope.client_id).set('value', '');
300                                 if (typeof M.core_formchangechecker != 'undefined') {
301                                     M.core_formchangechecker.set_form_changed();
302                                 }
303                             }
304                         });
305                     }
306                     if (!this.mkdir_dialog) {
307                         var node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.mkdir);
308                         this.mkdir_dialog = new Y.Panel({
309                             srcNode      : node,
310                             zIndex       : 8000,
311                             centered     : true,
312                             modal        : true,
313                             visible      : false,
314                             render       : true
315                         });
316                         this.mkdir_dialog.plug(Y.Plugin.Drag,{handles:['.yui3-widget-hd']});
317                         node.one('.fp-dlg-butcreate').on('click', perform_action, this);
318                         node.one('input').set('id', 'fm-newname-'+this.client_id).
319                             on('keydown', function(e){
320                                 if (e.keyCode == 13) {Y.bind(perform_action, this)(e);}
321                             }, this);
322                         node.one('label').set('for', 'fm-newname-' + this.client_id);
323                         node.all('.fp-dlg-butcancel').on('click', function(e){e.preventDefault();this.mkdir_dialog.hide();}, this);
324                         node.all('.fp-dlg-curpath').set('id', 'fm-curpath-'+this.client_id);
325                     }
326                     this.mkdir_dialog.show();
327                     Y.one('#fm-newname-'+scope.client_id).focus();
328                     Y.all('#fm-curpath-'+scope.client_id).setContent(Y.Escape.html(this.currentpath))
329                 }, this);
330             } else {
331                 this.filemanager.addClass('fm-nomkdir');
332             }
334             // setup 'download this folder' button
335             button_download.on('click',function(e) {
336                 e.preventDefault();
337                 if (this.is_disabled()) {
338                     return;
339                 }
340                 var scope = this;
341                 // perform downloaddir ajax request
342                 this.request({
343                     action: 'downloaddir',
344                     scope: scope,
345                     callback: function(id, obj, args) {
346                         if (obj) {
347                             scope.refresh(obj.filepath);
348                             node = Y.Node.create('<iframe></iframe>').setStyles({
349                                 visibility : 'hidden',
350                                 width : '1px',
351                                 height : '1px'
352                             });
353                             node.set('src', obj.fileurl);
354                             Y.one('body').appendChild(node);
355                         } else {
356                             scope.print_msg(M.str.repository.draftareanofiles, 'error');
357                         }
358                     }
359                 });
360             }, this);
362             this.filemanager.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').
363                 on('click', function(e) {
364                     e.preventDefault();
365                     var viewbar = this.filemanager.one('.fp-viewbar')
366                     if (!this.is_disabled() && (!viewbar || !viewbar.hasClass('disabled'))) {
367                         this.filemanager.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').removeClass('checked')
368                         if (e.currentTarget.hasClass('fp-vb-tree')) {
369                             this.viewmode = 2;
370                         } else if (e.currentTarget.hasClass('fp-vb-details')) {
371                             this.viewmode = 3;
372                         } else {
373                             this.viewmode = 1;
374                         }
375                         e.currentTarget.addClass('checked')
376                         this.render();
377                     }
378                 }, this);
379         },
381         show_filepicker: function (e) {
382             // if maxfiles == -1, the no limit
383             e.preventDefault();
384             if (this.is_disabled()) {
385                 return;
386             }
387             var options = this.filepicker_options;
388             options.formcallback = this.filepicker_callback;
389             // XXX: magic here, to let filepicker use filemanager scope
390             options.magicscope = this;
391             options.savepath = this.currentpath;
392             M.core_filepicker.show(Y, options);
393         },
395         print_path: function() {
396             var p = this.options.path;
397             this.pathbar.setContent('').addClass('empty');
398             if (p && p.length!=0 && this.viewmode != 2) {
399                 for(var i = 0; i < p.length; i++) {
400                     var el = this.pathnode.cloneNode(true);
401                     this.pathbar.appendChild(el);
403                     if (i == 0) {
404                         el.addClass('first');
405                     }
406                     if (i == p.length-1) {
407                         el.addClass('last');
408                     }
410                     if (i%2) {
411                         el.addClass('even');
412                     } else {
413                         el.addClass('odd');
414                     }
415                     el.one('.fp-path-folder-name').setContent(Y.Escape.html(p[i].name)).
416                         on('click', function(e, path) {
417                             e.preventDefault();
418                             if (!this.is_disabled()) {
419                                 this.refresh(path);
420                             }
421                         }, this, p[i].path);
422                 }
423                 this.pathbar.removeClass('empty');
424             }
425         },
426         get_filepath: function(obj) {
427             if (obj.path && obj.path.length) {
428                 return obj.path[obj.path.length-1].path;
429             }
430             return '';
431         },
432         treeview_dynload: function(node, cb) {
433             var retrieved_children = {};
434             if (node.children) {
435                 for (var i in node.children) {
436                     retrieved_children[node.children[i].path] = node.children[i];
437                 }
438             }
439             if (!node.path || node.path == '/') {
440                 // this is a root pseudo folder
441                 node.fileinfo.filepath = '/';
442                 node.fileinfo.type = 'folder';
443                 node.fileinfo.fullname = node.fileinfo.title;
444                 node.fileinfo.filename = '.';
445             }
446             this.request({
447                 action:'list',
448                 params: {filepath:node.path?node.path:''},
449                 scope:this,
450                 callback: function(id, obj, args) {
451                     var list = obj.list;
452                     var scope = args.scope;
453                     // check that user did not leave the view mode before recieving this response
454                     if (!(scope.viewmode == 2 && node && node.getChildrenEl())) {
455                         return;
456                     }
457                     if (cb != null) { // (in manual mode do not update current path)
458                         scope.options = obj;
459                         scope.currentpath = node.path?node.path:'/';
460                     }
461                     node.highlight(false);
462                     node.origlist = obj.list ? obj.list : null;
463                     node.origpath = obj.path ? obj.path : null;
464                     node.children = [];
465                     for(k in list) {
466                         if (list[k].type == 'folder' && retrieved_children[list[k].filepath]) {
467                             // if this child is a folder and has already been retrieved
468                             retrieved_children[list[k].filepath].fileinfo = list[k];
469                             node.children[node.children.length] = retrieved_children[list[k].filepath];
470                         } else {
471                             // append new file to the list
472                             scope.view_files([list[k]]);
473                         }
474                     }
475                     if (cb == null) {
476                         node.refresh();
477                     } else {
478                         // invoke callback requested by TreeView component
479                         cb();
480                     }
481                     scope.content_scrolled();
482                 }
483             }, false);
484         },
485         content_scrolled: function(e) {
486             setTimeout(Y.bind(function() {
487                 if (this.processingimages) {return;}
488                 this.processingimages = true;
489                 var scope = this,
490                     fpcontent = this.filemanager.one('.fp-content'),
491                     fpcontenty = fpcontent.getY(),
492                     fpcontentheight = fpcontent.getStylePx('height'),
493                     is_node_visible = function(node) {
494                         var offset = node.getY()-fpcontenty;
495                         if (offset <= fpcontentheight && (offset >=0 || offset+node.getStylePx('height')>=0)) {
496                             return true;
497                         }
498                         return false;
499                     };
500                 // replace src for visible images that need to be lazy-loaded
501                 if (scope.lazyloading) {
502                     fpcontent.all('img').each( function(node) {
503                         if (node.get('id') && scope.lazyloading[node.get('id')] && is_node_visible(node)) {
504                             node.setImgRealSrc(scope.lazyloading);
505                         }
506                     });
507                 }
508                 this.processingimages = false;
509             }, this), 200)
510         },
511         view_files: function(appendfiles) {
512             this.filemanager.removeClass('fm-updating').removeClass('fm-noitems');
513             if ((appendfiles == null) && (!this.options.list || this.options.list.length == 0) && this.viewmode != 2) {
514                 this.filemanager.addClass('fm-noitems');
515                 return;
516             }
517             var list = (appendfiles != null) ? appendfiles : this.options.list;
518             var element_template;
519             if (this.viewmode == 2 || this.viewmode == 3) {
520                 element_template = Y.Node.create(M.form_filemanager.templates.listfilename);
521             } else {
522                 this.viewmode = 1;
523                 element_template = Y.Node.create(M.form_filemanager.templates.iconfilename);
524             }
525             var options = {
526                 viewmode : this.viewmode,
527                 appendonly : appendfiles != null,
528                 filenode : element_template,
529                 callbackcontext : this,
530                 callback : function(e, node) {
531                     if (e.preventDefault) { e.preventDefault(); }
532                     if (node.type == 'folder') {
533                         this.refresh(node.filepath);
534                     } else {
535                         this.select_file(node);
536                     }
537                 },
538                 rightclickcallback : function(e, node) {
539                     if (e.preventDefault) { e.preventDefault(); }
540                     this.select_file(node);
541                 },
542                 classnamecallback : function(node) {
543                     var classname = '';
544                     if (node.type == 'folder' || (!node.type && !node.filename)) {
545                         classname = classname + ' fp-folder';
546                     }
547                     if (node.filename || node.filepath || (node.path && node.path != '/')) {
548                         classname = classname + ' fp-hascontextmenu';
549                     }
550                     if (node.isref) {
551                         classname = classname + ' fp-isreference';
552                     }
553                     if (node.refcount) {
554                         classname = classname + ' fp-hasreferences';
555                     }
556                     if (node.originalmissing) {
557                         classname = classname + ' fp-originalmissing';
558                     }
559                     if (node.sortorder == 1) { classname = classname + ' fp-mainfile';}
560                     return Y.Lang.trim(classname);
561                 }
562             };
563             if (this.viewmode == 2) {
564                 options.dynload = true;
565                 options.filepath = this.options.path;
566                 options.treeview_dynload = this.treeview_dynload;
567                 options.norootrightclick = true;
568                 options.callback = function(e, node) {
569                     // TODO MDL-32736 e is not an event here but an object with properties 'event' and 'node'
570                     if (!node.fullname) {return;}
571                     if (node.type != 'folder') {
572                         if (e.node.parent && e.node.parent.origpath) {
573                             // set the current path
574                             this.options.path = e.node.parent.origpath;
575                             this.options.list = e.node.parent.origlist;
576                             this.print_path();
577                         }
578                         this.currentpath = node.filepath;
579                         this.select_file(node);
580                     } else {
581                         // save current path and filelist (in case we want to jump to other viewmode)
582                         this.options.path = e.node.origpath;
583                         this.options.list = e.node.origlist;
584                         this.currentpath = node.filepath;
585                         this.print_path();
586                         //this.content_scrolled();
587                     }
588                 };
589             }
590             if (!this.lazyloading) {
591                 this.lazyloading={};
592             }
593             this.filemanager.one('.fp-content').fp_display_filelist(options, list, this.lazyloading);
594             this.content_scrolled();
595         },
596         populate_licenses_select: function(node) {
597             if (!node) {
598                 return;
599             }
600             node.setContent('');
601             var licenses = this.options.licenses;
602             for (var i in licenses) {
603                 var option = Y.Node.create('<option/>').
604                     set('value', licenses[i].shortname).
605                     setContent(Y.Escape.html(licenses[i].fullname));
606                 node.appendChild(option)
607             }
608         },
609         set_current_tree: function(tree) {
610             var appendfilepaths = function(list, node) {
611                 if (!node || !node.children || !node.children.length) {return;}
612                 for (var i in node.children) {
613                     list[list.length] = node.children[i].filepath;
614                     appendfilepaths(list, node.children[i]);
615                 }
616             }
617             var list = ['/'];
618             appendfilepaths(list, tree);
619             var selectnode = this.selectnode;
620             node = selectnode.one('.fp-path select');
621             node.setContent('');
622             for (var i in list) {
623                 node.appendChild(Y.Node.create('<option/>').
624                     set('value', list[i]).setContent(Y.Escape.html(list[i])));
625             }
626         },
627         update_file: function(confirmed) {
628             var selectnode = this.selectnode;
629             var fileinfo = this.selectui.fileinfo;
631             var newfilename = Y.Lang.trim(selectnode.one('.fp-saveas input').get('value'));
632             var filenamechanged = (newfilename && newfilename != fileinfo.fullname);
633             var pathselect = selectnode.one('.fp-path select'),
634                     pathindex = pathselect.get('selectedIndex'),
635                     targetpath = pathselect.get("options").item(pathindex).get('value');
636             var filepathchanged = (targetpath != this.get_parent_folder_name(fileinfo));
637             var newauthor = Y.Lang.trim(selectnode.one('.fp-author input').get('value'));
638             var authorchanged = (newauthor != Y.Lang.trim(fileinfo.author));
639             var licenseselect = selectnode.one('.fp-license select'),
640                     licenseindex = licenseselect.get('selectedIndex'),
641                     newlicense = licenseselect.get("options").item(licenseindex).get('value');
642             var licensechanged = (newlicense != fileinfo.license);
644             var params, action;
645             var dialog_options = {callback:this.update_file, callbackargs:[true], scope:this};
646             if (fileinfo.type == 'folder') {
647                 if (!newfilename) {
648                     this.print_msg(M.str.repository.entername, 'error');
649                     return;
650                 }
651                 if (filenamechanged || filepathchanged) {
652                     if (!confirmed) {
653                         dialog_options.message = M.str.repository.confirmrenamefolder;
654                         this.show_confirm_dialog(dialog_options);
655                         return;
656                     }
657                     params = {filepath:fileinfo.filepath, newdirname:newfilename, newfilepath:targetpath};
658                     action = 'updatedir';
659                 }
660             } else {
661                 if (!newfilename) {
662                     this.print_msg(M.str.repository.enternewname, 'error');
663                     return;
664                 }
665                 if ((filenamechanged || filepathchanged) && !confirmed && fileinfo.refcount) {
666                     dialog_options.message = M.util.get_string('confirmrenamefile', 'repository', fileinfo.refcount);
667                     this.show_confirm_dialog(dialog_options);
668                     return;
669                 }
670                 if (filenamechanged || filepathchanged || licensechanged || authorchanged) {
671                     params = {filepath:fileinfo.filepath, filename:fileinfo.fullname,
672                         newfilename:newfilename, newfilepath:targetpath,
673                         newlicense:newlicense, newauthor:newauthor};
674                     action = 'updatefile';
675                 }
676             }
677             if (!action) {
678                 // no changes
679                 this.selectui.hide();
680                 return;
681             }
682             selectnode.addClass('loading');
683             this.request({
684                 action: action,
685                 scope: this,
686                 params: params,
687                 callback: function(id, obj, args) {
688                     if (obj.error) {
689                         selectnode.removeClass('loading');
690                         args.scope.print_msg(obj.error, 'error');
691                     } else {
692                         args.scope.selectui.hide();
693                         args.scope.refresh((obj && obj.filepath) ? obj.filepath : '/');
694                         if (typeof M.core_formchangechecker != 'undefined') {
695                             M.core_formchangechecker.set_form_changed();
696                         }
697                     }
698                 }
699             });
700         },
701         /**
702          * Displays a confirmation dialog
703          * Expected attributes in dialog_options: message, callback, callbackargs(optional), scope(optional)
704          */
705         show_confirm_dialog: function(dialog_options) {
706             // instead of M.util.show_confirm_dialog(e, dialog_options);
707             if (!this.confirm_dlg) {
708                 this.confirm_dlg_node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.confirmdialog);
709                 var node = this.confirm_dlg_node;
710                 node.generateID();
711                 this.confirm_dlg = new Y.Panel({
712                     srcNode      : node,
713                     zIndex       : 8000,
714                     centered     : true,
715                     modal        : true,
716                     visible      : false,
717                     render       : true,
718                     buttons      : {}
719                 });
720                 this.confirm_dlg.plug(Y.Plugin.Drag,{handles:['#'+node.get('id')+' .yui3-widget-hd']});
721                 var handle_confirm = function(ev) {
722                     var dlgopt = this.confirm_dlg.dlgopt;
723                     ev.preventDefault();
724                     this.confirm_dlg.hide();
725                     if (dlgopt.callback) {
726                         if (dlgopt.callbackargs) {
727                             dlgopt.callback.apply(dlgopt.scope || this, dlgopt.callbackargs);
728                         } else {
729                             dlgopt.callback.apply(dlgopt.scope || this);
730                         }
731                     }
732                 }
733                 var handle_cancel = function(ev) {
734                     ev.preventDefault();
735                     this.confirm_dlg.hide();
736                 }
737                 node.one('.fp-dlg-butconfirm').on('click', handle_confirm, this);
738                 node.one('.fp-dlg-butcancel').on('click', handle_cancel, this);
739             }
740             this.confirm_dlg.dlgopt = dialog_options;
741             this.confirm_dlg_node.one('.fp-dlg-text').setContent(dialog_options.message);
742             this.confirm_dlg.show();
743         },
744         setup_select_file: function() {
745             var selectnode = this.selectnode;
746             // bind labels with corresponding inputs
747             selectnode.all('.fp-saveas,.fp-path,.fp-author,.fp-license').each(function (node) {
748                 node.all('label').set('for', node.one('input,select').generateID());
749             });
750             this.populate_licenses_select(selectnode.one('.fp-license select'));
751             // register event on clicking buttons
752             selectnode.one('.fp-file-update').on('click', function(e) {
753                 e.preventDefault();
754                 this.update_file();
755             }, this);
756             selectnode.all('form').on('keydown', function(e) {
757                 if (e.keyCode == 13) {
758                     e.preventDefault();
759                     this.update_file();
760                 }
761             }, this);
762             selectnode.one('.fp-file-download').on('click', function(e) {
763                 e.preventDefault();
764                 if (this.selectui.fileinfo.type != 'folder') {
765                     node = Y.Node.create('<iframe></iframe>').setStyles({
766                         visibility : 'hidden',
767                         width : '1px',
768                         height : '1px'
769                     });
770                     node.set('src', this.selectui.fileinfo.url);
771                     Y.one('body').appendChild(node);
772                 }
773             }, this);
774             selectnode.one('.fp-file-delete').on('click', function(e) {
775                 e.preventDefault();
776                 var dialog_options = {};
777                 var params = {};
778                 var fileinfo = this.selectui.fileinfo;
779                 dialog_options.scope = this;
780                 params.filepath = fileinfo.filepath;
781                 if (fileinfo.type == 'folder') {
782                     params.filename = '.';
783                     dialog_options.message = M.str.repository.confirmdeletefolder;
784                 } else {
785                     params.filename = fileinfo.fullname;
786                     if (fileinfo.refcount) {
787                         dialog_options.message = M.util.get_string('confirmdeletefilewithhref', 'repository', fileinfo.refcount);
788                     } else {
789                         dialog_options.message = M.str.repository.confirmdeletefile;
790                     }
791                 }
792                 dialog_options.callbackargs = [params];
793                 dialog_options.callback = function(params) {
794                     //selectnode.addClass('loading');
795                     this.request({
796                         action: 'delete',
797                         scope: this,
798                         params: params,
799                         callback: function(id, obj, args) {
800                             //args.scope.selectui.hide();
801                             args.scope.filecount--;
802                             args.scope.refresh(obj.filepath);
803                             if (typeof M.core_formchangechecker != 'undefined') {
804                                 M.core_formchangechecker.set_form_changed();
805                             }
806                         }
807                     });
808                 };
809                 this.selectui.hide(); // TODO remove this after confirm dialog is replaced with YUI3
810                 this.show_confirm_dialog(dialog_options);
811             }, this);
812             selectnode.one('.fp-file-zip').on('click', function(e) {
813                 e.preventDefault();
814                 var params = {};
815                 var fileinfo = this.selectui.fileinfo;
816                 if (fileinfo.type != 'folder') {
817                     // this button should not even be shown
818                     return;
819                 }
820                 params['filepath']   = fileinfo.filepath;
821                 params['filename']   = '.';
822                 selectnode.addClass('loading');
823                 this.request({
824                     action: 'zip',
825                     scope: this,
826                     params: params,
827                     callback: function(id, obj, args) {
828                         args.scope.selectui.hide();
829                         args.scope.refresh(obj.filepath);
830                     }
831                 });
832             }, this);
833             selectnode.one('.fp-file-unzip').on('click', function(e) {
834                 e.preventDefault();
835                 var params = {};
836                 var fileinfo = this.selectui.fileinfo;
837                 if (fileinfo.type != 'zip') {
838                     // this button should not even be shown
839                     return;
840                 }
841                 params['filepath'] = fileinfo.filepath;
842                 params['filename'] = fileinfo.fullname;
843                 selectnode.addClass('loading');
844                 this.request({
845                     action: 'unzip',
846                     scope: this,
847                     params: params,
848                     callback: function(id, obj, args) {
849                         args.scope.selectui.hide();
850                         args.scope.refresh(obj.filepath);
851                     }
852                 });
853             }, this);
854             selectnode.one('.fp-file-setmain').on('click', function(e) {
855                 e.preventDefault();
856                 var params = {};
857                 var fileinfo = this.selectui.fileinfo;
858                 if (!this.enablemainfile || fileinfo.type == 'folder') {
859                     // this button should not even be shown for folders or when mainfile is disabled
860                     return;
861                 }
862                 params['filepath'] = fileinfo.filepath;
863                 params['filename'] = fileinfo.fullname;
864                 selectnode.addClass('loading');
865                 this.request({
866                     action: 'setmainfile',
867                     scope: this,
868                     params: params,
869                     callback: function(id, obj, args) {
870                         args.scope.selectui.hide();
871                         args.scope.refresh(fileinfo.filepath);
872                     }
873                 });
874             }, this);
875             selectnode.all('.fp-file-cancel').on('click', function(e) {
876                 e.preventDefault();
877                 // TODO if changed asked to confirm, the same with close button
878                 this.selectui.hide();
879             }, this);
880         },
881         get_parent_folder_name: function(node) {
882             if (node.type != 'folder' || node.filepath.length < node.fullname.length+1) {
883                 return node.filepath;
884             }
885             var basedir = node.filepath.substr(0, node.filepath.length - node.fullname.length - 1);
886             var lastdir = node.filepath.substr(node.filepath.length - node.fullname.length - 2);
887             if (lastdir == '/' + node.fullname + '/') {
888                 return basedir;
889             }
890             return node.filepath;
891         },
892         select_file: function(node) {
893             if (this.is_disabled()) {
894                 return;
895             }
896             var selectnode = this.selectnode;
897             selectnode.removeClass('loading').removeClass('fp-folder').
898                 removeClass('fp-file').removeClass('fp-zip').removeClass('fp-cansetmain');
899             if (node.type == 'folder' || node.type == 'zip') {
900                 selectnode.addClass('fp-'+node.type);
901             } else {
902                 selectnode.addClass('fp-file');
903             }
904             if (this.enablemainfile && (node.sortorder != 1) && node.type == 'file') {
905                 selectnode.addClass('fp-cansetmain');
906             }
907             this.selectui.fileinfo = node;
908             selectnode.one('.fp-saveas input').set('value', node.fullname);
909             var foldername = this.get_parent_folder_name(node);
910             selectnode.all('.fp-author input').set('value', node.author ? node.author : '');
911             selectnode.all('.fp-license select option[selected]').set('selected', false);
912             selectnode.all('.fp-license select option[value='+node.license+']').set('selected', true);
913             selectnode.all('.fp-path select option[selected]').set('selected', false);
914             selectnode.all('.fp-path select option').each(function(el){
915                 if (el.get('value') == foldername) {
916                     el.set('selected', true);
917                 }
918             });
919             selectnode.all('.fp-author input, .fp-license select').set('disabled',(node.type == 'folder')?'disabled':'');
920             // display static information about a file (when known)
921             var attrs = ['datemodified','datecreated','size','dimensions','original','reflist'];
922             for (var i in attrs) {
923                 if (selectnode.one('.fp-'+attrs[i])) {
924                     var value = (node[attrs[i]+'_f']) ? node[attrs[i]+'_f'] : (node[attrs[i]] ? node[attrs[i]] : '');
925                     selectnode.one('.fp-'+attrs[i]).addClassIf('fp-unknown', ''+value == '')
926                         .one('.fp-value').setContent(Y.Escape.html(value));
927                 }
928             }
929             // display thumbnail
930             var imgnode = Y.Node.create('<img/>').
931                 set('src', node.realthumbnail ? node.realthumbnail : node.thumbnail).
932                 setStyle('maxHeight', ''+(node.thumbnail_height ? node.thumbnail_height : 90)+'px').
933                 setStyle('maxWidth', ''+(node.thumbnail_width ? node.thumbnail_width : 90)+'px');
934             selectnode.one('.fp-thumbnail').setContent('').appendChild(imgnode);
935             // load original location if applicable
936             if (node.isref && !node.original) {
937                 selectnode.one('.fp-original').removeClass('fp-unknown').addClass('fp-loading');
938                 this.request({
939                     action: 'getoriginal',
940                     scope: this,
941                     params: {'filepath':node.filepath,'filename':node.fullname},
942                     callback: function(id, obj, args) {
943                         // check if we did not select another file meanwhile
944                         var scope = args.scope;
945                         if (scope.selectui.fileinfo && node &&
946                                 scope.selectui.fileinfo.filepath == node.filepath &&
947                                 scope.selectui.fileinfo.fullname == node.fullname) {
948                             selectnode.one('.fp-original').removeClass('fp-loading');
949                             if (obj.original) {
950                                 node.original = obj.original;
951                                 selectnode.one('.fp-original .fp-value').setContent(Y.Escape.html(node.original));
952                             } else {
953                                 selectnode.one('.fp-original .fp-value').setContent(M.str.repository.unknownsource);
954                             }
955                         }
956                     }
957                 }, false);
958             }
959             // load references list if applicable
960             selectnode.one('.fp-refcount').setContent(node.refcount ? M.util.get_string('referencesexist', 'repository', node.refcount) : '');
961             if (node.refcount && !node.reflist) {
962                 selectnode.one('.fp-reflist').removeClass('fp-unknown').addClass('fp-loading');
963                 this.request({
964                     action: 'getreferences',
965                     scope: this,
966                     params: {'filepath':node.filepath,'filename':node.fullname},
967                     callback: function(id, obj, args) {
968                         // check if we did not select another file meanwhile
969                         var scope = args.scope;
970                         if (scope.selectui.fileinfo && node &&
971                                 scope.selectui.fileinfo.filepath == node.filepath &&
972                                 scope.selectui.fileinfo.fullname == node.fullname) {
973                             selectnode.one('.fp-reflist').removeClass('fp-loading');
974                             if (obj.references) {
975                                 node.reflist = '';
976                                 for (var i in obj.references) {
977                                     node.reflist += '<li>'+obj.references[i]+'</li>';
978                                 }
979                                 selectnode.one('.fp-reflist .fp-value').setContent(Y.Escape.html(node.reflist));
980                             } else {
981                                 selectnode.one('.fp-reflist .fp-value').setContent('');
982                             }
983                         }
984                     }
985                 }, false);
986             }
987             // show panel
988             this.selectui.show();
989         },
990         render: function() {
991             this.print_path();
992             this.view_files();
993         }
994     });
996     // finally init everything needed
997     // hide loading picture, display filemanager interface
998     var filemanager = Y.one('#filemanager-'+options.client_id);
999     filemanager.removeClass('fm-loading').addClass('fm-loaded');
1001     var manager = new FileManagerHelper(options);
1002     var dndoptions = {
1003         filemanager: manager,
1004         acceptedtypes: options.filepicker.accepted_types,
1005         clientid: options.client_id,
1006         author: options.author,
1007         maxfiles: options.maxfiles,
1008         maxbytes: options.maxbytes,
1009         areamaxbytes: options.areamaxbytes,
1010         itemid: options.itemid,
1011         repositories: manager.filepicker_options.repositories,
1012         containerid: manager.dndcontainer.get('id')
1013     };
1014     M.form_dndupload.init(Y, dndoptions);
1015 };