1 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
19 * this.api, stores the URL to make ajax request
21 * this.filepicker_options
22 * this.movefile_dialog
26 * this.filecount, how many files in this filemanager
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
34 * FileManager options:
36 * this.options.currentpath
41 M.form_filemanager = {templates:{}};
43 M.form_filemanager.set_templates = function(Y, templates) {
44 M.form_filemanager.templates = templates;
48 * This fucntion is called for each file picker on page.
50 M.form_filemanager.init = function(Y, options) {
51 var FileManagerHelper = function(options) {
52 FileManagerHelper.superclass.constructor.apply(this, arguments);
54 FileManagerHelper.NAME = "FileManager";
55 FileManagerHelper.ATTRS = {
60 Y.extend(FileManagerHelper, Y.Base, {
61 api: M.cfg.wwwroot+'/repository/draftfiles_ajax.php',
63 initializer: function(options) {
64 this.options = options;
65 if (options.mainfile) {
66 this.enablemainfile = options.mainfile;
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;
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;
94 this.dndcontainer = this.filemanager.one('.filemanager-container');
95 if (!this.dndcontainer.get('id')) {
96 this.dndcontainer.generateID();
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);
105 // initialize 'select file' panel
106 this.selectnode = Y.Node.createWithFilesSkin(M.form_filemanager.templates.fileselectlayout);
107 this.selectnode.setAttribute('aria-live', 'assertive');
108 this.selectnode.setAttribute('role', 'dialog');
109 this.selectnode.generateID();
111 var labelid = 'fm-dialog-label_'+ this.selectnode.get('id');
112 this.selectui = new Y.Panel({
113 headerContent: '<span id="' + labelid +'">' + M.str.moodle.edit + '</span>',
114 srcNode : this.selectnode,
121 this.selectui.plug(Y.Plugin.Drag,{handles:['#'+this.selectnode.get('id')+' .yui3-widget-hd']});
122 Y.one('#'+this.selectnode.get('id')).setAttribute('aria-labelledby', labelid);
123 this.selectui.hide();
124 this.setup_select_file();
125 // setup buttons onclick events
126 this.setup_buttons();
127 // set event handler for lazy loading of thumbnails
128 this.filemanager.one('.fp-content').on(['scroll','resize'], this.content_scrolled, this);
130 this.viewmode = 1; // TODO take from cookies?
131 this.filemanager.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').removeClass('checked')
132 this.filemanager.all('.fp-vb-icons').addClass('checked')
133 this.refresh(this.currentpath); // MDL-31113 get latest list from server
137 this.filemanager.addClass('fm-updating');
139 request: function(args, redraw) {
140 var api = this.api + '?action='+args.action;
144 scope = args['scope'];
146 params['sesskey'] = M.cfg.sesskey;
147 params['client_id'] = this.client_id;
148 params['filepath'] = this.currentpath;
149 params['itemid'] = this.options.itemid?this.options.itemid:0;
150 if (args['params']) {
151 for (i in args['params']) {
152 params[i] = args['params'][i];
158 complete: function(id,o,p) {
165 data = Y.JSON.parse(o.responseText);
167 scope.print_msg(M.str.repository.invalidjson, 'error');
168 Y.error(M.str.repository.invalidjson+":\n"+o.responseText);
171 if (data && data.tree && scope.set_current_tree) {
172 scope.set_current_tree(data.tree);
174 args.callback(id,data,p);
181 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
183 data: build_querystring(params)
186 cfg.form = args.form;
193 filepicker_callback: function(obj) {
195 this.check_buttons();
196 this.refresh(this.currentpath);
197 if (typeof M.core_formchangechecker != 'undefined') {
198 M.core_formchangechecker.set_form_changed();
201 check_buttons: function() {
202 if (this.filecount>0) {
203 this.filemanager.removeClass('fm-nofiles');
205 this.filemanager.addClass('fm-nofiles');
207 if (this.filecount >= this.maxfiles && this.maxfiles!=-1) {
208 this.filemanager.addClass('fm-maxfiles');
211 this.filemanager.removeClass('fm-maxfiles');
214 refresh: function(filepath) {
216 this.currentpath = filepath;
218 filepath = this.currentpath;
220 this.currentpath = filepath;
225 params: {'filepath':filepath},
226 callback: function(id, obj, args) {
227 scope.filecount = obj.filecount;
229 scope.lazyloading = {};
230 scope.check_buttons();
235 /** displays message in a popup */
236 print_msg: function(msg, type) {
237 var header = M.str.moodle.error;
238 if (type != 'error') {
239 type = 'info'; // one of only two types excepted
240 header = M.str.moodle.info;
243 this.msg_dlg_node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.message);
244 var nodeid = this.msg_dlg_node.generateID();
246 this.msg_dlg = new Y.Panel({
247 srcNode : this.msg_dlg_node,
254 this.msg_dlg.plug(Y.Plugin.Drag,{handles:['#'+nodeid+' .yui3-widget-hd']});
255 this.msg_dlg_node.one('.fp-msg-butok').on('click', function(e) {
261 this.msg_dlg.set('headerContent', header);
262 this.msg_dlg_node.removeClass('fp-msg-info').removeClass('fp-msg-error').addClass('fp-msg-'+type)
263 this.msg_dlg_node.one('.fp-msg-text').setContent(Y.Escape.html(msg));
266 is_disabled: function() {
267 return this.filemanager.ancestor('.fitem.disabled') != null;
269 setup_buttons: function() {
270 var button_download = this.filemanager.one('.fp-btn-download');
271 var button_create = this.filemanager.one('.fp-btn-mkdir');
272 var button_addfile = this.filemanager.one('.fp-btn-add');
274 // setup 'add file' button
275 button_addfile.on('click', this.show_filepicker, this);
277 var dndarrow = this.filemanager.one('.dndupload-arrow');
279 dndarrow.on('click', this.show_filepicker, this);
282 // setup 'make a folder' button
283 if (this.options.subdirs) {
284 button_create.on('click',function(e) {
286 if (this.is_disabled()) {
290 // a function used to perform an ajax request
291 var perform_action = function(e) {
293 var foldername = Y.one('#fm-newname-'+scope.client_id).get('value');
295 scope.mkdir_dialog.hide();
300 params: {filepath:scope.currentpath, newdirname:foldername},
301 callback: function(id, obj, args) {
302 var filepath = obj.filepath;
303 scope.mkdir_dialog.hide();
304 scope.refresh(filepath);
305 Y.one('#fm-newname-'+scope.client_id).set('value', '');
306 if (typeof M.core_formchangechecker != 'undefined') {
307 M.core_formchangechecker.set_form_changed();
312 var validate_folder_name = function() {
314 var foldername = Y.one('#fm-newname-'+scope.client_id).get('value');
315 if (foldername.length > 0) {
318 var btn = Y.one('#fm-mkdir-butcreate-'+scope.client_id);
320 btn.set('disabled', !valid);
324 if (!this.mkdir_dialog) {
325 var node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.mkdir);
326 this.mkdir_dialog = new Y.Panel({
334 this.mkdir_dialog.plug(Y.Plugin.Drag,{handles:['.yui3-widget-hd']});
335 node.one('.fp-dlg-butcreate').set('id', 'fm-mkdir-butcreate-'+this.client_id).on('click',
336 perform_action, this);
337 node.one('input').set('id', 'fm-newname-'+this.client_id).on('keydown', function(e) {
338 var valid = Y.bind(validate_folder_name, this)();
339 if (valid && e.keyCode === 13) {
340 Y.bind(perform_action, this)(e);
343 node.one('#fm-newname-'+this.client_id).on(['keyup', 'change'], function(e) {
344 Y.bind(validate_folder_name, this)();
347 node.one('label').set('for', 'fm-newname-' + this.client_id);
348 node.all('.fp-dlg-butcancel').on('click', function(e){e.preventDefault();this.mkdir_dialog.hide();}, this);
349 node.all('.fp-dlg-curpath').set('id', 'fm-curpath-'+this.client_id);
351 this.mkdir_dialog.show();
353 // Default folder name:
354 var foldername = M.str.repository.newfolder;
355 while (this.has_folder(foldername)) {
356 foldername = increment_filename(foldername, true);
358 Y.one('#fm-newname-'+scope.client_id).set('value', foldername);
359 Y.bind(validate_folder_name, this)();
360 Y.one('#fm-newname-'+scope.client_id).focus().select();
361 Y.all('#fm-curpath-'+scope.client_id).setContent(this.currentpath);
364 this.filemanager.addClass('fm-nomkdir');
367 // setup 'download this folder' button
368 button_download.on('click',function(e) {
370 if (this.is_disabled()) {
374 // perform downloaddir ajax request
376 action: 'downloaddir',
378 callback: function(id, obj, args) {
380 scope.refresh(obj.filepath);
381 node = Y.Node.create('<iframe></iframe>').setStyles({
382 visibility : 'hidden',
386 node.set('src', obj.fileurl);
387 Y.one('body').appendChild(node);
389 scope.print_msg(M.str.repository.draftareanofiles, 'error');
395 this.filemanager.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').
396 on('click', function(e) {
398 var viewbar = this.filemanager.one('.fp-viewbar')
399 if (!this.is_disabled() && (!viewbar || !viewbar.hasClass('disabled'))) {
400 this.filemanager.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').removeClass('checked')
401 if (e.currentTarget.hasClass('fp-vb-tree')) {
403 } else if (e.currentTarget.hasClass('fp-vb-details')) {
408 e.currentTarget.addClass('checked')
414 show_filepicker: function (e) {
415 // if maxfiles == -1, the no limit
417 if (this.is_disabled()) {
420 var options = this.filepicker_options;
421 options.formcallback = this.filepicker_callback;
422 // XXX: magic here, to let filepicker use filemanager scope
423 options.magicscope = this;
424 options.savepath = this.currentpath;
425 M.core_filepicker.show(Y, options);
428 print_path: function() {
429 var p = this.options.path;
430 this.pathbar.setContent('').addClass('empty');
431 if (p && p.length!=0 && this.viewmode != 2) {
432 for(var i = 0; i < p.length; i++) {
433 var el = this.pathnode.cloneNode(true);
434 this.pathbar.appendChild(el);
437 el.addClass('first');
439 if (i == p.length-1) {
448 el.one('.fp-path-folder-name').setContent(Y.Escape.html(p[i].name)).
449 on('click', function(e, path) {
451 if (!this.is_disabled()) {
456 this.pathbar.removeClass('empty');
459 get_filepath: function(obj) {
460 if (obj.path && obj.path.length) {
461 return obj.path[obj.path.length-1].path;
465 treeview_dynload: function(node, cb) {
466 var retrieved_children = {};
468 for (var i in node.children) {
469 retrieved_children[node.children[i].path] = node.children[i];
472 if (!node.path || node.path == '/') {
473 // this is a root pseudo folder
474 node.fileinfo.filepath = '/';
475 node.fileinfo.type = 'folder';
476 node.fileinfo.fullname = node.fileinfo.title;
477 node.fileinfo.filename = '.';
481 params: {filepath:node.path?node.path:''},
483 callback: function(id, obj, args) {
485 var scope = args.scope;
486 // check that user did not leave the view mode before recieving this response
487 if (!(scope.viewmode == 2 && node && node.getChildrenEl())) {
490 if (cb != null) { // (in manual mode do not update current path)
492 scope.currentpath = node.path?node.path:'/';
494 node.highlight(false);
495 node.origlist = obj.list ? obj.list : null;
496 node.origpath = obj.path ? obj.path : null;
499 if (list[k].type == 'folder' && retrieved_children[list[k].filepath]) {
500 // if this child is a folder and has already been retrieved
501 retrieved_children[list[k].filepath].fileinfo = list[k];
502 node.children[node.children.length] = retrieved_children[list[k].filepath];
504 // append new file to the list
505 scope.view_files([list[k]]);
511 // invoke callback requested by TreeView component
514 scope.content_scrolled();
518 content_scrolled: function(e) {
519 setTimeout(Y.bind(function() {
520 if (this.processingimages) {return;}
521 this.processingimages = true;
523 fpcontent = this.filemanager.one('.fp-content'),
524 fpcontenty = fpcontent.getY(),
525 fpcontentheight = fpcontent.getStylePx('height'),
526 is_node_visible = function(node) {
527 var offset = node.getY()-fpcontenty;
528 if (offset <= fpcontentheight && (offset >=0 || offset+node.getStylePx('height')>=0)) {
533 // replace src for visible images that need to be lazy-loaded
534 if (scope.lazyloading) {
535 fpcontent.all('img').each( function(node) {
536 if (node.get('id') && scope.lazyloading[node.get('id')] && is_node_visible(node)) {
537 node.setImgRealSrc(scope.lazyloading);
541 this.processingimages = false;
544 view_files: function(appendfiles) {
545 this.filemanager.removeClass('fm-updating').removeClass('fm-noitems');
546 if ((appendfiles == null) && (!this.options.list || this.options.list.length == 0) && this.viewmode != 2) {
547 this.filemanager.addClass('fm-noitems');
550 var list = (appendfiles != null) ? appendfiles : this.options.list;
551 var element_template;
552 if (this.viewmode == 2 || this.viewmode == 3) {
553 element_template = Y.Node.create(M.form_filemanager.templates.listfilename);
556 element_template = Y.Node.create(M.form_filemanager.templates.iconfilename);
559 viewmode : this.viewmode,
560 appendonly : appendfiles != null,
561 filenode : element_template,
562 callbackcontext : this,
563 callback : function(e, node) {
564 if (e.preventDefault) { e.preventDefault(); }
565 if (node.type == 'folder') {
566 this.refresh(node.filepath);
568 this.select_file(node);
571 rightclickcallback : function(e, node) {
572 if (e.preventDefault) { e.preventDefault(); }
573 this.select_file(node);
575 classnamecallback : function(node) {
577 if (node.type == 'folder' || (!node.type && !node.filename)) {
578 classname = classname + ' fp-folder';
580 if (node.filename || node.filepath || (node.path && node.path != '/')) {
581 classname = classname + ' fp-hascontextmenu';
584 classname = classname + ' fp-isreference';
587 classname = classname + ' fp-hasreferences';
589 if (node.originalmissing) {
590 classname = classname + ' fp-originalmissing';
592 if (node.sortorder == 1) { classname = classname + ' fp-mainfile';}
593 return Y.Lang.trim(classname);
596 if (this.viewmode == 2) {
597 options.dynload = true;
598 options.filepath = this.options.path;
599 options.treeview_dynload = this.treeview_dynload;
600 options.norootrightclick = true;
601 options.callback = function(e, node) {
602 // TODO MDL-32736 e is not an event here but an object with properties 'event' and 'node'
603 if (!node.fullname) {return;}
604 if (node.type != 'folder') {
605 if (e.node.parent && e.node.parent.origpath) {
606 // set the current path
607 this.options.path = e.node.parent.origpath;
608 this.options.list = e.node.parent.origlist;
611 this.currentpath = node.filepath;
612 this.select_file(node);
614 // save current path and filelist (in case we want to jump to other viewmode)
615 this.options.path = e.node.origpath;
616 this.options.list = e.node.origlist;
617 this.currentpath = node.filepath;
619 //this.content_scrolled();
623 if (!this.lazyloading) {
626 this.filemanager.one('.fp-content').fp_display_filelist(options, list, this.lazyloading);
627 this.content_scrolled();
629 populate_licenses_select: function(node) {
634 var licenses = this.options.licenses;
635 for (var i in licenses) {
636 var option = Y.Node.create('<option/>').
637 set('value', licenses[i].shortname).
638 setContent(Y.Escape.html(licenses[i].fullname));
639 node.appendChild(option)
642 set_current_tree: function(tree) {
643 var appendfilepaths = function(list, node) {
644 if (!node || !node.children || !node.children.length) {return;}
645 for (var i in node.children) {
646 list[list.length] = node.children[i].filepath;
647 appendfilepaths(list, node.children[i]);
651 appendfilepaths(list, tree);
652 var selectnode = this.selectnode;
653 node = selectnode.one('.fp-path select');
655 for (var i in list) {
656 node.appendChild(Y.Node.create('<option/>').
657 set('value', list[i]).setContent(Y.Escape.html(list[i])));
660 update_file: function(confirmed) {
661 var selectnode = this.selectnode;
662 var fileinfo = this.selectui.fileinfo;
664 var newfilename = Y.Lang.trim(selectnode.one('.fp-saveas input').get('value'));
665 var filenamechanged = (newfilename && newfilename != fileinfo.fullname);
666 var pathselect = selectnode.one('.fp-path select'),
667 pathindex = pathselect.get('selectedIndex'),
668 targetpath = pathselect.get("options").item(pathindex).get('value');
669 var filepathchanged = (targetpath != this.get_parent_folder_name(fileinfo));
670 var newauthor = Y.Lang.trim(selectnode.one('.fp-author input').get('value'));
671 var authorchanged = (newauthor != Y.Lang.trim(fileinfo.author));
672 var licenseselect = selectnode.one('.fp-license select'),
673 licenseindex = licenseselect.get('selectedIndex'),
674 newlicense = licenseselect.get("options").item(licenseindex).get('value');
675 var licensechanged = (newlicense != fileinfo.license);
678 var dialog_options = {callback:this.update_file, callbackargs:[true], scope:this};
679 if (fileinfo.type == 'folder') {
681 this.print_msg(M.str.repository.entername, 'error');
684 if (filenamechanged || filepathchanged) {
686 dialog_options.message = M.str.repository.confirmrenamefolder;
687 this.show_confirm_dialog(dialog_options);
690 params = {filepath:fileinfo.filepath, newdirname:newfilename, newfilepath:targetpath};
691 action = 'updatedir';
695 this.print_msg(M.str.repository.enternewname, 'error');
698 if ((filenamechanged || filepathchanged) && !confirmed && fileinfo.refcount) {
699 dialog_options.message = M.util.get_string('confirmrenamefile', 'repository', fileinfo.refcount);
700 this.show_confirm_dialog(dialog_options);
703 if (filenamechanged || filepathchanged || licensechanged || authorchanged) {
704 params = {filepath:fileinfo.filepath, filename:fileinfo.fullname,
705 newfilename:newfilename, newfilepath:targetpath,
706 newlicense:newlicense, newauthor:newauthor};
707 action = 'updatefile';
712 this.selectui.hide();
715 selectnode.addClass('loading');
720 callback: function(id, obj, args) {
722 selectnode.removeClass('loading');
723 args.scope.print_msg(obj.error, 'error');
725 args.scope.selectui.hide();
726 args.scope.refresh((obj && obj.filepath) ? obj.filepath : '/');
727 if (typeof M.core_formchangechecker != 'undefined') {
728 M.core_formchangechecker.set_form_changed();
735 * Displays a confirmation dialog
736 * Expected attributes in dialog_options: message, callback, callbackargs(optional), scope(optional)
738 show_confirm_dialog: function(dialog_options) {
739 // instead of M.util.show_confirm_dialog(e, dialog_options);
740 if (!this.confirm_dlg) {
741 this.confirm_dlg_node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.confirmdialog);
742 var node = this.confirm_dlg_node;
744 this.confirm_dlg = new Y.Panel({
753 this.confirm_dlg.plug(Y.Plugin.Drag,{handles:['#'+node.get('id')+' .yui3-widget-hd']});
754 var handle_confirm = function(ev) {
755 var dlgopt = this.confirm_dlg.dlgopt;
757 this.confirm_dlg.hide();
758 if (dlgopt.callback) {
759 if (dlgopt.callbackargs) {
760 dlgopt.callback.apply(dlgopt.scope || this, dlgopt.callbackargs);
762 dlgopt.callback.apply(dlgopt.scope || this);
766 var handle_cancel = function(ev) {
768 this.confirm_dlg.hide();
770 node.one('.fp-dlg-butconfirm').on('click', handle_confirm, this);
771 node.one('.fp-dlg-butcancel').on('click', handle_cancel, this);
773 this.confirm_dlg.dlgopt = dialog_options;
774 this.confirm_dlg_node.one('.fp-dlg-text').setContent(dialog_options.message);
775 this.confirm_dlg.show();
777 setup_select_file: function() {
778 var selectnode = this.selectnode;
779 // bind labels with corresponding inputs
780 selectnode.all('.fp-saveas,.fp-path,.fp-author,.fp-license').each(function (node) {
781 node.all('label').set('for', node.one('input,select').generateID());
783 this.populate_licenses_select(selectnode.one('.fp-license select'));
784 // register event on clicking buttons
785 selectnode.one('.fp-file-update').on('click', function(e) {
789 selectnode.all('form').on('keydown', function(e) {
790 if (e.keyCode == 13) {
795 selectnode.one('.fp-file-download').on('click', function(e) {
797 if (this.selectui.fileinfo.type != 'folder') {
798 node = Y.Node.create('<iframe></iframe>').setStyles({
799 visibility : 'hidden',
803 node.set('src', this.selectui.fileinfo.url);
804 Y.one('body').appendChild(node);
807 selectnode.one('.fp-file-delete').on('click', function(e) {
809 var dialog_options = {};
811 var fileinfo = this.selectui.fileinfo;
812 dialog_options.scope = this;
813 params.filepath = fileinfo.filepath;
814 if (fileinfo.type == 'folder') {
815 params.filename = '.';
816 dialog_options.message = M.str.repository.confirmdeletefolder;
818 params.filename = fileinfo.fullname;
819 if (fileinfo.refcount) {
820 dialog_options.message = M.util.get_string('confirmdeletefilewithhref', 'repository', fileinfo.refcount);
822 dialog_options.message = M.str.repository.confirmdeletefile;
825 dialog_options.callbackargs = [params];
826 dialog_options.callback = function(params) {
827 //selectnode.addClass('loading');
832 callback: function(id, obj, args) {
833 //args.scope.selectui.hide();
834 args.scope.filecount--;
835 args.scope.refresh(obj.filepath);
836 if (typeof M.core_formchangechecker != 'undefined') {
837 M.core_formchangechecker.set_form_changed();
842 this.selectui.hide(); // TODO remove this after confirm dialog is replaced with YUI3
843 this.show_confirm_dialog(dialog_options);
845 selectnode.one('.fp-file-zip').on('click', function(e) {
848 var fileinfo = this.selectui.fileinfo;
849 if (fileinfo.type != 'folder') {
850 // this button should not even be shown
853 params['filepath'] = fileinfo.filepath;
854 params['filename'] = '.';
855 selectnode.addClass('loading');
860 callback: function(id, obj, args) {
861 args.scope.selectui.hide();
862 args.scope.refresh(obj.filepath);
866 selectnode.one('.fp-file-unzip').on('click', function(e) {
869 var fileinfo = this.selectui.fileinfo;
870 if (fileinfo.type != 'zip') {
871 // this button should not even be shown
874 params['filepath'] = fileinfo.filepath;
875 params['filename'] = fileinfo.fullname;
876 selectnode.addClass('loading');
881 callback: function(id, obj, args) {
882 args.scope.selectui.hide();
883 args.scope.refresh(obj.filepath);
887 selectnode.one('.fp-file-setmain').on('click', function(e) {
890 var fileinfo = this.selectui.fileinfo;
891 if (!this.enablemainfile || fileinfo.type == 'folder') {
892 // this button should not even be shown for folders or when mainfile is disabled
895 params['filepath'] = fileinfo.filepath;
896 params['filename'] = fileinfo.fullname;
897 selectnode.addClass('loading');
899 action: 'setmainfile',
902 callback: function(id, obj, args) {
903 args.scope.selectui.hide();
904 args.scope.refresh(fileinfo.filepath);
908 selectnode.all('.fp-file-cancel').on('click', function(e) {
910 // TODO if changed asked to confirm, the same with close button
911 this.selectui.hide();
914 get_parent_folder_name: function(node) {
915 if (node.type != 'folder' || node.filepath.length < node.fullname.length+1) {
916 return node.filepath;
918 var basedir = node.filepath.substr(0, node.filepath.length - node.fullname.length - 1);
919 var lastdir = node.filepath.substr(node.filepath.length - node.fullname.length - 2);
920 if (lastdir == '/' + node.fullname + '/') {
923 return node.filepath;
925 select_file: function(node) {
926 if (this.is_disabled()) {
929 var selectnode = this.selectnode;
930 selectnode.removeClass('loading').removeClass('fp-folder').
931 removeClass('fp-file').removeClass('fp-zip').removeClass('fp-cansetmain');
932 if (node.type == 'folder' || node.type == 'zip') {
933 selectnode.addClass('fp-'+node.type);
935 selectnode.addClass('fp-file');
937 if (this.enablemainfile && (node.sortorder != 1) && node.type == 'file') {
938 selectnode.addClass('fp-cansetmain');
940 this.selectui.fileinfo = node;
941 selectnode.one('.fp-saveas input').set('value', node.fullname);
942 var foldername = this.get_parent_folder_name(node);
943 selectnode.all('.fp-author input').set('value', node.author ? node.author : '');
944 selectnode.all('.fp-license select option[selected]').set('selected', false);
945 selectnode.all('.fp-license select option[value='+node.license+']').set('selected', true);
946 selectnode.all('.fp-path select option[selected]').set('selected', false);
947 selectnode.all('.fp-path select option').each(function(el){
948 if (el.get('value') == foldername) {
949 el.set('selected', true);
952 selectnode.all('.fp-author input, .fp-license select').set('disabled',(node.type == 'folder')?'disabled':'');
953 // display static information about a file (when known)
954 var attrs = ['datemodified','datecreated','size','dimensions','original','reflist'];
955 for (var i in attrs) {
956 if (selectnode.one('.fp-'+attrs[i])) {
957 var value = (node[attrs[i]+'_f']) ? node[attrs[i]+'_f'] : (node[attrs[i]] ? node[attrs[i]] : '');
958 selectnode.one('.fp-'+attrs[i]).addClassIf('fp-unknown', ''+value == '')
959 .one('.fp-value').setContent(Y.Escape.html(value));
963 var imgnode = Y.Node.create('<img/>').
964 set('src', node.realthumbnail ? node.realthumbnail : node.thumbnail).
965 setStyle('maxHeight', ''+(node.thumbnail_height ? node.thumbnail_height : 90)+'px').
966 setStyle('maxWidth', ''+(node.thumbnail_width ? node.thumbnail_width : 90)+'px');
967 selectnode.one('.fp-thumbnail').setContent('').appendChild(imgnode);
968 // load original location if applicable
969 if (node.isref && !node.original) {
970 selectnode.one('.fp-original').removeClass('fp-unknown').addClass('fp-loading');
972 action: 'getoriginal',
974 params: {'filepath':node.filepath,'filename':node.fullname},
975 callback: function(id, obj, args) {
976 // check if we did not select another file meanwhile
977 var scope = args.scope;
978 if (scope.selectui.fileinfo && node &&
979 scope.selectui.fileinfo.filepath == node.filepath &&
980 scope.selectui.fileinfo.fullname == node.fullname) {
981 selectnode.one('.fp-original').removeClass('fp-loading');
983 node.original = obj.original;
984 selectnode.one('.fp-original .fp-value').setContent(Y.Escape.html(node.original));
986 selectnode.one('.fp-original .fp-value').setContent(M.str.repository.unknownsource);
992 // load references list if applicable
993 selectnode.one('.fp-refcount').setContent(node.refcount ? M.util.get_string('referencesexist', 'repository', node.refcount) : '');
994 if (node.refcount && !node.reflist) {
995 selectnode.one('.fp-reflist').removeClass('fp-unknown').addClass('fp-loading');
997 action: 'getreferences',
999 params: {'filepath':node.filepath,'filename':node.fullname},
1000 callback: function(id, obj, args) {
1001 // check if we did not select another file meanwhile
1002 var scope = args.scope;
1003 if (scope.selectui.fileinfo && node &&
1004 scope.selectui.fileinfo.filepath == node.filepath &&
1005 scope.selectui.fileinfo.fullname == node.fullname) {
1006 selectnode.one('.fp-reflist').removeClass('fp-loading');
1007 if (obj.references) {
1009 for (var i in obj.references) {
1010 node.reflist += '<li>'+obj.references[i]+'</li>';
1012 selectnode.one('.fp-reflist .fp-value').setContent(Y.Escape.html(node.reflist));
1014 selectnode.one('.fp-reflist .fp-value').setContent('');
1020 // update dialog header
1021 var nodename = node.fullname;
1022 // Limit the string length so it fits nicely on mobile devices
1023 var namelength = 50;
1024 if (nodename.length > namelength) {
1025 nodename = nodename.substring(0, namelength) + '...';
1027 Y.one('#fm-dialog-label_'+selectnode.get('id')).setContent(Y.Escape.html(M.str.moodle.edit+' '+nodename));
1029 this.selectui.show();
1030 Y.one('#'+selectnode.get('id')).focus();
1032 render: function() {
1036 has_folder: function(foldername) {
1038 for (var i in this.options.list) {
1039 element = this.options.list[i];
1040 if (element.type == 'folder' && element.fullname == foldername) {
1048 // finally init everything needed
1049 // hide loading picture, display filemanager interface
1050 var filemanager = Y.one('#filemanager-'+options.client_id);
1051 filemanager.removeClass('fm-loading').addClass('fm-loaded');
1053 var manager = new FileManagerHelper(options);
1055 filemanager: manager,
1056 acceptedtypes: options.filepicker.accepted_types,
1057 clientid: options.client_id,
1058 author: options.author,
1059 maxfiles: options.maxfiles,
1060 maxbytes: options.maxbytes,
1061 areamaxbytes: options.areamaxbytes,
1062 itemid: options.itemid,
1063 repositories: manager.filepicker_options.repositories,
1064 containerid: manager.dndcontainer.get('id')
1066 M.form_dndupload.init(Y, dndoptions);