bedf3a477cdaee5c84728616ec84b23b181d9d5f
[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  *
30  * FileManager options:
31  * =====
32  * this.options.currentpath
33  * this.options.itemid
34  */
37 M.form_filemanager = {};
39 /**
40  * This fucntion is called for each file picker on page.
41  */
42 M.form_filemanager.init = function(Y, options) {
43     var FileManagerHelper = function(options) {
44         FileManagerHelper.superclass.constructor.apply(this, arguments);
45     };
46     FileManagerHelper.NAME = "FileManager";
47     FileManagerHelper.ATTRS = {
48         options: {},
49         lang: {}
50     };
52     Y.extend(FileManagerHelper, Y.Base, {
53         api: M.cfg.wwwroot+'/repository/draftfiles_ajax.php',
54         menus: {},
55         initializer: function(options) {
56             //For client side validation, remove hidden draft_id
57             Y.one('#id_'+options.elementname).set('value', '');
59             this.options = options;
60             if (options.mainfile) {
61                 this.enablemainfile = options.mainfile;
62             }
63             this.client_id = options.client_id;
64             this.currentpath = '/';
65             this.maxfiles = options.maxfiles;
66             this.maxbytes = options.maxbytes;
68             this.filepicker_options = options.filepicker?options.filepicker:{};
69             this.filepicker_options.client_id = this.client_id;
70             this.filepicker_options.context = options.context;
71             this.filepicker_options.maxfiles = this.maxfiles;
72             this.filepicker_options.maxbytes = this.maxbytes;
73             this.filepicker_options.env = 'filemanager';
74             this.filepicker_options.itemid = options.itemid;
75             this.filepicker_options.elementname = options.elementname;
77             if (options.filecount) {
78                 this.filecount = options.filecount;
79             } else {
80                 this.filecount = 0;
81             }
82             this.setup_buttons();
83             this.render();
84         },
86         wait: function(client_id) {
87             var container = Y.one('#filemanager-'+client_id);
88             container.set('innerHTML', '');
89             var html = Y.Node.create('<ul id="draftfiles-'+client_id+'"></ul>');
90             container.appendChild(html);
91             var panel = Y.one('#draftfiles-'+client_id);
92             var name = '';
93             var str = '<div style="text-align:center">';
94             str += '<img src="'+M.util.image_url('i/loading_small')+'" />';
95             str += '</div>';
96             try {
97                 panel.set('innerHTML', str);
98             } catch(e) {
99                 alert(e.toString());
100             }
101         },
102         request: function(args, redraw) {
103             var api = this.api + '?action='+args.action;
104             var params = {};
105             var scope = this;
106             if (args['scope']) {
107                 scope = args['scope'];
108             }
109             params['sesskey'] = M.cfg.sesskey;
110             params['client_id'] = this.client_id;
111             params['filepath'] = this.currentpath;
112             params['itemid'] = this.options.itemid?this.options.itemid:0;
113             if (args['params']) {
114                 for (i in args['params']) {
115                     params[i] = args['params'][i];
116                 }
117             }
118             var cfg = {
119                 method: 'POST',
120                 on: {
121                     complete: function(id,o,p) {
122                         if (!o) {
123                             alert('IO FATAL');
124                             return;
125                         }
126                         var data = Y.JSON.parse(o.responseText);
127                         args.callback(id,data,p);
128                     }
129                 },
130                 arguments: {
131                     scope: scope
132                 },
133                 headers: {
134                     'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
135                     'User-Agent': 'MoodleFileManager/3.0'
136                 },
137                 data: build_querystring(params)
138             };
139             if (args.form) {
140                 cfg.form = args.form;
141             }
142             Y.io(api, cfg);
143             if (redraw) {
144                 this.wait(this.client_id);
145             }
146         },
147         filepicker_callback: function(obj) {
148             var button_addfile  = Y.one("#btnadd-"+this.client_id);
149             this.filecount++;
150             if (this.filecount > 0) {
151                 Y.one("#btndwn-"+this.client_id).setStyle('display', 'inline');
152             }
153             if (this.filecount >= this.maxfiles && this.maxfiles!=-1) {
154                 button_addfile.setStyle('display', 'none');
155             }
156             this.refresh(this.currentpath);
157             //When file is added then set draftid for validation
158             var elementname = M.core_filepicker.instances[this.client_id].options.elementname;
159             var itemid = M.core_filepicker.instances[this.client_id].options.itemid;
160             Y.one('#id_'+elementname).set('value', itemid);
161             //generate event to indicate changes which will be used by disable if code.
162             Y.one('#id_'+elementname).simulate('change');
163         },
164         refresh: function(filepath) {
165             var scope = this;
166             this.currentpath = filepath;
167             if (!filepath) {
168                 filepath = this.currentpath;
169             } else {
170                 this.currentpath = filepath;
171             }
172             this.request({
173                 action: 'list',
174                 scope: scope,
175                 params: {'filepath':filepath},
176                 callback: function(id, obj, args) {
177                     scope.options = obj;
178                     scope.render(obj);
179                 }
180             }, true);
181         },
182         setup_buttons: function() {
183             var button_download = Y.one("#btndwn-"+this.client_id);
184             var button_create   = Y.one("#btncrt-"+this.client_id);
185             var button_addfile  = Y.one("#btnadd-"+this.client_id);
187             // setup 'add file' button
188             // if maxfiles == -1, the no limit
189             if (this.filecount >= this.maxfiles
190                     && this.maxfiles!=-1) {
191                 button_addfile.setStyle('display', 'none');
192             } else {
193                 button_addfile.on('click', function(e) {
194                     var options = this.filepicker_options;
195                     options.formcallback = this.filepicker_callback;
196                     // XXX: magic here, to let filepicker use filemanager scope
197                     options.magicscope = this;
198                     options.savepath = this.currentpath;
199                     M.core_filepicker.show(Y, options);
200                 }, this);
201             }
203             // setup 'make a folder' button
204             if (this.options.subdirs) {
205                 button_create.on('click',function(e) {
206                     var scope = this;
207                     // a function used to perform an ajax request
208                     function perform_action(e) {
209                         var foldername = Y.one('#fm-newname').get('value');
210                         if (!foldername) {
211                             return;
212                         }
213                         scope.request({
214                             action:'mkdir',
215                             params: {filepath:scope.currentpath, newdirname:foldername},
216                             callback: function(id, obj, args) {
217                                 var filepath = obj.filepath;
218                                 scope.mkdir_dialog.hide();
219                                 scope.refresh(filepath);
220                                 Y.one('#fm-newname').set('value', '');
221                             }
222                         });
223                     }
224                     if (!Y.one('#fm-mkdir-dlg')) {
225                         var dialog = Y.Node.create('<div id="fm-mkdir-dlg"><div class="hd">'+M.str.repository.entername+'</div><div class="bd"><input type="text" id="fm-newname" /></div></div>');
226                         Y.one(document.body).appendChild(dialog);
227                         this.mkdir_dialog = new YAHOO.widget.Dialog("fm-mkdir-dlg", {
228                              width: "300px",
229                              visible: true,
230                              x:e.pageX,
231                              y:e.pageY,
232                              constraintoviewport : true
233                              });
235                     }
236                     var buttons = [ { text:M.str.moodle.ok, handler:perform_action, isDefault:true },
237                                   { text:M.str.moodle.cancel, handler:function(){this.cancel();}}];
239                     this.mkdir_dialog.cfg.queueProperty("buttons", buttons);
240                     this.mkdir_dialog.render();
241                     this.mkdir_dialog.show();
242                 }, this);
243             } else {
244                 button_create.setStyle('display', 'none');
245             }
247             // setup 'download this folder' button
248             // NOTE: popup window must be enabled to perform download process
249             button_download.on('click',function() {
250                 var scope = this;
251                 // perform downloaddir ajax request
252                 this.request({
253                     action: 'downloaddir',
254                     scope: scope,
255                     callback: function(id, obj, args) {
256                         if (obj) {
257                             scope.refresh(obj.filepath);
258                             var win = window.open(obj.fileurl, 'fm-download-folder');
259                             if (!win) {
260                                 alert(M.str.repository.popupblockeddownload);
261                             }
262                         } else {
263                             alert(M.str.repository.draftareanofiles);
264                         }
265                     }
266                 });
267             }, this);
268         },
269         empty_filelist: function(container) {
270             container.set('innerHTML', '<div class="mdl-align">'+M.str.repository.nofilesattached+'</div>');
271         },
272         render: function() {
273             var options = this.options;
274             var path = this.options.path;
275             var list = this.options.list;
276             var breadcrumb = Y.one('#fm-path-'+this.client_id);
277             // build breadcrumb
278             if (path) {
279                 // empty breadcrumb
280                 breadcrumb.set('innerHTML', '');
281                 var count = 0;
282                 for(var p in path) {
283                     var arrow = '';
284                     if (count==0) {
285                         arrow = Y.Node.create('<span>'+M.str.moodle.path + ': </span>');
286                     } else {
287                         arrow = Y.Node.create('<span> ▶ </span>');
288                     }
289                     count++;
291                     var pathid  = 'fm-path-node-'+this.client_id;
292                     pathid += ('-'+count);
294                     var crumb = Y.Node.create('<a href="###" id="'+pathid+'">'+path[p].name+'</a>');
295                     breadcrumb.appendChild(arrow);
296                     breadcrumb.appendChild(crumb);
298                     var args = {};
299                     args.requestpath = path[p].path;
300                     args.client_id = this.client_id;
301                     Y.one('#'+pathid).on('click', function(e, args) {
302                         var scope = this;
303                         var params = {};
304                         params['filepath'] = args.requestpath;
305                         this.currentpath = args.requestpath;
306                         this.request({
307                             action: 'list',
308                             scope: scope,
309                             params: params,
310                             callback: function(id, obj, args) {
311                                 scope.options = obj;
312                                 scope.render(obj);
313                             }
314                         }, true);
315                     }, this, args);
316                 }
317             }
318             var template = Y.one('#fm-template');
319             var container = Y.one('#filemanager-' + this.client_id);
320             var listhtml = '';
322             // folder list items
323             var folder_ids = [];
324             var folder_data = {};
326             // normal file list items
327             var file_ids   = [];
328             var file_data  = {};
330             // archives list items
331             var zip_ids    = [];
332             var zip_data = {};
334             var html_ids = [];
335             var html_data = {};
337             file_data.itemid = folder_data.itemid = zip_data.itemid = options.itemid;
338             file_data.client_id = folder_data.client_id = zip_data.client_id = this.client_id;
340             var foldername_ids = [];
341             if (!list || list.length == 0) {
342                 // hide file browser and breadcrumb
343                 //container.setStyle('display', 'none');
344                 this.empty_filelist(container);
345                 if (!path || path.length <= 1) {
346                     breadcrumb.setStyle('display', 'none');
347                 }
348                 return;
349             } else {
350                 container.setStyle('display', 'block');
351                 breadcrumb.setStyle('display', 'block');
352             }
354             var count = 0;
355             for(var i in list) {
356                 count++;
357                 // the li html element
358                 var htmlid = 'fileitem-'+this.client_id+'-'+count;
359                 // link to file
360                 var fileid = 'filename-'+this.client_id+'-'+count;
361                 // file menu
362                 var action = 'action-'  +this.client_id+'-'+count;
364                 var html = template.get('innerHTML');
366                 html_ids.push('#'+htmlid);
367                 html_data[htmlid] = action;
369                 list[i].htmlid = htmlid;
370                 list[i].fileid = fileid;
371                 list[i].action = action;
373                 var url = "###";
375                 switch (list[i].type) {
376                     case 'folder':
377                         // click folder name
378                         foldername_ids.push('#'+fileid);
379                         // click folder menu
380                         folder_ids.push('#'+action);
381                         folder_data[action] = list[i];
382                         folder_data[fileid] = list[i];
383                         break;
384                     case 'file':
385                         file_ids.push('#'+action);
386                         // click file name
387                         file_ids.push('#'+fileid);
388                         file_data[action] = list[i];
389                         file_data[fileid] = list[i];
390                         if (list[i].url) {
391                             url = list[i].url;
392                         }
393                     break;
394                     case 'zip':
395                         zip_ids.push('#'+action);
396                         zip_ids.push('#'+fileid);
397                         zip_data[action] = list[i];
398                         zip_data[fileid] = list[i];
399                         if (list[i].url) {
400                             url = list[i].url;
401                         }
402                     break;
403                 }
404                 var fullname = list[i].fullname;
406                 if (list[i].sortorder == 1) {
407                     html = html.replace('___fullname___', '<strong><a title="'+fullname+'" href="'+url+'" id="'+fileid+'"><img src="'+list[i].icon+'" /> ' + fullname + '</a></strong>');
408                 } else {
409                     html = html.replace('___fullname___', '<a title="'+fullname+'" href="'+url+'" id="'+fileid+'"><img src="'+list[i].icon+'" /> ' + fullname + '</a>');
410                 }
411                 html = html.replace('___action___', '<span class="fm-menuicon" id="'+action+'"><img alt="▶" src="'+M.util.image_url('i/menu')+'" /></span>');
412                 html = '<li id="'+htmlid+'">'+html+'</li>';
413                 listhtml += html;
414             }
415             if (!Y.one('#draftfiles-'+this.client_id)) {
416                 var filelist = Y.Node.create('<ul id="draftfiles-'+this.client_id+'"></ul>');
417                 container.appendChild(filelist);
418             }
419             Y.one('#draftfiles-'+this.client_id).set('innerHTML', listhtml);
421             // click normal file menu
422             Y.on('click', this.create_filemenu, file_ids, this, file_data);
423             Y.on('contextmenu', this.create_filemenu, file_ids, this, file_data);
424             // click folder menu
425             Y.on('click', this.create_foldermenu, folder_ids, this, folder_data);
426             Y.on('contextmenu', this.create_foldermenu, folder_ids, this, folder_data);
427             Y.on('contextmenu', this.create_foldermenu, foldername_ids, this, folder_data);
428             // click archievs menu
429             Y.on('click', this.create_zipmenu, zip_ids, this, zip_data);
430             Y.on('contextmenu', this.create_zipmenu, zip_ids, this, zip_data);
431             // click folder name
432             Y.on('click', this.enter_folder, foldername_ids, this, folder_data);
433         },
434         enter_folder: function(e, data) {
435             var node = e.currentTarget;
436             var file = data[node.get('id')];
437             this.refresh(file.filepath);
438         },
439         create_filemenu: function(e, data) {
440             e.preventDefault();
441             var options = this.options;
442             var node = e.currentTarget;
443             var file = data[node.get('id')];
444             var scope = this;
446             var menuitems = [
447                 {text: M.str.moodle.download, url:file.url}
448                 ];
449             function setmainfile(type, ev, obj) {
450                 var file = obj[node.get('id')];
451                 //Y.one(mainid).set('value', file.filepath+file.filename);
452                 var params = {};
453                 params['filepath']   = file.filepath;
454                 params['filename']   = file.filename;
455                 this.request({
456                     action: 'setmainfile',
457                     scope: scope,
458                     params: params,
459                     callback: function(id, obj, args) {
460                         scope.refresh(scope.currentpath);
461                     }
462                 });
463             }
464             if (this.enablemainfile && (file.sortorder != 1)) {
465                 var mainid = '#id_'+this.enablemainfile;
466                 var menu = {text: M.str.repository.setmainfile, onclick:{fn: setmainfile, obj:data, scope:this}};
467                 menuitems.push(menu);
468             }
469             this.create_menu(e, 'filemenu', menuitems, file, data);
470         },
471         create_foldermenu: function(e, data) {
472             e.preventDefault();
473             var scope = this;
474             var node = e.currentTarget;
475             var fileinfo = data[node.get('id')];
476             // an extra menu item for folder to zip it
477             function archive_folder(type,ev,obj) {
478                 var params = {};
479                 params['filepath']   = fileinfo.filepath;
480                 params['filename']   = '.';
481                 this.request({
482                     action: 'zip',
483                     scope: scope,
484                     params: params,
485                     callback: function(id, obj, args) {
486                         scope.refresh(obj.filepath);
487                     }
488                 });
489             }
490             var menuitems = [
491                 {text: M.str.editor.zip, onclick: {fn: archive_folder, obj: data, scope: this}},
492                 ];
493             this.create_menu(e, 'foldermenu', menuitems, fileinfo, data);
494         },
495         create_zipmenu: function(e, data) {
496             e.preventDefault();
497             var scope = this;
498             var node = e.currentTarget;
499             var fileinfo = data[node.get('id')];
501             function unzip(type, ev, obj) {
502                 var params = {};
503                 params['filepath'] = fileinfo.filepath;
504                 params['filename'] = fileinfo.fullname;
505                 this.request({
506                     action: 'unzip',
507                     scope: scope,
508                     params: params,
509                     callback: function(id, obj, args) {
510                         scope.refresh(obj.filepath);
511                     }
512                 });
513             }
514             var menuitems = [
515                 {text: M.str.moodle.download, url:fileinfo.url},
516                 {text: M.str.moodle.unzip, onclick: {fn: unzip, obj: data, scope: this}}
517                 ];
518             function setmainfile(type, ev, obj) {
519                 var file = obj[node.get('id')];
520                 //Y.one(mainid).set('value', file.filepath+file.filename);
521                 var params = {};
522                 params['filepath']   = file.filepath;
523                 params['filename']   = file.filename;
524                 this.request({
525                     action: 'setmainfile',
526                     scope: scope,
527                     params: params,
528                     callback: function(id, obj, args) {
529                         scope.refresh(scope.currentpath);
530                     }
531                 });
532             }
533             if (this.enablemainfile && (fileinfo.sortorder != 1)) {
534                 var mainid = '#id_'+this.enablemainfile;
535                 var menu = {text: M.str.repository.setmainfile, onclick:{fn: setmainfile, obj:data, scope:this}};
536                 menuitems.push(menu);
537             }
538             this.create_menu(e, 'zipmenu', menuitems, fileinfo, data);
539         },
540         create_menu: function(ev, menuid, menuitems, fileinfo, options) {
541             var position = [ev.pageX, ev.pageY];
542             var scope = this;
543             function remove(type, ev, obj) {
544                 var dialog_options = {};
545                 var params = {};
546                 dialog_options.message = M.str.repository.confirmdeletefile;
547                 dialog_options.scope = this;
548                 var filename = '';
549                 var filepath = '';
550                 if (fileinfo.type == 'folder') {
551                     params.filename = '.';
552                     params.filepath = fileinfo.filepath;
553                 } else {
554                     params.filename = fileinfo.fullname;
555                 }
556                 dialog_options.callbackargs = [params];
557                 dialog_options.callback = function(params) {
558                     this.request({
559                         action: 'delete',
560                         scope: this,
561                         params: params,
562                         callback: function(id, obj, args) {
563                             scope.filecount--;
564                             scope.refresh(obj.filepath);
565                             if (scope.filecount < scope.maxfiles && scope.maxfiles!=-1) {
566                                 var button_addfile  = Y.one("#btnadd-"+scope.client_id);
567                                 button_addfile.setStyle('display', 'inline');
568                                 button_addfile.on('click', function(e) {
569                                     var options = scope.filepicker_options;
570                                     options.formcallback = scope.filepicker_callback;
571                                     // XXX: magic here, to let filepicker use filemanager scope
572                                     options.magicscope = scope;
573                                     options.savepath = scope.currentpath;
574                                     M.core_filepicker.show(Y, options);
575                                 }, this);
576                             }
577                         }
578                     });
579                 };
580                 M.util.show_confirm_dialog(ev, dialog_options);
581             }
582             function rename (type, ev, obj) {
583                 var scope = this;
584                 var perform = function(e) {
585                     var newfilename = Y.one('#fm-rename-input').get('value');
586                     if (!newfilename) {
587                         return;
588                     }
590                     var action = '';
591                     var params = {};
592                     if (fileinfo.type == 'folder') {
593                         params['filepath']   = fileinfo.filepath;
594                         params['filename']   = '.';
595                         params['newdirname'] = newfilename;
596                         action = 'renamedir';
597                     } else {
598                         params['filepath']   = fileinfo.filepath;
599                         params['filename']   = fileinfo.fullname;
600                         params['newfilename'] = newfilename;
601                         action = 'rename';
602                     }
603                     scope.request({
604                         action: action,
605                         scope: scope,
606                         params: params,
607                         callback: function(id, obj, args) {
608                             if (obj == false) {
609                                 alert(M.str.repository.fileexists);
610                             } else {
611                                 scope.refresh(obj.filepath);
612                             }
613                             Y.one('#fm-rename-input').set('value', '');
614                             scope.rename_dialog.hide();
615                         }
616                     });
617                 };
619                 var dialog = Y.one('#fm-rename-dlg');
620                 if (!dialog) {
621                     dialog = Y.Node.create('<div id="fm-rename-dlg"><div class="hd">'+M.str.repository.enternewname+'</div><div class="bd"><input type="text" id="fm-rename-input" /></div></div>');
622                     Y.one(document.body).appendChild(dialog);
623                     this.rename_dialog = new YAHOO.widget.Dialog("fm-rename-dlg", {
624                          width: "300px",
625                          fixedcenter: true,
626                          visible: true,
627                          constraintoviewport : true
628                          });
630                 }
631                 var buttons = [ { text:M.str.moodle.rename, handler:perform, isDefault:true},
632                                   { text:M.str.moodle.cancel, handler:function(){this.cancel();}}];
634                 this.rename_dialog.cfg.queueProperty('buttons', buttons);
635                 this.rename_dialog.render();
636                 this.rename_dialog.show();
637                 //var k1 = new YAHOO.util.KeyListener(scope, {keys:13}, {fn:function(){perform();}, correctScope: true});
638                 //k1.enable();
639                 Y.one('#fm-rename-input').set('value', fileinfo.fullname);
640             }
641             function move(type, ev, obj) {
642                 var scope = this;
643                 var itemid = this.options.itemid;
644                 // setup move file dialog
645                 var dialog = null;
646                 if (!Y.one('#fm-move-dlg')) {
647                     dialog = Y.Node.create('<div id="fm-move-dlg"></div>');
648                     Y.one(document.body).appendChild(dialog);
649                 } else {
650                     dialog = Y.one('#fm-move-dlg');
651                 }
653                 dialog.set('innerHTML', '<div class="hd">'+M.str.repository.moving+'</div><div class="bd"><div id="fm-move-div">'+M.str.repository.nopathselected+'</div><div id="fm-tree"></div></div>');
655                 this.movefile_dialog = new YAHOO.widget.Dialog("fm-move-dlg", {
656                      width : "600px",
657                      fixedcenter : true,
658                      visible : false,
659                      constraintoviewport : true
660                      });
662                 var treeview = new YAHOO.widget.TreeView("fm-tree");
664                 var dialog = this.movefile_dialog;
665                 function _move(e) {
666                     if (!treeview.targetpath) {
667                         return;
668                     }
669                     var params = {};
670                     if (fileinfo.type == 'folder') {
671                         action = 'movedir';
672                     } else {
673                         action = 'movefile';
674                     }
675                     params['filepath'] = fileinfo.filepath;
676                     params['filename'] = fileinfo.fullname;
677                     params['newfilepath'] = treeview.targetpath;
678                     scope.request({
679                         action: action,
680                         scope: scope,
681                         params: params,
682                         callback: function(id, obj, args) {
683                             var p = '/';
684                             if (obj) {
685                                 p = obj.filepath;
686                             }
687                             dialog.cancel();
688                             scope.refresh(p);
689                         }
690                     });
691                 }
693                 var buttons = [ { text:M.str.moodle.move, handler:_move, isDefault:true },
694                                   { text:M.str.moodle.cancel, handler:function(){this.cancel();}}];
696                 this.movefile_dialog.cfg.queueProperty("buttons", buttons);
697                 this.movefile_dialog.render();
699                 treeview.subscribe("dblClickEvent", function(e) {
700                     // update destidatoin folder
701                     this.targetpath = e.node.data.path;
702                     var title = Y.one('#fm-move-div');
703                     title.set('innerHTML', '<strong>"' + this.targetpath + '"</strong> has been selected.');
704                 });
706                 function loadDataForNode(node, onCompleteCallback) {
707                     var params = {};
708                     params['filepath'] = node.data.path;
709                     var obj = {
710                         action: 'dir',
711                         scope: scope,
712                         params: params,
713                         callback: function(id, obj, args) {
714                             data = obj.children;
715                             if (data.length == 0) {
716                                 // so it is empty
717                             } else {
718                                 for (var i in data) {
719                                     var textnode = {label: data[i].fullname, path: data[i].filepath, itemid: this.itemid};
720                                     var tmpNode = new YAHOO.widget.TextNode(textnode, node, false);
721                                 }
722                             }
723                             this.oncomplete();
724                         }
725                     };
726                     obj.oncomplete = onCompleteCallback;
727                     scope.request(obj);
728                 }
730                 this.movefile_dialog.subscribe('show', function(){
731                     var rootNode = treeview.getRoot();
732                     treeview.setDynamicLoad(loadDataForNode);
733                     treeview.removeChildren(rootNode);
734                     var textnode = {label: M.str.moodle.files, path: '/'};
735                     var tmpNode = new YAHOO.widget.TextNode(textnode, rootNode, true);
736                     treeview.draw();
737                 }, this, true);
739                 this.movefile_dialog.show();
740             }
741             var shared_items = [
742                 {text: M.str.moodle.rename+'...', onclick: {fn: rename, obj: options, scope: this}},
743                 {text: M.str.moodle.move+'...', onclick: {fn: move, obj: options, scope: this}}
744             ];
745             // delete is reserve word in Javascript
746             shared_items.push({text: M.str.moodle['delete']+'...', onclick: {fn: remove, obj: options, scope: this}});
747             var menu = new YAHOO.widget.Menu(menuid, {xy:position, clicktohide:true});
748             menu.clearContent();
749             menu.addItems(menuitems);
750             menu.addItems(shared_items);
751             menu.render(document.body);
752             menu.subscribe('hide', function(){
753                 this.fireEvent('destroy');
754             });
755             menu.show();
756         }
757     });
759     // finally init everything needed
760     // kill nonjs filemanager
761     var item = document.getElementById('nonjs-filemanager-'+options.client_id);
762     if (item && !options.usenonjs) {
763         item.parentNode.removeChild(item);
764     }
765     // hide loading picture
766     item = document.getElementById('filemanager-loading-'+options.client_id);
767     if (item) {
768         item.parentNode.removeChild(item);
769     }
770     // display filemanager interface
771     item = document.getElementById('filemanager-wrapper-'+options.client_id);
772     if (item) {
773         item.style.display = '';
774     }
776     new FileManagerHelper(options);
777 };