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