MDL-14636: Support table view in Filepicker, provide more info about files
[moodle.git] / repository / filepicker.js
CommitLineData
99eaca9d
DC
1// YUI3 File Picker module for moodle
2// Author: Dongsheng Cai <dongsheng@moodle.com>
3
4/**
5 *
6 * File Picker UI
7 * =====
b5e7b638 8 * this.fpnode, contains reference to filepicker Node, non-empty if and only if rendered
99eaca9d 9 * this.api, stores the URL to make ajax request
99eaca9d 10 * this.mainui, YUI Panel
b5e7b638
MG
11 * this.selectui, YUI Panel for selecting particular file
12 * this.msg_dlg, YUI Panel for error or info message
13 * this.process_dlg, YUI Panel for processing existing filename
99eaca9d 14 * this.treeview, YUI Treeview
99eaca9d 15 * this.viewmode, store current view mode
b5e7b638
MG
16 * this.pathbar, reference to the Node with path bar
17 * this.pathnode, a Node element representing one folder in a path bar (not attached anywhere, just used for template)
99eaca9d
DC
18 *
19 * Filepicker options:
20 * =====
99eaca9d
DC
21 * this.options.client_id, the instance id
22 * this.options.contextid
23 * this.options.itemid
24 * this.options.repositories, stores all repositories displaied in file picker
25 * this.options.formcallback
26 *
27 * Active repository options
28 * =====
29 * this.active_repo.id
30 * this.active_repo.nosearch
31 * this.active_repo.norefresh
32 * this.active_repo.nologin
33 * this.active_repo.help
34 * this.active_repo.manage
8cbef19e 35 *
99eaca9d
DC
36 * Server responses
37 * =====
38 * this.filelist, cached filelist
39 * this.pages
40 * this.page
41 * this.filepath, current path
42 * this.logindata, cached login form
43 */
44
4c508047 45M.core_filepicker = M.core_filepicker || {};
99eaca9d 46
4c508047
PS
47/**
48 * instances of file pickers used on page
49 */
50M.core_filepicker.instances = M.core_filepicker.instances || {};
539d4041 51M.core_filepicker.active_filepicker = null;
4c508047 52
b5e7b638
MG
53/**
54 * HTML Templates to use in FilePicker
55 */
56M.core_filepicker.templates = M.core_filepicker.templates || {};
57
4c508047
PS
58/**
59 * Init and show file picker
60 */
61M.core_filepicker.show = function(Y, options) {
62 if (!M.core_filepicker.instances[options.client_id]) {
8cbef19e 63 M.core_filepicker.init(Y, options);
99eaca9d 64 }
4c508047
PS
65 M.core_filepicker.instances[options.client_id].show();
66};
67
68/**
69 * Add new file picker to current instances
70 */
71M.core_filepicker.init = function(Y, options) {
b5e7b638
MG
72 if (options.templates);
73 for (var templid in options.templates) {
74 this.templates[templid] = options.templates[templid];
75 }
76
4c508047
PS
77 var FilePickerHelper = function(options) {
78 FilePickerHelper.superclass.constructor.apply(this, arguments);
8cbef19e 79 };
4c508047
PS
80
81 FilePickerHelper.NAME = "FilePickerHelper";
82 FilePickerHelper.ATTRS = {
99eaca9d
DC
83 options: {},
84 lang: {}
85 };
4c508047
PS
86
87 Y.extend(FilePickerHelper, Y.Base, {
9598d578 88 api: M.cfg.wwwroot+'/repository/repository_ajax.php',
7f9358fc 89 cached_responses: {},
4c508047
PS
90
91 initializer: function(options) {
92 this.options = options;
392d5fd4
DC
93 if (!this.options.savepath) {
94 this.options.savepath = '/';
95 }
99eaca9d 96 },
4c508047 97
99eaca9d
DC
98 destructor: function() {
99 },
4c508047 100
99eaca9d 101 request: function(args, redraw) {
3a1e425b 102 var api = (args.api?args.api:this.api) + '?action='+args.action;
99eaca9d 103 var params = {};
3a1e425b 104 var scope = args['scope']?args['scope']:this;
99eaca9d
DC
105 params['repo_id']=args.repository_id;
106 params['p'] = args.path?args.path:'';
107 params['page'] = args.page?args.page:'';
108 params['env']=this.options.env;
109 // the form element only accept certain file types
110 params['accepted_types']=this.options.accepted_types;
e35194be 111 params['sesskey'] = M.cfg.sesskey;
99eaca9d 112 params['client_id'] = args.client_id;
0c4edaa2 113 params['itemid'] = this.options.itemid?this.options.itemid:0;
8a3e6a56 114 params['maxbytes'] = this.options.maxbytes?this.options.maxbytes:-1;
be85f7ab
DC
115 if (this.options.context && this.options.context.id) {
116 params['ctx_id'] = this.options.context.id;
117 }
99eaca9d
DC
118 if (args['params']) {
119 for (i in args['params']) {
120 params[i] = args['params'][i];
121 }
122 }
64654e78
DC
123 if (args.action == 'upload') {
124 var list = [];
125 for(var k in params) {
126 var value = params[k];
127 if(value instanceof Array) {
128 for(var i in value) {
129 list.push(k+'[]='+value[i]);
130 }
131 } else {
132 list.push(k+'='+value);
133 }
134 }
135 params = list.join('&');
136 } else {
137 params = build_querystring(params);
138 }
99eaca9d
DC
139 var cfg = {
140 method: 'POST',
141 on: {
142 complete: function(id,o,p) {
143 if (!o) {
b5e7b638 144 // TODO
99eaca9d
DC
145 alert('IO FATAL');
146 return;
147 }
4c508047
PS
148 var data = null;
149 try {
150 data = Y.JSON.parse(o.responseText);
151 } catch(e) {
879b4f9a 152 scope.print_msg(M.str.repository.invalidjson, 'error');
b5e7b638 153 scope.display_error(M.str.repository.invalidjson+'<pre>'+stripHTML(o.responseText)+'</pre>', 'invalidjson')
c26855ff 154 return;
4c508047 155 }
1dce6261 156 // error checking
e35194be
DC
157 if (data && data.error) {
158 scope.print_msg(data.error, 'error');
a5159b86
MG
159 if (args.onerror) {
160 args.onerror(id,data,p);
161 } else {
3a1e425b 162 this.fpnode.one('.fp-content').setContent('');
a5159b86 163 }
1dce6261 164 return;
f392caba
DC
165 } else if (data && data.event) {
166 switch (data.event) {
167 case 'fileexists':
168 scope.process_existing_file(data);
169 break;
170 default:
171 break;
172 }
1dce6261 173 } else {
879b4f9a
DC
174 if (data.msg) {
175 scope.print_msg(data.msg, 'info');
176 }
7f9358fc
MG
177 // cache result if applicable
178 if (args.action != 'upload' && data.allowcaching) {
179 scope.cached_responses[params] = data;
180 }
181 // invoke callback
1dce6261
DC
182 args.callback(id,data,p);
183 }
99eaca9d
DC
184 }
185 },
186 arguments: {
187 scope: scope
188 },
189 headers: {
bd2db41a 190 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
99eaca9d 191 },
64654e78 192 data: params,
4c508047 193 context: this
99eaca9d
DC
194 };
195 if (args.form) {
196 cfg.form = args.form;
197 }
7f9358fc
MG
198 // check if result of the same request has been already cached. If not, request it
199 // (never applicable in case of form submission and/or upload action):
200 if (!args.form && args.action != 'upload' && scope.cached_responses[params]) {
201 args.callback(null, scope.cached_responses[params], {scope: scope})
202 } else {
203 Y.io(api, cfg);
204 if (redraw) {
b5e7b638 205 this.wait();
7f9358fc 206 }
99eaca9d
DC
207 }
208 },
b5e7b638 209 /** displays the dialog and processes rename/overwrite if there is a file with the same name in the same filearea*/
f392caba
DC
210 process_existing_file: function(data) {
211 var scope = this;
b5e7b638 212 var handleOverwrite = function(e) {
f392caba 213 // overwrite
b5e7b638
MG
214 e.preventDefault();
215 var data = this.process_dlg.dialogdata;
f392caba
DC
216 var params = {}
217 params['existingfilename'] = data.existingfile.filename;
218 params['existingfilepath'] = data.existingfile.filepath;
219 params['newfilename'] = data.newfile.filename;
220 params['newfilepath'] = data.newfile.filepath;
b5e7b638
MG
221 this.hide_header();
222 this.request({
f392caba 223 'params': params,
b5e7b638 224 'scope': this,
f392caba
DC
225 'action':'overwrite',
226 'path': '',
b5e7b638
MG
227 'client_id': this.options.client_id,
228 'repository_id': this.active_repo.id,
f392caba 229 'callback': function(id, o, args) {
f392caba
DC
230 scope.hide();
231 // editor needs to update url
232 // filemanager do nothing
c8ad2c12
SH
233 if (scope.options.editor_target && scope.options.env == 'editor') {
234 scope.options.editor_target.value = data.existingfile.url;
f392caba 235 scope.options.editor_target.onchange();
1ae299f5 236 } else if (scope.options.env === 'filepicker') {
b5e7b638 237 var fileinfo = {'client_id':scope.options.client_id,
913b3cb3
JP
238 'url':data.existingfile.url,
239 'file':data.existingfile.filename};
240 scope.options.formcallback.apply(scope, [fileinfo]);
f392caba
DC
241 }
242 }
243 }, true);
244 }
b5e7b638
MG
245 var handleRename = function(e) {
246 // inserts file with the new name
247 e.preventDefault();
248 var scope = this;
249 var data = this.process_dlg.dialogdata;
c8ad2c12
SH
250 if (scope.options.editor_target && scope.options.env == 'editor') {
251 scope.options.editor_target.value = data.newfile.url;
f392caba
DC
252 scope.options.editor_target.onchange();
253 }
f392caba 254 scope.hide();
f392caba
DC
255 var formcallback_scope = null;
256 if (scope.options.magicscope) {
257 formcallback_scope = scope.options.magicscope;
258 } else {
259 formcallback_scope = scope;
260 }
b5e7b638 261 var fileinfo = {'client_id':scope.options.client_id,
794cc7e1
JP
262 'url':data.newfile.url,
263 'file':data.newfile.filename};
264 scope.options.formcallback.apply(formcallback_scope, [fileinfo]);
f392caba 265 }
b5e7b638 266 var handleCancel = function(e) {
f392caba 267 // Delete tmp file
b5e7b638 268 e.preventDefault();
f392caba 269 var params = {};
b5e7b638
MG
270 params['newfilename'] = this.process_dlg.dialogdata.newfile.filename;
271 params['newfilepath'] = this.process_dlg.dialogdata.newfile.filepath;
272 this.request({
f392caba 273 'params': params,
b5e7b638 274 'scope': this,
f392caba
DC
275 'action':'deletetmpfile',
276 'path': '',
b5e7b638
MG
277 'client_id': this.options.client_id,
278 'repository_id': this.active_repo.id,
f392caba 279 'callback': function(id, o, args) {
b5e7b638 280 // let it be in background, from user point of view nothing is happenning
f392caba 281 }
b5e7b638
MG
282 }, false);
283 this.process_dlg.hide();
284 this.selectui.hide();
f392caba 285 }
b5e7b638
MG
286 if (!this.process_dlg) {
287 var node = Y.Node.create(M.core_filepicker.templates.processexistingfile);
288 this.fpnode.appendChild(node);
289 this.process_dlg = new Y.Panel({
290 srcNode : node,
291 headerContent: M.str.repository.fileexistsdialogheader,
292 zIndex : 800000,
293 centered : true,
294 modal : true,
295 visible : false,
296 render : true,
297 buttons : {}
298 });
299 node.one('.fp-dlg-butoverwrite').on('click', handleOverwrite, this);
300 node.one('.fp-dlg-butrename').on('click', handleRename, this);
301 node.one('.fp-dlg-butcancel').on('click', handleCancel, this);
302 if (this.options.env == 'editor') {
303 node.one('.fp-dlg-text').setContent(M.str.repository.fileexistsdialog_editor);
304 } else {
305 node.one('.fp-dlg-text').setContent(M.str.repository.fileexistsdialog_filemanager);
306 }
f392caba 307 }
3a1e425b 308 this.fpnode.one('.fp-select').removeClass('loading');
b5e7b638
MG
309 this.process_dlg.dialogdata = data;
310 this.fpnode.one('.fp-dlg .fp-dlg-butrename').setContent(M.util.get_string('renameto', 'repository', data.newfile.filename));
311 this.process_dlg.show();
312 },
313 /** displays error instead of filepicker contents */
314 display_error: function(errortext, errorcode) {
315 this.fpnode.one('.fp-content').setContent(M.core_filepicker.templates.error);
316 this.fpnode.one('.fp-content .fp-error').
317 addClass(errorcode).
318 setContent(errortext);
f392caba 319 },
b5e7b638 320 /** displays message in a popup */
879b4f9a 321 print_msg: function(msg, type) {
b5e7b638
MG
322 var header = M.str.moodle.error;
323 if (type != 'error') {
324 type = 'info'; // one of only two types excepted
325 header = M.str.moodle.info;
879b4f9a
DC
326 }
327 if (!this.msg_dlg) {
b5e7b638
MG
328 var node = Y.Node.create(M.core_filepicker.templates.message);
329 this.fpnode.appendChild(node);
330
331 this.msg_dlg = new Y.Panel({
332 srcNode : node,
333 zIndex : 800000,
334 centered : true,
335 modal : true,
336 visible : false,
337 render : true
338 });
339 node.one('.fp-msg-butok').on('click', function(e) {
340 e.preventDefault();
341 this.msg_dlg.hide();
342 }, this);
879b4f9a 343 }
b5e7b638
MG
344
345 this.msg_dlg.set('headerContent', header);
346 this.fpnode.one('.fp-msg').removeClass('fp-msg-info').removeClass('fp-msg-error').addClass('fp-msg-'+type)
347 this.fpnode.one('.fp-msg .fp-msg-text').setContent(msg);
879b4f9a 348 this.msg_dlg.show();
879b4f9a 349 },
99eaca9d
DC
350 build_tree: function(node, level) {
351 var client_id = this.options.client_id;
1fb0173e 352 var dynload = this.active_repo.dynload;
5bdf63cc
MG
353 // prepare file name with icon
354 var el = Y.Node.create('<div/>').setContent(M.core_filepicker.templates.listfilename);
355 el.one('.fp-filename').setContent(node.title);
356 if (node.icon && !node.children) {
357 el.one('.fp-icon').appendChild(Y.Node.create('<img/>').set('src', node.icon));
358 }
359 // create node
360 var tmpNode = new YAHOO.widget.HTMLNode(el.getContent(), level, false);
2f6749f4 361 if (node.dynamicLoadComplete) {
5bdf63cc 362 tmpNode.dynamicLoadComplete = true;
99eaca9d 363 }
5bdf63cc 364 tmpNode.fileinfo = node;
2f6749f4
MG
365 tmpNode.isLeaf = node.children ? false : true;
366 if (!tmpNode.isLeaf) {
99eaca9d
DC
367 if(node.expanded) {
368 tmpNode.expand();
369 }
1fb0173e
DC
370 if (dynload) {
371 tmpNode.scope = this;
372 }
5bdf63cc 373 tmpNode.path = node.path ? node.path : '';
99eaca9d
DC
374 for(var c in node.children) {
375 this.build_tree(node.children[c], tmpNode);
376 }
99eaca9d
DC
377 }
378 },
4adecd7b 379 view_files: function() {
60a4bf98
DC
380 if (this.active_repo.issearchresult) {
381 // list view is desiged to display treeview
382 // it is not working well with search result
99eaca9d 383 this.view_as_icons();
99eaca9d 384 } else {
b5e7b638 385 this.viewbar_set_enabled(true);
2f6749f4 386 this.print_path();
5bdf63cc 387 if (this.viewmode == 2) {
4adecd7b 388 this.view_as_list();
5bdf63cc
MG
389 } else if (this.viewmode == 3) {
390 this.view_as_table();
60a4bf98 391 } else {
4adecd7b 392 this.view_as_icons();
60a4bf98 393 }
99eaca9d
DC
394 }
395 },
1fb0173e
DC
396 treeview_dynload: function(node, cb) {
397 var scope = node.scope;
398 var client_id = scope.options.client_id;
399 var repository_id = scope.active_repo.id;
2f6749f4
MG
400 var retrieved_children = {};
401 if (node.children) {
402 for (var i in node.children) {
403 retrieved_children[node.children[i].path] = node.children[i];
404 }
405 }
1fb0173e
DC
406 scope.request({
407 action:'list',
408 client_id: client_id,
409 repository_id: repository_id,
410 path:node.path?node.path:'',
411 page:node.page?args.page:'',
412 callback: function(id, obj, args) {
1fb0173e 413 var list = obj.list;
2f6749f4
MG
414 // check that user did not leave the view mode before recieving this response
415 if (!(scope.active_repo.id == obj.repo_id && scope.viewmode == 2 && node && node.getChildrenEl())) {
416 return;
417 }
418 if (cb != null) { // (in manual mode do not update current path)
419 scope.viewbar_set_enabled(true);
420 scope.parse_repository_options(obj);
421 }
422 node.origlist = obj.list?obj.list:null;
423 node.origpath = obj.path?obj.path:null;
424 node.children = [];
1fb0173e 425 for(k in list) {
2f6749f4
MG
426 if (list[k].children && retrieved_children[list[k].path]) {
427 // if this child is a folder and has already been retrieved
428 node.children[node.children.length] = retrieved_children[list[k].path];
429 } else {
430 scope.build_tree(list[k], node);
431 }
432 }
433 if (cb == null) {
434 node.refresh();
435 } else {
436 // invoke callback requested by TreeView
437 cb();
1fb0173e 438 }
1fb0173e
DC
439 }
440 }, false);
441 },
4adecd7b 442 view_as_list: function() {
1fb0173e 443 var scope = this;
4adecd7b
MG
444 var client_id = scope.options.client_id;
445 var dynload = scope.active_repo.dynload;
446 var list = this.filelist;
4adecd7b 447 scope.viewmode = 2;
5bdf63cc 448 if (!list || list.length==0 && (!this.filepath || !this.filepath.length)) {
b5e7b638 449 this.display_error(M.str.repository.nofilesavailable, 'nofilesavailable');
4adecd7b
MG
450 return;
451 }
879b4f9a 452
2f6749f4
MG
453 var treeviewnode = Y.Node.create('<div/>').
454 setAttrs({'class':'fp-treeview', id:'treeview-'+client_id});
455 this.fpnode.one('.fp-content').setContent('').appendChild(treeviewnode);
b5e7b638 456
4adecd7b
MG
457 scope.treeview = new YAHOO.widget.TreeView('treeview-'+client_id);
458 if (dynload) {
459 scope.treeview.setDynamicLoad(scope.treeview_dynload, 1);
460 }
2f6749f4
MG
461 if (scope.filepath && scope.filepath.length) {
462 // we just jumped from icon/details view, we need to show all parents
463 // we extract as much information as possible from filepath and filelist
464 // and send additional requests to retrieve siblings for parent folders
465 var mytree = {};
466 var mytreeel = null;
467 for (var i in scope.filepath) {
468 if (mytreeel == null) {
469 mytreeel = mytree;
470 } else {
471 mytreeel.children = [{}];
472 mytreeel = mytreeel.children[0];
473 }
474 var parent = scope.filepath[i];
475 mytreeel.path = parent.path;
476 mytreeel.title = parent.name;
477 mytreeel.dynamicLoadComplete = true; // we will call it manually
478 mytreeel.expanded = true;
479 }
480 mytreeel.children = scope.filelist
481 scope.build_tree(mytree, scope.treeview.getRoot());
482 // manually call dynload for parent elements in the tree so we can load other siblings
483 if (dynload) {
484 var root = scope.treeview.getRoot();
485 while (root && root.children && root.children.length) {
486 root = root.children[0];
5bdf63cc
MG
487 if (root.path == mytreeel.path) {
488 root.origpath = scope.filepath;
489 root.origlist = scope.filelist;
490 } else if (!root.isLeaf && root.expanded) {
2f6749f4
MG
491 scope.treeview_dynload(root, null);
492 }
493 }
494 }
495 } else {
496 // there is no path information, just display all elements as a list, without hierarchy
497 for(k in list) {
498 scope.build_tree(list[k], scope.treeview.getRoot());
499 }
4adecd7b
MG
500 }
501 scope.treeview.subscribe('clickEvent', function(e){
502 if(e.node.isLeaf){
2f6749f4
MG
503 if (e.node.parent && e.node.parent.origpath) {
504 // set the current path
505 scope.filepath = e.node.parent.origpath;
506 scope.filelist = e.node.parent.origlist;
507 scope.print_path();
508 }
5bdf63cc
MG
509 e.node.highlight(false);
510 scope.select_file(e.node.fileinfo);
2f6749f4
MG
511 } else {
512 // save current path and filelist (in case we want to jump to other viewmode)
513 scope.filepath = e.node.origpath;
514 scope.filelist = e.node.origlist;
515 scope.print_path();
99eaca9d 516 }
4adecd7b
MG
517 });
518 scope.treeview.draw();
99eaca9d
DC
519 },
520 view_as_icons: function() {
98b15580 521 var scope = this;
99eaca9d 522 var list = this.filelist;
99eaca9d 523 this.viewmode = 1;
99eaca9d 524
5bdf63cc 525 if (!list || list.length==0) {
b5e7b638
MG
526 this.display_error(M.str.repository.nofilesavailable, 'nofilesavailable');
527 return;
879b4f9a 528 }
b5e7b638 529 this.fpnode.one('.fp-content').setContent(M.core_filepicker.templates.iconview);
879b4f9a 530
b5e7b638
MG
531 var element_template = this.fpnode.one('.fp-content').one('.fp-file');
532 var container = element_template.get('parentNode');
533 container.removeChild(element_template);
99eaca9d
DC
534 var count = 0;
535 for(var k in list) {
536 var node = list[k];
b5e7b638
MG
537 var element = element_template.cloneNode(true);
538 container.appendChild(element);
b5e7b638
MG
539 var filename = node.shorttitle ? node.shorttitle : node.title;
540 var filenamediv = element.one('.fp-filename');
541 filenamediv.setContent(filename);
542 var imgdiv = element.one('.fp-thumbnail');
543 var set_width = function(node, width) {
544 var widthmatches = node.getStyle('minWidth').match(/^(\d+)px$/)
545 if (widthmatches && parseInt(widthmatches[1])>width) {
546 width = parseInt(widthmatches[1]);
547 }
548 node.setStyle('width', '' + width + 'px')
99eaca9d 549 }
b5e7b638
MG
550 var set_height = function(node, height) {
551 var heightmatches = node.getStyle('minHeight').match(/^(\d+)px$/)
552 if (heightmatches && parseInt(heightmatches[1])>height) {
553 height = parseInt(heightmatches[1]);
554 }
555 node.setStyle('height', '' + height + 'px')
99eaca9d 556 }
b5e7b638
MG
557 var width = node.thumbnail_width ? node.thumbnail_width : 90;
558 var height = node.thumbnail_height ? node.thumbnail_height : 90;
559 set_width(filenamediv, width)
560 set_width(imgdiv, width)
561 set_height(imgdiv, height);
3a1e425b 562 var img = Y.Node.create('<img/>').setAttrs({src:node.thumbnail,title:node.title});
99eaca9d 563 if(node.thumbnail_alt) {
b5e7b638 564 img.set('alt', node.thumbnail_alt);
99eaca9d
DC
565 }
566 if(node.thumbnail_title) {
b5e7b638 567 img.set('title', node.thumbnail_title);
99eaca9d 568 }
b5e7b638
MG
569 img.setStyle('maxWidth', ''+width+'px').setStyle('maxHeight', ''+height+'px');
570 imgdiv.appendChild(img)
99eaca9d 571
98b15580 572 var dynload = this.active_repo.dynload;
99eaca9d 573 if(node.children) {
b5e7b638 574 element.on('click', function(e, p) {
4adecd7b 575 e.preventDefault();
98b15580 576 if(dynload) {
5bdf63cc 577 scope.list({'path':p.path});
99eaca9d 578 }else{
5bdf63cc 579 this.filepath = p.path;
99eaca9d
DC
580 this.filelist = p.children;
581 this.view_files();
582 }
583 }, this, node);
99eaca9d 584 } else {
b5e7b638 585 element.on('click', function(e, args) {
4adecd7b 586 e.preventDefault();
99eaca9d 587 this.select_file(args);
5bdf63cc 588 }, this, list[k]);
99eaca9d
DC
589 }
590 count++;
591 }
99eaca9d 592 },
5bdf63cc
MG
593 view_as_table: function() {
594 var list = this.filelist;
595 var client_id = this.options.client_id;
596 this.viewmode = 3;
597
598 if (!list || list.length==0) {
599 this.display_error(M.str.repository.nofilesavailable, 'nofilesavailable');
600 return;
601 }
602 var treeviewnode = Y.Node.create('<div/>').
603 setAttrs({'class':'fp-tableview', id:'tableview-'+client_id});
604 this.fpnode.one('.fp-content').setContent('').appendChild(treeviewnode);
605 var formatValue = function (o){
606 if (o.data[''+o.field+'_f_s']) { return o.data[''+o.field+'_f_s']; }
607 else if (o.data[''+o.field+'_f']) { return o.data[''+o.field+'_f']; }
608 else if (o.value) { return o.value; }
609 else { return ''; }
610 };
611 var formatTitle = function(o) {
612 var el = Y.Node.create('<div/>').setContent(M.core_filepicker.templates.listfilename);
613 el.one('.fp-filename').setContent(o.value);
614 el.one('.fp-icon').appendChild(Y.Node.create('<img/>').set('src', o.data['icon']));
615 return el.getContent();
616 }
617
618 var cols = [
619 {key: "title", label: M.str.moodle.name, sortable: true, formatter: formatTitle},
620 {key: "datemodified", label: M.str.moodle.lastmodified, sortable: true, formatter: formatValue},
621 {key: "size", label: M.str.repository.size, sortable: true, formatter: formatValue},
622 {key: "type", label: M.str.repository.type, sortable: true}
623 ];
624 var table = new Y.DataTable.Base({
625 columnset: cols,
626 recordset: list
627 });
628 // TODO allow sorting only if repository allows it, remember last sort order
629 table.plug(Y.Plugin.DataTableSort/*, { lastSortedBy: {key: "title", dir: "asc"} }*/);
630
631 table.render('#tableview-'+client_id);
632 table.delegate('click', function (e) {
633 var rs = table.get('recordset');
634 var id = e.currentTarget.get('id'), len = rs.size(), i;
635 for (i = 0; i < len; ++i) {
636 var record = rs.item(i);
637 if (record.get('id') == id) {
638 // we found the clicked record
639 var data = record.getValue();
640 if (data.children) {
641 if (this.active_repo.dynload) {
642 this.list({'path':data.path});
643 } else {
644 this.filepath = data.path;
645 this.filelist = data.children;
646 this.view_files();
647 }
648 } else {
649 this.select_file(data);
650 }
651 }
652 }
653 }, 'tr', this);
654 },
99eaca9d 655 select_file: function(args) {
b5e7b638 656 this.selectui.show();
99eaca9d 657 var client_id = this.options.client_id;
b5e7b638 658 var selectnode = this.fpnode.one('.fp-select');
3a1e425b 659 selectnode.removeClass('loading');
b5e7b638
MG
660 selectnode.one('#newname-'+client_id).set('value', args.title);
661 selectnode.one('#text-author-'+client_id).set('value', this.options.author);
99eaca9d 662
b5e7b638
MG
663 var imgnode = Y.Node.create('<img/>').set('src', args.thumbnail)
664 selectnode.one('#img-'+client_id).setContent('').appendChild(imgnode);
665
666 selectnode.one('#linkexternal-'+client_id).set('checked', ''); // default to unchecked
4adecd7b 667 if ((this.options.externallink && this.options.env == 'editor' && this.options.return_types != 1)) {
b5e7b638
MG
668 // enable checkbox 'Link external'
669 selectnode.one('#linkexternal-'+client_id).set('disabled', '');
670 selectnode.all('#linkexternal-'+client_id+',#wrap-linkexternal-'+client_id).removeClass('uneditable')
671 } else {
672 // disable checkbox 'Link external'
673 selectnode.one('#linkexternal-'+client_id).set('disabled', 'disabled');
674 selectnode.all('#linkexternal-'+client_id+',#wrap-linkexternal-'+client_id).addClass('uneditable')
675 if (this.options.return_types == 1) {
676 // support external links only
677 selectnode.one('#linkexternal-'+client_id).set('checked', 'checked');
678 }
99eaca9d 679 }
1dce6261 680
b5e7b638
MG
681 if (args.hasauthor) {
682 selectnode.one('#text-author-'+client_id).set('disabled', 'disabled');
683 selectnode.all('#text-author-'+client_id+',#wrap-text-author-'+client_id).addClass('uneditable')
684 } else {
685 selectnode.one('#text-author-'+client_id).set('disabled', '');
686 selectnode.all('#text-author-'+client_id+',#wrap-text-author-'+client_id).removeClass('uneditable')
1dce6261
DC
687 }
688
689 if (!args.haslicense) {
690 // the license of the file
b5e7b638
MG
691 this.populate_licenses_select(selectnode.one('#select-license-'+client_id));
692 selectnode.one('#wrap-select-license-'+client_id).set('disabled', '');
693 selectnode.all('#select-license-'+client_id+'#wrap-select-license-'+client_id).removeClass('uneditable');
694 } else {
695 selectnode.one('#wrap-select-license-'+client_id).set('disabled', 'disabled');
696 selectnode.all('#select-license-'+client_id+'#wrap-select-license-'+client_id).addClass('uneditable');
1dce6261 697 }
b5e7b638
MG
698 selectnode.one('form #filesource-'+client_id).set('value', args.source);
699 },
700 setup_select_file: function() {
701 var client_id = this.options.client_id;
702 var selectnode = this.fpnode.one('.fp-select');
703 var getfile = selectnode.one('#fp-confirm-'+client_id);
99eaca9d 704 getfile.on('click', function(e) {
b5e7b638 705 e.preventDefault();
99eaca9d
DC
706 var client_id = this.options.client_id;
707 var scope = this;
708 var repository_id = this.active_repo.id;
b5e7b638
MG
709 var title = selectnode.one('#newname-'+client_id).get('value');
710 var filesource = selectnode.one('form #filesource-'+client_id).get('value');
14469892 711 var params = {'title':title, 'source':filesource, 'savepath': this.options.savepath};
b5e7b638 712 var license = selectnode.one('#select-license-'+client_id);
1dce6261
DC
713 if (license) {
714 params['license'] = license.get('value');
b5e7b638 715 Y.Cookie.set('recentlicense', license.get('value'));
1dce6261 716 }
b5e7b638 717 var author = selectnode.one('#text-author-'+client_id);
392d5fd4 718 if (author){
1dce6261
DC
719 params['author'] = author.get('value');
720 }
99eaca9d 721
400d228e 722 if (this.options.externallink && this.options.env == 'editor') {
392d5fd4
DC
723 // in editor, images are stored in '/' only
724 params.savepath = '/';
766514a0 725 // when image or media button is clicked
4adecd7b 726 if ( this.options.return_types != 1 ) {
b5e7b638 727 var linkexternal = selectnode.one('#linkexternal-'+client_id);
400d228e 728 if (linkexternal && linkexternal.get('checked')) {
766514a0
DC
729 params['linkexternal'] = 'yes';
730 }
731 } else {
732 // when link button in editor clicked
99eaca9d
DC
733 params['linkexternal'] = 'yes';
734 }
766514a0
DC
735 }
736
737 if (this.options.env == 'url') {
99eaca9d
DC
738 params['linkexternal'] = 'yes';
739 }
740
3a1e425b 741 selectnode.addClass('loading');
99eaca9d 742 this.request({
840912d5
DC
743 action:'download',
744 client_id: client_id,
745 repository_id: repository_id,
746 'params': params,
a5159b86 747 onerror: function(id, obj, args) {
3a1e425b 748 selectnode.removeClass('loading');
b5e7b638 749 scope.selectui.hide();
a5159b86 750 },
840912d5 751 callback: function(id, obj, args) {
3a1e425b 752 selectnode.removeClass('loading');
e0b85db4 753 if (scope.options.editor_target && scope.options.env=='editor') {
840912d5
DC
754 scope.options.editor_target.value=obj.url;
755 scope.options.editor_target.onchange();
756 }
757 scope.hide();
758 obj.client_id = client_id;
759 var formcallback_scope = null;
411caa63 760 if (args.scope.options.magicscope) {
840912d5
DC
761 formcallback_scope = args.scope.options.magicscope;
762 } else {
763 formcallback_scope = args.scope;
99eaca9d 764 }
840912d5
DC
765 scope.options.formcallback.apply(formcallback_scope, [obj]);
766 }
b5e7b638 767 }, false);
99eaca9d 768 }, this);
b5e7b638 769 var elform = selectnode.one('form');
3a1e425b
MG
770 elform.appendChild(Y.Node.create('<input/>').
771 setAttrs({type:'hidden',id:'filesource-'+client_id}));
e0b85db4
DC
772 elform.on('keydown', function(e) {
773 if (e.keyCode == 13) {
774 getfile.simulate('click');
8cbef19e 775 e.preventDefault();
e0b85db4
DC
776 }
777 }, this);
b5e7b638 778 var cancel = selectnode.one('#fp-cancel-'+client_id);
99eaca9d 779 cancel.on('click', function(e) {
b5e7b638
MG
780 e.preventDefault();
781 this.selectui.hide();
99eaca9d 782 }, this);
99eaca9d 783 },
b5e7b638
MG
784 wait: function() {
785 this.fpnode.one('.fp-content').setContent(M.core_filepicker.templates.loading);
786 },
787 viewbar_set_enabled: function(mode) {
788 var viewbar = this.fpnode.one('.fp-viewbar')
789 if (viewbar) {
790 if (mode) {
791 viewbar.addClass('enabled').removeClass('disabled')
792 } else {
793 viewbar.removeClass('enabled').addClass('disabled')
794 }
99eaca9d 795 }
b5e7b638
MG
796 this.fpnode.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').removeClass('checked')
797 var modes = {1:'icons', 2:'tree', 3:'details'};
798 this.fpnode.all('.fp-vb-'+modes[this.viewmode]).addClass('checked');
799 },
800 viewbar_clicked: function(e) {
801 e.preventDefault();
802 var viewbar = this.fpnode.one('.fp-viewbar')
803 if (!viewbar || !viewbar.hasClass('disabled')) {
804 if (e.currentTarget.hasClass('fp-vb-tree')) {
805 this.viewmode = 2;
806 } else if (e.currentTarget.hasClass('fp-vb-details')) {
807 this.viewmode = 3;
808 } else {
809 this.viewmode = 1;
810 }
811 this.viewbar_set_enabled(true)
812 this.view_files();
813 Y.Cookie.set('recentviewmode', this.viewmode);
99eaca9d
DC
814 }
815 },
816 render: function() {
817 var client_id = this.options.client_id;
b5e7b638
MG
818 var nodecontent = M.core_filepicker.templates.generallayout.
819 replace(/\{TOOLBARID}/g, 'fp-tb-'+client_id).
820 replace(/\{TOOLBACKID}/g, 'fp-tb-back-'+client_id).
821 replace(/\{TOOLSEARCHID}/g, 'fp-tb-search-'+client_id).
822 replace(/\{TOOLREFRESHID}/g, 'fp-tb-refresh-'+client_id).
823 replace(/\{TOOLLOGOUTID}/g, 'fp-tb-logout-'+client_id).
824 replace(/\{TOOLMANAGEID}/g, 'fp-tb-manage-'+client_id).
825 replace(/\{TOOLHELPID}/g, 'fp-tb-help-'+client_id);
3a1e425b 826 this.fpnode = Y.Node.create(nodecontent).set('id', 'filepicker-'+client_id);
b5e7b638
MG
827 var fpselectnode = Y.Node.create(M.core_filepicker.templates.selectlayout.
828 replace(/\{IMGID}/g, 'img-'+client_id).
829 replace(/\{NEWNAMEID}/g, 'newname-'+client_id).
830 replace(/\{LINKEXTID}/g, 'linkexternal-'+client_id).
831 replace(/\{AUTHORID}/g, 'text-author-'+client_id).
832 replace(/\{LICENSEID}/g, 'select-license-'+client_id).
833 replace(/\{BUTCONFIRMID}/g, 'fp-confirm-'+client_id).
834 replace(/\{BUTCANCELID}/g, 'fp-cancel-'+client_id)
835 );
836 Y.one(document.body).appendChild(this.fpnode);
837 this.fpnode.appendChild(fpselectnode);
838 this.mainui = new Y.Panel({
839 srcNode : this.fpnode,
840 headerContent: M.str.repository.filepicker,
841 zIndex : 500000,
842 centered : true,
843 modal : true,
844 visible : false,
845 render : true,
846 plugins : [Y.Plugin.Drag]
99eaca9d 847 });
b5e7b638
MG
848 this.mainui.show();
849 this.selectui = new Y.Panel({
850 srcNode : fpselectnode,
851 zIndex : 600000,
852 centered : true,
853 modal : true,
854 close : true,
855 render : true
99eaca9d 856 });
b5e7b638
MG
857 this.selectui.hide();
858 // save template for one path element and location of path bar
859 if (this.fpnode.one('.fp-path-folder')) {
860 this.pathnode = this.fpnode.one('.fp-path-folder');
861 this.pathbar = this.pathnode.get('parentNode');
862 this.pathbar.removeChild(this.pathnode);
863 }
864 // assign callbacks for view mode switch buttons
865 this.fpnode.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').
866 on('click', this.viewbar_clicked, this);
867 // assign callbacks for toolbar links
868 this.setup_toolbar();
869 this.setup_select_file();
3a1e425b 870 this.hide_header();
934291d6 871
99eaca9d 872 // processing repository listing
b5e7b638
MG
873 // Resort the repositories by sortorder
874 var sorted_repositories = []
875 for (var i in this.options.repositories) {
876 sorted_repositories[i] = this.options.repositories[i]
877 }
878 sorted_repositories.sort(function(a,b){return a.sortorder-b.sortorder})
879 // extract one repository template and repeat it for all repositories available,
880 // set name and icon and assign callbacks
881 var reponode = this.fpnode.one('.fp-repo');
882 if (reponode) {
883 var list = reponode.get('parentNode');
884 list.removeChild(reponode);
885 for (i in sorted_repositories) {
886 var repository = sorted_repositories[i]
887 var node = reponode.cloneNode(true);
888 list.appendChild(node);
889 node.
890 set('id', 'fp-repo-'+client_id+'-'+repository.id).
891 on('click', function(e, repository_id) {
892 e.preventDefault();
893 Y.Cookie.set('recentrepository', repository_id);
894 this.hide_header();
895 this.list({'repo_id':repository_id});
896 }, this /*handler running scope*/, repository.id/*second argument of handler*/);
897 node.one('.fp-repo-name').setContent(repository.name)
898 node.one('.fp-repo-icon').set('src', repository.icon)
899 if (i==0) {node.addClass('first');}
900 if (i==sorted_repositories.length-1) {node.addClass('last');}
901 if (i%2) {node.addClass('even');} else {node.addClass('odd');}
99eaca9d 902 }
b5e7b638
MG
903 }
904 // display error if no repositories found
905 if (sorted_repositories.length==0) {
3a1e425b 906 this.display_error(M.str.repository.norepositoriesavailable, 'norepositoriesavailable')
b5e7b638
MG
907 }
908 // display repository that was used last time
909 this.show_recent_repository();
99eaca9d
DC
910 },
911 parse_repository_options: function(data) {
912 this.filelist = data.list?data.list:null;
913 this.filepath = data.path?data.path:null;
914 this.active_repo = {};
4adecd7b 915 this.active_repo.issearchresult = data.issearchresult?true:false;
98b15580 916 this.active_repo.dynload = data.dynload?data.dynload:false;
99eaca9d
DC
917 this.active_repo.pages = Number(data.pages?data.pages:null);
918 this.active_repo.page = Number(data.page?data.page:null);
919 this.active_repo.id = data.repo_id?data.repo_id:null;
b5e7b638
MG
920 this.active_repo.nosearch = (data.login || data.nosearch); // this is either login form or 'nosearch' attribute set
921 this.active_repo.norefresh = (data.login || data.norefresh); // this is either login form or 'norefresh' attribute set
922 this.active_repo.nologin = (data.login || data.nologin); // this is either login form or 'nologin' attribute is set
fdfb9cbe 923 this.active_repo.logouttext = data.logouttext?data.logouttext:null;
99eaca9d
DC
924 this.active_repo.help = data.help?data.help:null;
925 this.active_repo.manage = data.manage?data.manage:null;
b5e7b638 926 this.print_header();
99eaca9d
DC
927 },
928 print_login: function(data) {
97b151ea 929 this.parse_repository_options(data);
99eaca9d
DC
930 var client_id = this.options.client_id;
931 var repository_id = data.repo_id;
932 var l = this.logindata = data.login;
933 var loginurl = '';
3a1e425b 934 var action = data['login_btn_action'] ? data['login_btn_action'] : 'login';
99eaca9d 935 var form_id = 'fp-form-'+client_id;
99eaca9d 936
5ce13292
MG
937 var loginform_node = Y.Node.create(M.core_filepicker.templates.loginform);
938 loginform_node.one('form').set('id', form_id);
939 this.fpnode.one('.fp-content').setContent('').appendChild(loginform_node);
940 var templates = {
941 'popup' : loginform_node.one('.fp-login-popup'),
942 'textarea' : loginform_node.one('.fp-login-textarea'),
943 'select' : loginform_node.one('.fp-login-select'),
944 'text' : loginform_node.one('.fp-login-text'),
3a1e425b 945 'radio' : loginform_node.one('.fp-login-radiogroup'),
5ce13292
MG
946 'checkbox' : loginform_node.one('.fp-login-checkbox'),
947 'input' : loginform_node.one('.fp-login-input')
948 };
949 var container;
950 for (var i in templates) {
951 if (templates[i]) {
952 container = templates[i].get('parentNode');
953 container.removeChild(templates[i])
954 }
955 }
956
957 for(var k in l) {
958 if (templates[l[k].type]) {
959 var node = templates[l[k].type].cloneNode(true);
960 } else {
961 node = templates['input'].cloneNode(true);
962 }
963 if (l[k].type == 'popup') {
3a1e425b 964 // submit button
2f6749f4 965 loginurl = l[k].url;
3a1e425b
MG
966 var popupbutton = node.one('button');
967 popupbutton.on('click', function(e){
968 M.core_filepicker.active_filepicker = this;
969 window.open(loginurl, 'repo_auth', 'location=0,status=0,width=500,height=300,scrollbars=yes');
970 e.preventDefault();
971 }, this);
972 loginform_node.one('form').on('keydown', function(e) {
973 if (e.keyCode == 13) {
974 popupbutton.simulate('click');
975 e.preventDefault();
976 }
977 }, this);
5ce13292
MG
978 loginform_node.all('.fp-login-submit').remove();
979 action = 'popup';
980 }else if(l[k].type=='textarea') {
981 // textarea element
982 if (node.one('label')) { node.one('label').set('for', l[k].id).setContent(l[k].label) }
3a1e425b 983 node.one('textarea').setAttrs({id:l[k].id, name:l[k].name});
5ce13292
MG
984 }else if(l[k].type=='select') {
985 // select element
986 if (node.one('label')) { node.one('label').set('for', l[k].id).setContent(l[k].label) }
3a1e425b 987 node.one('select').setAttrs({id:l[k].id, name:l[k].name}).setContent('');
5ce13292
MG
988 for (i in l[k].options) {
989 node.one('select').appendChild(
990 Y.Node.create('<option/>').
991 set('value', l[k].options[i].value).
992 setContent(l[k].options[i].label))
993 }
994 }else if(l[k].type=='radio') {
995 // radio input element
3a1e425b
MG
996 node.all('label').setContent(l[k].label);
997 var list = l[k].value.split('|');
998 var labels = l[k].value_label.split('|');
999 var radionode = null;
1000 for(var item in list) {
1001 if (radionode == null) {
1002 radionode = node.one('.fp-login-radio');
1003 radionode.one('input').set('checked', 'checked');
1004 } else {
1005 var x = radionode.cloneNode(true);
1006 radionode.insert(x, 'after');
1007 radionode = x;
1008 radionode.one('input').set('checked', '');
1009 }
1010 radionode.one('input').setAttrs({id:''+l[k].id+item, name:l[k].name,
1011 type:l[k].type, value:list[item]});
1012 radionode.all('label').setContent(labels[item]).set('for', ''+l[k].id+item)
1013 }
1014 if (radionode == null) {
1015 node.one('.fp-login-radio').remove();
1016 }
5ce13292
MG
1017 }else {
1018 // input element
1019 if (node.one('label')) { node.one('label').set('for', l[k].id).setContent(l[k].label) }
1020 node.one('input').
1021 set('type', l[k].type).
1022 set('id', l[k].id).
1023 set('name', l[k].name).
1024 set('value', l[k].value?l[k].value:'')
1025 }
1026 container.appendChild(node);
1027 }
3a1e425b
MG
1028 // custom label text for submit button
1029 if (data['login_btn_label']) {
1030 loginform_node.all('.fp-login-submit').setContent(data['login_btn_label'])
99eaca9d 1031 }
3a1e425b
MG
1032 // register button action for login and search
1033 if (action == 'login' || action == 'search') {
1034 loginform_node.one('.fp-login-submit').on('click', function(e){
5ce13292 1035 e.preventDefault();
b5e7b638 1036 this.hide_header();
99eaca9d 1037 this.request({
3a1e425b
MG
1038 'scope': this,
1039 'action':(action == 'search') ? 'search' : 'signin',
99eaca9d
DC
1040 'path': '',
1041 'client_id': client_id,
1042 'repository_id': repository_id,
3a1e425b 1043 'form': {id:form_id, upload:false, useDisabled:true},
4adecd7b 1044 'callback': this.display_response
99eaca9d
DC
1045 }, true);
1046 }, this);
1047 }
3a1e425b
MG
1048 // if 'Enter' is pressed in the form, simulate the button click
1049 if (loginform_node.one('.fp-login-submit')) {
1050 loginform_node.one('form').on('keydown', function(e) {
1051 if (e.keyCode == 13) {
1052 loginform_node.one('.fp-login-submit').simulate('click')
1053 e.preventDefault();
99eaca9d 1054 }
99eaca9d
DC
1055 }, this);
1056 }
99eaca9d 1057 },
4adecd7b
MG
1058 display_response: function(id, obj, args) {
1059 var scope = args.scope
1060 // highlight the current repository in repositories list
b5e7b638
MG
1061 scope.fpnode.all('.fp-repo.active').removeClass('active');
1062 scope.fpnode.all('#fp-repo-'+scope.options.client_id+'-'+obj.repo_id).addClass('active')
5ce13292
MG
1063 // add class repository_REPTYPE to the filepicker (for repository-specific styles)
1064 for (var i in scope.options.repositories) {
1065 scope.fpnode.removeClass('repository_'+scope.options.repositories[i].type)
1066 }
1067 if (obj.repo_id && scope.options.repositories[obj.repo_id]) {
1068 scope.fpnode.addClass('repository_'+scope.options.repositories[obj.repo_id].type)
1069 }
4adecd7b
MG
1070 // display response
1071 if (obj.login) {
b5e7b638 1072 scope.viewbar_set_enabled(false);
4adecd7b
MG
1073 scope.print_login(obj);
1074 } else if (obj.upload) {
b5e7b638 1075 scope.viewbar_set_enabled(false);
4adecd7b
MG
1076 scope.parse_repository_options(obj);
1077 scope.create_upload_form(obj);
1078 } else if (obj.iframe) {
99eaca9d 1079
4adecd7b 1080 } else if (obj.list) {
b5e7b638 1081 scope.viewbar_set_enabled(true);
4adecd7b
MG
1082 scope.parse_repository_options(obj);
1083 scope.view_files();
99eaca9d 1084 }
99eaca9d
DC
1085 },
1086 list: function(args) {
99eaca9d
DC
1087 if (!args) {
1088 args = {};
1089 }
1090 if (!args.repo_id) {
4adecd7b 1091 args.repo_id = this.active_repo.id;
99eaca9d 1092 }
4adecd7b
MG
1093 this.request({
1094 action: 'list',
1095 client_id: this.options.client_id,
99eaca9d 1096 repository_id: args.repo_id,
4adecd7b
MG
1097 path: args.path,
1098 page: args.page,
1099 scope: this,
1100 callback: this.display_response
99eaca9d
DC
1101 }, true);
1102 },
b5e7b638
MG
1103 populate_licenses_select: function(node) {
1104 if (!node) {
1105 return;
e35194be 1106 }
b5e7b638 1107 node.setContent('');
1dce6261 1108 var licenses = this.options.licenses;
b5e7b638 1109 var recentlicense = Y.Cookie.get('recentlicense');
a756cb37
DC
1110 if (recentlicense) {
1111 this.options.defaultlicense=recentlicense;
1112 }
1dce6261 1113 for (var i in licenses) {
b5e7b638
MG
1114 var option = Y.Node.create('<option/>').
1115 set('selected', (this.options.defaultlicense==licenses[i].shortname)).
1116 set('value', licenses[i].shortname).
1117 setContent(licenses[i].fullname);
1118 node.appendChild(option)
1dce6261 1119 }
b5e7b638
MG
1120 },
1121 create_upload_form: function(data) {
1122 var client_id = this.options.client_id;
1123 var id = data.upload.id+'_'+client_id;
1124 var str = M.core_filepicker.templates.uploadform.
1125 replace(/\{UPLOADFORMID}/g, id).
1126 replace(/\{INPUTFILEID}/g, id+'_file').
1127 replace(/\{NEWNAMEID}/g, 'newname-'+client_id).
1128 replace(/\{AUTHORID}/g, 'author-'+client_id).
1129 replace(/\{LICENSEID}/g, 'license-'+client_id).
1130 replace(/\{BUTUPLOADID}/g, id+'_action');
1131 this.fpnode.one('.fp-content').setContent(str);
1132
1133 Y.all('#'+id+'_file').set('name', 'repo_upload_file');
1134 Y.all('#'+'newname-'+client_id).set('name', 'title');
1135 Y.all('#'+'author-'+client_id).set('name', 'author');
1136 Y.all('#'+'author-'+client_id).set('value', this.options.author);
1137 Y.all('#'+'license-'+client_id).set('name', 'license');
1138 this.populate_licenses_select(Y.one('#'+'license-'+client_id))
3a1e425b
MG
1139 Y.one('#'+id).appendChild(Y.Node.create('<input/>').
1140 setAttrs({type:'hidden',name:'itemid',value:this.options.itemid}));
b5e7b638
MG
1141 var types = this.options.accepted_types;
1142 for (var i in types) {
3a1e425b
MG
1143 Y.one('#'+id).appendChild(Y.Node.create('<input/>').
1144 setAttrs({type:'hidden',name:'accepted_types[]',value:types[i]}));
b5e7b638
MG
1145 }
1146
99eaca9d 1147 var scope = this;
46325d3e 1148 Y.one('#'+id+'_action').on('click', function(e) {
8cbef19e 1149 e.preventDefault();
b5e7b638
MG
1150 var license = Y.one('#license-'+client_id);
1151 Y.Cookie.set('recentlicense', license.get('value'));
2a03b97b 1152 if (!Y.one('#'+id+'_file').get('value')) {
ce6297d2 1153 scope.print_msg(M.str.repository.nofilesattached, 'error');
2a03b97b
DC
1154 return false;
1155 }
b5e7b638 1156 this.hide_header();
9d753c38
PS
1157 scope.request({
1158 scope: scope,
1159 action:'upload',
1160 client_id: client_id,
1161 params: {'savepath':scope.options.savepath},
1162 repository_id: scope.active_repo.id,
1163 form: {id: id, upload:true},
a5159b86
MG
1164 onerror: function(id, o, args) {
1165 scope.create_upload_form(data);
1166 },
9d753c38
PS
1167 callback: function(id, o, args) {
1168 if (scope.options.editor_target&&scope.options.env=='editor') {
1169 scope.options.editor_target.value=o.url;
1170 scope.options.editor_target.onchange();
0c4edaa2 1171 }
9d753c38
PS
1172 scope.hide();
1173 o.client_id = client_id;
1174 var formcallback_scope = null;
1175 if (args.scope.options.magicscope) {
1176 formcallback_scope = args.scope.options.magicscope;
1177 } else {
1178 formcallback_scope = args.scope;
1179 }
1180 scope.options.formcallback.apply(formcallback_scope, [o]);
1181 }
1182 }, true);
99eaca9d
DC
1183 }, this);
1184 },
b5e7b638
MG
1185 /** setting handlers and labels for elements in toolbar. Called once during the initial render of filepicker */
1186 setup_toolbar: function() {
99eaca9d 1187 var client_id = this.options.client_id;
b5e7b638
MG
1188 Y.one('#fp-tb-logout-'+client_id).on('click', function(e) {
1189 e.preventDefault();
1190 if (!this.active_repo.nologin) {
1191 this.hide_header();
1192 this.request({
1193 action:'logout',
1194 client_id: this.options.client_id,
1195 repository_id: this.active_repo.id,
1196 path:'',
1197 callback: this.display_response
1198 }, true);
1199 }
1200 }, this);
1201 Y.one('#fp-tb-refresh-'+client_id).on('click', function(e) {
1202 e.preventDefault();
1203 if (!this.active_repo.norefresh) {
1204 this.list();
1205 }
1206 }, this);
1207 Y.one('#fp-tb-search-'+client_id).
1208 set('method', 'POST').
1209 on('submit', function(e) {
4adecd7b 1210 e.preventDefault();
b5e7b638
MG
1211 if (!this.active_repo.nosearch) {
1212 this.request({
1213 scope: this,
1214 action:'search',
1215 client_id: this.options.client_id,
1216 repository_id: this.active_repo.id,
1217 form: {id: 'fp-tb-search-'+client_id, upload:false, useDisabled:true},
1218 callback: this.display_response
1219 }, true);
1220 }
1221 }, this);
99eaca9d 1222
b5e7b638
MG
1223 // it does not matter what kind of element is {TOOLMANAGEID}, we create a dummy <a>
1224 // element and use it to open url on click event
3a1e425b
MG
1225 var managelnk = Y.Node.create('<a/>').
1226 setAttrs({id:'fp-tb-manage-'+client_id+'-link', target:'_blank'}).
1227 setStyle('display', 'none');
b5e7b638
MG
1228 Y.one('#fp-tb-'+client_id).append(managelnk);
1229 Y.one('#fp-tb-manage-'+client_id).on('click', function(e) {
1230 e.preventDefault();
1231 managelnk.simulate('click')
1232 });
99eaca9d 1233
b5e7b638 1234 // same with {TOOLHELPID}
3a1e425b
MG
1235 var helplnk = Y.Node.create('<a/>').
1236 setAttrs({id:'fp-tb-help-'+client_id+'-link', target:'_blank'}).
1237 setStyle('display', 'none');
b5e7b638
MG
1238 Y.one('#fp-tb-'+client_id).append(helplnk);
1239 Y.one('#fp-tb-help-'+client_id).on('click', function(e) {
1240 e.preventDefault();
1241 helplnk.simulate('click')
1242 });
1243 },
1244 hide_header: function() {
1245 var client_id = this.options.client_id;
1246 if (Y.one('#fp-tb-'+client_id)) {
1247 Y.one('#fp-tb-'+client_id).addClass('empty');
1248 }
3a1e425b
MG
1249 if (this.pathbar) {
1250 this.pathbar.setContent('').addClass('empty');
1251 }
1252 if (this.fpnode.one('.fp-paging')) {
1253 this.fpnode.one('.fp-paging').setContent('').addClass('empty');
1254 }
b5e7b638
MG
1255 },
1256 print_header: function() {
1257 var r = this.active_repo;
1258 var scope = this;
1259 var client_id = this.options.client_id;
2f6749f4 1260 this.hide_header();
b5e7b638 1261 this.print_paging();
99eaca9d 1262
b5e7b638
MG
1263 var enable_tb_control = function(elementid, enabled) {
1264 if (!enabled) {
1265 Y.all('#'+elementid+',#wrap-'+elementid).addClass('disabled').removeClass('enabled')
1266 } else {
1267 Y.all('#'+elementid+',#wrap-'+elementid).removeClass('disabled').addClass('enabled')
1268 Y.one('#fp-tb-'+client_id).removeClass('empty');
1269 }
1270 }
99eaca9d 1271
b5e7b638
MG
1272 // TODO 'back' permanently disabled for now. Note, flickr_public uses 'Logout' for it!
1273 enable_tb_control('fp-tb-back-'+client_id, false);
99eaca9d 1274
b5e7b638
MG
1275 // search form
1276 enable_tb_control('fp-tb-search-'+client_id, !r.nosearch);
1277 if(!r.nosearch) {
1278 Y.all('#fp-tb-search-'+client_id).setContent('');
1279 this.request({
1280 scope: this,
1281 action:'searchform',
1282 repository_id: this.active_repo.id,
1283 callback: function(id, obj, args) {
1284 if (obj.repo_id == scope.active_repo.id && obj.form) {
1285 // if we did not jump to another repository meanwhile
1286 Y.all('#fp-tb-search-'+scope.options.client_id).setContent(obj.form);
99eaca9d 1287 }
b5e7b638
MG
1288 }
1289 }, false);
99eaca9d 1290 }
b5e7b638
MG
1291
1292 // refresh button
99eaca9d 1293 // weather we use cache for this instance, this button will reload listing anyway
b5e7b638
MG
1294 enable_tb_control('fp-tb-refresh-'+client_id, !r.norefresh);
1295
1296 // login button
1297 enable_tb_control('fp-tb-logout-'+client_id, !r.nologin);
99eaca9d 1298 if(!r.nologin) {
fdfb9cbe 1299 var label = r.logouttext?r.logouttext:M.str.repository.logout;
b5e7b638 1300 Y.one('#fp-tb-logout-'+client_id).setContent(label)
99eaca9d
DC
1301 }
1302
b5e7b638
MG
1303 // manage url
1304 enable_tb_control('fp-tb-manage-'+client_id, r.manage);
1305 Y.one('#fp-tb-manage-'+client_id+'-link').set('href', r.manage);
1306
1307 // help url
1308 enable_tb_control('fp-tb-help-'+client_id, r.help);
1309 Y.one('#fp-tb-help-'+client_id+'-link').set('href', r.help);
99eaca9d 1310
ea44dd2e 1311 this.print_path();
99eaca9d
DC
1312 },
1313 get_page_button: function(page) {
1314 var r = this.active_repo;
1315 var css = '';
1316 if (page == r.page) {
1317 css = 'class="cur_page" ';
1318 }
1319 var str = '<a '+css+'href="###" id="repo-page-'+page+'">';
1320 return str;
1321 },
1322 print_paging: function(html_id) {
b5e7b638 1323 // TODO !!!
99eaca9d
DC
1324 var client_id = this.options.client_id;
1325 var scope = this;
1326 var r = this.active_repo;
1327 var str = '';
1328 var action = '';
8ebbe295
EL
1329 var lastpage = r.pages;
1330 var lastpagetext = r.pages;
20ee5084 1331 if (r.pages == -1) {
8ebbe295
EL
1332 lastpage = r.page + 1;
1333 lastpagetext = M.str.moodle.next;
20ee5084 1334 }
8ebbe295 1335 if (lastpage > 1) {
99eaca9d
DC
1336 str += this.get_page_button(1)+'1</a> ';
1337
1338 var span = 5;
1339 var ex = (span-1)/2;
1340
20ee5084
MG
1341 if (r.page+ex>=lastpage) {
1342 var max = lastpage;
99eaca9d
DC
1343 } else {
1344 if (r.page<span) {
1345 var max = span;
1346 } else {
1347 var max = r.page+ex;
1348 }
1349 }
1350
1351 // won't display upper boundary
1352 if (r.page >= span) {
1353 str += ' ... ';
1354 for(var i=r.page-ex; i<max; i++) {
1355 str += this.get_page_button(i);
1356 str += String(i);
1357 str += '</a> ';
1358 }
1359 } else {
1360 // this very first elements
1361 for(var i = 2; i < max; i++) {
1362 str += this.get_page_button(i);
1363 str += String(i);
1364 str += '</a> ';
1365 }
1366 }
1367
1368 // won't display upper boundary
20ee5084
MG
1369 if (max==lastpage) {
1370 str += this.get_page_button(lastpage)+lastpagetext+'</a>';
99eaca9d
DC
1371 } else {
1372 str += this.get_page_button(max)+max+'</a>';
20ee5084 1373 str += ' ... '+this.get_page_button(lastpage)+lastpagetext+'</a>';
99eaca9d 1374 }
99eaca9d 1375 }
b5e7b638
MG
1376 this.fpnode.one('.fp-paging').setContent(str);
1377 this.fpnode.all('.fp-paging a').on('click', function(e) {
4adecd7b 1378 e.preventDefault();
b5e7b638 1379 var id = e.currentTarget.get('id');
99eaca9d
DC
1380 var re = new RegExp("repo-page-(\\d+)", "i");
1381 var result = id.match(re);
1382 var args = {};
1383 args.page = result[1];
1384 if (scope.active_repo.issearchresult) {
1385 scope.request({
1386 scope: scope,
1387 action:'search',
1388 client_id: client_id,
1389 repository_id: r.id,
1390 params: {'page':result[1]},
4adecd7b 1391 callback: scope.display_response
99eaca9d
DC
1392 }, true);
1393
1394 } else {
4adecd7b 1395 scope.list(args);
99eaca9d
DC
1396 }
1397 });
99eaca9d
DC
1398 },
1399 print_path: function() {
b5e7b638 1400 if (!this.pathbar) { return; }
3a1e425b 1401 this.pathbar.setContent('').addClass('empty');
99eaca9d 1402 var p = this.filepath;
2f6749f4 1403 if (p && p.length!=0 && this.viewmode != 2) {
99eaca9d 1404 for(var i = 0; i < p.length; i++) {
b5e7b638
MG
1405 var el = this.pathnode.cloneNode(true);
1406 this.pathbar.appendChild(el);
1407 if (i == 0) {el.addClass('first');}
1408 if (i == p.length-1) {el.addClass('last');}
1409 if (i%2) {el.addClass('even');} else {el.addClass('odd');}
1410 el.all('.fp-path-folder-name').setContent(p[i].name);
1411 el.on('click',
1412 function(e, path) {
1413 e.preventDefault();
1414 this.list({'path':path});
1415 },
1416 this, p[i].path);
99eaca9d 1417 }
b5e7b638 1418 this.pathbar.removeClass('empty');
99eaca9d
DC
1419 }
1420 },
1421 hide: function() {
b5e7b638
MG
1422 this.selectui.hide();
1423 if (this.process_dlg) {
1424 this.process_dlg.hide();
1425 }
1426 if (this.msg_dlg) {
1427 this.msg_dlg.hide();
1428 }
99eaca9d
DC
1429 this.mainui.hide();
1430 },
1431 show: function() {
b5e7b638
MG
1432 if (this.fpnode) {
1433 this.hide();
99eaca9d 1434 this.mainui.show();
a756cb37 1435 this.show_recent_repository();
99eaca9d
DC
1436 } else {
1437 this.launch();
1438 }
1439 },
1440 launch: function() {
7b42e81a 1441 this.render();
a756cb37
DC
1442 },
1443 show_recent_repository: function() {
b5e7b638
MG
1444 this.hide_header();
1445 this.viewbar_set_enabled(false);
1446 var repository_id = Y.Cookie.get('recentrepository');
1447 this.viewmode = Y.Cookie.get('recentviewmode', Number);
5bdf63cc 1448 if (this.viewmode != 2 && this.viewmode != 3) {
b5e7b638
MG
1449 this.viewmode = 1;
1450 }
a756cb37
DC
1451 if (this.options.repositories[repository_id]) {
1452 this.list({'repo_id':repository_id});
1453 }
99eaca9d
DC
1454 }
1455 });
bb496de7
DC
1456 var loading = Y.one('#filepicker-loading-'+options.client_id);
1457 if (loading) {
1458 loading.setStyle('display', 'none');
1459 }
4c508047
PS
1460 M.core_filepicker.instances[options.client_id] = new FilePickerHelper(options);
1461};