"MDL-13766, fixed a problem of icon view"
[moodle.git] / repository / filepicker.js
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();
57 };
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['filearea'] = this.options.filearea?this.options.filearea:'user_draft';
103             params['itemid'] = this.options.itemid?this.options.itemid:0;
104             params['maxbytes'] = this.options.maxbytes?this.options.maxbytes:-1;
105             if (args['params']) {
106                 for (i in args['params']) {
107                     params[i] = args['params'][i];
108                 }
109             }
110             var cfg = {
111                 method: 'POST',
112                 on: {
113                     complete: function(id,o,p) {
114                         var panel_id = '#panel-'+client_id;
115                         if (!o) {
116                             alert('IO FATAL');
117                             return;
118                         }
119                         var data = null;
120                         try {
121                             data = Y.JSON.parse(o.responseText);
122                         } catch(e) {
123                             Y.one(panel_id).set('innerHTML', 'ERROR: '+M.str.repository.invalidjson);
124                             return;
125                         }
126                         // error checking
127                         if (data && data.e) {
128                             Y.one(panel_id).set('innerHTML', 'ERROR: '+data.e);
129                             return;
130                         } else {
131                             args.callback(id,data,p);
132                         }
133                     }
134                 },
135                 arguments: {
136                     scope: scope
137                 },
138                 headers: {
139                     'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
140                     'User-Agent': 'MoodleFilePicker/3.0'
141                 },
142                 data: build_querystring(params),
143                 context: this
144             };
145             if (args.form) {
146                 cfg.form = args.form;
147             }
148             Y.io(api, cfg);
149             if (redraw) {
150                 this.wait('load');
151             }
152         },
154         build_tree: function(node, level) {
155             var client_id = this.options.client_id;
156             var dynload = this.active_repo.dynload;
157             if(node.children) {
158                 node.title = '<i><u>'+node.title+'</u></i>';
159             }
160             var info = {
161                 label:node.title,
162                 //title:fp_lang.date+' '+node.date+fp_lang.size+' '+node.size,
163                 filename:node.title,
164                 source:node.source?node.source:'',
165                 thumbnail:node.thumbnail,
166                 path:node.path?node.path:[]
167             };
168             var tmpNode = new YAHOO.widget.TextNode(info, level, false);
169             //var tooltip = new YAHOO.widget.Tooltip(tmpNode.labelElId, {
170                 //context:tmpNode.labelElId, text:info.title});
171             if(node.repo_id) {
172                 tmpNode.repo_id=node.repo_id;
173             }else{
174                 tmpNode.repo_id=this.active_repo.id;
175             }
176             if(node.children) {
177                 if(node.expanded) {
178                     tmpNode.expand();
179                 }
180                 if (dynload) {
181                     tmpNode.scope = this;
182                 }
183                 tmpNode.isLeaf = false;
184                 tmpNode.client_id = client_id;
185                 if (node.path) {
186                     tmpNode.path = node.path;
187                 } else {
188                     tmpNode.path = '';
189                 }
190                 for(var c in node.children) {
191                     this.build_tree(node.children[c], tmpNode);
192                 }
193             } else {
194                 tmpNode.isLeaf = true;
195             }
196         },
197         view_files: function() {
198             this.viewbar.set('disabled', false);
199             if (this.viewmode == 1) {
200                 this.view_as_icons();
201             } else if (this.viewmode ==2) {
202                 this.view_as_list();
203             } else {
204                 this.view_as_icons();
205             }
206         },
207         treeview_dynload: function(node, cb) {
208             var scope = node.scope;
209             var client_id = scope.options.client_id;
210             var repository_id = scope.active_repo.id;
211             scope.request({
212                 action:'list',
213                 client_id: client_id,
214                 repository_id: repository_id,
215                 path:node.path?node.path:'',
216                 page:node.page?args.page:'',
217                 callback: function(id, obj, args) {
218                     obj.issearchresult = false;
219                     var list = obj.list;
220                     scope.viewbar.set('disabled', false);
221                     scope.parse_repository_options(obj);
222                     for(k in list) {
223                         scope.build_tree(list[k], node);
224                     }
225                     cb();
226                 }
227             }, false);
228         },
229         view_as_list: function() {
230             var scope = this;
231             var client_id = this.options.client_id;
232             var dynload = this.active_repo.dynload;
233             var list = this.filelist;
234             var panel_id = '#panel-'+client_id;
235             this.viewmode = 2;
236             Y.one(panel_id).set('innerHTML', '');
238             this.print_header();
239             var tree = Y.Node.create('<div id="treeview-'+client_id+'"></div>');
240             Y.one(panel_id).appendChild(tree);
241             this.treeview = new YAHOO.widget.TreeView('treeview-'+client_id);
242             if (dynload) {
243                 this.treeview.setDynamicLoad(this.treeview_dynload, 1);
244             }
246             for(k in list) {
247                 this.build_tree(list[k], this.treeview.getRoot());
248             }
249             var scope = this;
250             this.treeview.subscribe('clickEvent', function(e){
251                 if(e.node.isLeaf){
252                     var fileinfo = {};
253                     fileinfo['title'] = e.node.data.filename;
254                     fileinfo['source'] = e.node.data.source;
255                     fileinfo['thumbnail'] = e.node.data.thumbnail;
256                     scope.select_file(fileinfo);
257                 }
258             });
259             this.treeview.draw();
260         },
261         view_as_icons: function() {
262             var scope = this;
263             var client_id = this.options.client_id;
264             var list = this.filelist;
265             var panel_id = '#panel-'+client_id;
266             this.viewmode = 1;
267             Y.one(panel_id).set('innerHTML', '');
269             this.print_header();
271             var gridpanel = Y.Node.create('<div id="fp-grid-panel-'+client_id+'"></div>');
272             Y.one('#panel-'+client_id).appendChild(gridpanel);
273             var count = 0;
274             for(var k in list) {
275                 var node = list[k];
276                 var grid = document.createElement('DIV');
277                 grid.className='fp-grid';
278                 // the file name
279                 var title = document.createElement('DIV');
280                 title.id = 'grid-title-'+client_id+'-'+String(count);
281                 title.className = 'label';
282                 if (node.shorttitle) {
283                     node.title = node.shorttitle;
284                 }
285                 title.innerHTML += '<a href="###"><span>'+node.title+"</span></a>";
287                 if(node.thumbnail_width){
288                     grid.style.width = node.thumbnail_width+'px';
289                     title.style.width = (node.thumbnail_width-10)+'px';
290                 } else {
291                     grid.style.width = title.style.width = '90px';
292                 }
293                 var frame = document.createElement('DIV');
294                 frame.style.textAlign='center';
295                 if(node.thumbnail_height){
296                     frame.style.height = node.thumbnail_height+'px';
297                 }
298                 var img = document.createElement('img');
299                 img.src = node.thumbnail;
300                 if(node.thumbnail_alt) {
301                     img.alt = node.thumbnail_alt;
302                 }
303                 if(node.thumbnail_title) {
304                     img.title = node.thumbnail_title;
305                 }
307                 var link = document.createElement('A');
308                 link.href='###';
309                 link.id = 'img-id-'+client_id+'-'+String(count);
310                 if(node.url) {
311                     // hide 
312                     //grid.innerHTML += '<p><a target="_blank" href="'+node.url+'">'+M.str.repository.preview+'</a></p>';
313                 }
314                 link.appendChild(img);
315                 frame.appendChild(link);
316                 grid.appendChild(frame);
317                 grid.appendChild(title);
318                 gridpanel.appendChild(grid);
320                 var y_title = Y.one('#'+title.id);
321                 var y_file = Y.one('#'+link.id);
322                 var dynload = this.active_repo.dynload;
323                 if(node.children) {
324                     y_file.on('click', function(e, p) {
325                         if(dynload) {
326                             var params = {'path':p.path};
327                             scope.list(params);
328                         }else{
329                             this.filelist = p.children;
330                             this.view_files();
331                         }
332                     }, this, node);
333                     y_title.on('click', function(e, p, id){
334                         var icon = Y.one(id);
335                         icon.simulate('click');
336                     }, this, node, '#'+link.id);
337                 } else {
338                     var fileinfo = {};
339                     fileinfo['title'] = list[k].title;
340                     fileinfo['source'] = list[k].source;
341                     fileinfo['thumbnail'] = list[k].thumbnail;
342                     fileinfo['haslicense'] = list[k].haslicense?true:false;
343                     fileinfo['hasauthor'] = list[k].hasauthor?true:false;
344                     y_title.on('click', function(e, args) {
345                         this.select_file(args);
346                     }, this, fileinfo);
347                     y_file.on('click', function(e, args) {
348                         this.select_file(args);
349                     }, this, fileinfo);
350                 }
351                 count++;
352             }
353         },
354         select_file: function(args) {
355             var client_id = this.options.client_id;
356             var thumbnail = Y.one('#fp-grid-panel-'+client_id);
357             if(thumbnail){
358                 thumbnail.setStyle('display', 'none');
359             }
360             var header = Y.one('#fp-header-'+client_id);
361             if (header) {
362                 header.setStyle('display', 'none');
363             }
364             var footer = Y.one('#fp-footer-'+client_id);
365             if (footer) {
366                 footer.setStyle('display', 'none');
367             }
368             var path = Y.one('#path-'+client_id);
369             if(path){
370                 path.setStyle('display', 'none');
371             }
372             var panel = Y.one('#panel-'+client_id);
373             var form_id = 'fp-rename-form-'+client_id;
374             var html = '<div class="fp-rename-form" id="'+form_id+'">';
375             html += '<p><img src="'+args.thumbnail+'" /></p>';
376             html += '<p><label for="newname-'+client_id+'">'+M.str.repository.saveas+':</label>';
377             html += '<input type="text" id="newname-'+client_id+'" value="'+args.title+'" /></p>';
379             var le_checked = '';
380             var le_style = '';
381             if (this.options.repositories[this.active_repo.id].return_types == 1) {
382                 // support external links only
383                 le_checked = 'checked';
384                 le_style = ' style="display:none;"';
385             } else if(this.options.repositories[this.active_repo.id].return_types == 2) {
386                 // support internal files only
387                 le_style = ' style="display:none;"';
388             }
389             if (this.options.externallink && this.options.env == 'editor') {
390                 html += '<p'+le_style+'><input type="checkbox" id="linkexternal-'+client_id+'" value="" '+le_checked+' />'+M.str.repository.linkexternal+'</p>';
391             }
393             if (!args.hasauthor) {
394                 // the author of the file
395                 html += '<p><label for="text-author">'+M.str.repository.author+' :</label>';
396                 html += '<input id="text-author-'+client_id+'" type="text" name="author" value="'+this.options.author+'" />';
397                 html += '</p>';
398             }
400             if (!args.haslicense) {
401                 // the license of the file
402                 var licenses = this.options.licenses;
403                 html += '<p><label for="select-license-'+client_id+'">'+M.str.repository.chooselicense+' :</label>';
404                 html += '<select name="license" id="select-license-'+client_id+'">';
405                 for (var i in licenses) {
406                     html += '<option value="'+licenses[i].shortname+'">'+licenses[i].fullname+'</option>';
407                 }
408                 html += '</select></p>';
409             }
411             html += '<p><input type="hidden" id="filesource-'+client_id+'" value="'+args.source+'" />';
412             html += '<input type="button" id="fp-confirm-'+client_id+'" value="'+M.str.repository.getfile+'" />';
413             html += '<input type="button" id="fp-cancel-'+client_id+'" value="'+M.str.moodle.cancel+'" /></p>';
414             html += '</div>';
416             var getfile_form = Y.Node.create(html);
417             panel.appendChild(getfile_form);
419             var getfile = Y.one('#fp-confirm-'+client_id);
420             getfile.on('click', function(e) {
421                 var client_id = this.options.client_id;
422                 var scope = this;
423                 var repository_id = this.active_repo.id;
424                 var title = Y.one('#newname-'+client_id).get('value');
425                 var filesource = Y.one('#filesource-'+client_id).get('value');
426                 var params = {'title':title, 'source':filesource, 'savepath': this.options.savepath};
427                 var license = Y.one('#select-license-'+client_id);
428                 if (license) {
429                     params['license'] = license.get('value');
430                 }
431                 var author = Y.one('#text-author-'+client_id);
432                 if (author){
433                     params['author'] = author.get('value');
434                 }
436                 if (this.options.env == 'editor') {
437                     // in editor, images are stored in '/' only
438                     params.savepath = '/';
439                     var linkexternal = Y.one('#linkexternal-'+client_id).get('checked');
440                     if (linkexternal) {
441                         params['linkexternal'] = 'yes';
442                     }
443                 } if (this.options.env == 'url') {
444                     params['linkexternal'] = 'yes';
445                 }
447                 this.wait('download', title);
448                 this.request({
449                     action:'download',
450                     client_id: client_id,
451                     repository_id: repository_id,
452                     'params': params,
453                     callback: function(id, obj, args) {
454                         if (scope.options.editor_target && scope.options.env=='editor') {
455                             scope.options.editor_target.value=obj.url;
456                             scope.options.editor_target.onchange();
457                         }
458                         scope.hide();
459                         obj.client_id = client_id;
460                         var formcallback_scope = null;
461                         if (args.scope.options.magicscope) {
462                             formcallback_scope = args.scope.options.magicscope;
463                         } else {
464                             formcallback_scope = args.scope;
465                         }
466                         scope.options.formcallback.apply(formcallback_scope, [obj]);
467                     }
468                 }, true);
469             }, this);
470             var elform = Y.one('#'+form_id);
471             elform.on('keydown', function(e) {
472                 if (e.keyCode == 13) {
473                     getfile.simulate('click');
474                     e.preventDefault(); 
475                 }
476             }, this);
477             var cancel = Y.one('#fp-cancel-'+client_id);
478             cancel.on('click', function(e) {
479                 this.view_files();
480             }, this);
481             var treeview = Y.one('#treeview-'+client_id);
482             if (treeview){
483                 treeview.setStyle('display', 'none');
484             }
485         },
486         wait: function(type) {
487             var panel = Y.one('#panel-'+this.options.client_id);
488             panel.set('innerHTML', '');
489             var name = '';
490             var str = '<div style="text-align:center">';
491             if(type=='load') {
492                 str += '<img src="'+M.util.image_url('i/loading')+'" />';
493                 str += '<p>'+M.str.repository.loading+'</p>';
494             }else{
495                 str += '<img src="'+M.util.image_url('i/progressbar')+'" />';
496                 str += '<p>'+M.str.repository.copying+' <strong>'+name+'</strong></p>';
497             }
498             str += '</div>';
499             try {
500                 panel.set('innerHTML', str);
501             } catch(e) {
502                 alert(e.toString());
503             }
504         },
505         render: function() {
506             var client_id = this.options.client_id;
507             var filepicker_id = 'filepicker-'+client_id;
508             var fpnode = Y.Node.create('<div class="file-picker" id="'+filepicker_id+'"></div>');
509             Y.one(document.body).appendChild(fpnode);
510             // render file picker panel
511             this.mainui = new YAHOO.widget.Panel(filepicker_id, {
512                 draggable: true,
513                 close: true,
514                 underlay: 'none',
515                 zindex: 9999990,
516                 monitorresize: false,
517                 xy: [50, YAHOO.util.Dom.getDocumentScrollTop()+20]
518             });
519             var layout = null;
520             this.mainui.beforeRenderEvent.subscribe(function() {
521                 YAHOO.util.Event.onAvailable('layout-'+client_id, function() {
522                     layout = new YAHOO.widget.Layout('layout-'+client_id, {
523                         height: 480, width: 700,
524                         units: [
525                         {position: 'top', height: 32, resize: false,
526                         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'},
527                         {position: 'left', width: 200, resize: true, scroll:true,
528                         body:'<ul class="fp-list" id="fp-list-'+client_id+'"></ul>', gutter: '0 5 0 2', minWidth: 150, maxWidth: 300 },
529                         {position: 'center', body: '<div class="fp-panel" id="panel-'+client_id+'"></div>',
530                         scroll: true, gutter: '0 2 0 0' }
531                         ]
532                     });
533                     layout.render();
534                 });
535             });
537             this.mainui.setHeader('File Picker');
538             this.mainui.setBody('<div id="layout-'+client_id+'"></div>');
539             this.mainui.render();
540             this.rendered = true;
542             var scope = this;
543             // adding buttons
544             var view_icons = {label: M.str.repository.iconview, value: 't',
545                 onclick: {
546                     fn: function(){
547                         scope.view_as_icons();
548                     }
549                 }
550             };
551             var view_listing = {label: M.str.repository.listview, value: 'l',
552                 onclick: {
553                     fn: function(){
554                         scope.view_as_list();
555                     }
556                 }
557             };
558             this.viewbar = new YAHOO.widget.ButtonGroup({
559                 id: 'btngroup-'+client_id,
560                 name: 'buttons',
561                 disabled: true,
562                 container: 'fp-viewbar-'+client_id
563             });
564             this.viewbar.addButtons([view_icons, view_listing]);
565             // processing repository listing
566             var r = this.options.repositories;
567             Y.on('contentready', function(el) {
568                 var list = Y.one(el);
569                 var count = 0;
570                 for (var i in r) {
571                     var id = 'repository-'+client_id+'-'+count;
572                     var link_id = id + '-link';
573                     list.append('<li id="'+id+'"><a class="fp-repo-name" id="'+link_id+'" href="###">'+r[i].name+'</a></li>');
574                     Y.one('#'+link_id).prepend('<img src="'+r[i].icon+'" width="16" height="16" />&nbsp;');
575                     Y.one('#'+link_id).on('click', function(e, scope, repository_id) {
576                         scope.repository_id = repository_id;
577                         Y.all(el+' li a').setStyle('backgroundColor', 'transparent');
578                         e.currentTarget.setStyle('backgroundColor', '#CCC');
579                         this.list({'repo_id':repository_id});
580                     }, this /*handler running scope*/, this/*second argument*/, r[i].id/*third argument of handler*/);
581                     count++;
582                 }
583             }, '#fp-list-'+client_id, this /* handler running scope */, '#fp-list-'+client_id /*first argument of handler*/);
584         },
585         parse_repository_options: function(data) {
586             this.filelist = data.list?data.list:null;
587             this.filepath = data.path?data.path:null;
588             this.active_repo = {};
589             this.active_repo.issearchresult = Boolean(data.issearchresult);
590             this.active_repo.dynload = data.dynload?data.dynload:false;
591             this.active_repo.pages = Number(data.pages?data.pages:null);
592             this.active_repo.page = Number(data.page?data.page:null);
593             this.active_repo.id = data.repo_id?data.repo_id:null;
594             this.active_repo.nosearch = data.nosearch?true:false;
595             this.active_repo.norefresh = data.norefresh?true:false;
596             this.active_repo.nologin = data.nologin?true:false;
597             this.active_repo.help = data.help?data.help:null;
598             this.active_repo.manage = data.manage?data.manage:null;
599         },
600         print_login: function(data) {
601             this.parse_repository_options(data);
602             var client_id = this.options.client_id;
603             var repository_id = data.repo_id;
604             var l = this.logindata = data.login;
605             var loginurl = '';
606             var panel = Y.one('#panel-'+client_id);
607             var action = 'login';
608             if (data['login_btn_action']) {
609                 action=data['login_btn_action'];
610             }
611             var form_id = 'fp-form-'+client_id;
612             var download_button_id = 'fp-form-download-button-'+client_id;
613             var search_button_id   = 'fp-form-search-button-'+client_id;
614             var login_button_id    = 'fp-form-login-button-'+client_id;
615             var popup_button_id    = 'fp-form-popup-button-'+client_id;
617             var str = '<div class="fp-login-form">';
618             str += '<form id="'+form_id+'">';
619             var has_pop = false;
620             str +='<table width="100%">';
621             for(var k in l) {
622                 str +='<tr>';
623                 if(l[k].type=='popup') {
624                     // pop element
625                     loginurl = l[k].url;
626                     str += '<td colspan="2"><p class="fp-popup">'+M.str.repository.popup+'</p>';
627                     str += '<p class="fp-popup"><button id="'+popup_button_id+'">'+M.str.repository.login+'</button>';
628                     str += '</p></td>';
629                     action = 'popup';
630                 }else if(l[k].type=='textarea') {
631                     // textarea element
632                     str += '<td colspan="2"><p><textarea id="'+l[k].id+'" name="'+l[k].name+'"></textarea></p></td>';
633                 }else if(l[k].type=='select') {
634                     // select element
635                     str += '<td align="right"><label>'+l[k].label+':</label></td>';
636                     str += '<td align="left"><select id="'+l[k].id+'" name="'+l[k].name+'">';
637                     for (i in l[k].options) {
638                         str += '<option value="'+l[k].options[i].value+'">'+l[k].options[i].label+'</option>';
639                     }
640                     str += '</select></td>';
641                 }else{
642                     // input element
643                     var label_id = '';
644                     var field_id = '';
645                     var field_value = '';
646                     if(l[k].id) {
647                         label_id = ' for="'+l[k].id+'"';
648                         field_id = ' id="'+l[k].id+'"';
649                     }
650                     if (l[k].label) {
651                         str += '<td align="right" width="30%" valign="center">';
652                         str += '<label'+label_id+'>'+l[k].label+'</label> </td>';
653                     } else {
654                         str += '<td width="30%"></td>';
655                     }
656                     if(l[k].value) {
657                         field_value = ' value="'+l[k].value+'"';
658                     }
659                     if(l[k].type=='radio'){
660                         var list = l[k].value.split('|');
661                         var labels = l[k].value_label.split('|');
662                         str += '<td align="left">';
663                         for(var item in list) {
664                             str +='<input type="'+l[k].type+'"'+' name="'+l[k].name+'"'+
665                                 field_id+' value="'+list[item]+'" />'+labels[item]+'<br />';
666                         }
667                         str += '</td>';
668                     }else{
669                         str += '<td align="left">';
670                         str += '<input type="'+l[k].type+'"'+' name="'+l[k].name+'"'+field_value+' '+field_id+' />';
671                         str += '</td>';
672                     }
673                 }
674                 str +='</tr>';
675             }
676             str +='</table>';
677             str += '</form>';
679             // custom lable text
680             var btn_label = data['login_btn_label']?data['login_btn_label']:M.str.repository.submit;
681             if (action != 'popup') {
682                 str += '<p><input type="button" id="';
683                 switch (action) {
684                     case 'search':
685                         str += search_button_id;
686                         break;
687                     case 'download':
688                         str += download_button_id;
689                         break;
690                     default:
691                         str += login_button_id;
692                         break;
693                 }
694                 str += '" value="'+btn_label+'" /></p>';
695             }
697             str += '</div>';
699             // insert login form
700             try {
701                 panel.set('innerHTML', str);
702             } catch(e) {
703                 alert(e.toString()+M.str.quiz.xhtml);
704             }
705             // register buttons
706             // process login action
707             var login_button = Y.one('#'+login_button_id);
708             var scope = this;
709             if (login_button) {
710                 login_button.on('click', function(){
711                     // collect form data
712                     var data = this.logindata;
713                     var scope = this;
714                     var params = {};
715                     for (var k in data) {
716                         if(data[k].type!='popup') {
717                             var el = Y.one('[name='+data[k].name+']');
718                             var type = el.get('type');
719                             params[data[k].name] = '';
720                             if(type == 'checkbox') {
721                                 params[data[k].name] = el.get('checked');
722                             } else {
723                                 params[data[k].name] = el.get('value');
724                             }
725                         }
726                     }
727                     // start ajax request
728                     this.request({
729                         'params': params,
730                         'scope': scope,
731                         'action':'signin',
732                         'path': '',
733                         'client_id': client_id,
734                         'repository_id': repository_id,
735                         'callback': function(id, o, args) {
736                             scope.parse_repository_options(o);
737                             scope.view_files();
738                             if (o.msg) {
739                                 // do something
740                             }
741                         }
742                     }, true);
743                 }, this);
744             }
745             var search_button = Y.one('#'+search_button_id);
746             if (search_button) {
747                 search_button.on('click', function(){
748                     var data = this.logindata;
749                     var params = {};
751                     for (var k in data) {
752                         if(data[k].type!='popup') {
753                             var el = document.getElementsByName(data[k].name)[0];
754                             params[data[k].name] = '';
755                             if(el.type == 'checkbox') {
756                                 params[data[k].name] = el.checked;
757                             } else if(el.type == 'radio') {
758                                 var tmp = document.getElementsByName(data[k].name);
759                                 for(var i in tmp) {
760                                     if (tmp[i].checked) {
761                                         params[data[k].name] = tmp[i].value;
762                                     }
763                                 }
764                             } else {
765                                 params[data[k].name] = el.value;
766                             }
767                         }
768                     }
769                     this.request({
770                             scope: scope,
771                             action:'search',
772                             client_id: client_id,
773                             repository_id: repository_id,
774                             form: {id: 'fp-form-'+scope.options.client_id,upload:false,useDisabled:true},
775                             callback: function(id, o, args) {
776                                 o.issearchresult = true;
777                                 scope.parse_repository_options(o);
778                                 scope.view_files();
779                             }
780                     }, true);
781                 }, this);
782             }
783             var download_button = Y.one('#'+download_button_id);
784             if (download_button) {
785                 download_button.on('click', function(){
786                     alert('download');
787                 });
788             }
789             var popup_button = Y.one('#'+popup_button_id);
790             if (popup_button) {
791                 popup_button.on('click', function(e){
792                     M.core_filepicker.active_filepicker = this;
793                     window.open(loginurl, 'repo_auth', 'location=0,status=0,width=500,height=300');
794                     e.preventDefault(); 
795                 }, this);
796             }
797             var elform = Y.one('#'+form_id);
798             elform.on('keydown', function(e) {
799                 if (e.keyCode == 13) {
800                     switch (action) {
801                         case 'search':
802                             search_button.simulate('click');
803                             break;
804                         default:
805                             login_button.simulate('click');
806                             break;
807                     }
808                     e.preventDefault(); 
809                 }
810             }, this);
812         },
813         search: function(args) {
814             var data = this.logindata;
815             var params = {};
817             for (var k in data) {
818                 if(data[k].type!='popup') {
819                     var el = document.getElementsByName(data[k].name)[0];
820                     params[data[k].name] = '';
821                     if(el.type == 'checkbox') {
822                         params[data[k].name] = el.checked;
823                     } else if(el.type == 'radio') {
824                         var tmp = document.getElementsByName(data[k].name);
825                         for(var i in tmp) {
826                             if (tmp[i].checked) {
827                                 params[data[k].name] = tmp[i].value;
828                             }
829                         }
830                     } else {
831                         params[data[k].name] = el.value;
832                     }
833                 }
834             }
835             this.request({
836                     scope: scope,
837                     action:'search',
838                     client_id: client_id,
839                     repository_id: repository_id,
840                     form: {id: 'fp-form-'+scope.options.client_id,upload:false,useDisabled:true},
841                     callback: function(id, o, args) {
842                         o.issearchresult = true;
843                         scope.parse_repository_options(o);
844                         scope.view_files();
845                     }
846             }, true);
847         },
848         list: function(args) {
849             var scope = this;
850             if (!args) {
851                 args = {};
852             }
853             if (!args.repo_id) {
854                 args.repo_id = scope.active_repo.id;
855             }
856             scope.request({
857                 action:'list',
858                 client_id: scope.options.client_id,
859                 repository_id: args.repo_id,
860                 path:args.path?args.path:'',
861                 page:args.page?args.page:'',
862                 callback: function(id, obj, args) {
863                     if (obj.login) {
864                         scope.viewbar.set('disabled', true);
865                         scope.print_login(obj);
866                     } else if (obj.upload) {
867                         scope.viewbar.set('disabled', true);
868                         scope.parse_repository_options(obj);
869                         scope.create_upload_form(obj);
870                     
871                     } else if (obj.iframe) {
873                     } else if (obj.list) {
874                         obj.issearchresult = false;
875                         scope.viewbar.set('disabled', false);
876                         scope.parse_repository_options(obj);
877                         scope.view_files();
878                     }
879                     if (obj.msg) {
880                         // TODO: Print message
881                     }
882                 }
883             }, true);
884         },
885         create_upload_form: function(data) {
886             var client_id = this.options.client_id;
887             Y.one('#panel-'+client_id).set('innerHTML', '');
889             this.print_header();
890             var id = data.upload.id+'_'+client_id;
891             var str = '<div id="'+id+'_div" class="fp-upload-form">';
892             str += '<form id="'+id+'" method="POST">';
893             str += '<table border=1>';
894             str += '<tr><td>';
895             str += '<label for="'+id+'_file">'+data.upload.label+': </label></td>';
896             str += '<td><input type="file" id="'+id+'_file" name="repo_upload_file" />';
897             str += '<input type="hidden" name="itemid" value="'+this.options.itemid+'" /></tr>';
898             str += '<tr>';
899             str += '<td><label>'+M.str.repository.author+': </label></td>';
900             str += '<td><input type="text" name="author" value="'+this.options.author+'" /></td>';
901             str += '</tr>';
902             str += '<tr>';
903             str += '<td>'+M.str.repository.chooselicense+': </td>';
904             str += '<td>';
905             var licenses = this.options.licenses;
906             str += '<select name="license" id="select-license-'+client_id+'">';
907             for (var i in licenses) {
908                 str += '<option value="'+licenses[i].shortname+'">'+licenses[i].fullname+'</option>';
909             }
910             str += '</select>';
911             str += '</td>';
912             str += '</tr></table>';
913             str += '</form>';
914             str += '<div class="fp-upload-btn"><button id="'+id+'_action">'+M.str.repository.upload+'...</button></div>';
915             str += '</div>';
916             var upload_form = Y.Node.create(str);
917             Y.one('#panel-'+client_id).appendChild(upload_form);
918             var scope = this;
919             Y.one('#'+id+'_action').on('click', function(e) {
920                 e.preventDefault(); 
921                 Y.use('io-upload-iframe', function() {
922                     scope.request({
923                             scope: scope,
924                             action:'upload',
925                             client_id: client_id,
926                             params: {'savepath':scope.options.savepath},
927                             repository_id: scope.active_repo.id,
928                             form: {id: id, upload:true},
929                             callback: function(id, o, args) {
930                                 if (scope.options.editor_target&&scope.options.env=='editor') {
931                                     scope.options.editor_target.value=o.url;
932                                     scope.options.editor_target.onchange();
933                                 }
934                                 scope.hide();
935                                 o.client_id = client_id;
936                                 var formcallback_scope = null;
937                                 if (args.scope.options.magicscope) {
938                                     formcallback_scope = args.scope.options.magicscope;
939                                 } else {
940                                     formcallback_scope = args.scope;
941                                 }
942                                 scope.options.formcallback.apply(formcallback_scope, [o]);
943                             }
944                     }, true);
945                 });
946             }, this);
947         },
948         print_header: function() {
949             var r = this.active_repo;
950             var scope = this;
951             var client_id = this.options.client_id;
952             var repository_id = this.active_repo.id;
953             var panel = Y.one('#panel-'+client_id);
954             var str = '<div id="fp-header-'+client_id+'">';
955             str += '<div class="fp-toolbar" id="repo-tb-'+client_id+'"></div>';
956             str += '</div>';
957             var head = Y.Node.create(str);
958             panel.appendChild(head);
959             //if(this.active_repo.pages < 8){
960                 this.print_paging('header');
961             //}
964             var toolbar = Y.one('#repo-tb-'+client_id);
966             if(!r.nosearch) {
967                 var html = '<a href="###"><img src="'+M.util.image_url('a/search')+'" /> '+M.str.repository.search+'</a>';
968                 var search = Y.Node.create(html);
969                 search.on('click', function() {
970                     scope.request({
971                         scope: scope,
972                         action:'searchform',
973                         repository_id: repository_id,
974                         callback: function(id, obj, args) {
975                             var scope = args.scope;
976                             var client_id = scope.options.client_id;
977                             var repository_id = scope.active_repo.id;
978                             var container = document.getElementById('fp-search-dlg');
979                             if(container) {
980                                 container.innerHTML = '';
981                                 container.parentNode.removeChild(container);
982                             }
983                             var container = document.createElement('DIV');
984                             container.id = 'fp-search-dlg';
986                             var dlg_title = document.createElement('DIV');
987                             dlg_title.className = 'hd';
988                             dlg_title.innerHTML = 'filepicker';
990                             var dlg_body = document.createElement('DIV');
991                             dlg_body.className = 'bd';
993                             var sform = document.createElement('FORM');
994                             sform.method = 'POST';
995                             sform.id = "fp-search-form";
996                             sform.innerHTML = obj.form;
998                             dlg_body.appendChild(sform);
999                             container.appendChild(dlg_title);
1000                             container.appendChild(dlg_body);
1001                             Y.one(document.body).appendChild(container);
1002                             var search_dialog= null;
1003                             function dialog_handler() {
1004                                 scope.viewbar.set('disabled', false);
1005                                 scope.request({
1006                                         scope: scope,
1007                                         action:'search',
1008                                         client_id: client_id,
1009                                         repository_id: repository_id,
1010                                         form: {id: 'fp-search-form',upload:false,useDisabled:true},
1011                                         callback: function(id, o, args) {
1012                                             scope.parse_repository_options(o);
1013                                             scope.view_files();
1014                                         }
1015                                 }, true);
1016                                 search_dialog.cancel();
1017                             }
1019                             search_dialog = new YAHOO.widget.Dialog("fp-search-dlg", {
1020                                postmethod: 'async',
1021                                draggable: true,
1022                                width : "30em",
1023                                fixedcenter : true,
1024                                zindex: 9999991,
1025                                visible : false,
1026                                constraintoviewport : true,
1027                                buttons: [
1028                                {
1029                                    text:M.str.repository.submit,
1030                                    handler:dialog_handler,
1031                                    isDefault:true
1032                                }, {
1033                                    text:M.str.moodle.cancel,
1034                                    handler:function(){
1035                                        this.destroy()
1036                                    }
1037                                }]
1038                             });
1039                             search_dialog.render();
1040                             search_dialog.show();
1041                         }
1042                     });
1043                 },this);
1044                 toolbar.appendChild(search);
1045             }
1046             // weather we use cache for this instance, this button will reload listing anyway
1047             if(!r.norefresh) {
1048                 var html = '<a href="###"><img src="'+M.util.image_url('a/refresh')+'" /> '+M.str.repository.refresh+'</a>';
1049                 var refresh = Y.Node.create(html);
1050                 refresh.on('click', function() {
1051                     this.list();
1052                 }, this);
1053                 toolbar.appendChild(refresh);
1054             }
1055             if(!r.nologin) {
1056                 var html = '<a href="###"><img src="'+M.util.image_url('a/logout')+'" /> '+M.str.repository.logout+'</a>';
1057                 var logout = Y.Node.create(html);
1058                 logout.on('click', function() {
1059                     this.request({
1060                         action:'logout',
1061                         client_id: client_id,
1062                         repository_id: repository_id,
1063                         path:'',
1064                         callback: function(id, obj, args) {
1065                             scope.viewbar.set('disabled', true);
1066                             scope.print_login(obj);
1067                         }
1068                     }, true);
1069                 }, this);
1070                 toolbar.appendChild(logout);
1071             }
1073             if(r.manage) {
1074                 var mgr = document.createElement('A');
1075                 mgr.href = r.manage;
1076                 mgr.target = "_blank";
1077                 mgr.innerHTML = '<img src="'+M.util.image_url('a/setting')+'" /> '+M.str.repository.manageurl;
1078                 toolbar.appendChild(mgr);
1079             }
1080             if(r.help) {
1081                 var help = document.createElement('A');
1082                 help.href = r.help;
1083                 help.target = "_blank";
1084                 help.innerHTML = '<img src="'+M.util.image_url('a/help')+'" /> '+M.str.repository.help;
1085                 toolbar.appendChild(help);
1086             }
1088             // only show in icons view
1089             if (this.viewmode == 1) {
1090                 this.print_path();
1091             }
1092         },
1093         get_page_button: function(page) {
1094             var r = this.active_repo;
1095             var css = '';
1096             if (page == r.page) {
1097                 css = 'class="cur_page" ';
1098             }
1099             var str = '<a '+css+'href="###" id="repo-page-'+page+'">';
1100             return str;
1101         },
1102         print_paging: function(html_id) {
1103             var client_id = this.options.client_id;
1104             var scope = this;
1105             var r = this.active_repo;
1106             var str = '';
1107             var action = '';
1108             if(r.pages) {
1109                 str += '<div class="fp-paging" id="paging-'+html_id+'-'+client_id+'">';
1110                 str += this.get_page_button(1)+'1</a> ';
1112                 var span = 5;
1113                 var ex = (span-1)/2;
1115                 if (r.page+ex>=r.pages) {
1116                     var max = r.pages;
1117                 } else {
1118                     if (r.page<span) {
1119                         var max = span;
1120                     } else {
1121                         var max = r.page+ex;
1122                     }
1123                 }
1125                 // won't display upper boundary
1126                 if (r.page >= span) {
1127                     str += ' ... ';
1128                     for(var i=r.page-ex; i<max; i++) {
1129                         str += this.get_page_button(i);
1130                         str += String(i);
1131                         str += '</a> ';
1132                     }
1133                 } else {
1134                     // this very first elements
1135                     for(var i = 2; i < max; i++) {
1136                         str += this.get_page_button(i);
1137                         str += String(i);
1138                         str += '</a> ';
1139                     }
1140                 }
1142                 // won't display upper boundary
1143                 if (max==r.pages) {
1144                     str += this.get_page_button(r.pages)+r.pages+'</a>';
1145                 } else {
1146                     str += this.get_page_button(max)+max+'</a>';
1147                     str += ' ... '+this.get_page_button(r.pages)+r.pages+'</a>';
1148                 }
1149                 str += '</div>';
1150             }
1151             if (str) {
1152                 var a = Y.Node.create(str);
1153                 Y.one('#fp-header-'+client_id).appendChild(a);
1155                 Y.all('#fp-header-'+client_id+' .fp-paging a').each(
1156                     function(node, id) {
1157                         node.on('click', function(e) {
1158                             var id = node.get('id');
1159                             var re = new RegExp("repo-page-(\\d+)", "i");
1160                             var result = id.match(re);
1161                             var args = {};
1162                             args.page = result[1];
1163                             if (scope.active_repo.issearchresult) {
1164                                 scope.request({
1165                                         scope: scope,
1166                                         action:'search',
1167                                         client_id: client_id,
1168                                         repository_id: r.id,
1169                                         params: {'page':result[1]},
1170                                         callback: function(id, o, args) {
1171                                             o.issearchresult = true;
1172                                             scope.parse_repository_options(o);
1173                                             scope.view_files();
1174                                         }
1175                                 }, true);
1177                             } else {
1178                                 scope.list(args);
1179                             }
1180                         });
1181                     });
1182             }
1183         },
1184         print_path: function() {
1185             var client_id = this.options.client_id;
1186             if (this.viewmode == 2) {
1187                 return;
1188             }
1189             var panel = Y.one('#panel-'+client_id);
1190             var p = this.filepath;
1191             if (p && p.length!=0) {
1192                 var path = Y.Node.create('<div id="path-'+client_id+'" class="fp-pathbar"></div>');
1193                 panel.appendChild(path);
1194                 for(var i = 0; i < p.length; i++) {
1195                     var link_path = p[i].path;
1196                     var link = document.createElement('A');
1197                     link.href = "###";
1198                     link.innerHTML = p[i].name;
1199                     link.id = 'path-node-'+client_id+'-'+i;
1200                     var sep = Y.Node.create('<span>/</span>');
1201                     path.appendChild(link);
1202                     path.appendChild(sep);
1203                     Y.one('#'+link.id).on('click', function(Y, path){
1204                         this.list({'path':path});
1205                         }, this, link_path)
1206                 }
1207             }
1208         },
1209         hide: function() {
1210             this.mainui.hide();
1211         },
1212         show: function() {
1213             if (this.rendered) {
1214                 var panel = Y.one('#panel-'+this.options.client_id);
1215                 panel.set('innerHTML', '');
1216                 this.mainui.show();
1217             } else {
1218                 this.launch();
1219             }
1220         },
1221         launch: function() {
1222             this.render();
1223         }
1224     });
1226     M.core_filepicker.instances[options.client_id] = new FilePickerHelper(options);
1227 };