Merge branch 'MDL-26735' of git://github.com/timhunt/moodle
[moodle.git] / repository / filepicker.js
blob68c7ad77a3148f1a4337a1f41087081ec81448bf
1 // YUI3 File Picker module for moodle
2 // Author: Dongsheng Cai <dongsheng@moodle.com>
4 /**
5  *
6  * File Picker UI
7  * =====
8  * this.rendered, it tracks if YUI Panel rendered
9  * this.api, stores the URL to make ajax request
10  * this.mainui, YUI Panel
11  * this.treeview, YUI Treeview
12  * this.viewbar, a button group to switch view mode
13  * this.viewmode, store current view mode
14  *
15  * Filepicker options:
16  * =====
17  * this.options.client_id, the instance id
18  * this.options.contextid
19  * this.options.itemid
20  * this.options.repositories, stores all repositories displaied in file picker
21  * this.options.formcallback
22  *
23  * Active repository options
24  * =====
25  * this.active_repo.id
26  * this.active_repo.nosearch
27  * this.active_repo.norefresh
28  * this.active_repo.nologin
29  * this.active_repo.help
30  * this.active_repo.manage
31  *
32  * Server responses
33  * =====
34  * this.filelist, cached filelist
35  * this.pages
36  * this.page
37  * this.filepath, current path
38  * this.logindata, cached login form
39  */
41 M.core_filepicker = M.core_filepicker || {};
43 /**
44  * instances of file pickers used on page
45  */
46 M.core_filepicker.instances = M.core_filepicker.instances || {};
47 M.core_filepicker.active_filepicker = null;
49 /**
50  * Init and show file picker
51  */
52 M.core_filepicker.show = function(Y, options) {
53     if (!M.core_filepicker.instances[options.client_id]) {
54         M.core_filepicker.init(Y, options);
55     }
56     M.core_filepicker.instances[options.client_id].show();
59 /**
60  * Add new file picker to current instances
61  */
62 M.core_filepicker.init = function(Y, options) {
63     var FilePickerHelper = function(options) {
64         FilePickerHelper.superclass.constructor.apply(this, arguments);
65     };
67     FilePickerHelper.NAME = "FilePickerHelper";
68     FilePickerHelper.ATTRS = {
69         options: {},
70         lang: {}
71     };
73     Y.extend(FilePickerHelper, Y.Base, {
74         api: M.cfg.wwwroot+'/repository/repository_ajax.php',
76         initializer: function(options) {
77             this.options = options;
78             if (!this.options.savepath) {
79                 this.options.savepath = '/';
80             }
81         },
83         destructor: function() {
84         },
86         request: function(args, redraw) {
87             var client_id = args.client_id;
88             var api = this.api + '?action='+args.action;
89             var params = {};
90             var scope = this;
91             if (args['scope']) {
92                 scope = args['scope'];
93             }
94             params['repo_id']=args.repository_id;
95             params['p'] = args.path?args.path:'';
96             params['page'] = args.page?args.page:'';
97             params['env']=this.options.env;
98             // the form element only accept certain file types
99             params['accepted_types']=this.options.accepted_types;
100             params['sesskey'] = M.cfg.sesskey;
101             params['client_id'] = args.client_id;
102             params['itemid'] = this.options.itemid?this.options.itemid:0;
103             params['maxbytes'] = this.options.maxbytes?this.options.maxbytes:-1;
104             if (this.options.context && this.options.context.id) {
105                 params['ctx_id'] = this.options.context.id;
106             }
107             if (args['params']) {
108                 for (i in args['params']) {
109                     params[i] = args['params'][i];
110                 }
111             }
112             if (args.action == 'upload') {
113                 var list = [];
114                 for(var k in params) {
115                     var value = params[k];
116                     if(value instanceof Array) {
117                         for(var i in value) {
118                             list.push(k+'[]='+value[i]);
119                         }
120                     } else {
121                         list.push(k+'='+value);
122                     }
123                 }
124                 params = list.join('&');
125             } else {
126                 params = build_querystring(params);
127             }
128             var cfg = {
129                 method: 'POST',
130                 on: {
131                     complete: function(id,o,p) {
132                         var panel_id = '#panel-'+client_id;
133                         if (!o) {
134                             alert('IO FATAL');
135                             return;
136                         }
137                         var data = null;
138                         try {
139                             data = Y.JSON.parse(o.responseText);
140                         } catch(e) {
141                             scope.print_msg(M.str.repository.invalidjson, 'error');
142                             Y.one(panel_id).set('innerHTML', 'ERROR: '+M.str.repository.invalidjson+'<pre>'+stripHTML(o.responseText)+'</pre>');
143                             return;
144                         }
145                         // error checking
146                         if (data && data.error) {
147                             scope.print_msg(data.error, 'error');
148                             scope.list();
149                             return;
150                         } else {
151                             if (data.msg) {
152                                 scope.print_msg(data.msg, 'info');
153                             }
154                             args.callback(id,data,p);
155                         }
156                     }
157                 },
158                 arguments: {
159                     scope: scope
160                 },
161                 headers: {
162                     'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
163                 },
164                 data: params,
165                 context: this
166             };
167             if (args.form) {
168                 cfg.form = args.form;
169             }
170             Y.io(api, cfg);
171             if (redraw) {
172                 this.wait('load');
173             }
174         },
175         print_msg: function(msg, type) {
176             var client_id = this.options.client_id;
177             var dlg_id = 'fp-msg-dlg-'+client_id;
178             function handleYes() {
179                 this.hide();
180             }
181             var icon = YAHOO.widget.SimpleDialog.ICON_INFO;
182             if (type=='error') {
183                 icon = YAHOO.widget.SimpleDialog.ICON_ALARM;
184             }
185             if (!this.msg_dlg) {
186                 this.msg_dlg = new YAHOO.widget.SimpleDialog(dlg_id,
187                      { width: "300px",
188                        fixedcenter: true,
189                        visible: true,
190                        draggable: true,
191                        close: true,
192                        text: msg,
193                        modal: false,
194                        icon: icon,
195                        zindex: 9999992,
196                        constraintoviewport: true,
197                        buttons: [{ text:M.str.moodle.ok, handler:handleYes, isDefault:true }]
198                      });
199                 this.msg_dlg.render(document.body);
200             } else {
201                 this.msg_dlg.setBody(msg);
202             }
203             var header = M.str.moodle.info;
204             if (type=='error') {
205                 header = M.str.moodle.error;
206             }
207             this.msg_dlg.setHeader(type);
208             this.msg_dlg.show();
209         },
210         build_tree: function(node, level) {
211             var client_id = this.options.client_id;
212             var dynload = this.active_repo.dynload;
213             if(node.children) {
214                 node.title = '<i><u>'+node.title+'</u></i>';
215             }
216             var info = {
217                 label:node.title,
218                 //title:fp_lang.date+' '+node.date+fp_lang.size+' '+node.size,
219                 filename:node.title,
220                 source:node.source?node.source:'',
221                 thumbnail:node.thumbnail,
222                 path:node.path?node.path:[]
223             };
224             var tmpNode = new YAHOO.widget.TextNode(info, level, false);
225             if(node.repo_id) {
226                 tmpNode.repo_id=node.repo_id;
227             }else{
228                 tmpNode.repo_id=this.active_repo.id;
229             }
230             if(node.children) {
231                 if(node.expanded) {
232                     tmpNode.expand();
233                 }
234                 if (dynload) {
235                     tmpNode.scope = this;
236                 }
237                 tmpNode.isLeaf = false;
238                 tmpNode.client_id = client_id;
239                 if (node.path) {
240                     tmpNode.path = node.path;
241                 } else {
242                     tmpNode.path = '';
243                 }
244                 for(var c in node.children) {
245                     this.build_tree(node.children[c], tmpNode);
246                 }
247             } else {
248                 tmpNode.isLeaf = true;
249             }
250         },
251         view_files: function() {
252             this.viewbar.set('disabled', false);
253             if (this.viewmode == 1) {
254                 this.view_as_icons();
255             } else if (this.viewmode ==2) {
256                 this.view_as_list();
257             } else {
258                 this.view_as_icons();
259             }
260         },
261         treeview_dynload: function(node, cb) {
262             var scope = node.scope;
263             var client_id = scope.options.client_id;
264             var repository_id = scope.active_repo.id;
265             scope.request({
266                 action:'list',
267                 client_id: client_id,
268                 repository_id: repository_id,
269                 path:node.path?node.path:'',
270                 page:node.page?args.page:'',
271                 callback: function(id, obj, args) {
272                     obj.issearchresult = false;
273                     var list = obj.list;
274                     scope.viewbar.set('disabled', false);
275                     scope.parse_repository_options(obj);
276                     for(k in list) {
277                         scope.build_tree(list[k], node);
278                     }
279                     cb();
280                 }
281             }, false);
282         },
283         view_as_list: function() {
284             var scope = this;
285             scope.request({
286                 action:'list',
287                 client_id: scope.options.client_id,
288                 repository_id: scope.active_repo.id,
289                 path:'',
290                 page:'',
291                 callback: function(id, obj, args) {
292                     var client_id = scope.options.client_id;
293                     var dynload = scope.active_repo.dynload;
294                     var list = obj.list;
295                     var panel_id = '#panel-'+client_id;
296                     scope.viewmode = 2;
297                     Y.one(panel_id).set('innerHTML', '');
299                     scope.print_header();
301                     var html = '<div class="fp-tree-panel" id="treeview-'+client_id+'">';
302                     if (list.length==0) {
303                         html += '<div class="fp-emptylist mdl-align">' +M.str.repository.nofilesavailable+'</div>';
304                     }
305                     html += '</div>';
307                     var tree = Y.Node.create(html);
308                     Y.one(panel_id).appendChild(tree);
309                     if (list.length==0) {
310                         return;
311                     }
313                     scope.treeview = new YAHOO.widget.TreeView('treeview-'+client_id);
314                     if (dynload) {
315                         scope.treeview.setDynamicLoad(scope.treeview_dynload, 1);
316                     }
318                     for(k in list) {
319                         scope.build_tree(list[k], scope.treeview.getRoot());
320                     }
321                     scope.treeview.subscribe('clickEvent', function(e){
322                         if(e.node.isLeaf){
323                             var fileinfo = {};
324                             fileinfo['title'] = e.node.data.filename;
325                             fileinfo['source'] = e.node.data.source;
326                             fileinfo['thumbnail'] = e.node.data.thumbnail;
327                             scope.select_file(fileinfo);
328                         }
329                     });
330                     scope.treeview.draw();
331                 }
332             }, true);
333         },
334         view_as_icons: function() {
335             var scope = this;
336             var client_id = this.options.client_id;
337             var list = this.filelist;
338             var panel_id = '#panel-'+client_id;
339             this.viewmode = 1;
340             Y.one(panel_id).set('innerHTML', '');
342             this.print_header();
344             var html = '<div class="fp-grid-panel" id="fp-grid-panel-'+client_id+'">';
345             if (list.length==0) {
346                 html += '<div class="fp-emptylist mdl-align">' +M.str.repository.nofilesavailable+'</div>';
347             }
348             html += '</div>';
350             var gridpanel = Y.Node.create(html);
351             Y.one('#panel-'+client_id).appendChild(gridpanel);
352             var count = 0;
353             for(var k in list) {
354                 var node = list[k];
355                 var grid = document.createElement('DIV');
356                 grid.className='fp-grid';
357                 // the file name
358                 var title = document.createElement('DIV');
359                 title.id = 'grid-title-'+client_id+'-'+String(count);
360                 title.className = 'label';
361                 var filename = node.title;
362                 if (node.shorttitle) {
363                     filename = node.shorttitle;
364                 }
365                 var filename_id = 'filname-link-'+client_id+'-'+String(count);
366                 title.innerHTML += '<a href="###" id="'+filename_id+'" title="'+node.title+'"><span>'+filename+"</span></a>";
369                 if(node.thumbnail_width){
370                     grid.style.width = node.thumbnail_width+'px';
371                     title.style.width = (node.thumbnail_width-10)+'px';
372                 } else {
373                     grid.style.width = title.style.width = '90px';
374                 }
375                 var frame = document.createElement('DIV');
376                 frame.style.textAlign='center';
377                 if(node.thumbnail_height){
378                     frame.style.height = node.thumbnail_height+'px';
379                 }
380                 var img = document.createElement('img');
381                 img.src = node.thumbnail;
382                 img.title = node.title;
383                 if(node.thumbnail_alt) {
384                     img.alt = node.thumbnail_alt;
385                 }
386                 if(node.thumbnail_title) {
387                     img.title = node.thumbnail_title;
388                 }
390                 var link = document.createElement('A');
391                 link.href='###';
392                 link.id = 'img-id-'+client_id+'-'+String(count);
393                 if(node.url) {
394                     // hide
395                     //grid.innerHTML += '<p><a target="_blank" href="'+node.url+'">'+M.str.repository.preview+'</a></p>';
396                 }
397                 link.appendChild(img);
398                 frame.appendChild(link);
399                 grid.appendChild(frame);
400                 grid.appendChild(title);
401                 gridpanel.appendChild(grid);
403                 var y_title = Y.one('#'+title.id);
404                 var y_file = Y.one('#'+link.id);
405                 var dynload = this.active_repo.dynload;
406                 if(node.children) {
407                     y_file.on('click', function(e, p) {
408                         if(dynload) {
409                             var params = {'path':p.path};
410                             scope.list(params);
411                         }else{
412                             this.filelist = p.children;
413                             this.view_files();
414                         }
415                     }, this, node);
416                     y_title.on('click', function(e, p, id){
417                         var icon = Y.one(id);
418                         icon.simulate('click');
419                     }, this, node, '#'+link.id);
420                 } else {
421                     var fileinfo = {};
422                     fileinfo['title'] = list[k].title;
423                     fileinfo['source'] = list[k].source;
424                     fileinfo['thumbnail'] = list[k].thumbnail;
425                     fileinfo['haslicense'] = list[k].haslicense?true:false;
426                     fileinfo['hasauthor'] = list[k].hasauthor?true:false;
427                     y_title.on('click', function(e, args) {
428                         this.select_file(args);
429                     }, this, fileinfo);
430                     y_file.on('click', function(e, args) {
431                         this.select_file(args);
432                     }, this, fileinfo);
433                 }
434                 count++;
435             }
436         },
437         select_file: function(args) {
438             var client_id = this.options.client_id;
439             var thumbnail = Y.one('#fp-grid-panel-'+client_id);
440             if(thumbnail){
441                 thumbnail.setStyle('display', 'none');
442             }
443             var header = Y.one('#fp-header-'+client_id);
444             if (header) {
445                 header.setStyle('display', 'none');
446             }
447             var footer = Y.one('#fp-footer-'+client_id);
448             if (footer) {
449                 footer.setStyle('display', 'none');
450             }
451             var path = Y.one('#path-'+client_id);
452             if(path){
453                 path.setStyle('display', 'none');
454             }
455             var panel = Y.one('#panel-'+client_id);
456             var form_id = 'fp-rename-form-'+client_id;
457             var html = '<div class="fp-rename-form" id="'+form_id+'">';
458             html += '<p><img src="'+args.thumbnail+'" /></p>';
459             html += '<table width="100%">';
460             html += '<tr><td class="mdl-right"><label for="newname-'+client_id+'">'+M.str.repository.saveas+':</label></td>';
461             html += '<td class="mdl-left"><input type="text" id="newname-'+client_id+'" value="'+args.title+'" /></td></tr>';
463             var le_checked = '';
464             var le_style = '';
465             if (this.options.repositories[this.active_repo.id].return_types == 1) {
466                 // support external links only
467                 le_checked = 'checked';
468                 le_style = ' style="display:none;"';
469             } else if(this.options.repositories[this.active_repo.id].return_types == 2) {
470                 // support internal files only
471                 le_style = ' style="display:none;"';
472             }
473             if ((this.options.externallink && this.options.env == 'editor' && this.options.return_types != 1)) {
474                 html += '<tr'+le_style+'><td></td><td class="mdl-left"><input type="checkbox" id="linkexternal-'+client_id+'" value="" '+le_checked+' />'+M.str.repository.linkexternal+'</td></tr>';
475             }
477             if (!args.hasauthor) {
478                 // the author of the file
479                 html += '<tr><td class="mdl-right"><label for="text-author">'+M.str.repository.author+' :</label></td>';
480                 html += '<td class="mdl-left"><input id="text-author-'+client_id+'" type="text" name="author" value="'+this.options.author+'" /></td>';
481                 html += '</tr>';
482             }
484             if (!args.haslicense) {
485                 // the license of the file
486                 var licenses = this.options.licenses;
487                 html += '<tr><td class="mdl-right"><label for="select-license-'+client_id+'">'+M.str.repository.chooselicense+' :</label></td>';
488                 html += '<td class="mdl-left"><select name="license" id="select-license-'+client_id+'">';
489                 var recentlicense = YAHOO.util.Cookie.get('recentlicense');
490                 if (recentlicense) {
491                     this.options.defaultlicense=recentlicense;
492                 }
493                 for (var i in licenses) {
494                     if (this.options.defaultlicense==licenses[i].shortname) {
495                         var selected = ' selected';
496                     } else {
497                         var selected = '';
498                     }
499                     html += '<option value="'+licenses[i].shortname+'"'+selected+'>'+licenses[i].fullname+'</option>';
500                 }
501                 html += '</select></td></tr>';
502             }
503             html += '</table>';
505             html += '<p><input type="hidden" id="filesource-'+client_id+'" value="'+args.source+'" />';
506             html += '<input type="button" id="fp-confirm-'+client_id+'" value="'+M.str.repository.getfile+'" />';
507             html += '<input type="button" id="fp-cancel-'+client_id+'" value="'+M.str.moodle.cancel+'" /></p>';
508             html += '</div>';
510             var getfile_form = Y.Node.create(html);
511             panel.appendChild(getfile_form);
513             var getfile = Y.one('#fp-confirm-'+client_id);
514             getfile.on('click', function(e) {
515                 var client_id = this.options.client_id;
516                 var scope = this;
517                 var repository_id = this.active_repo.id;
518                 var title = Y.one('#newname-'+client_id).get('value');
519                 var filesource = Y.one('#filesource-'+client_id).get('value');
520                 var params = {'title':title, 'source':filesource, 'savepath': this.options.savepath};
521                 var license = Y.one('#select-license-'+client_id);
522                 if (license) {
523                     params['license'] = license.get('value');
524                     YAHOO.util.Cookie.set('recentlicense', license.get('value'));
525                 }
526                 var author = Y.one('#text-author-'+client_id);
527                 if (author){
528                     params['author'] = author.get('value');
529                 }
531                 if (this.options.env == 'editor') {
532                     // in editor, images are stored in '/' only
533                     params.savepath = '/';
534                     // when image or media button is clicked
535                     if ( this.options.return_types != 1 ) {
536                         var linkexternal = Y.one('#linkexternal-'+client_id).get('checked');
537                         if (linkexternal) {
538                             params['linkexternal'] = 'yes';
539                         }
540                     } else {
541                         // when link button in editor clicked
542                         params['linkexternal'] = 'yes';
543                     }
544                 }
546                 if (this.options.env == 'url') {
547                     params['linkexternal'] = 'yes';
548                 }
550                 this.wait('download', title);
551                 this.request({
552                     action:'download',
553                     client_id: client_id,
554                     repository_id: repository_id,
555                     'params': params,
556                     callback: function(id, obj, args) {
557                         if (scope.options.editor_target && scope.options.env=='editor') {
558                             scope.options.editor_target.value=obj.url;
559                             scope.options.editor_target.onchange();
560                         }
561                         scope.hide();
562                         obj.client_id = client_id;
563                         var formcallback_scope = null;
564                         if (args.scope.options.magicscope) {
565                             formcallback_scope = args.scope.options.magicscope;
566                         } else {
567                             formcallback_scope = args.scope;
568                         }
569                         scope.options.formcallback.apply(formcallback_scope, [obj]);
570                     }
571                 }, true);
572             }, this);
573             var elform = Y.one('#'+form_id);
574             elform.on('keydown', function(e) {
575                 if (e.keyCode == 13) {
576                     getfile.simulate('click');
577                     e.preventDefault();
578                 }
579             }, this);
580             var cancel = Y.one('#fp-cancel-'+client_id);
581             cancel.on('click', function(e) {
582                 this.view_files();
583             }, this);
584             var treeview = Y.one('#treeview-'+client_id);
585             if (treeview){
586                 treeview.setStyle('display', 'none');
587             }
588         },
589         wait: function(type) {
590             var panel = Y.one('#panel-'+this.options.client_id);
591             panel.set('innerHTML', '');
592             var name = '';
593             var str = '<div style="text-align:center">';
594             if(type=='load') {
595                 str += '<img src="'+M.util.image_url('i/loading')+'" />';
596                 str += '<p>'+M.str.repository.loading+'</p>';
597             }else{
598                 str += '<img src="'+M.util.image_url('i/progressbar')+'" />';
599                 str += '<p>'+M.str.repository.copying+' <strong>'+name+'</strong></p>';
600             }
601             str += '</div>';
602             try {
603                 panel.set('innerHTML', str);
604             } catch(e) {
605                 alert(e.toString());
606             }
607         },
608         render: function() {
609             var client_id = this.options.client_id;
610             var scope = this;
611             var filepicker_id = 'filepicker-'+client_id;
612             var fpnode = Y.Node.create('<div class="file-picker" id="'+filepicker_id+'"></div>');
613             Y.one(document.body).appendChild(fpnode);
614             // render file picker panel
615             this.mainui = new YAHOO.widget.Panel(filepicker_id, {
616                 draggable: true,
617                 close: true,
618                 underlay: 'none',
619                 zindex: 9999990,
620                 monitorresize: false,
621                 xy: [50, YAHOO.util.Dom.getDocumentScrollTop()+20]
622             });
623             var layout = null;
624             this.mainui.beforeRenderEvent.subscribe(function() {
625                 YAHOO.util.Event.onAvailable('layout-'+client_id, function() {
626                     layout = new YAHOO.widget.Layout('layout-'+client_id, {
627                         height: 480, width: 700,
628                         units: [
629                         {position: 'top', height: 32, resize: false,
630                         body:'<div class="yui-buttongroup fp-viewbar" id="fp-viewbar-'+client_id+'"></div><div class="fp-searchbar" id="search-div-'+client_id+'"></div>', gutter: '2'},
631                         {position: 'left', width: 200, resize: true, scroll:true,
632                         body:'<ul class="fp-list" id="fp-list-'+client_id+'"></ul>', gutter: '0 5 0 2', minWidth: 150, maxWidth: 300 },
633                         {position: 'center', body: '<div class="fp-panel" id="panel-'+client_id+'"></div>',
634                         scroll: true, gutter: '0 2 0 0' }
635                         ]
636                     });
637                     layout.render();
638                     scope.show_recent_repository();
639                 });
640             });
642             this.mainui.setHeader(M.str.repository.filepicker);
643             this.mainui.setBody('<div id="layout-'+client_id+'"></div>');
644             this.mainui.render();
645             this.rendered = true;
647             var scope = this;
648             // adding buttons
649             var view_icons = {label: M.str.repository.iconview, value: 't',
650                 onclick: {
651                     fn: function(){
652                         scope.view_as_icons();
653                     }
654                 }
655             };
656             var view_listing = {label: M.str.repository.listview, value: 'l',
657                 onclick: {
658                     fn: function(){
659                         scope.view_as_list();
660                     }
661                 }
662             };
663             this.viewbar = new YAHOO.widget.ButtonGroup({
664                 id: 'btngroup-'+client_id,
665                 name: 'buttons',
666                 disabled: true,
667                 container: 'fp-viewbar-'+client_id
668             });
669             this.viewbar.addButtons([view_icons, view_listing]);
670             // processing repository listing
671             var r = this.options.repositories;
672             Y.on('contentready', function(el) {
673                 var list = Y.one(el);
674                 var count = 0;
675                 for (var i in r) {
676                     var id = 'repository-'+client_id+'-'+r[i].id;
677                     var link_id = id + '-link';
678                     list.append('<li id="'+id+'"><a class="fp-repo-name" id="'+link_id+'" href="###">'+r[i].name+'</a></li>');
679                     Y.one('#'+link_id).prepend('<img src="'+r[i].icon+'" width="16" height="16" />&nbsp;');
680                     Y.one('#'+link_id).on('click', function(e, scope, repository_id) {
681                         YAHOO.util.Cookie.set('recentrepository', repository_id);
682                         scope.repository_id = repository_id;
683                         this.list({'repo_id':repository_id});
684                     }, this /*handler running scope*/, this/*second argument*/, r[i].id/*third argument of handler*/);
685                     count++;
686                 }
687                 if (count==0) {
688                     if (this.options.externallink) {
689                         list.set('innerHTML', M.str.repository.norepositoriesexternalavailable);
690                     } else {
691                         list.set('innerHTML', M.str.repository.norepositoriesavailable);
692                     }
693                 }
694             }, '#fp-list-'+client_id, this /* handler running scope */, '#fp-list-'+client_id /*first argument of handler*/);
695         },
696         parse_repository_options: function(data) {
697             this.filelist = data.list?data.list:null;
698             this.filepath = data.path?data.path:null;
699             this.active_repo = {};
700             this.active_repo.issearchresult = Boolean(data.issearchresult);
701             this.active_repo.dynload = data.dynload?data.dynload:false;
702             this.active_repo.pages = Number(data.pages?data.pages:null);
703             this.active_repo.page = Number(data.page?data.page:null);
704             this.active_repo.id = data.repo_id?data.repo_id:null;
705             this.active_repo.nosearch = data.nosearch?true:false;
706             this.active_repo.norefresh = data.norefresh?true:false;
707             this.active_repo.nologin = data.nologin?true:false;
708             this.active_repo.logouttext = data.logouttext?data.logouttext:null;
709             this.active_repo.help = data.help?data.help:null;
710             this.active_repo.manage = data.manage?data.manage:null;
711         },
712         print_login: function(data) {
713             this.parse_repository_options(data);
714             var client_id = this.options.client_id;
715             var repository_id = data.repo_id;
716             var l = this.logindata = data.login;
717             var loginurl = '';
718             var panel = Y.one('#panel-'+client_id);
719             var action = 'login';
720             if (data['login_btn_action']) {
721                 action=data['login_btn_action'];
722             }
723             var form_id = 'fp-form-'+client_id;
724             var download_button_id = 'fp-form-download-button-'+client_id;
725             var search_button_id   = 'fp-form-search-button-'+client_id;
726             var login_button_id    = 'fp-form-login-button-'+client_id;
727             var popup_button_id    = 'fp-form-popup-button-'+client_id;
729             var str = '<div class="fp-login-form">';
730             str += '<form id="'+form_id+'">';
731             var has_pop = false;
732             str +='<table width="100%">';
733             for(var k in l) {
734                 str +='<tr>';
735                 if(l[k].type=='popup') {
736                     // pop element
737                     loginurl = l[k].url;
738                     str += '<td colspan="2"><p class="fp-popup">'+M.str.repository.popup+'</p>';
739                     str += '<p class="fp-popup"><button id="'+popup_button_id+'">'+M.str.repository.login+'</button>';
740                     str += '</p></td>';
741                     action = 'popup';
742                 }else if(l[k].type=='textarea') {
743                     // textarea element
744                     str += '<td colspan="2"><p><textarea id="'+l[k].id+'" name="'+l[k].name+'"></textarea></p></td>';
745                 }else if(l[k].type=='select') {
746                     // select element
747                     str += '<td align="right"><label>'+l[k].label+':</label></td>';
748                     str += '<td align="left"><select id="'+l[k].id+'" name="'+l[k].name+'">';
749                     for (i in l[k].options) {
750                         str += '<option value="'+l[k].options[i].value+'">'+l[k].options[i].label+'</option>';
751                     }
752                     str += '</select></td>';
753                 }else{
754                     // input element
755                     var label_id = '';
756                     var field_id = '';
757                     var field_value = '';
758                     if(l[k].id) {
759                         label_id = ' for="'+l[k].id+'"';
760                         field_id = ' id="'+l[k].id+'"';
761                     }
762                     if (l[k].label) {
763                         str += '<td align="right" width="30%" valign="center">';
764                         str += '<label'+label_id+'>'+l[k].label+'</label> </td>';
765                     } else {
766                         str += '<td width="30%"></td>';
767                     }
768                     if(l[k].value) {
769                         field_value = ' value="'+l[k].value+'"';
770                     }
771                     if(l[k].type=='radio'){
772                         var list = l[k].value.split('|');
773                         var labels = l[k].value_label.split('|');
774                         str += '<td align="left">';
775                         for(var item in list) {
776                             str +='<input type="'+l[k].type+'"'+' name="'+l[k].name+'"'+
777                                 field_id+' value="'+list[item]+'" />'+labels[item]+'<br />';
778                         }
779                         str += '</td>';
780                     }else{
781                         str += '<td align="left">';
782                         str += '<input type="'+l[k].type+'"'+' name="'+l[k].name+'"'+field_value+' '+field_id+' />';
783                         str += '</td>';
784                     }
785                 }
786                 str +='</tr>';
787             }
788             str +='</table>';
789             str += '</form>';
791             // custom lable text
792             var btn_label = data['login_btn_label']?data['login_btn_label']:M.str.repository.submit;
793             if (action != 'popup') {
794                 str += '<p><input type="button" id="';
795                 switch (action) {
796                     case 'search':
797                         str += search_button_id;
798                         break;
799                     case 'download':
800                         str += download_button_id;
801                         break;
802                     default:
803                         str += login_button_id;
804                         break;
805                 }
806                 str += '" value="'+btn_label+'" /></p>';
807             }
809             str += '</div>';
811             // insert login form
812             try {
813                 panel.set('innerHTML', str);
814             } catch(e) {
815                 alert(e.toString()+M.str.quiz.xhtml);
816             }
817             // register buttons
818             // process login action
819             var login_button = Y.one('#'+login_button_id);
820             var scope = this;
821             if (login_button) {
822                 login_button.on('click', function(){
823                     // collect form data
824                     var data = this.logindata;
825                     var scope = this;
826                     var params = {};
827                     for (var k in data) {
828                         if(data[k].type!='popup') {
829                             var el = Y.one('[name='+data[k].name+']');
830                             var type = el.get('type');
831                             params[data[k].name] = '';
832                             if(type == 'checkbox') {
833                                 params[data[k].name] = el.get('checked');
834                             } else {
835                                 params[data[k].name] = el.get('value');
836                             }
837                         }
838                     }
839                     // start ajax request
840                     this.request({
841                         'params': params,
842                         'scope': scope,
843                         'action':'signin',
844                         'path': '',
845                         'client_id': client_id,
846                         'repository_id': repository_id,
847                         'callback': function(id, o, args) {
848                             scope.parse_repository_options(o);
849                             scope.view_files();
850                         }
851                     }, true);
852                 }, this);
853             }
854             var search_button = Y.one('#'+search_button_id);
855             if (search_button) {
856                 search_button.on('click', function(){
857                     var data = this.logindata;
858                     var params = {};
860                     for (var k in data) {
861                         if(data[k].type!='popup') {
862                             var el = document.getElementsByName(data[k].name)[0];
863                             params[data[k].name] = '';
864                             if(el.type == 'checkbox') {
865                                 params[data[k].name] = el.checked;
866                             } else if(el.type == 'radio') {
867                                 var tmp = document.getElementsByName(data[k].name);
868                                 for(var i in tmp) {
869                                     if (tmp[i].checked) {
870                                         params[data[k].name] = tmp[i].value;
871                                     }
872                                 }
873                             } else {
874                                 params[data[k].name] = el.value;
875                             }
876                         }
877                     }
878                     this.request({
879                             scope: scope,
880                             action:'search',
881                             client_id: client_id,
882                             repository_id: repository_id,
883                             form: {id: 'fp-form-'+scope.options.client_id,upload:false,useDisabled:true},
884                             callback: function(id, o, args) {
885                                 o.issearchresult = true;
886                                 scope.parse_repository_options(o);
887                                 scope.view_files();
888                             }
889                     }, true);
890                 }, this);
891             }
892             var download_button = Y.one('#'+download_button_id);
893             if (download_button) {
894                 download_button.on('click', function(){
895                     alert('download');
896                 });
897             }
898             var popup_button = Y.one('#'+popup_button_id);
899             if (popup_button) {
900                 popup_button.on('click', function(e){
901                     M.core_filepicker.active_filepicker = this;
902                     window.open(loginurl, 'repo_auth', 'location=0,status=0,width=500,height=300,scrollbars=yes');
903                     e.preventDefault();
904                 }, this);
905             }
906             var elform = Y.one('#'+form_id);
907             elform.on('keydown', function(e) {
908                 if (e.keyCode == 13) {
909                     switch (action) {
910                         case 'search':
911                             search_button.simulate('click');
912                             break;
913                         default:
914                             login_button.simulate('click');
915                             break;
916                     }
917                     e.preventDefault();
918                 }
919             }, this);
921         },
922         search: function(args) {
923             var data = this.logindata;
924             var params = {};
926             for (var k in data) {
927                 if(data[k].type!='popup') {
928                     var el = document.getElementsByName(data[k].name)[0];
929                     params[data[k].name] = '';
930                     if(el.type == 'checkbox') {
931                         params[data[k].name] = el.checked;
932                     } else if(el.type == 'radio') {
933                         var tmp = document.getElementsByName(data[k].name);
934                         for(var i in tmp) {
935                             if (tmp[i].checked) {
936                                 params[data[k].name] = tmp[i].value;
937                             }
938                         }
939                     } else {
940                         params[data[k].name] = el.value;
941                     }
942                 }
943             }
944             this.request({
945                     scope: scope,
946                     action:'search',
947                     client_id: client_id,
948                     repository_id: repository_id,
949                     form: {id: 'fp-form-'+scope.options.client_id,upload:false,useDisabled:true},
950                     callback: function(id, o, args) {
951                         o.issearchresult = true;
952                         scope.parse_repository_options(o);
953                         scope.view_files();
954                     }
955             }, true);
956         },
957         list: function(args) {
958             var scope = this;
959             if (!args) {
960                 args = {};
961             }
962             if (!args.repo_id) {
963                 args.repo_id = scope.active_repo.id;
964             }
965             scope.request({
966                 action:'list',
967                 client_id: scope.options.client_id,
968                 repository_id: args.repo_id,
969                 path:args.path?args.path:'',
970                 page:args.page?args.page:'',
971                 callback: function(id, obj, args) {
972                     Y.all('#fp-list-'+scope.options.client_id+' li a').setStyle('backgroundColor', 'transparent');
973                     var el = Y.one('#repository-'+scope.options.client_id+'-'+obj.repo_id+'-link');
974                     if (el) {
975                         el.setStyle('backgroundColor', '#AACCEE');
976                     }
977                     if (obj.login) {
978                         scope.viewbar.set('disabled', true);
979                         scope.print_login(obj);
980                     } else if (obj.upload) {
981                         scope.viewbar.set('disabled', true);
982                         scope.parse_repository_options(obj);
983                         scope.create_upload_form(obj);
985                     } else if (obj.iframe) {
987                     } else if (obj.list) {
988                         obj.issearchresult = false;
989                         scope.viewbar.set('disabled', false);
990                         scope.parse_repository_options(obj);
991                         scope.view_files();
992                     }
993                 }
994             }, true);
995         },
996         create_upload_form: function(data) {
997             var client_id = this.options.client_id;
998             Y.one('#panel-'+client_id).set('innerHTML', '');
999             var types = this.options.accepted_types;
1001             this.print_header();
1002             var id = data.upload.id+'_'+client_id;
1003             var str = '<div id="'+id+'_div" class="fp-upload-form mdl-align">';
1004             str += '<form id="'+id+'" method="POST">';
1005             str += '<table width="100%">';
1006             str += '<tr><td class="mdl-right">';
1007             str += '<label for="'+id+'_file">'+data.upload.label+': </label></td>';
1008             str += '<td class="mdl-left"><input type="file" id="'+id+'_file" name="repo_upload_file" />';
1009             str += '<tr><td class="mdl-right"><label for="newname-'+client_id+'">'+M.str.repository.saveas+':</label></td>';
1010             str += '<td class="mdl-left"><input type="text" name="title" id="newname-'+client_id+'" value="" /></td></tr>';
1011             str += '<input type="hidden" name="itemid" value="'+this.options.itemid+'" />';
1012             for (var i in types) {
1013                 str += '<input type="hidden" name="accepted_types[]" value="'+types[i]+'" />';
1014             }
1015             str += '</td></tr><tr>';
1016             str += '<td class="mdl-right"><label>'+M.str.repository.author+': </label></td>';
1017             str += '<td class="mdl-left"><input type="text" name="author" value="'+this.options.author+'" /></td>';
1018             str += '</tr>';
1019             str += '<tr>';
1020             str += '<td class="mdl-right">'+M.str.repository.chooselicense+': </td>';
1021             str += '<td class="mdl-left">';
1022             var licenses = this.options.licenses;
1023             str += '<select name="license" id="select-license-'+client_id+'">';
1024             var recentlicense = YAHOO.util.Cookie.get('recentlicense');
1025             if (recentlicense) {
1026                 this.options.defaultlicense=recentlicense;
1027             }
1028             for (var i in licenses) {
1029                 if (this.options.defaultlicense==licenses[i].shortname) {
1030                     var selected = ' selected';
1031                 } else {
1032                     var selected = '';
1033                 }
1034                 str += '<option value="'+licenses[i].shortname+'"'+selected+'>'+licenses[i].fullname+'</option>';
1035             }
1036             str += '</select>';
1037             str += '</td>';
1038             str += '</tr></table>';
1039             str += '</form>';
1040             str += '<div class="fp-upload-btn"><button id="'+id+'_action">'+M.str.repository.upload+'</button></div>';
1041             str += '</div>';
1042             var upload_form = Y.Node.create(str);
1043             Y.one('#panel-'+client_id).appendChild(upload_form);
1044             var scope = this;
1045             Y.one('#'+id+'_action').on('click', function(e) {
1046                 e.preventDefault();
1047                 var license = Y.one('#select-license-'+client_id).get('value');
1048                 YAHOO.util.Cookie.set('recentlicense', license);
1049                 if (!Y.one('#'+id+'_file').get('value')) {
1050                     scope.print_msg(M.str.repository.nofilesattached, 'error');
1051                     return false;
1052                 }
1053                 Y.use('io-upload-iframe', function() {
1054                     scope.request({
1055                             scope: scope,
1056                             action:'upload',
1057                             client_id: client_id,
1058                             params: {'savepath':scope.options.savepath},
1059                             repository_id: scope.active_repo.id,
1060                             form: {id: id, upload:true},
1061                             callback: function(id, o, args) {
1062                                 if (scope.options.editor_target&&scope.options.env=='editor') {
1063                                     scope.options.editor_target.value=o.url;
1064                                     scope.options.editor_target.onchange();
1065                                 }
1066                                 scope.hide();
1067                                 o.client_id = client_id;
1068                                 var formcallback_scope = null;
1069                                 if (args.scope.options.magicscope) {
1070                                     formcallback_scope = args.scope.options.magicscope;
1071                                 } else {
1072                                     formcallback_scope = args.scope;
1073                                 }
1074                                 scope.options.formcallback.apply(formcallback_scope, [o]);
1075                             }
1076                     }, true);
1077                 });
1078             }, this);
1079         },
1080         print_header: function() {
1081             var r = this.active_repo;
1082             var scope = this;
1083             var client_id = this.options.client_id;
1084             var repository_id = this.active_repo.id;
1085             var panel = Y.one('#panel-'+client_id);
1086             var str = '<div id="fp-header-'+client_id+'">';
1087             str += '<div class="fp-toolbar" id="repo-tb-'+client_id+'"></div>';
1088             str += '</div>';
1089             var head = Y.Node.create(str);
1090             panel.appendChild(head);
1091             //if(this.active_repo.pages < 8){
1092                 this.print_paging('header');
1093             //}
1096             var toolbar = Y.one('#repo-tb-'+client_id);
1098             if(!r.nosearch) {
1099                 var html = '<a href="###"><img src="'+M.util.image_url('a/search')+'" /> '+M.str.repository.search+'</a>';
1100                 var search = Y.Node.create(html);
1101                 search.on('click', function() {
1102                     scope.request({
1103                         scope: scope,
1104                         action:'searchform',
1105                         repository_id: repository_id,
1106                         callback: function(id, obj, args) {
1107                             var scope = args.scope;
1108                             var client_id = scope.options.client_id;
1109                             var repository_id = scope.active_repo.id;
1110                             var container = document.getElementById('fp-search-dlg');
1111                             if(container) {
1112                                 container.innerHTML = '';
1113                                 container.parentNode.removeChild(container);
1114                             }
1115                             var container = document.createElement('DIV');
1116                             container.id = 'fp-search-dlg';
1118                             var dlg_title = document.createElement('DIV');
1119                             dlg_title.className = 'hd';
1120                             dlg_title.innerHTML = 'filepicker';
1122                             var dlg_body = document.createElement('DIV');
1123                             dlg_body.className = 'bd';
1125                             var sform = document.createElement('FORM');
1126                             sform.method = 'POST';
1127                             sform.id = "fp-search-form";
1128                             sform.innerHTML = obj.form;
1130                             dlg_body.appendChild(sform);
1131                             container.appendChild(dlg_title);
1132                             container.appendChild(dlg_body);
1133                             Y.one(document.body).appendChild(container);
1134                             var search_dialog= null;
1135                             function dialog_handler() {
1136                                 scope.viewbar.set('disabled', false);
1137                                 scope.request({
1138                                         scope: scope,
1139                                         action:'search',
1140                                         client_id: client_id,
1141                                         repository_id: repository_id,
1142                                         form: {id: 'fp-search-form',upload:false,useDisabled:true},
1143                                         callback: function(id, o, args) {
1144                                             scope.parse_repository_options(o);
1145                                             scope.view_files();
1146                                         }
1147                                 }, true);
1148                                 search_dialog.cancel();
1149                             }
1151                             search_dialog = new YAHOO.widget.Dialog("fp-search-dlg", {
1152                                postmethod: 'async',
1153                                draggable: true,
1154                                width : "30em",
1155                                fixedcenter : true,
1156                                zindex: 9999991,
1157                                visible : false,
1158                                constraintoviewport : true,
1159                                buttons: [
1160                                {
1161                                    text:M.str.repository.submit,
1162                                    handler:dialog_handler,
1163                                    isDefault:true
1164                                }, {
1165                                    text:M.str.moodle.cancel,
1166                                    handler:function(){
1167                                        this.destroy()
1168                                    }
1169                                }]
1170                             });
1171                             search_dialog.render();
1172                             search_dialog.show();
1173                         }
1174                     });
1175                 },this);
1176                 toolbar.appendChild(search);
1177             }
1178             // weather we use cache for this instance, this button will reload listing anyway
1179             if(!r.norefresh) {
1180                 var html = '<a href="###"><img src="'+M.util.image_url('a/refresh')+'" /> '+M.str.repository.refresh+'</a>';
1181                 var refresh = Y.Node.create(html);
1182                 refresh.on('click', function() {
1183                     this.list();
1184                 }, this);
1185                 toolbar.appendChild(refresh);
1186             }
1187             if(!r.nologin) {
1188                 var label = r.logouttext?r.logouttext:M.str.repository.logout;
1189                 var html = '<a href="###"><img src="'+M.util.image_url('a/logout')+'" /> '+label+'</a>';
1190                 var logout = Y.Node.create(html);
1191                 logout.on('click', function() {
1192                     this.request({
1193                         action:'logout',
1194                         client_id: client_id,
1195                         repository_id: repository_id,
1196                         path:'',
1197                         callback: function(id, obj, args) {
1198                             scope.viewbar.set('disabled', true);
1199                             scope.print_login(obj);
1200                         }
1201                     }, true);
1202                 }, this);
1203                 toolbar.appendChild(logout);
1204             }
1206             if(r.manage) {
1207                 var mgr = document.createElement('A');
1208                 mgr.href = r.manage;
1209                 mgr.target = "_blank";
1210                 mgr.innerHTML = '<img src="'+M.util.image_url('a/setting')+'" /> '+M.str.repository.manageurl;
1211                 toolbar.appendChild(mgr);
1212             }
1213             if(r.help) {
1214                 var help = document.createElement('A');
1215                 help.href = r.help;
1216                 help.target = "_blank";
1217                 help.innerHTML = '<img src="'+M.util.image_url('a/help')+'" /> '+M.str.repository.help;
1218                 toolbar.appendChild(help);
1219             }
1221             this.print_path();
1222         },
1223         get_page_button: function(page) {
1224             var r = this.active_repo;
1225             var css = '';
1226             if (page == r.page) {
1227                 css = 'class="cur_page" ';
1228             }
1229             var str = '<a '+css+'href="###" id="repo-page-'+page+'">';
1230             return str;
1231         },
1232         print_paging: function(html_id) {
1233             var client_id = this.options.client_id;
1234             var scope = this;
1235             var r = this.active_repo;
1236             var str = '';
1237             var action = '';
1238             if(r.pages > 1) {
1239                 str += '<div class="fp-paging" id="paging-'+html_id+'-'+client_id+'">';
1240                 str += this.get_page_button(1)+'1</a> ';
1242                 var span = 5;
1243                 var ex = (span-1)/2;
1245                 if (r.page+ex>=r.pages) {
1246                     var max = r.pages;
1247                 } else {
1248                     if (r.page<span) {
1249                         var max = span;
1250                     } else {
1251                         var max = r.page+ex;
1252                     }
1253                 }
1255                 // won't display upper boundary
1256                 if (r.page >= span) {
1257                     str += ' ... ';
1258                     for(var i=r.page-ex; i<max; i++) {
1259                         str += this.get_page_button(i);
1260                         str += String(i);
1261                         str += '</a> ';
1262                     }
1263                 } else {
1264                     // this very first elements
1265                     for(var i = 2; i < max; i++) {
1266                         str += this.get_page_button(i);
1267                         str += String(i);
1268                         str += '</a> ';
1269                     }
1270                 }
1272                 // won't display upper boundary
1273                 if (max==r.pages) {
1274                     str += this.get_page_button(r.pages)+r.pages+'</a>';
1275                 } else {
1276                     str += this.get_page_button(max)+max+'</a>';
1277                     str += ' ... '+this.get_page_button(r.pages)+r.pages+'</a>';
1278                 }
1279                 str += '</div>';
1280             }
1281             if (str) {
1282                 var a = Y.Node.create(str);
1283                 Y.one('#fp-header-'+client_id).appendChild(a);
1285                 Y.all('#fp-header-'+client_id+' .fp-paging a').each(
1286                     function(node, id) {
1287                         node.on('click', function(e) {
1288                             var id = node.get('id');
1289                             var re = new RegExp("repo-page-(\\d+)", "i");
1290                             var result = id.match(re);
1291                             var args = {};
1292                             args.page = result[1];
1293                             if (scope.active_repo.issearchresult) {
1294                                 scope.request({
1295                                         scope: scope,
1296                                         action:'search',
1297                                         client_id: client_id,
1298                                         repository_id: r.id,
1299                                         params: {'page':result[1]},
1300                                         callback: function(id, o, args) {
1301                                             o.issearchresult = true;
1302                                             scope.parse_repository_options(o);
1303                                             scope.view_files();
1304                                         }
1305                                 }, true);
1307                             } else {
1308                                 scope.list(args);
1309                             }
1310                         });
1311                     });
1312             }
1313         },
1314         print_path: function() {
1315             var client_id = this.options.client_id;
1316             var panel = Y.one('#panel-'+client_id);
1317             var p = this.filepath;
1318             if (p && p.length!=0) {
1319                 var path = Y.Node.create('<div id="path-'+client_id+'" class="fp-pathbar"></div>');
1320                 panel.appendChild(path);
1321                 for(var i = 0; i < p.length; i++) {
1322                     var link_path = p[i].path;
1323                     var link = document.createElement('A');
1324                     link.href = "###";
1325                     link.innerHTML = p[i].name;
1326                     link.id = 'path-node-'+client_id+'-'+i;
1327                     var sep = Y.Node.create('<span>/</span>');
1328                     path.appendChild(link);
1329                     path.appendChild(sep);
1330                     Y.one('#'+link.id).on('click', function(Y, path){
1331                         this.list({'path':path});
1332                         }, this, link_path)
1333                 }
1334             }
1335         },
1336         hide: function() {
1337             this.mainui.hide();
1338         },
1339         show: function() {
1340             if (this.rendered) {
1341                 var panel = Y.one('#panel-'+this.options.client_id);
1342                 panel.set('innerHTML', '');
1343                 this.mainui.show();
1344                 this.show_recent_repository();
1345             } else {
1346                 this.launch();
1347             }
1348         },
1349         launch: function() {
1350             this.render();
1351         },
1352         show_recent_repository: function() {
1353             var repository_id = YAHOO.util.Cookie.get('recentrepository');
1354             if (this.options.repositories[repository_id]) {
1355                 this.list({'repo_id':repository_id});
1356             }
1357         }
1358     });
1359     var loading = Y.one('#filepicker-loading-'+options.client_id);
1360     if (loading) {
1361         loading.setStyle('display', 'none');
1362     }
1363     M.core_filepicker.instances[options.client_id] = new FilePickerHelper(options);