1 // YUI3 File Picker module for moodle
2 // Author: Dongsheng Cai <dongsheng@moodle.com>
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
17 * this.options.client_id, the instance id
18 * this.options.contextid
20 * this.options.repositories, stores all repositories displaied in file picker
21 * this.options.formcallback
23 * Active repository options
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
34 * this.filelist, cached filelist
37 * this.filepath, current path
38 * this.logindata, cached login form
41 M.core_filepicker = M.core_filepicker || {};
44 * instances of file pickers used on page
46 M.core_filepicker.instances = M.core_filepicker.instances || {};
47 M.core_filepicker.active_filepicker = null;
50 * Init and show file picker
52 M.core_filepicker.show = function(Y, options) {
53 if (!M.core_filepicker.instances[options.client_id]) {
54 M.core_filepicker.init(Y, options);
56 M.core_filepicker.instances[options.client_id].show();
60 * Add new file picker to current instances
62 M.core_filepicker.init = function(Y, options) {
63 var FilePickerHelper = function(options) {
64 FilePickerHelper.superclass.constructor.apply(this, arguments);
67 FilePickerHelper.NAME = "FilePickerHelper";
68 FilePickerHelper.ATTRS = {
73 Y.extend(FilePickerHelper, Y.Base, {
74 api: M.cfg.wwwroot+'/repository/repository_ajax.php',
77 initializer: function(options) {
78 this.options = options;
79 if (!this.options.savepath) {
80 this.options.savepath = '/';
84 destructor: function() {
87 request: function(args, redraw) {
88 var client_id = args.client_id;
90 var api = this.api + '?action='+args.action;
92 var api = args.api + '?action='+args.action;
97 scope = args['scope'];
99 params['repo_id']=args.repository_id;
100 params['p'] = args.path?args.path:'';
101 params['page'] = args.page?args.page:'';
102 params['env']=this.options.env;
103 // the form element only accept certain file types
104 params['accepted_types']=this.options.accepted_types;
105 params['sesskey'] = M.cfg.sesskey;
106 params['client_id'] = args.client_id;
107 params['itemid'] = this.options.itemid?this.options.itemid:0;
108 params['maxbytes'] = this.options.maxbytes?this.options.maxbytes:-1;
109 if (this.options.context && this.options.context.id) {
110 params['ctx_id'] = this.options.context.id;
112 if (args['params']) {
113 for (i in args['params']) {
114 params[i] = args['params'][i];
117 if (args.action == 'upload') {
119 for(var k in params) {
120 var value = params[k];
121 if(value instanceof Array) {
122 for(var i in value) {
123 list.push(k+'[]='+value[i]);
126 list.push(k+'='+value);
129 params = list.join('&');
131 params = build_querystring(params);
136 complete: function(id,o,p) {
137 var panel_id = '#panel-'+client_id;
144 data = Y.JSON.parse(o.responseText);
146 scope.print_msg(M.str.repository.invalidjson, 'error');
147 Y.one(panel_id).set('innerHTML', 'ERROR: '+M.str.repository.invalidjson+'<pre>'+stripHTML(o.responseText)+'</pre>');
151 if (data && data.error) {
152 scope.print_msg(data.error, 'error');
154 args.onerror(id,data,p);
156 Y.one(panel_id).set('innerHTML', '');
159 } else if (data && data.event) {
160 switch (data.event) {
162 scope.process_existing_file(data);
169 scope.print_msg(data.msg, 'info');
171 // cache result if applicable
172 if (args.action != 'upload' && data.allowcaching) {
173 scope.cached_responses[params] = data;
176 args.callback(id,data,p);
184 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
190 cfg.form = args.form;
192 // check if result of the same request has been already cached. If not, request it
193 // (never applicable in case of form submission and/or upload action):
194 if (!args.form && args.action != 'upload' && scope.cached_responses[params]) {
195 args.callback(null, scope.cached_responses[params], {scope: scope})
203 process_existing_file: function(data) {
205 var repository_id = scope.active_repo.id;
206 var client_id = scope.options.client_id;
207 var handleOverwrite = function() {
211 params['existingfilename'] = data.existingfile.filename;
212 params['existingfilepath'] = data.existingfile.filepath;
213 params['newfilename'] = data.newfile.filename;
214 params['newfilepath'] = data.newfile.filepath;
218 'action':'overwrite',
220 'client_id': client_id,
221 'repository_id': repository_id,
222 'callback': function(id, o, args) {
225 // editor needs to update url
226 // filemanager do nothing
227 if (scope.options.editor_target && scope.options.env == 'editor') {
228 scope.options.editor_target.value = data.existingfile.url;
229 scope.options.editor_target.onchange();
230 } else if (scope.options.env === 'filepicker') {
231 var fileinfo = {'client_id':client_id,
232 'url':data.existingfile.url,
233 'file':data.existingfile.filename};
234 scope.options.formcallback.apply(scope, [fileinfo]);
239 var handleRename = function() {
240 if (scope.options.editor_target && scope.options.env == 'editor') {
241 scope.options.editor_target.value = data.newfile.url;
242 scope.options.editor_target.onchange();
246 var formcallback_scope = null;
247 if (scope.options.magicscope) {
248 formcallback_scope = scope.options.magicscope;
250 formcallback_scope = scope;
252 var fileinfo = {'client_id':client_id,
253 'url':data.newfile.url,
254 'file':data.newfile.filename};
255 scope.options.formcallback.apply(formcallback_scope, [fileinfo]);
257 var handleCancel = function() {
261 params['newfilename'] = data.newfile.filename;
262 params['newfilepath'] = data.newfile.filepath;
266 'action':'deletetmpfile',
268 'client_id': client_id,
269 'repository_id': repository_id,
270 'callback': function(id, o, args) {
276 var dialog = new YAHOO.widget.SimpleDialog("dlg", {
280 icon: YAHOO.widget.SimpleDialog.ICON_HELP,
284 buttons: [{ text: M.str.repository.overwrite, handler: handleOverwrite },
285 { text: M.str.repository.renameto + ' "' + data.newfile.filename + '"', handler: handleRename },
286 { text: M.str.moodle.cancel, handler: handleCancel, isDefault: true}]
288 dialog.setHeader(M.str.repository.fileexistsdialogheader);
289 if (scope.options.env == 'editor') {
290 dialog.setBody(M.str.repository.fileexistsdialog_editor);
292 dialog.setBody(M.str.repository.fileexistsdialog_filemanager);
295 dialog.render(document.body);
298 print_msg: function(msg, type) {
299 var client_id = this.options.client_id;
300 var dlg_id = 'fp-msg-dlg-'+client_id;
301 function handleYes() {
304 var icon = YAHOO.widget.SimpleDialog.ICON_INFO;
306 icon = YAHOO.widget.SimpleDialog.ICON_ALARM;
309 this.msg_dlg = new YAHOO.widget.SimpleDialog(dlg_id,
319 constraintoviewport: true,
320 buttons: [{ text:M.str.moodle.ok, handler:handleYes, isDefault:true }]
322 this.msg_dlg.render(document.body);
324 this.msg_dlg.setBody(msg);
326 var header = M.str.moodle.info;
328 header = M.str.moodle.error;
330 this.msg_dlg.setHeader(header);
333 build_tree: function(node, level) {
334 var client_id = this.options.client_id;
335 var dynload = this.active_repo.dynload;
338 //title:fp_lang.date+' '+node.date+fp_lang.size+' '+node.size,
340 source:node.source?node.source:'',
341 thumbnail:node.thumbnail,
342 path:node.path?node.path:[]
344 var tmpNode = new YAHOO.widget.TextNode(info, level, false);
346 tmpNode.repo_id=node.repo_id;
348 tmpNode.repo_id=this.active_repo.id;
355 tmpNode.scope = this;
357 tmpNode.isLeaf = false;
358 tmpNode.client_id = client_id;
360 tmpNode.path = node.path;
364 for(var c in node.children) {
365 this.build_tree(node.children[c], tmpNode);
368 tmpNode.isLeaf = true;
371 view_files: function(page) {
372 var p= page?page:null;
373 if (this.active_repo.issearchresult) {
374 // list view is desiged to display treeview
375 // it is not working well with search result
376 this.view_as_icons();
378 this.viewbar.set('disabled', false);
379 if (this.viewmode == 1) {
380 this.view_as_icons();
381 } else if (this.viewmode == 2) {
382 this.view_as_list(p);
384 this.view_as_icons();
388 treeview_dynload: function(node, cb) {
389 var scope = node.scope;
390 var client_id = scope.options.client_id;
391 var repository_id = scope.active_repo.id;
394 client_id: client_id,
395 repository_id: repository_id,
396 path:node.path?node.path:'',
397 page:node.page?args.page:'',
398 callback: function(id, obj, args) {
399 obj.issearchresult = false;
401 scope.viewbar.set('disabled', false);
402 scope.parse_repository_options(obj);
404 scope.build_tree(list[k], node);
410 view_as_list: function(p) {
414 if (scope.active_repo.page) {
415 page = scope.active_repo.page;
422 client_id: scope.options.client_id,
423 repository_id: scope.active_repo.id,
426 callback: function(id, obj, args) {
427 scope.parse_repository_options(obj);
429 scope.viewbar.set('disabled', true);
430 scope.print_login(obj);
433 var client_id = scope.options.client_id;
434 var dynload = scope.active_repo.dynload;
436 var panel_id = '#panel-'+client_id;
438 Y.one(panel_id).set('innerHTML', '');
440 scope.print_header();
442 var html = '<div class="fp-tree-panel" id="treeview-'+client_id+'">';
443 if (list && list.length==0) {
444 html += '<div class="fp-emptylist mdl-align">' +M.str.repository.nofilesavailable+'</div>';
448 var tree = Y.Node.create(html);
449 Y.one(panel_id).appendChild(tree);
450 if (!list || list.length==0) {
454 scope.treeview = new YAHOO.widget.TreeView('treeview-'+client_id);
456 scope.treeview.setDynamicLoad(scope.treeview_dynload, 1);
460 scope.build_tree(list[k], scope.treeview.getRoot());
462 scope.treeview.subscribe('clickEvent', function(e){
465 fileinfo['title'] = e.node.data.filename;
466 fileinfo['source'] = e.node.data.source;
467 fileinfo['thumbnail'] = e.node.data.thumbnail;
468 scope.select_file(fileinfo);
471 scope.treeview.draw();
475 view_as_icons: function() {
477 var client_id = this.options.client_id;
478 var list = this.filelist;
479 var panel_id = '#panel-'+client_id;
481 Y.one(panel_id).set('innerHTML', '');
485 var html = '<div class="fp-grid-panel" id="fp-grid-panel-'+client_id+'">';
486 if (list && list.length==0) {
487 html += '<div class="fp-emptylist mdl-align">' +M.str.repository.nofilesavailable+'</div>';
491 var gridpanel = Y.Node.create(html);
492 Y.one('#panel-'+client_id).appendChild(gridpanel);
496 var grid = document.createElement('DIV');
497 grid.className='fp-grid';
499 var title = document.createElement('DIV');
500 title.id = 'grid-title-'+client_id+'-'+String(count);
501 title.className = 'label';
502 var filename = node.title;
503 if (node.shorttitle) {
504 filename = node.shorttitle;
506 var filename_id = 'filname-link-'+client_id+'-'+String(count);
507 title.innerHTML += '<a href="###" id="'+filename_id+'" title="'+node.title+'"><span>'+filename+"</span></a>";
510 if(node.thumbnail_width){
511 grid.style.width = node.thumbnail_width+'px';
512 title.style.width = (node.thumbnail_width-10)+'px';
514 grid.style.width = title.style.width = '90px';
516 var frame = document.createElement('DIV');
517 frame.style.textAlign='center';
518 if(node.thumbnail_height){
519 frame.style.height = node.thumbnail_height+'px';
521 var img = document.createElement('img');
522 img.src = node.thumbnail;
523 img.title = node.title;
524 if(node.thumbnail_alt) {
525 img.alt = node.thumbnail_alt;
527 if(node.thumbnail_title) {
528 img.title = node.thumbnail_title;
531 var link = document.createElement('A');
533 link.id = 'img-id-'+client_id+'-'+String(count);
536 //grid.innerHTML += '<p><a target="_blank" href="'+node.url+'">'+M.str.repository.preview+'</a></p>';
538 link.appendChild(img);
539 frame.appendChild(link);
540 grid.appendChild(frame);
541 grid.appendChild(title);
542 gridpanel.appendChild(grid);
544 var y_title = Y.one('#'+title.id);
545 var y_file = Y.one('#'+link.id);
546 var dynload = this.active_repo.dynload;
548 y_file.on('click', function(e, p) {
550 var params = {'path':p.path};
553 this.filelist = p.children;
557 y_title.on('click', function(e, p, id){
558 var icon = Y.one(id);
559 icon.simulate('click');
560 }, this, node, '#'+link.id);
563 fileinfo['title'] = list[k].title;
564 fileinfo['source'] = list[k].source;
565 fileinfo['thumbnail'] = list[k].thumbnail;
566 fileinfo['haslicense'] = list[k].haslicense?true:false;
567 fileinfo['hasauthor'] = list[k].hasauthor?true:false;
568 y_title.on('click', function(e, args) {
569 this.select_file(args);
571 y_file.on('click', function(e, args) {
572 this.select_file(args);
578 select_file: function(args) {
579 var client_id = this.options.client_id;
580 var thumbnail = Y.one('#fp-grid-panel-'+client_id);
582 thumbnail.setStyle('display', 'none');
584 var header = Y.one('#fp-header-'+client_id);
586 header.setStyle('display', 'none');
588 var footer = Y.one('#fp-footer-'+client_id);
590 footer.setStyle('display', 'none');
592 var path = Y.one('#path-'+client_id);
594 path.setStyle('display', 'none');
596 var panel = Y.one('#panel-'+client_id);
597 var form_id = 'fp-rename-form-'+client_id;
598 var html = '<div class="fp-rename-form" id="'+form_id+'">';
599 html += '<p><img src="'+args.thumbnail+'" /></p>';
600 html += '<table width="100%">';
601 html += '<tr><td class="mdl-right"><label for="newname-'+client_id+'">'+M.str.repository.saveas+':</label></td>';
602 html += '<td class="mdl-left"><input type="text" id="newname-'+client_id+'" value="'+args.title+'" /></td></tr>';
606 if (this.options.repositories[this.active_repo.id].return_types == 1) {
607 // support external links only
608 le_checked = 'checked';
609 le_style = ' style="display:none;"';
610 } else if(this.options.repositories[this.active_repo.id].return_types == 2) {
611 // support internal files only
612 le_style = ' style="display:none;"';
614 if ((this.options.externallink && this.options.env == 'editor' && this.options.return_types != 1)) {
615 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>';
618 if (!args.hasauthor) {
619 // the author of the file
620 html += '<tr><td class="mdl-right"><label for="text-author">'+M.str.repository.author+' :</label></td>';
621 html += '<td class="mdl-left"><input id="text-author-'+client_id+'" type="text" name="author" value="'+this.options.author+'" /></td>';
625 if (!args.haslicense) {
626 // the license of the file
627 var licenses = this.options.licenses;
628 html += '<tr><td class="mdl-right"><label for="select-license-'+client_id+'">'+M.str.repository.chooselicense+' :</label></td>';
629 html += '<td class="mdl-left"><select name="license" id="select-license-'+client_id+'">';
630 var recentlicense = YAHOO.util.Cookie.get('recentlicense');
632 this.options.defaultlicense=recentlicense;
634 for (var i in licenses) {
635 if (this.options.defaultlicense==licenses[i].shortname) {
636 var selected = ' selected';
640 html += '<option value="'+licenses[i].shortname+'"'+selected+'>'+licenses[i].fullname+'</option>';
642 html += '</select></td></tr>';
646 html += '<p><input type="hidden" id="filesource-'+client_id+'" value="'+args.source+'" />';
647 html += '<input type="button" id="fp-confirm-'+client_id+'" value="'+M.str.repository.getfile+'" />';
648 html += '<input type="button" id="fp-cancel-'+client_id+'" value="'+M.str.moodle.cancel+'" /></p>';
651 var getfile_form = Y.Node.create(html);
652 panel.appendChild(getfile_form);
654 var getfile = Y.one('#fp-confirm-'+client_id);
655 getfile.on('click', function(e) {
656 var client_id = this.options.client_id;
658 var repository_id = this.active_repo.id;
659 var title = Y.one('#newname-'+client_id).get('value');
660 var filesource = Y.one('#filesource-'+client_id).get('value');
661 var params = {'title':title, 'source':filesource, 'savepath': this.options.savepath};
662 var license = Y.one('#select-license-'+client_id);
664 params['license'] = license.get('value');
665 YAHOO.util.Cookie.set('recentlicense', license.get('value'));
667 var author = Y.one('#text-author-'+client_id);
669 params['author'] = author.get('value');
672 if (this.options.externallink && this.options.env == 'editor') {
673 // in editor, images are stored in '/' only
674 params.savepath = '/';
675 // when image or media button is clicked
676 if ( this.options.return_types != 1 ) {
677 var linkexternal = Y.one('#linkexternal-'+client_id);
678 if (linkexternal && linkexternal.get('checked')) {
679 params['linkexternal'] = 'yes';
682 // when link button in editor clicked
683 params['linkexternal'] = 'yes';
687 if (this.options.env == 'url') {
688 params['linkexternal'] = 'yes';
691 this.wait('download', title);
694 client_id: client_id,
695 repository_id: repository_id,
697 onerror: function(id, obj, args) {
700 callback: function(id, obj, args) {
701 if (scope.options.editor_target && scope.options.env=='editor') {
702 scope.options.editor_target.value=obj.url;
703 scope.options.editor_target.onchange();
706 obj.client_id = client_id;
707 var formcallback_scope = null;
708 if (args.scope.options.magicscope) {
709 formcallback_scope = args.scope.options.magicscope;
711 formcallback_scope = args.scope;
713 scope.options.formcallback.apply(formcallback_scope, [obj]);
717 var elform = Y.one('#'+form_id);
718 elform.on('keydown', function(e) {
719 if (e.keyCode == 13) {
720 getfile.simulate('click');
724 var cancel = Y.one('#fp-cancel-'+client_id);
725 cancel.on('click', function(e) {
728 var treeview = Y.one('#treeview-'+client_id);
730 treeview.setStyle('display', 'none');
733 wait: function(type) {
734 var panel = Y.one('#panel-'+this.options.client_id);
735 panel.set('innerHTML', '');
737 var str = '<div style="text-align:center">';
739 str += '<img src="'+M.util.image_url('i/loading')+'" />';
740 str += '<p>'+M.str.repository.loading+'</p>';
742 str += '<img src="'+M.util.image_url('i/progressbar')+'" />';
743 str += '<p>'+M.str.repository.copying+' <strong>'+name+'</strong></p>';
747 panel.set('innerHTML', str);
753 var client_id = this.options.client_id;
755 var filepicker_id = 'filepicker-'+client_id;
756 var fpnode = Y.Node.create('<div class="file-picker" id="'+filepicker_id+'"></div>');
757 Y.one(document.body).appendChild(fpnode);
758 // render file picker panel
759 this.mainui = new YAHOO.widget.Panel(filepicker_id, {
764 monitorresize: false,
765 xy: [50, YAHOO.util.Dom.getDocumentScrollTop()+20]
768 this.mainui.beforeRenderEvent.subscribe(function() {
769 YAHOO.util.Event.onAvailable('layout-'+client_id, function() {
770 layout = new YAHOO.widget.Layout('layout-'+client_id, {
771 height: 480, width: 700,
773 {position: 'top', height: 32, resize: false,
774 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'},
775 {position: 'left', width: 200, resize: true, scroll:true,
776 body:'<ul class="fp-list" id="fp-list-'+client_id+'"></ul>', gutter: '0 5 0 2', minWidth: 150, maxWidth: 300 },
777 {position: 'center', body: '<div class="fp-panel" id="panel-'+client_id+'"></div>',
778 scroll: true, gutter: '0 2 0 0' }
782 scope.show_recent_repository();
786 this.mainui.setHeader(M.str.repository.filepicker);
787 this.mainui.setBody('<div id="layout-'+client_id+'"></div>');
788 this.mainui.render();
789 this.rendered = true;
793 var view_icons = {label: M.str.repository.iconview, value: 't', 'checked': true,
796 scope.view_as_icons();
800 var view_listing = {label: M.str.repository.listview, value: 'l',
803 scope.view_as_list();
807 this.viewbar = new YAHOO.widget.ButtonGroup({
808 id: 'btngroup-'+client_id,
811 container: 'fp-viewbar-'+client_id
813 this.viewbar.addButtons([view_icons, view_listing]);
814 // processing repository listing
815 var r = this.options.repositories;
816 Y.on('contentready', function(el) {
817 var list = Y.one(el);
819 // Resort the repositories by sortorder
820 var sorted_repositories = new Array();
822 sorted_repositories[r[i].sortorder - 1] = r[i];
824 for (var i in sorted_repositories){
825 repository = sorted_repositories[i];
826 var id = 'repository-'+client_id+'-'+repository.id;
827 var link_id = id + '-link';
828 list.append('<li id="'+id+'"><a class="fp-repo-name" id="'+link_id+'" href="###">'+repository.name+'</a></li>');
829 Y.one('#'+link_id).prepend('<img src="'+repository.icon+'" width="16" height="16" /> ');
830 Y.one('#'+link_id).on('click', function(e, scope, repository_id) {
831 YAHOO.util.Cookie.set('recentrepository', repository_id);
832 scope.repository_id = repository_id;
833 this.list({'repo_id':repository_id});
834 }, this /*handler running scope*/, this/*second argument*/, repository.id/*third argument of handler*/);
838 if (this.options.externallink) {
839 list.set('innerHTML', M.str.repository.norepositoriesexternalavailable);
841 list.set('innerHTML', M.str.repository.norepositoriesavailable);
844 }, '#fp-list-'+client_id, this /* handler running scope */, '#fp-list-'+client_id /*first argument of handler*/);
846 parse_repository_options: function(data) {
847 this.filelist = data.list?data.list:null;
848 this.filepath = data.path?data.path:null;
849 this.active_repo = {};
850 this.active_repo.issearchresult = Boolean(data.issearchresult);
851 this.active_repo.dynload = data.dynload?data.dynload:false;
852 this.active_repo.pages = Number(data.pages?data.pages:null);
853 this.active_repo.page = Number(data.page?data.page:null);
854 this.active_repo.id = data.repo_id?data.repo_id:null;
855 this.active_repo.nosearch = data.nosearch?true:false;
856 this.active_repo.norefresh = data.norefresh?true:false;
857 this.active_repo.nologin = data.nologin?true:false;
858 this.active_repo.logouttext = data.logouttext?data.logouttext:null;
859 this.active_repo.help = data.help?data.help:null;
860 this.active_repo.manage = data.manage?data.manage:null;
862 print_login: function(data) {
863 this.parse_repository_options(data);
864 var client_id = this.options.client_id;
865 var repository_id = data.repo_id;
866 var l = this.logindata = data.login;
868 var panel = Y.one('#panel-'+client_id);
869 var action = 'login';
870 if (data['login_btn_action']) {
871 action=data['login_btn_action'];
873 var form_id = 'fp-form-'+client_id;
874 var download_button_id = 'fp-form-download-button-'+client_id;
875 var search_button_id = 'fp-form-search-button-'+client_id;
876 var login_button_id = 'fp-form-login-button-'+client_id;
877 var popup_button_id = 'fp-form-popup-button-'+client_id;
879 var str = '<div class="fp-login-form">';
880 str += '<form id="'+form_id+'">';
882 str +='<table width="100%">';
885 if(l[k].type=='popup') {
888 str += '<td colspan="2"><p class="fp-popup">'+M.str.repository.popup+'</p>';
889 str += '<p class="fp-popup"><button id="'+popup_button_id+'">'+M.str.repository.login+'</button>';
892 }else if(l[k].type=='textarea') {
894 str += '<td colspan="2"><p><textarea id="'+l[k].id+'" name="'+l[k].name+'"></textarea></p></td>';
895 }else if(l[k].type=='select') {
897 str += '<td align="right"><label>'+l[k].label+':</label></td>';
898 str += '<td align="left"><select id="'+l[k].id+'" name="'+l[k].name+'">';
899 for (i in l[k].options) {
900 str += '<option value="'+l[k].options[i].value+'">'+l[k].options[i].label+'</option>';
902 str += '</select></td>';
907 var field_value = '';
909 label_id = ' for="'+l[k].id+'"';
910 field_id = ' id="'+l[k].id+'"';
913 str += '<td align="right" width="30%" valign="center">';
914 str += '<label'+label_id+'>'+l[k].label+'</label> </td>';
916 str += '<td width="30%"></td>';
919 field_value = ' value="'+l[k].value+'"';
921 if(l[k].type=='radio'){
922 var list = l[k].value.split('|');
923 var labels = l[k].value_label.split('|');
924 str += '<td align="left">';
925 for(var item in list) {
926 str +='<input type="'+l[k].type+'"'+' name="'+l[k].name+'"'+
927 field_id+' value="'+list[item]+'" />'+labels[item]+'<br />';
931 str += '<td align="left">';
932 str += '<input type="'+l[k].type+'"'+' name="'+l[k].name+'"'+field_value+' '+field_id+' />';
942 var btn_label = data['login_btn_label']?data['login_btn_label']:M.str.repository.submit;
943 if (action != 'popup') {
944 str += '<p><input type="button" id="';
947 str += search_button_id;
950 str += download_button_id;
953 str += login_button_id;
956 str += '" value="'+btn_label+'" /></p>';
963 panel.set('innerHTML', str);
965 alert(M.str.repository.xhtmlerror);
968 // process login action
969 var login_button = Y.one('#'+login_button_id);
972 login_button.on('click', function(){
974 var data = this.logindata;
977 for (var k in data) {
978 if(data[k].type!='popup') {
979 var el = Y.one('[name='+data[k].name+']');
980 var type = el.get('type');
981 params[data[k].name] = '';
982 if(type == 'checkbox') {
983 params[data[k].name] = el.get('checked');
985 params[data[k].name] = el.get('value');
989 // start ajax request
995 'client_id': client_id,
996 'repository_id': repository_id,
997 'callback': function(id, o, args) {
998 scope.parse_repository_options(o);
1004 var search_button = Y.one('#'+search_button_id);
1005 if (search_button) {
1006 search_button.on('click', function(){
1007 var data = this.logindata;
1010 for (var k in data) {
1011 if(data[k].type!='popup') {
1012 var el = document.getElementsByName(data[k].name)[0];
1013 params[data[k].name] = '';
1014 if(el.type == 'checkbox') {
1015 params[data[k].name] = el.checked;
1016 } else if(el.type == 'radio') {
1017 var tmp = document.getElementsByName(data[k].name);
1019 if (tmp[i].checked) {
1020 params[data[k].name] = tmp[i].value;
1024 params[data[k].name] = el.value;
1031 client_id: client_id,
1032 repository_id: repository_id,
1033 form: {id: 'fp-form-'+scope.options.client_id,upload:false,useDisabled:true},
1034 callback: function(id, o, args) {
1035 o.issearchresult = true;
1036 scope.parse_repository_options(o);
1042 var download_button = Y.one('#'+download_button_id);
1043 if (download_button) {
1044 download_button.on('click', function(){
1048 var popup_button = Y.one('#'+popup_button_id);
1050 popup_button.on('click', function(e){
1051 M.core_filepicker.active_filepicker = this;
1052 window.open(loginurl, 'repo_auth', 'location=0,status=0,width=500,height=300,scrollbars=yes');
1056 var elform = Y.one('#'+form_id);
1057 elform.on('keydown', function(e) {
1058 if (e.keyCode == 13) {
1061 search_button.simulate('click');
1064 login_button.simulate('click');
1072 search: function(args) {
1073 var data = this.logindata;
1076 for (var k in data) {
1077 if(data[k].type!='popup') {
1078 var el = document.getElementsByName(data[k].name)[0];
1079 params[data[k].name] = '';
1080 if(el.type == 'checkbox') {
1081 params[data[k].name] = el.checked;
1082 } else if(el.type == 'radio') {
1083 var tmp = document.getElementsByName(data[k].name);
1085 if (tmp[i].checked) {
1086 params[data[k].name] = tmp[i].value;
1090 params[data[k].name] = el.value;
1097 client_id: client_id,
1098 repository_id: repository_id,
1099 form: {id: 'fp-form-'+scope.options.client_id,upload:false,useDisabled:true},
1100 callback: function(id, o, args) {
1101 o.issearchresult = true;
1102 scope.parse_repository_options(o);
1107 list: function(args) {
1112 if (!args.repo_id) {
1113 args.repo_id = scope.active_repo.id;
1117 client_id: scope.options.client_id,
1118 repository_id: args.repo_id,
1119 path:args.path?args.path:'',
1120 page:args.page?args.page:'',
1121 callback: function(id, obj, args) {
1122 Y.all('#fp-list-'+scope.options.client_id+' li a').setStyle('backgroundColor', 'transparent');
1123 var el = Y.one('#repository-'+scope.options.client_id+'-'+obj.repo_id+'-link');
1125 el.setStyle('backgroundColor', '#AACCEE');
1128 scope.viewbar.set('disabled', true);
1129 scope.print_login(obj);
1130 } else if (obj.upload) {
1131 scope.viewbar.set('disabled', true);
1132 scope.parse_repository_options(obj);
1133 scope.create_upload_form(obj);
1135 } else if (obj.iframe) {
1137 } else if (obj.list) {
1138 obj.issearchresult = false;
1139 scope.viewbar.set('disabled', false);
1140 scope.parse_repository_options(obj);
1146 create_upload_form: function(data) {
1147 var client_id = this.options.client_id;
1148 Y.one('#panel-'+client_id).set('innerHTML', '');
1149 var types = this.options.accepted_types;
1151 this.print_header();
1152 var id = data.upload.id+'_'+client_id;
1153 var str = '<div id="'+id+'_div" class="fp-upload-form mdl-align">';
1154 str += '<form id="'+id+'" enctype="multipart/form-data" method="POST">';
1155 str += '<table width="100%">';
1156 str += '<tr><td class="mdl-right">';
1157 str += '<label for="'+id+'_file">'+data.upload.label+': </label></td>';
1158 str += '<td class="mdl-left"><input type="file" id="'+id+'_file" name="repo_upload_file" />';
1159 str += '<tr><td class="mdl-right"><label for="newname-'+client_id+'">'+M.str.repository.saveas+':</label></td>';
1160 str += '<td class="mdl-left"><input type="text" name="title" id="newname-'+client_id+'" value="" /></td></tr>';
1161 str += '<input type="hidden" name="itemid" value="'+this.options.itemid+'" />';
1162 for (var i in types) {
1163 str += '<input type="hidden" name="accepted_types[]" value="'+types[i]+'" />';
1165 str += '</td></tr><tr>';
1166 str += '<td class="mdl-right"><label>'+M.str.repository.author+': </label></td>';
1167 str += '<td class="mdl-left"><input type="text" name="author" value="'+this.options.author+'" /></td>';
1170 str += '<td class="mdl-right">'+M.str.repository.chooselicense+': </td>';
1171 str += '<td class="mdl-left">';
1172 var licenses = this.options.licenses;
1173 str += '<select name="license" id="select-license-'+client_id+'">';
1174 var recentlicense = YAHOO.util.Cookie.get('recentlicense');
1175 if (recentlicense) {
1176 this.options.defaultlicense=recentlicense;
1178 for (var i in licenses) {
1179 if (this.options.defaultlicense==licenses[i].shortname) {
1180 var selected = ' selected';
1184 str += '<option value="'+licenses[i].shortname+'"'+selected+'>'+licenses[i].fullname+'</option>';
1188 str += '</tr></table>';
1190 str += '<div class="fp-upload-btn"><button id="'+id+'_action">'+M.str.repository.upload+'</button></div>';
1192 var upload_form = Y.Node.create(str);
1193 Y.one('#panel-'+client_id).appendChild(upload_form);
1195 Y.one('#'+id+'_action').on('click', function(e) {
1197 var license = Y.one('#select-license-'+client_id).get('value');
1198 YAHOO.util.Cookie.set('recentlicense', license);
1199 if (!Y.one('#'+id+'_file').get('value')) {
1200 scope.print_msg(M.str.repository.nofilesattached, 'error');
1206 client_id: client_id,
1207 params: {'savepath':scope.options.savepath},
1208 repository_id: scope.active_repo.id,
1209 form: {id: id, upload:true},
1210 onerror: function(id, o, args) {
1211 scope.create_upload_form(data);
1213 callback: function(id, o, args) {
1214 if (scope.options.editor_target&&scope.options.env=='editor') {
1215 scope.options.editor_target.value=o.url;
1216 scope.options.editor_target.onchange();
1219 o.client_id = client_id;
1220 var formcallback_scope = null;
1221 if (args.scope.options.magicscope) {
1222 formcallback_scope = args.scope.options.magicscope;
1224 formcallback_scope = args.scope;
1226 scope.options.formcallback.apply(formcallback_scope, [o]);
1231 print_header: function() {
1232 var r = this.active_repo;
1234 var client_id = this.options.client_id;
1235 var repository_id = this.active_repo.id;
1236 var panel = Y.one('#panel-'+client_id);
1237 var str = '<div id="fp-header-'+client_id+'">';
1238 str += '<div class="fp-toolbar" id="repo-tb-'+client_id+'"></div>';
1240 var head = Y.Node.create(str);
1241 panel.appendChild(head);
1242 //if(this.active_repo.pages < 8){
1243 this.print_paging('header');
1246 var toolbar = Y.one('#repo-tb-'+client_id);
1249 var html = '<a href="###"><img src="'+M.util.image_url('a/search')+'" /> '+M.str.repository.search+'</a>';
1250 var search = Y.Node.create(html);
1251 search.on('click', function() {
1254 action:'searchform',
1255 repository_id: repository_id,
1256 callback: function(id, obj, args) {
1257 var scope = args.scope;
1258 var client_id = scope.options.client_id;
1259 var repository_id = scope.active_repo.id;
1260 var container = document.getElementById('fp-search-dlg');
1262 container.innerHTML = '';
1263 container.parentNode.removeChild(container);
1265 var container = document.createElement('DIV');
1266 container.id = 'fp-search-dlg';
1268 var dlg_title = document.createElement('DIV');
1269 dlg_title.className = 'hd';
1270 dlg_title.innerHTML = M.str.repository.search;
1272 var dlg_body = document.createElement('DIV');
1273 dlg_body.className = 'bd';
1275 var sform = document.createElement('FORM');
1276 sform.method = 'POST';
1277 sform.id = "fp-search-form";
1278 sform.innerHTML = obj.form;
1280 dlg_body.appendChild(sform);
1281 container.appendChild(dlg_title);
1282 container.appendChild(dlg_body);
1283 Y.one(document.body).appendChild(container);
1284 var search_dialog= null;
1285 function dialog_handler() {
1286 scope.viewbar.set('disabled', false);
1290 client_id: client_id,
1291 repository_id: repository_id,
1292 form: {id: 'fp-search-form',upload:false,useDisabled:true},
1293 callback: function(id, o, args) {
1294 scope.parse_repository_options(o);
1298 search_dialog.cancel();
1300 Y.one('#fp-search-form').on('keydown', function(e){
1301 if (e.keyCode == 13) {
1307 search_dialog = new YAHOO.widget.Dialog("fp-search-dlg", {
1308 postmethod: 'async',
1315 constraintoviewport : true,
1318 text:M.str.repository.submit,
1319 handler:dialog_handler,
1322 text:M.str.moodle.cancel,
1328 search_dialog.render();
1329 search_dialog.show();
1333 toolbar.appendChild(search);
1335 // weather we use cache for this instance, this button will reload listing anyway
1337 var html = '<a href="###"><img src="'+M.util.image_url('a/refresh')+'" /> '+M.str.repository.refresh+'</a>';
1338 var refresh = Y.Node.create(html);
1339 refresh.on('click', function() {
1342 toolbar.appendChild(refresh);
1345 var label = r.logouttext?r.logouttext:M.str.repository.logout;
1346 var html = '<a href="###"><img src="'+M.util.image_url('a/logout')+'" /> '+label+'</a>';
1347 var logout = Y.Node.create(html);
1348 logout.on('click', function() {
1351 client_id: client_id,
1352 repository_id: repository_id,
1354 callback: function(id, obj, args) {
1355 scope.viewbar.set('disabled', true);
1356 scope.print_login(obj);
1360 toolbar.appendChild(logout);
1364 var mgr = document.createElement('A');
1365 mgr.href = r.manage;
1366 mgr.target = "_blank";
1367 mgr.innerHTML = '<img src="'+M.util.image_url('a/setting')+'" /> '+M.str.repository.manageurl;
1368 toolbar.appendChild(mgr);
1371 var help = document.createElement('A');
1373 help.target = "_blank";
1374 help.innerHTML = '<img src="'+M.util.image_url('a/help')+'" /> '+M.str.repository.help;
1375 toolbar.appendChild(help);
1380 get_page_button: function(page) {
1381 var r = this.active_repo;
1383 if (page == r.page) {
1384 css = 'class="cur_page" ';
1386 var str = '<a '+css+'href="###" id="repo-page-'+page+'">';
1389 print_paging: function(html_id) {
1390 var client_id = this.options.client_id;
1392 var r = this.active_repo;
1395 var lastpage = r.pages;
1396 var lastpagetext = r.pages;
1397 if (r.pages == -1) {
1398 lastpage = r.page + 1;
1399 lastpagetext = M.str.moodle.next;
1402 str += '<div class="fp-paging" id="paging-'+html_id+'-'+client_id+'">';
1403 str += this.get_page_button(1)+'1</a> ';
1406 var ex = (span-1)/2;
1408 if (r.page+ex>=lastpage) {
1414 var max = r.page+ex;
1418 // won't display upper boundary
1419 if (r.page >= span) {
1421 for(var i=r.page-ex; i<max; i++) {
1422 str += this.get_page_button(i);
1427 // this very first elements
1428 for(var i = 2; i < max; i++) {
1429 str += this.get_page_button(i);
1435 // won't display upper boundary
1436 if (max==lastpage) {
1437 str += this.get_page_button(lastpage)+lastpagetext+'</a>';
1439 str += this.get_page_button(max)+max+'</a>';
1440 str += ' ... '+this.get_page_button(lastpage)+lastpagetext+'</a>';
1445 var a = Y.Node.create(str);
1446 Y.one('#fp-header-'+client_id).appendChild(a);
1448 Y.all('#fp-header-'+client_id+' .fp-paging a').each(
1449 function(node, id) {
1450 node.on('click', function(e) {
1451 var id = node.get('id');
1452 var re = new RegExp("repo-page-(\\d+)", "i");
1453 var result = id.match(re);
1455 args.page = result[1];
1456 if (scope.active_repo.issearchresult) {
1460 client_id: client_id,
1461 repository_id: r.id,
1462 params: {'page':result[1]},
1463 callback: function(id, o, args) {
1464 o.issearchresult = true;
1465 scope.parse_repository_options(o);
1466 scope.view_files(result[1]);
1471 if (scope.viewmode == 2) {
1472 scope.view_as_list(result[1]);
1481 print_path: function() {
1482 var client_id = this.options.client_id;
1483 var panel = Y.one('#panel-'+client_id);
1484 var p = this.filepath;
1485 if (p && p.length!=0) {
1486 var path = Y.Node.create('<div id="path-'+client_id+'" class="fp-pathbar"></div>');
1487 panel.appendChild(path);
1488 for(var i = 0; i < p.length; i++) {
1489 var link_path = p[i].path;
1490 var link = document.createElement('A');
1492 link.innerHTML = p[i].name;
1493 link.id = 'path-node-'+client_id+'-'+i;
1494 var sep = Y.Node.create('<span>/</span>');
1495 path.appendChild(link);
1496 path.appendChild(sep);
1497 Y.one('#'+link.id).on('click', function(Y, path){
1498 this.list({'path':path});
1507 if (this.rendered) {
1508 var panel = Y.one('#panel-'+this.options.client_id);
1509 panel.set('innerHTML', '');
1511 this.show_recent_repository();
1516 launch: function() {
1519 show_recent_repository: function() {
1520 var repository_id = YAHOO.util.Cookie.get('recentrepository');
1521 if (this.options.repositories[repository_id]) {
1522 this.list({'repo_id':repository_id});
1526 var loading = Y.one('#filepicker-loading-'+options.client_id);
1528 loading.setStyle('display', 'none');
1530 M.core_filepicker.instances[options.client_id] = new FilePickerHelper(options);