[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 // YUI3 File Picker module for moodle 2 // Author: Dongsheng Cai <dongsheng@moodle.com> 3 4 /** 5 * 6 * File Picker UI 7 * ===== 8 * this.fpnode, contains reference to filepicker Node, non-empty if and only if rendered 9 * this.api, stores the URL to make ajax request 10 * this.mainui, YUI Panel 11 * this.selectnode, contains reference to select-file Node 12 * this.selectui, YUI Panel for selecting particular file 13 * this.msg_dlg, YUI Panel for error or info message 14 * this.process_dlg, YUI Panel for processing existing filename 15 * this.treeview, YUI Treeview 16 * this.viewmode, store current view mode 17 * this.pathbar, reference to the Node with path bar 18 * this.pathnode, a Node element representing one folder in a path bar (not attached anywhere, just used for template) 19 * this.currentpath, the current path in the repository (or last requested path) 20 * 21 * Filepicker options: 22 * ===== 23 * this.options.client_id, the instance id 24 * this.options.contextid 25 * this.options.itemid 26 * this.options.repositories, stores all repositories displayed in file picker 27 * this.options.formcallback 28 * 29 * Active repository options 30 * ===== 31 * this.active_repo.id 32 * this.active_repo.nosearch 33 * this.active_repo.norefresh 34 * this.active_repo.nologin 35 * this.active_repo.help 36 * this.active_repo.manage 37 * 38 * Server responses 39 * ===== 40 * this.filelist, cached filelist 41 * this.pages 42 * this.page 43 * this.filepath, current path (each element of the array is a part of the breadcrumb) 44 * this.logindata, cached login form 45 */ 46 47 YUI.add('moodle-core_filepicker', function(Y) { 48 /** help function to extract width/height style as a number, not as a string */ 49 Y.Node.prototype.getStylePx = function(attr) { 50 var style = this.getStyle(attr); 51 if (''+style == '0' || ''+style == '0px') { 52 return 0; 53 } 54 var matches = style.match(/^([\d\.]+)px$/) 55 if (matches && parseFloat(matches[1])) { 56 return parseFloat(matches[1]); 57 } 58 return null; 59 } 60 61 /** if condition is met, the class is added to the node, otherwise - removed */ 62 Y.Node.prototype.addClassIf = function(className, condition) { 63 if (condition) { 64 this.addClass(className); 65 } else { 66 this.removeClass(className); 67 } 68 return this; 69 } 70 71 /** sets the width(height) of the node considering existing minWidth(minHeight) */ 72 Y.Node.prototype.setStyleAdv = function(stylename, value) { 73 var stylenameCap = stylename.substr(0,1).toUpperCase() + stylename.substr(1, stylename.length-1).toLowerCase(); 74 this.setStyle(stylename, '' + Math.max(value, this.getStylePx('min'+stylenameCap)) + 'px') 75 return this; 76 } 77 78 /** set image source to src, if there is preview, remember it in lazyloading. 79 * If there is a preview and it was already loaded, use it. */ 80 Y.Node.prototype.setImgSrc = function(src, realsrc, lazyloading) { 81 if (realsrc) { 82 if (M.core_filepicker.loadedpreviews[realsrc]) { 83 this.set('src', realsrc).addClass('realpreview'); 84 return this; 85 } else { 86 if (!this.get('id')) { 87 this.generateID(); 88 } 89 lazyloading[this.get('id')] = realsrc; 90 } 91 } 92 this.set('src', src); 93 return this; 94 } 95 96 /** 97 * Replaces the image source with preview. If the image is inside the treeview, we need 98 * also to update the html property of corresponding YAHOO.widget.HTMLNode 99 * @param array lazyloading array containing associations of imgnodeid->realsrc 100 */ 101 Y.Node.prototype.setImgRealSrc = function(lazyloading) { 102 if (this.get('id') && lazyloading[this.get('id')]) { 103 var newsrc = lazyloading[this.get('id')]; 104 M.core_filepicker.loadedpreviews[newsrc] = true; 105 this.set('src', newsrc).addClass('realpreview'); 106 delete lazyloading[this.get('id')]; 107 var treenode = this.ancestor('.fp-treeview') 108 if (treenode && treenode.get('parentNode').treeview) { 109 treenode.get('parentNode').treeview.getRoot().refreshPreviews(this.get('id'), newsrc); 110 } 111 } 112 return this; 113 } 114 115 /** scan TreeView to find which node contains image with id=imgid and replace it's html 116 * with the new image source. */ 117 Y.YUI2.widget.Node.prototype.refreshPreviews = function(imgid, newsrc, regex) { 118 if (!regex) { 119 regex = new RegExp("<img\\s[^>]*id=\""+imgid+"\"[^>]*?(/?)>", "im"); 120 } 121 if (this.expanded || this.isLeaf) { 122 var html = this.getContentHtml(); 123 if (html && this.setHtml && regex.test(html)) { 124 var newhtml = this.html.replace(regex, "<img id=\""+imgid+"\" src=\""+newsrc+"\" class=\"realpreview\"$1>", html); 125 this.setHtml(newhtml); 126 return true; 127 } 128 if (!this.isLeaf && this.children) { 129 for(var c in this.children) { 130 if (this.children[c].refreshPreviews(imgid, newsrc, regex)) { 131 return true; 132 } 133 } 134 } 135 } 136 return false; 137 } 138 139 /** 140 * Displays a list of files (used by filepicker, filemanager) inside the Node 141 * 142 * @param array options 143 * viewmode : 1 - icons, 2 - tree, 3 - table 144 * appendonly : whether fileslist need to be appended instead of replacing the existing content 145 * filenode : Node element that contains template for displaying one file 146 * callback : On click callback. The element of the fileslist array will be passed as argument 147 * rightclickcallback : On right click callback (optional). 148 * callbackcontext : context where callbacks are executed 149 * sortable : whether content may be sortable (in table mode) 150 * dynload : allow dynamic load for tree view 151 * filepath : for pre-building of tree view - the path to the current directory in filepicker format 152 * treeview_dynload : callback to function to dynamically load the folder in tree view 153 * classnamecallback : callback to function that returns the class name for an element 154 * @param array fileslist array of files to show, each array element may have attributes: 155 * title or fullname : file name 156 * shorttitle (optional) : display file name 157 * thumbnail : url of image 158 * icon : url of icon image 159 * thumbnail_width : width of thumbnail, default 90 160 * thumbnail_height : height of thumbnail, default 90 161 * thumbnail_alt : TODO not needed! 162 * description or thumbnail_title : alt text 163 * @param array lazyloading : reference to the array with lazy loading images 164 */ 165 Y.Node.prototype.fp_display_filelist = function(options, fileslist, lazyloading) { 166 var viewmodeclassnames = {1:'fp-iconview', 2:'fp-treeview', 3:'fp-tableview'}; 167 var classname = viewmodeclassnames[options.viewmode]; 168 var scope = this; 169 /** return whether file is a folder (different attributes in FileManager and FilePicker) */ 170 var file_is_folder = function(node) { 171 if (node.children) {return true;} 172 if (node.type && node.type == 'folder') {return true;} 173 return false; 174 }; 175 /** return the name of the file (different attributes in FileManager and FilePicker) */ 176 var file_get_filename = function(node) { 177 return node.title ? node.title : node.fullname; 178 }; 179 /** return display name of the file (different attributes in FileManager and FilePicker) */ 180 var file_get_displayname = function(node) { 181 var displayname = node.shorttitle ? node.shorttitle : file_get_filename(node); 182 return Y.Escape.html(displayname); 183 }; 184 /** return file description (different attributes in FileManager and FilePicker) */ 185 var file_get_description = function(node) { 186 var description = ''; 187 if (node.description) { 188 description = node.description; 189 } else if (node.thumbnail_title) { 190 description = node.thumbnail_title; 191 } else { 192 description = file_get_filename(node); 193 } 194 return Y.Escape.html(description); 195 }; 196 /** help funciton for tree view */ 197 var build_tree = function(node, level) { 198 // prepare file name with icon 199 var el = Y.Node.create('<div/>'); 200 el.appendChild(options.filenode.cloneNode(true)); 201 202 el.one('.fp-filename').setContent(file_get_displayname(node)); 203 // TODO add tooltip with node.title or node.thumbnail_title 204 var tmpnodedata = {className:options.classnamecallback(node)}; 205 el.get('children').addClass(tmpnodedata.className); 206 if (node.icon) { 207 el.one('.fp-icon').appendChild(Y.Node.create('<img/>')); 208 el.one('.fp-icon img').setImgSrc(node.icon, node.realicon, lazyloading); 209 } 210 // create node 211 tmpnodedata.html = el.getContent(); 212 var tmpNode = new Y.YUI2.widget.HTMLNode(tmpnodedata, level, false); 213 if (node.dynamicLoadComplete) { 214 tmpNode.dynamicLoadComplete = true; 215 } 216 tmpNode.fileinfo = node; 217 tmpNode.isLeaf = !file_is_folder(node); 218 if (!tmpNode.isLeaf) { 219 if(node.expanded) { 220 tmpNode.expand(); 221 } 222 tmpNode.path = node.path ? node.path : (node.filepath ? node.filepath : ''); 223 for(var c in node.children) { 224 build_tree(node.children[c], tmpNode); 225 } 226 } 227 }; 228 /** initialize tree view */ 229 var initialize_tree_view = function() { 230 var parentid = scope.one('.'+classname).get('id'); 231 // TODO MDL-32736 use YUI3 gallery TreeView 232 scope.treeview = new Y.YUI2.widget.TreeView(parentid); 233 if (options.dynload) { 234 scope.treeview.setDynamicLoad(Y.bind(options.treeview_dynload, options.callbackcontext), 1); 235 } 236 scope.treeview.singleNodeHighlight = true; 237 if (options.filepath && options.filepath.length) { 238 // we just jumped from icon/details view, we need to show all parents 239 // we extract as much information as possible from filepath and filelist 240 // and send additional requests to retrieve siblings for parent folders 241 var mytree = {}; 242 var mytreeel = null; 243 for (var i in options.filepath) { 244 if (mytreeel == null) { 245 mytreeel = mytree; 246 } else { 247 mytreeel.children = [{}]; 248 mytreeel = mytreeel.children[0]; 249 } 250 var pathelement = options.filepath[i]; 251 mytreeel.path = pathelement.path; 252 mytreeel.title = pathelement.name; 253 mytreeel.icon = pathelement.icon; 254 mytreeel.dynamicLoadComplete = true; // we will call it manually 255 mytreeel.expanded = true; 256 } 257 mytreeel.children = fileslist; 258 build_tree(mytree, scope.treeview.getRoot()); 259 // manually call dynload for parent elements in the tree so we can load other siblings 260 if (options.dynload) { 261 var root = scope.treeview.getRoot(); 262 while (root && root.children && root.children.length) { 263 root = root.children[0]; 264 if (root.path == mytreeel.path) { 265 root.origpath = options.filepath; 266 root.origlist = fileslist; 267 } else if (!root.isLeaf && root.expanded) { 268 Y.bind(options.treeview_dynload, options.callbackcontext)(root, null); 269 } 270 } 271 } 272 } else { 273 // there is no path information, just display all elements as a list, without hierarchy 274 for(k in fileslist) { 275 build_tree(fileslist[k], scope.treeview.getRoot()); 276 } 277 } 278 scope.treeview.subscribe('clickEvent', function(e){ 279 e.node.highlight(false); 280 var callback = options.callback; 281 if (options.rightclickcallback && e.event.target && 282 Y.Node(e.event.target).ancestor('.fp-treeview .fp-contextmenu', true)) { 283 callback = options.rightclickcallback; 284 } 285 Y.bind(callback, options.callbackcontext)(e, e.node.fileinfo); 286 Y.YUI2.util.Event.stopEvent(e.event) 287 }); 288 // TODO MDL-32736 support right click 289 /*if (options.rightclickcallback) { 290 scope.treeview.subscribe('dblClickEvent', function(e){ 291 e.node.highlight(false); 292 Y.bind(options.rightclickcallback, options.callbackcontext)(e, e.node.fileinfo); 293 }); 294 }*/ 295 scope.treeview.draw(); 296 }; 297 /** formatting function for table view */ 298 var formatValue = function (o){ 299 if (o.data[''+o.column.key+'_f_s']) {return o.data[''+o.column.key+'_f_s'];} 300 else if (o.data[''+o.column.key+'_f']) {return o.data[''+o.column.key+'_f'];} 301 else if (o.value) {return o.value;} 302 else {return '';} 303 }; 304 /** formatting function for table view */ 305 var formatTitle = function(o) { 306 var el = Y.Node.create('<div/>'); 307 el.appendChild(options.filenode.cloneNode(true)); // TODO not node but string! 308 el.get('children').addClass(o.data['classname']); 309 el.one('.fp-filename').setContent(o.value); 310 if (o.data['icon']) { 311 el.one('.fp-icon').appendChild(Y.Node.create('<img/>')); 312 el.one('.fp-icon img').setImgSrc(o.data['icon'], o.data['realicon'], lazyloading); 313 } 314 if (options.rightclickcallback) { 315 el.get('children').addClass('fp-hascontextmenu'); 316 } 317 // TODO add tooltip with o.data['title'] (o.value) or o.data['thumbnail_title'] 318 return el.getContent(); 319 } 320 /** sorting function for table view */ 321 var sortFoldersFirst = function(a, b, desc) { 322 if (a.get('isfolder') && !b.get('isfolder')) { 323 return -1; 324 } 325 if (!a.get('isfolder') && b.get('isfolder')) { 326 return 1; 327 } 328 var aa = a.get(this.key), bb = b.get(this.key), dir = desc ? -1 : 1; 329 return (aa > bb) ? dir : ((aa < bb) ? -dir : 0); 330 } 331 /** initialize table view */ 332 var initialize_table_view = function() { 333 var cols = [ 334 {key: "displayname", label: M.util.get_string('name', 'moodle'), allowHTML: true, formatter: formatTitle, 335 sortable: true, sortFn: sortFoldersFirst}, 336 {key: "datemodified", label: M.util.get_string('lastmodified', 'moodle'), allowHTML: true, formatter: formatValue, 337 sortable: true, sortFn: sortFoldersFirst}, 338 {key: "size", label: M.util.get_string('size', 'repository'), allowHTML: true, formatter: formatValue, 339 sortable: true, sortFn: sortFoldersFirst}, 340 {key: "mimetype", label: M.util.get_string('type', 'repository'), allowHTML: true, 341 sortable: true, sortFn: sortFoldersFirst} 342 ]; 343 scope.tableview = new Y.DataTable({columns: cols, data: fileslist}); 344 scope.tableview.delegate('click', function (e, tableview) { 345 var record = tableview.getRecord(e.currentTarget.get('id')); 346 if (record) { 347 var callback = options.callback; 348 if (options.rightclickcallback && e.target.ancestor('.fp-tableview .fp-contextmenu', true)) { 349 callback = options.rightclickcallback; 350 } 351 Y.bind(callback, this)(e, record.getAttrs()); 352 } 353 }, 'tr', options.callbackcontext, scope.tableview); 354 if (options.rightclickcallback) { 355 scope.tableview.delegate('contextmenu', function (e, tableview) { 356 var record = tableview.getRecord(e.currentTarget.get('id')); 357 if (record) { Y.bind(options.rightclickcallback, this)(e, record.getAttrs()); } 358 }, 'tr', options.callbackcontext, scope.tableview); 359 } 360 } 361 /** append items in table view mode */ 362 var append_files_table = function() { 363 if (options.appendonly) { 364 fileslist.forEach(function(el) { 365 this.tableview.data.add(el); 366 },scope); 367 } 368 scope.tableview.render(scope.one('.'+classname)); 369 scope.tableview.sortable = options.sortable ? true : false; 370 }; 371 /** append items in tree view mode */ 372 var append_files_tree = function() { 373 if (options.appendonly) { 374 var parentnode = scope.treeview.getRoot(); 375 if (scope.treeview.getHighlightedNode()) { 376 parentnode = scope.treeview.getHighlightedNode(); 377 if (parentnode.isLeaf) {parentnode = parentnode.parent;} 378 } 379 for (var k in fileslist) { 380 build_tree(fileslist[k], parentnode); 381 } 382 scope.treeview.draw(); 383 } else { 384 // otherwise files were already added in initialize_tree_view() 385 } 386 } 387 /** append items in icon view mode */ 388 var append_files_icons = function() { 389 parent = scope.one('.'+classname); 390 for (var k in fileslist) { 391 var node = fileslist[k]; 392 var element = options.filenode.cloneNode(true); 393 parent.appendChild(element); 394 element.addClass(options.classnamecallback(node)); 395 var filenamediv = element.one('.fp-filename'); 396 filenamediv.setContent(file_get_displayname(node)); 397 var imgdiv = element.one('.fp-thumbnail'), width, height, src; 398 if (node.thumbnail) { 399 width = node.thumbnail_width ? node.thumbnail_width : 90; 400 height = node.thumbnail_height ? node.thumbnail_height : 90; 401 src = node.thumbnail; 402 } else { 403 width = 16; 404 height = 16; 405 src = node.icon; 406 } 407 filenamediv.setStyleAdv('width', width); 408 imgdiv.setStyleAdv('width', width).setStyleAdv('height', height); 409 var img = Y.Node.create('<img/>').setAttrs({ 410 title: file_get_description(node), 411 alt: Y.Escape.html(node.thumbnail_alt ? node.thumbnail_alt : file_get_filename(node))}). 412 setStyle('maxWidth', ''+width+'px'). 413 setStyle('maxHeight', ''+height+'px'); 414 img.setImgSrc(src, node.realthumbnail, lazyloading); 415 imgdiv.appendChild(img); 416 element.on('click', function(e, nd) { 417 if (options.rightclickcallback && e.target.ancestor('.fp-iconview .fp-contextmenu', true)) { 418 Y.bind(options.rightclickcallback, this)(e, nd); 419 } else { 420 Y.bind(options.callback, this)(e, nd); 421 } 422 }, options.callbackcontext, node); 423 if (options.rightclickcallback) { 424 element.on('contextmenu', options.rightclickcallback, options.callbackcontext, node); 425 } 426 } 427 } 428 429 // If table view, need some additional properties 430 // before passing fileslist to the YUI tableview 431 if (options.viewmode == 3) { 432 fileslist.forEach(function(el) { 433 el.displayname = file_get_displayname(el); 434 el.isfolder = file_is_folder(el); 435 el.classname = options.classnamecallback(el); 436 }, scope); 437 } 438 439 // initialize files view 440 if (!options.appendonly) { 441 var parent = Y.Node.create('<div/>').addClass(classname); 442 this.setContent('').appendChild(parent); 443 parent.generateID(); 444 if (options.viewmode == 2) { 445 initialize_tree_view(); 446 } else if (options.viewmode == 3) { 447 initialize_table_view(); 448 } else { 449 // nothing to initialize for icon view 450 } 451 } 452 453 // append files to the list 454 if (options.viewmode == 2) { 455 append_files_tree(); 456 } else if (options.viewmode == 3) { 457 append_files_table(); 458 } else { 459 append_files_icons(); 460 } 461 462 } 463 464 /** 465 * creates a node and adds it to the div with id #filesskin. This is needed for CSS to be able 466 * to overwrite YUI skin styles (instead of using !important that does not work in IE) 467 */ 468 Y.Node.createWithFilesSkin = function(node) { 469 if (!Y.one('#filesskin')) { 470 Y.one(document.body).appendChild(Y.Node.create('<div/>').set('id', 'filesskin')); 471 } 472 return Y.one('#filesskin').appendChild(Y.Node.create(node)); 473 } 474 }, '@VERSION@', { 475 requires:['base', 'node', 'yui2-treeview', 'panel', 'cookie', 'datatable', 'datatable-sort'] 476 }); 477 478 M.core_filepicker = M.core_filepicker || {}; 479 480 /** 481 * instances of file pickers used on page 482 */ 483 M.core_filepicker.instances = M.core_filepicker.instances || {}; 484 M.core_filepicker.active_filepicker = null; 485 486 /** 487 * HTML Templates to use in FilePicker 488 */ 489 M.core_filepicker.templates = M.core_filepicker.templates || {}; 490 491 /** 492 * Array of image sources for real previews (realicon or realthumbnail) that are already loaded 493 */ 494 M.core_filepicker.loadedpreviews = M.core_filepicker.loadedpreviews || {}; 495 496 /** 497 * Set selected file info 498 * 499 * @param object file info 500 */ 501 M.core_filepicker.select_file = function(file) { 502 M.core_filepicker.active_filepicker.select_file(file); 503 } 504 505 /** 506 * Init and show file picker 507 */ 508 M.core_filepicker.show = function(Y, options) { 509 if (!M.core_filepicker.instances[options.client_id]) { 510 M.core_filepicker.init(Y, options); 511 } 512 M.core_filepicker.instances[options.client_id].show(); 513 }; 514 515 M.core_filepicker.set_templates = function(Y, templates) { 516 for (var templid in templates) { 517 M.core_filepicker.templates[templid] = templates[templid]; 518 } 519 } 520 521 /** 522 * Add new file picker to current instances 523 */ 524 M.core_filepicker.init = function(Y, options) { 525 var FilePickerHelper = function(options) { 526 FilePickerHelper.superclass.constructor.apply(this, arguments); 527 }; 528 529 FilePickerHelper.NAME = "FilePickerHelper"; 530 FilePickerHelper.ATTRS = { 531 options: {}, 532 lang: {} 533 }; 534 535 Y.extend(FilePickerHelper, Y.Base, { 536 api: M.cfg.wwwroot+'/repository/repository_ajax.php', 537 cached_responses: {}, 538 waitinterval : null, // When the loading template is being displayed and its animation is running this will be an interval instance. 539 initializer: function(options) { 540 this.options = options; 541 if (!this.options.savepath) { 542 this.options.savepath = '/'; 543 } 544 }, 545 546 destructor: function() { 547 }, 548 549 request: function(args, redraw) { 550 var api = (args.api ? args.api : this.api) + '?action='+args.action; 551 var params = {}; 552 var scope = args['scope'] ? args['scope'] : this; 553 params['repo_id']=args.repository_id; 554 params['p'] = args.path?args.path:''; 555 params['page'] = args.page?args.page:''; 556 params['env']=this.options.env; 557 // the form element only accept certain file types 558 params['accepted_types']=this.options.accepted_types; 559 params['sesskey'] = M.cfg.sesskey; 560 params['client_id'] = args.client_id; 561 params['itemid'] = this.options.itemid?this.options.itemid:0; 562 params['maxbytes'] = this.options.maxbytes?this.options.maxbytes:-1; 563 // The unlimited value of areamaxbytes is -1, it is defined by FILE_AREA_MAX_BYTES_UNLIMITED. 564 params['areamaxbytes'] = this.options.areamaxbytes ? this.options.areamaxbytes : -1; 565 if (this.options.context && this.options.context.id) { 566 params['ctx_id'] = this.options.context.id; 567 } 568 if (args['params']) { 569 for (i in args['params']) { 570 params[i] = args['params'][i]; 571 } 572 } 573 if (args.action == 'upload') { 574 var list = []; 575 for(var k in params) { 576 var value = params[k]; 577 if(value instanceof Array) { 578 for(var i in value) { 579 list.push(k+'[]='+value[i]); 580 } 581 } else { 582 list.push(k+'='+value); 583 } 584 } 585 params = list.join('&'); 586 } else { 587 params = build_querystring(params); 588 } 589 var cfg = { 590 method: 'POST', 591 on: { 592 complete: function(id,o,p) { 593 var data = null; 594 try { 595 data = Y.JSON.parse(o.responseText); 596 } catch(e) { 597 if (o && o.status && o.status > 0) { 598 Y.use('moodle-core-notification-exception', function() { 599 return new M.core.exception(e); 600 }); 601 return; 602 } 603 } 604 // error checking 605 if (data && data.error) { 606 Y.use('moodle-core-notification-ajaxexception', function () { 607 return new M.core.ajaxException(data); 608 }); 609 this.fpnode.one('.fp-content').setContent(''); 610 return; 611 } else { 612 if (data.msg) { 613 scope.print_msg(data.msg, 'info'); 614 } 615 // cache result if applicable 616 if (args.action != 'upload' && data.allowcaching) { 617 scope.cached_responses[params] = data; 618 } 619 // invoke callback 620 args.callback(id,data,p); 621 } 622 } 623 }, 624 arguments: { 625 scope: scope 626 }, 627 headers: { 628 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' 629 }, 630 data: params, 631 context: this 632 }; 633 if (args.form) { 634 cfg.form = args.form; 635 } 636 // check if result of the same request has been already cached. If not, request it 637 // (never applicable in case of form submission and/or upload action): 638 if (!args.form && args.action != 'upload' && scope.cached_responses[params]) { 639 args.callback(null, scope.cached_responses[params], {scope: scope}) 640 } else { 641 Y.io(api, cfg); 642 if (redraw) { 643 this.wait(); 644 } 645 } 646 }, 647 /** displays the dialog and processes rename/overwrite if there is a file with the same name in the same filearea*/ 648 process_existing_file: function(data) { 649 var scope = this; 650 var handleOverwrite = function(e) { 651 // overwrite 652 e.preventDefault(); 653 var data = this.process_dlg.dialogdata; 654 var params = {} 655 params['existingfilename'] = data.existingfile.filename; 656 params['existingfilepath'] = data.existingfile.filepath; 657 params['newfilename'] = data.newfile.filename; 658 params['newfilepath'] = data.newfile.filepath; 659 this.hide_header(); 660 this.request({ 661 'params': params, 662 'scope': this, 663 'action':'overwrite', 664 'path': '', 665 'client_id': this.options.client_id, 666 'repository_id': this.active_repo.id, 667 'callback': function(id, o, args) { 668 scope.hide(); 669 if (scope.options.editor_target && scope.options.env == 'editor') { 670 // editor needs to update url 671 scope.options.editor_target.value = data.existingfile.url; 672 scope.options.editor_target.onchange(); 673 } 674 var fileinfo = {'client_id':scope.options.client_id, 675 'url':data.existingfile.url, 676 'file':data.existingfile.filename}; 677 var formcallback_scope = scope.options.magicscope ? scope.options.magicscope : scope; 678 scope.options.formcallback.apply(formcallback_scope, [fileinfo]); 679 } 680 }, true); 681 } 682 var handleRename = function(e) { 683 // inserts file with the new name 684 e.preventDefault(); 685 var scope = this; 686 var data = this.process_dlg.dialogdata; 687 if (scope.options.editor_target && scope.options.env == 'editor') { 688 scope.options.editor_target.value = data.newfile.url; 689 scope.options.editor_target.onchange(); 690 } 691 scope.hide(); 692 var formcallback_scope = scope.options.magicscope ? scope.options.magicscope : scope; 693 var fileinfo = {'client_id':scope.options.client_id, 694 'url':data.newfile.url, 695 'file':data.newfile.filename}; 696 scope.options.formcallback.apply(formcallback_scope, [fileinfo]); 697 } 698 var handleCancel = function(e) { 699 // Delete tmp file 700 e.preventDefault(); 701 var params = {}; 702 params['newfilename'] = this.process_dlg.dialogdata.newfile.filename; 703 params['newfilepath'] = this.process_dlg.dialogdata.newfile.filepath; 704 this.request({ 705 'params': params, 706 'scope': this, 707 'action':'deletetmpfile', 708 'path': '', 709 'client_id': this.options.client_id, 710 'repository_id': this.active_repo.id, 711 'callback': function(id, o, args) { 712 // let it be in background, from user point of view nothing is happenning 713 } 714 }, false); 715 this.process_dlg.hide(); 716 this.selectui.hide(); 717 } 718 if (!this.process_dlg) { 719 this.process_dlg_node = Y.Node.createWithFilesSkin(M.core_filepicker.templates.processexistingfile); 720 var node = this.process_dlg_node; 721 node.generateID(); 722 this.process_dlg = new M.core.dialogue({ 723 draggable : true, 724 bodyContent : node, 725 headerContent: M.util.get_string('fileexistsdialogheader', 'repository'), 726 centered : true, 727 modal : true, 728 visible : false, 729 zIndex : this.options.zIndex 730 }); 731 node.one('.fp-dlg-butoverwrite').on('click', handleOverwrite, this); 732 node.one('.fp-dlg-butrename').on('click', handleRename, this); 733 node.one('.fp-dlg-butcancel').on('click', handleCancel, this); 734 if (this.options.env == 'editor') { 735 node.one('.fp-dlg-text').setContent(M.util.get_string('fileexistsdialog_editor', 'repository')); 736 } else { 737 node.one('.fp-dlg-text').setContent(M.util.get_string('fileexistsdialog_filemanager', 'repository')); 738 } 739 } 740 this.selectnode.removeClass('loading'); 741 this.process_dlg.dialogdata = data; 742 this.process_dlg_node.one('.fp-dlg-butrename').setContent(M.util.get_string('renameto', 'repository', data.newfile.filename)); 743 this.process_dlg.show(); 744 }, 745 /** displays error instead of filepicker contents */ 746 display_error: function(errortext, errorcode) { 747 this.fpnode.one('.fp-content').setContent(M.core_filepicker.templates.error); 748 this.fpnode.one('.fp-content .fp-error'). 749 addClass(errorcode). 750 setContent(Y.Escape.html(errortext)); 751 }, 752 /** displays message in a popup */ 753 print_msg: function(msg, type) { 754 var header = M.util.get_string('error', 'moodle'); 755 if (type != 'error') { 756 type = 'info'; // one of only two types excepted 757 header = M.util.get_string('info', 'moodle'); 758 } 759 if (!this.msg_dlg) { 760 this.msg_dlg_node = Y.Node.createWithFilesSkin(M.core_filepicker.templates.message); 761 this.msg_dlg_node.generateID(); 762 763 this.msg_dlg = new M.core.dialogue({ 764 draggable : true, 765 bodyContent : this.msg_dlg_node, 766 centered : true, 767 modal : true, 768 visible : false, 769 zIndex : this.options.zIndex 770 }); 771 this.msg_dlg_node.one('.fp-msg-butok').on('click', function(e) { 772 e.preventDefault(); 773 this.msg_dlg.hide(); 774 }, this); 775 } 776 777 this.msg_dlg.set('headerContent', header); 778 this.msg_dlg_node.removeClass('fp-msg-info').removeClass('fp-msg-error').addClass('fp-msg-'+type) 779 this.msg_dlg_node.one('.fp-msg-text').setContent(Y.Escape.html(msg)); 780 this.msg_dlg.show(); 781 }, 782 view_files: function(appenditems) { 783 this.viewbar_set_enabled(true); 784 this.print_path(); 785 /*if ((appenditems == null) && (!this.filelist || !this.filelist.length) && !this.active_repo.hasmorepages) { 786 // TODO do it via classes and adjust for each view mode! 787 // If there are no items and no next page, just display status message and quit 788 this.display_error(M.util.get_string('nofilesavailable', 'repository'), 'nofilesavailable'); 789 return; 790 }*/ 791 if (this.viewmode == 2) { 792 this.view_as_list(appenditems); 793 } else if (this.viewmode == 3) { 794 this.view_as_table(appenditems); 795 } else { 796 this.view_as_icons(appenditems); 797 } 798 this.fpnode.one('.fp-content').setAttribute('tabindex', '0'); 799 this.fpnode.one('.fp-content').focus(); 800 // display/hide the link for requesting next page 801 if (!appenditems && this.active_repo.hasmorepages) { 802 if (!this.fpnode.one('.fp-content .fp-nextpage')) { 803 this.fpnode.one('.fp-content').append(M.core_filepicker.templates.nextpage); 804 } 805 this.fpnode.one('.fp-content .fp-nextpage').one('a,button').on('click', function(e) { 806 e.preventDefault(); 807 this.fpnode.one('.fp-content .fp-nextpage').addClass('loading'); 808 this.request_next_page(); 809 }, this); 810 } 811 if (!this.active_repo.hasmorepages && this.fpnode.one('.fp-content .fp-nextpage')) { 812 this.fpnode.one('.fp-content .fp-nextpage').remove(); 813 } 814 if (this.fpnode.one('.fp-content .fp-nextpage')) { 815 this.fpnode.one('.fp-content .fp-nextpage').removeClass('loading'); 816 } 817 this.content_scrolled(); 818 }, 819 content_scrolled: function(e) { 820 setTimeout(Y.bind(function() { 821 if (this.processingimages) { 822 return; 823 } 824 this.processingimages = true; 825 var scope = this, 826 fpcontent = this.fpnode.one('.fp-content'), 827 fpcontenty = fpcontent.getY(), 828 fpcontentheight = fpcontent.getStylePx('height'), 829 nextpage = fpcontent.one('.fp-nextpage'), 830 is_node_visible = function(node) { 831 var offset = node.getY()-fpcontenty; 832 if (offset <= fpcontentheight && (offset >=0 || offset+node.getStylePx('height')>=0)) { 833 return true; 834 } 835 return false; 836 }; 837 // automatically load next page when 'more' link becomes visible 838 if (nextpage && !nextpage.hasClass('loading') && is_node_visible(nextpage)) { 839 nextpage.one('a,button').simulate('click'); 840 } 841 // replace src for visible images that need to be lazy-loaded 842 if (scope.lazyloading) { 843 fpcontent.all('img').each( function(node) { 844 if (node.get('id') && scope.lazyloading[node.get('id')] && is_node_visible(node)) { 845 node.setImgRealSrc(scope.lazyloading); 846 } 847 }); 848 } 849 this.processingimages = false; 850 }, this), 200) 851 }, 852 treeview_dynload: function(node, cb) { 853 var retrieved_children = {}; 854 if (node.children) { 855 for (var i in node.children) { 856 retrieved_children[node.children[i].path] = node.children[i]; 857 } 858 } 859 this.request({ 860 action:'list', 861 client_id: this.options.client_id, 862 repository_id: this.active_repo.id, 863 path:node.path?node.path:'', 864 page:node.page?args.page:'', 865 scope:this, 866 callback: function(id, obj, args) { 867 var list = obj.list; 868 var scope = args.scope; 869 // check that user did not leave the view mode before recieving this response 870 if (!(scope.active_repo.id == obj.repo_id && scope.viewmode == 2 && node && node.getChildrenEl())) { 871 return; 872 } 873 if (cb != null) { // (in manual mode do not update current path) 874 scope.viewbar_set_enabled(true); 875 scope.parse_repository_options(obj); 876 } 877 node.highlight(false); 878 node.origlist = obj.list ? obj.list : null; 879 node.origpath = obj.path ? obj.path : null; 880 node.children = []; 881 for(k in list) { 882 if (list[k].children && retrieved_children[list[k].path]) { 883 // if this child is a folder and has already been retrieved 884 node.children[node.children.length] = retrieved_children[list[k].path]; 885 } else { 886 // append new file to the list 887 scope.view_as_list([list[k]]); 888 } 889 } 890 if (cb == null) { 891 node.refresh(); 892 } else { 893 // invoke callback requested by TreeView component 894 cb(); 895 } 896 scope.content_scrolled(); 897 } 898 }, false); 899 }, 900 classnamecallback : function(node) { 901 var classname = ''; 902 if (node.children) { 903 classname = classname + ' fp-folder'; 904 } 905 if (node.isref) { 906 classname = classname + ' fp-isreference'; 907 } 908 if (node.refcount) { 909 classname = classname + ' fp-hasreferences'; 910 } 911 if (node.originalmissing) { 912 classname = classname + ' fp-originalmissing'; 913 } 914 return Y.Lang.trim(classname); 915 }, 916 /** displays list of files in tree (list) view mode. If param appenditems is specified, 917 * appends those items to the end of the list. Otherwise (default behaviour) 918 * clears the contents and displays the items from this.filelist */ 919 view_as_list: function(appenditems) { 920 var list = (appenditems != null) ? appenditems : this.filelist; 921 this.viewmode = 2; 922 if (!this.filelist || this.filelist.length==0 && (!this.filepath || !this.filepath.length)) { 923 this.display_error(M.util.get_string('nofilesavailable', 'repository'), 'nofilesavailable'); 924 return; 925 } 926 927 var element_template = Y.Node.create(M.core_filepicker.templates.listfilename); 928 var options = { 929 viewmode : this.viewmode, 930 appendonly : (appenditems != null), 931 filenode : element_template, 932 callbackcontext : this, 933 callback : function(e, node) { 934 // TODO MDL-32736 e is not an event here but an object with properties 'event' and 'node' 935 if (!node.children) { 936 if (e.node.parent && e.node.parent.origpath) { 937 // set the current path 938 this.filepath = e.node.parent.origpath; 939 this.filelist = e.node.parent.origlist; 940 this.print_path(); 941 } 942 this.select_file(node); 943 } else { 944 // save current path and filelist (in case we want to jump to other viewmode) 945 this.filepath = e.node.origpath; 946 this.filelist = e.node.origlist; 947 this.currentpath = e.node.path; 948 this.print_path(); 949 this.content_scrolled(); 950 } 951 }, 952 classnamecallback : this.classnamecallback, 953 dynload : this.active_repo.dynload, 954 filepath : this.filepath, 955 treeview_dynload : this.treeview_dynload 956 }; 957 this.fpnode.one('.fp-content').fp_display_filelist(options, list, this.lazyloading); 958 }, 959 /** displays list of files in icon view mode. If param appenditems is specified, 960 * appends those items to the end of the list. Otherwise (default behaviour) 961 * clears the contents and displays the items from this.filelist */ 962 view_as_icons: function(appenditems) { 963 this.viewmode = 1; 964 var list = (appenditems != null) ? appenditems : this.filelist; 965 var element_template = Y.Node.create(M.core_filepicker.templates.iconfilename); 966 if ((appenditems == null) && (!this.filelist || !this.filelist.length)) { 967 this.display_error(M.util.get_string('nofilesavailable', 'repository'), 'nofilesavailable'); 968 return; 969 } 970 var options = { 971 viewmode : this.viewmode, 972 appendonly : (appenditems != null), 973 filenode : element_template, 974 callbackcontext : this, 975 callback : function(e, node) { 976 if (e.preventDefault) { 977 e.preventDefault(); 978 } 979 if(node.children) { 980 if (this.active_repo.dynload) { 981 this.list({'path':node.path}); 982 } else { 983 this.filelist = node.children; 984 this.view_files(); 985 } 986 } else { 987 this.select_file(node); 988 } 989 }, 990 classnamecallback : this.classnamecallback 991 }; 992 this.fpnode.one('.fp-content').fp_display_filelist(options, list, this.lazyloading); 993 }, 994 /** displays list of files in table view mode. If param appenditems is specified, 995 * appends those items to the end of the list. Otherwise (default behaviour) 996 * clears the contents and displays the items from this.filelist */ 997 view_as_table: function(appenditems) { 998 this.viewmode = 3; 999 var list = (appenditems != null) ? appenditems : this.filelist; 1000 if (!appenditems && (!this.filelist || this.filelist.length==0) && !this.active_repo.hasmorepages) { 1001 this.display_error(M.util.get_string('nofilesavailable', 'repository'), 'nofilesavailable'); 1002 return; 1003 } 1004 var element_template = Y.Node.create(M.core_filepicker.templates.listfilename); 1005 var options = { 1006 viewmode : this.viewmode, 1007 appendonly : (appenditems != null), 1008 filenode : element_template, 1009 callbackcontext : this, 1010 sortable : !this.active_repo.hasmorepages, 1011 callback : function(e, node) { 1012 if (e.preventDefault) {e.preventDefault();} 1013 if (node.children) { 1014 if (this.active_repo.dynload) { 1015 this.list({'path':node.path}); 1016 } else { 1017 this.filelist = node.children; 1018 this.view_files(); 1019 } 1020 } else { 1021 this.select_file(node); 1022 } 1023 }, 1024 classnamecallback : this.classnamecallback 1025 }; 1026 this.fpnode.one('.fp-content').fp_display_filelist(options, list, this.lazyloading); 1027 }, 1028 /** If more than one page available, requests and displays the files from the next page */ 1029 request_next_page: function() { 1030 if (!this.active_repo.hasmorepages || this.active_repo.nextpagerequested) { 1031 // nothing to load 1032 return; 1033 } 1034 this.active_repo.nextpagerequested = true; 1035 var nextpage = this.active_repo.page+1; 1036 var args = { 1037 page: nextpage, 1038 repo_id: this.active_repo.id 1039 }; 1040 var action = this.active_repo.issearchresult ? 'search' : 'list'; 1041 this.request({ 1042 path: this.currentpath, 1043 scope: this, 1044 action: action, 1045 client_id: this.options.client_id, 1046 repository_id: args.repo_id, 1047 params: args, 1048 callback: function(id, obj, args) { 1049 var scope = args.scope; 1050 // Check that we are still in the same repository and are expecting this page. We have no way 1051 // to compare the requested page and the one returned, so we assume that if the last chunk 1052 // of the breadcrumb is similar, then we probably are on the same page. 1053 var samepage = true; 1054 if (obj.path && scope.filepath) { 1055 var pathbefore = scope.filepath[scope.filepath.length-1]; 1056 var pathafter = obj.path[obj.path.length-1]; 1057 if (pathbefore.path != pathafter.path) { 1058 samepage = false; 1059 } 1060 } 1061 if (scope.active_repo.hasmorepages && obj.list && obj.page && 1062 obj.repo_id == scope.active_repo.id && 1063 obj.page == scope.active_repo.page+1 && samepage) { 1064 scope.parse_repository_options(obj, true); 1065 scope.view_files(obj.list) 1066 } 1067 } 1068 }, false); 1069 }, 1070 select_file: function(args) { 1071 var argstitle = args.title; 1072 // Limit the string length so it fits nicely on mobile devices 1073 var titlelength = 30; 1074 if (argstitle.length > titlelength) { 1075 argstitle = argstitle.substring(0, titlelength) + '...'; 1076 } 1077 Y.one('#fp-file_label_'+this.options.client_id).setContent(Y.Escape.html(M.util.get_string('select', 'repository')+' '+argstitle)); 1078 this.selectui.show(); 1079 Y.one('#'+this.selectnode.get('id')).focus(); 1080 var client_id = this.options.client_id; 1081 var selectnode = this.selectnode; 1082 var return_types = this.options.repositories[this.active_repo.id].return_types; 1083 selectnode.removeClass('loading'); 1084 selectnode.one('.fp-saveas input').set('value', args.title); 1085 1086 var imgnode = Y.Node.create('<img/>'). 1087 set('src', args.realthumbnail ? args.realthumbnail : args.thumbnail). 1088 setStyle('maxHeight', ''+(args.thumbnail_height ? args.thumbnail_height : 90)+'px'). 1089 setStyle('maxWidth', ''+(args.thumbnail_width ? args.thumbnail_width : 90)+'px'); 1090 selectnode.one('.fp-thumbnail').setContent('').appendChild(imgnode); 1091 1092 // filelink is the array of file-link-types available for this repository in this env 1093 var filelinktypes = [2/*FILE_INTERNAL*/,1/*FILE_EXTERNAL*/,4/*FILE_REFERENCE*/]; 1094 var filelink = {}, firstfilelink = null, filelinkcount = 0; 1095 for (var i in filelinktypes) { 1096 var allowed = (return_types & filelinktypes[i]) && 1097 (this.options.return_types & filelinktypes[i]); 1098 if (filelinktypes[i] == 1/*FILE_EXTERNAL*/ && !this.options.externallink && this.options.env == 'editor') { 1099 // special configuration setting 'repositoryallowexternallinks' may prevent 1100 // using external links in editor environment 1101 allowed = false; 1102 } 1103 filelink[filelinktypes[i]] = allowed; 1104 firstfilelink = (firstfilelink==null && allowed) ? filelinktypes[i] : firstfilelink; 1105 filelinkcount += allowed ? 1 : 0; 1106 } 1107 // make radio buttons enabled if this file-link-type is available and only if there are more than one file-link-type option 1108 // check the first available file-link-type option 1109 for (var linktype in filelink) { 1110 var el = selectnode.one('.fp-linktype-'+linktype); 1111 el.addClassIf('uneditable', !(filelink[linktype] && filelinkcount>1)); 1112 el.one('input').set('checked', (firstfilelink == linktype) ? 'checked' : '').simulate('change'); 1113 } 1114 1115 // TODO MDL-32532: attributes 'hasauthor' and 'haslicense' need to be obsolete, 1116 selectnode.one('.fp-setauthor input').set('value', args.author ? args.author : this.options.author); 1117 this.set_selected_license(selectnode.one('.fp-setlicense'), args.license); 1118 selectnode.one('form #filesource-'+client_id).set('value', args.source); 1119 1120 // display static information about a file (when known) 1121 var attrs = ['datemodified','datecreated','size','license','author','dimensions']; 1122 for (var i in attrs) { 1123 if (selectnode.one('.fp-'+attrs[i])) { 1124 var value = (args[attrs[i]+'_f']) ? args[attrs[i]+'_f'] : (args[attrs[i]] ? args[attrs[i]] : ''); 1125 selectnode.one('.fp-'+attrs[i]).addClassIf('fp-unknown', ''+value == '') 1126 .one('.fp-value').setContent(Y.Escape.html(value)); 1127 } 1128 } 1129 }, 1130 setup_select_file: function() { 1131 var client_id = this.options.client_id; 1132 var selectnode = this.selectnode; 1133 var getfile = selectnode.one('.fp-select-confirm'); 1134 // bind labels with corresponding inputs 1135 selectnode.all('.fp-saveas,.fp-linktype-2,.fp-linktype-1,.fp-linktype-4,.fp-setauthor,.fp-setlicense').each(function (node) { 1136 node.all('label').set('for', node.one('input,select').generateID()); 1137 }); 1138 selectnode.one('.fp-linktype-2 input').setAttrs({value: 2, name: 'linktype'}); 1139 selectnode.one('.fp-linktype-1 input').setAttrs({value: 1, name: 'linktype'}); 1140 selectnode.one('.fp-linktype-4 input').setAttrs({value: 4, name: 'linktype'}); 1141 var changelinktype = function(e) { 1142 if (e.currentTarget.get('checked')) { 1143 var allowinputs = e.currentTarget.get('value') != 1/*FILE_EXTERNAL*/; 1144 selectnode.all('.fp-setauthor,.fp-setlicense,.fp-saveas').each(function(node){ 1145 node.addClassIf('uneditable', !allowinputs); 1146 node.all('input,select').set('disabled', allowinputs?'':'disabled'); 1147 }); 1148 } 1149 }; 1150 selectnode.all('.fp-linktype-2,.fp-linktype-1,.fp-linktype-4').each(function (node) { 1151 node.one('input').on('change', changelinktype, this); 1152 }); 1153 this.populate_licenses_select(selectnode.one('.fp-setlicense select')); 1154 // register event on clicking submit button 1155 getfile.on('click', function(e) { 1156 e.preventDefault(); 1157 var client_id = this.options.client_id; 1158 var scope = this; 1159 var repository_id = this.active_repo.id; 1160 var title = selectnode.one('.fp-saveas input').get('value'); 1161 var filesource = selectnode.one('form #filesource-'+client_id).get('value'); 1162 var params = {'title':title, 'source':filesource, 'savepath': this.options.savepath}; 1163 var license = selectnode.one('.fp-setlicense select'); 1164 if (license) { 1165 params['license'] = license.get('value'); 1166 var origlicense = selectnode.one('.fp-license .fp-value'); 1167 if (origlicense) { 1168 origlicense = origlicense.getContent(); 1169 } 1170 this.set_preference('recentlicense', license.get('value')); 1171 } 1172 params['author'] = selectnode.one('.fp-setauthor input').get('value'); 1173 1174 var return_types = this.options.repositories[this.active_repo.id].return_types; 1175 if (this.options.env == 'editor') { 1176 // in editor, images are stored in '/' only 1177 params.savepath = '/'; 1178 } 1179 if ((this.options.externallink || this.options.env != 'editor') && 1180 (return_types & 1/*FILE_EXTERNAL*/) && 1181 (this.options.return_types & 1/*FILE_EXTERNAL*/) && 1182 selectnode.one('.fp-linktype-1 input').get('checked')) { 1183 params['linkexternal'] = 'yes'; 1184 } else if ((return_types & 4/*FILE_REFERENCE*/) && 1185 (this.options.return_types & 4/*FILE_REFERENCE*/) && 1186 selectnode.one('.fp-linktype-4 input').get('checked')) { 1187 params['usefilereference'] = '1'; 1188 } 1189 1190 selectnode.addClass('loading'); 1191 this.request({ 1192 action:'download', 1193 client_id: client_id, 1194 repository_id: repository_id, 1195 'params': params, 1196 onerror: function(id, obj, args) { 1197 selectnode.removeClass('loading'); 1198 scope.selectui.hide(); 1199 }, 1200 callback: function(id, obj, args) { 1201 selectnode.removeClass('loading'); 1202 if (obj.event == 'fileexists') { 1203 scope.process_existing_file(obj); 1204 return; 1205 } 1206 if (scope.options.editor_target && scope.options.env=='editor') { 1207 scope.options.editor_target.value=obj.url; 1208 scope.options.editor_target.onchange(); 1209 } 1210 scope.hide(); 1211 obj.client_id = client_id; 1212 var formcallback_scope = args.scope.options.magicscope ? args.scope.options.magicscope : args.scope; 1213 scope.options.formcallback.apply(formcallback_scope, [obj]); 1214 } 1215 }, false); 1216 }, this); 1217 var elform = selectnode.one('form'); 1218 elform.appendChild(Y.Node.create('<input/>'). 1219 setAttrs({type:'hidden',id:'filesource-'+client_id})); 1220 elform.on('keydown', function(e) { 1221 if (e.keyCode == 13) { 1222 getfile.simulate('click'); 1223 e.preventDefault(); 1224 } 1225 }, this); 1226 var cancel = selectnode.one('.fp-select-cancel'); 1227 cancel.on('click', function(e) { 1228 e.preventDefault(); 1229 this.selectui.hide(); 1230 }, this); 1231 }, 1232 wait: function() { 1233 // First check there isn't already an interval in play, and if there is kill it now. 1234 if (this.waitinterval != null) { 1235 clearInterval(this.waitinterval); 1236 } 1237 // Prepare the root node we will set content for and the loading template we want to display as a YUI node. 1238 var root = this.fpnode.one('.fp-content'); 1239 var content = Y.Node.create(M.core_filepicker.templates.loading).addClass('fp-content-hidden').setStyle('opacity', 0); 1240 var count = 0; 1241 // Initiate an interval, we will have a count which will increment every 100 milliseconds. 1242 // Count 0 - the loading icon will have visibility set to hidden (invisible) and have an opacity of 0 (invisible also) 1243 // Count 5 - the visiblity will be switched to visible but opacity will still be at 0 (inivisible) 1244 // Counts 6 - 15 opacity will be increased by 0.1 making the loading icon visible over the period of a second 1245 // Count 16 - The interval will be cancelled. 1246 var interval = setInterval(function(){ 1247 if (!content || !root.contains(content) || count >= 15) { 1248 clearInterval(interval); 1249 return true; 1250 } 1251 if (count == 5) { 1252 content.removeClass('fp-content-hidden'); 1253 } else if (count > 5) { 1254 var opacity = parseFloat(content.getStyle('opacity')); 1255 content.setStyle('opacity', opacity + 0.1); 1256 } 1257 count++; 1258 return false; 1259 }, 100); 1260 // Store the wait interval so that we can check it in the future. 1261 this.waitinterval = interval; 1262 // Set the content to the loading template. 1263 root.setContent(content); 1264 }, 1265 viewbar_set_enabled: function(mode) { 1266 var viewbar = this.fpnode.one('.fp-viewbar') 1267 if (viewbar) { 1268 if (mode) { 1269 viewbar.addClass('enabled').removeClass('disabled'); 1270 this.fpnode.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').setAttribute("aria-disabled", "false"); 1271 this.fpnode.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').setAttribute("tabindex", ""); 1272 } else { 1273 viewbar.removeClass('enabled').addClass('disabled'); 1274 this.fpnode.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').setAttribute("aria-disabled", "true"); 1275 this.fpnode.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').setAttribute("tabindex", "-1"); 1276 } 1277 } 1278 this.fpnode.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').removeClass('checked'); 1279 var modes = {1:'icons', 2:'tree', 3:'details'}; 1280 this.fpnode.all('.fp-vb-'+modes[this.viewmode]).addClass('checked'); 1281 }, 1282 viewbar_clicked: function(e) { 1283 e.preventDefault(); 1284 var viewbar = this.fpnode.one('.fp-viewbar') 1285 if (!viewbar || !viewbar.hasClass('disabled')) { 1286 if (e.currentTarget.hasClass('fp-vb-tree')) { 1287 this.viewmode = 2; 1288 } else if (e.currentTarget.hasClass('fp-vb-details')) { 1289 this.viewmode = 3; 1290 } else { 1291 this.viewmode = 1; 1292 } 1293 this.viewbar_set_enabled(true) 1294 this.view_files(); 1295 this.set_preference('recentviewmode', this.viewmode); 1296 } 1297 }, 1298 render: function() { 1299 var client_id = this.options.client_id; 1300 var fpid = "filepicker-"+ client_id; 1301 var labelid = 'fp-dialog-label_'+ client_id; 1302 var width = 873; 1303 var draggable = true; 1304 this.fpnode = Y.Node.createWithFilesSkin(M.core_filepicker.templates.generallayout). 1305 set('id', 'filepicker-'+client_id).set('aria-labelledby', labelid); 1306 1307 if (this.in_iframe()) { 1308 width = Math.floor(window.innerWidth * 0.95); 1309 draggable = false; 1310 } 1311 1312 this.mainui = new M.core.dialogue({ 1313 extraClasses : ['filepicker'], 1314 draggable : draggable, 1315 bodyContent : this.fpnode, 1316 headerContent: '<h3 id="'+ labelid +'">'+ M.util.get_string('filepicker', 'repository') +'</h3>', 1317 centered : true, 1318 modal : true, 1319 visible : false, 1320 width : width+'px', 1321 responsiveWidth : 768, 1322 height : '558px', 1323 zIndex : this.options.zIndex 1324 }); 1325 1326 // create panel for selecting a file (initially hidden) 1327 this.selectnode = Y.Node.createWithFilesSkin(M.core_filepicker.templates.selectlayout). 1328 set('id', 'filepicker-select-'+client_id). 1329 set('aria-live', 'assertive'). 1330 set('role', 'dialog'); 1331 1332 var fplabel = 'fp-file_label_'+ client_id; 1333 this.selectui = new M.core.dialogue({ 1334 headerContent: '<h3 id="' + fplabel +'">'+M.util.get_string('select', 'repository')+'</h3>', 1335 draggable : true, 1336 width : '450px', 1337 bodyContent : this.selectnode, 1338 centered : true, 1339 modal : true, 1340 visible : false, 1341 zIndex : this.options.zIndex 1342 }); 1343 Y.one('#'+this.selectnode.get('id')).setAttribute('aria-labelledby', fplabel); 1344 // event handler for lazy loading of thumbnails and next page 1345 this.fpnode.one('.fp-content').on(['scroll','resize'], this.content_scrolled, this); 1346 // save template for one path element and location of path bar 1347 if (this.fpnode.one('.fp-path-folder')) { 1348 this.pathnode = this.fpnode.one('.fp-path-folder'); 1349 this.pathbar = this.pathnode.get('parentNode'); 1350 this.pathbar.removeChild(this.pathnode); 1351 } 1352 // assign callbacks for view mode switch buttons 1353 this.fpnode.one('.fp-vb-icons').on('click', this.viewbar_clicked, this); 1354 this.fpnode.one('.fp-vb-tree').on('click', this.viewbar_clicked, this); 1355 this.fpnode.one('.fp-vb-details').on('click', this.viewbar_clicked, this); 1356 1357 // assign callbacks for toolbar links 1358 this.setup_toolbar(); 1359 this.setup_select_file(); 1360 this.hide_header(); 1361 1362 // processing repository listing 1363 // Resort the repositories by sortorder 1364 var sorted_repositories = []; 1365 for (var i in this.options.repositories) { 1366 sorted_repositories[i] = this.options.repositories[i]; 1367 } 1368 sorted_repositories.sort(function(a,b){return a.sortorder-b.sortorder}); 1369 // extract one repository template and repeat it for all repositories available, 1370 // set name and icon and assign callbacks 1371 var reponode = this.fpnode.one('.fp-repo'); 1372 if (reponode) { 1373 var list = reponode.get('parentNode'); 1374 list.removeChild(reponode); 1375 for (i in sorted_repositories) { 1376 var repository = sorted_repositories[i]; 1377 var node = reponode.cloneNode(true); 1378 list.appendChild(node); 1379 node. 1380 set('id', 'fp-repo-'+client_id+'-'+repository.id). 1381 on('click', function(e, repository_id) { 1382 e.preventDefault(); 1383 this.set_preference('recentrepository', repository_id); 1384 this.hide_header(); 1385 this.list({'repo_id':repository_id}); 1386 }, this /*handler running scope*/, repository.id/*second argument of handler*/); 1387 node.one('.fp-repo-name').setContent(Y.Escape.html(repository.name)); 1388 node.one('.fp-repo-icon').set('src', repository.icon); 1389 if (i==0) { 1390 node.addClass('first'); 1391 } 1392 if (i==sorted_repositories.length-1) { 1393 node.addClass('last'); 1394 } 1395 if (i%2) { 1396 node.addClass('even'); 1397 } else { 1398 node.addClass('odd'); 1399 } 1400 } 1401 } 1402 // display error if no repositories found 1403 if (sorted_repositories.length==0) { 1404 this.display_error(M.util.get_string('norepositoriesavailable', 'repository'), 'norepositoriesavailable') 1405 } 1406 // display repository that was used last time 1407 this.mainui.show(); 1408 this.show_recent_repository(); 1409 }, 1410 parse_repository_options: function(data, appendtolist) { 1411 if (appendtolist) { 1412 if (data.list) { 1413 if (!this.filelist) { 1414 this.filelist = []; 1415 } 1416 for (var i in data.list) { 1417 this.filelist[this.filelist.length] = data.list[i]; 1418 } 1419 } 1420 } else { 1421 this.filelist = data.list?data.list:null; 1422 this.lazyloading = {}; 1423 } 1424 this.filepath = data.path?data.path:null; 1425 this.objecttag = data.object?data.object:null; 1426 this.active_repo = {}; 1427 this.active_repo.issearchresult = data.issearchresult ? true : false; 1428 this.active_repo.dynload = data.dynload?data.dynload:false; 1429 this.active_repo.pages = Number(data.pages?data.pages:null); 1430 this.active_repo.page = Number(data.page?data.page:null); 1431 this.active_repo.hasmorepages = (this.active_repo.pages && this.active_repo.page && (this.active_repo.page < this.active_repo.pages || this.active_repo.pages == -1)) 1432 this.active_repo.id = data.repo_id?data.repo_id:null; 1433 this.active_repo.nosearch = (data.login || data.nosearch); // this is either login form or 'nosearch' attribute set 1434 this.active_repo.norefresh = (data.login || data.norefresh); // this is either login form or 'norefresh' attribute set 1435 this.active_repo.nologin = (data.login || data.nologin); // this is either login form or 'nologin' attribute is set 1436 this.active_repo.logouttext = data.logouttext?data.logouttext:null; 1437 this.active_repo.logouturl = (data.logouturl || ''); 1438 this.active_repo.message = (data.message || ''); 1439 this.active_repo.help = data.help?data.help:null; 1440 this.active_repo.manage = data.manage?data.manage:null; 1441 this.print_header(); 1442 }, 1443 print_login: function(data) { 1444 this.parse_repository_options(data); 1445 var client_id = this.options.client_id; 1446 var repository_id = data.repo_id; 1447 var l = this.logindata = data.login; 1448 var loginurl = ''; 1449 var action = data['login_btn_action'] ? data['login_btn_action'] : 'login'; 1450 var form_id = 'fp-form-'+client_id; 1451 1452 var loginform_node = Y.Node.create(M.core_filepicker.templates.loginform); 1453 loginform_node.one('form').set('id', form_id); 1454 this.fpnode.one('.fp-content').setContent('').appendChild(loginform_node); 1455 var templates = { 1456 'popup' : loginform_node.one('.fp-login-popup'), 1457 'textarea' : loginform_node.one('.fp-login-textarea'), 1458 'select' : loginform_node.one('.fp-login-select'), 1459 'text' : loginform_node.one('.fp-login-text'), 1460 'radio' : loginform_node.one('.fp-login-radiogroup'), 1461 'checkbox' : loginform_node.one('.fp-login-checkbox'), 1462 'input' : loginform_node.one('.fp-login-input') 1463 }; 1464 var container; 1465 for (var i in templates) { 1466 if (templates[i]) { 1467 container = templates[i].get('parentNode'); 1468 container.removeChild(templates[i]); 1469 } 1470 } 1471 1472 for(var k in l) { 1473 if (templates[l[k].type]) { 1474 var node = templates[l[k].type].cloneNode(true); 1475 } else { 1476 node = templates['input'].cloneNode(true); 1477 } 1478 if (l[k].type == 'popup') { 1479 // submit button 1480 loginurl = l[k].url; 1481 var popupbutton = node.one('button'); 1482 popupbutton.on('click', function(e){ 1483 M.core_filepicker.active_filepicker = this; 1484 window.open(loginurl, 'repo_auth', 'location=0,status=0,width=500,height=300,scrollbars=yes'); 1485 e.preventDefault(); 1486 }, this); 1487 loginform_node.one('form').on('keydown', function(e) { 1488 if (e.keyCode == 13) { 1489 popupbutton.simulate('click'); 1490 e.preventDefault(); 1491 } 1492 }, this); 1493 loginform_node.all('.fp-login-submit').remove(); 1494 action = 'popup'; 1495 } else if(l[k].type=='textarea') { 1496 // textarea element 1497 if (node.one('label')) { 1498 node.one('label').set('for', l[k].id).setContent(l[k].label); 1499 } 1500 node.one('textarea').setAttrs({id:l[k].id, name:l[k].name}); 1501 } else if(l[k].type=='select') { 1502 // select element 1503 if (node.one('label')) { 1504 node.one('label').set('for', l[k].id).setContent(l[k].label); 1505 } 1506 node.one('select').setAttrs({id:l[k].id, name:l[k].name}).setContent(''); 1507 for (i in l[k].options) { 1508 node.one('select').appendChild( 1509 Y.Node.create('<option/>'). 1510 set('value', l[k].options[i].value). 1511 setContent(l[k].options[i].label)); 1512 } 1513 } else if(l[k].type=='radio') { 1514 // radio input element 1515 node.all('label').setContent(l[k].label); 1516 var list = l[k].value.split('|'); 1517 var labels = l[k].value_label.split('|'); 1518 var radionode = null; 1519 for(var item in list) { 1520 if (radionode == null) { 1521 radionode = node.one('.fp-login-radio'); 1522 radionode.one('input').set('checked', 'checked'); 1523 } else { 1524 var x = radionode.cloneNode(true); 1525 radionode.insert(x, 'after'); 1526 radionode = x; 1527 radionode.one('input').set('checked', ''); 1528 } 1529 radionode.one('input').setAttrs({id:''+l[k].id+item, name:l[k].name, 1530 type:l[k].type, value:list[item]}); 1531 radionode.all('label').setContent(labels[item]).set('for', ''+l[k].id+item) 1532 } 1533 if (radionode == null) { 1534 node.one('.fp-login-radio').remove(); 1535 } 1536 } else { 1537 // input element 1538 if (node.one('label')) { node.one('label').set('for', l[k].id).setContent(l[k].label) } 1539 node.one('input'). 1540 set('type', l[k].type). 1541 set('id', l[k].id). 1542 set('name', l[k].name). 1543 set('value', l[k].value?l[k].value:'') 1544 } 1545 container.appendChild(node); 1546 } 1547 // custom label text for submit button 1548 if (data['login_btn_label']) { 1549 loginform_node.all('.fp-login-submit').setContent(data['login_btn_label']) 1550 } 1551 // register button action for login and search 1552 if (action == 'login' || action == 'search') { 1553 loginform_node.one('.fp-login-submit').on('click', function(e){ 1554 e.preventDefault(); 1555 this.hide_header(); 1556 this.request({ 1557 'scope': this, 1558 'action':(action == 'search') ? 'search' : 'signin', 1559 'path': '', 1560 'client_id': client_id, 1561 'repository_id': repository_id, 1562 'form': {id:form_id, upload:false, useDisabled:true}, 1563 'callback': this.display_response 1564 }, true); 1565 }, this); 1566 } 1567 // if 'Enter' is pressed in the form, simulate the button click 1568 if (loginform_node.one('.fp-login-submit')) { 1569 loginform_node.one('form').on('keydown', function(e) { 1570 if (e.keyCode == 13) { 1571 loginform_node.one('.fp-login-submit').simulate('click') 1572 e.preventDefault(); 1573 } 1574 }, this); 1575 } 1576 }, 1577 display_response: function(id, obj, args) { 1578 var scope = args.scope; 1579 // highlight the current repository in repositories list 1580 scope.fpnode.all('.fp-repo.active').removeClass('active'); 1581 scope.fpnode.all('#fp-repo-'+scope.options.client_id+'-'+obj.repo_id).addClass('active') 1582 // add class repository_REPTYPE to the filepicker (for repository-specific styles) 1583 for (var i in scope.options.repositories) { 1584 scope.fpnode.removeClass('repository_'+scope.options.repositories[i].type) 1585 } 1586 if (obj.repo_id && scope.options.repositories[obj.repo_id]) { 1587 scope.fpnode.addClass('repository_'+scope.options.repositories[obj.repo_id].type) 1588 } 1589 Y.one('.file-picker .fp-repo-items').focus(); 1590 1591 // display response 1592 if (obj.login) { 1593 scope.viewbar_set_enabled(false); 1594 scope.print_login(obj); 1595 } else if (obj.upload) { 1596 scope.viewbar_set_enabled(false); 1597 scope.parse_repository_options(obj); 1598 scope.create_upload_form(obj); 1599 } else if (obj.object) { 1600 M.core_filepicker.active_filepicker = scope; 1601 scope.viewbar_set_enabled(false); 1602 scope.parse_repository_options(obj); 1603 scope.create_object_container(obj.object); 1604 } else if (obj.list) { 1605 scope.viewbar_set_enabled(true); 1606 scope.parse_repository_options(obj); 1607 scope.view_files(); 1608 } 1609 }, 1610 list: function(args) { 1611 if (!args) { 1612 args = {}; 1613 } 1614 if (!args.repo_id) { 1615 args.repo_id = this.active_repo.id; 1616 } 1617 if (!args.path) { 1618 args.path = ''; 1619 } 1620 this.currentpath = args.path; 1621 this.request({ 1622 action: 'list', 1623 client_id: this.options.client_id, 1624 repository_id: args.repo_id, 1625 path: args.path, 1626 page: args.page, 1627 scope: this, 1628 callback: this.display_response 1629 }, true); 1630 }, 1631 populate_licenses_select: function(node) { 1632 if (!node) { 1633 return; 1634 } 1635 node.setContent(''); 1636 var licenses = this.options.licenses; 1637 var recentlicense = this.get_preference('recentlicense'); 1638 if (recentlicense) { 1639 this.options.defaultlicense=recentlicense; 1640 } 1641 for (var i in licenses) { 1642 var option = Y.Node.create('<option/>'). 1643 set('selected', (this.options.defaultlicense==licenses[i].shortname)). 1644 set('value', licenses[i].shortname). 1645 setContent(Y.Escape.html(licenses[i].fullname)); 1646 node.appendChild(option) 1647 } 1648 }, 1649 set_selected_license: function(node, value) { 1650 var licenseset = false; 1651 node.all('option').each(function(el) { 1652 if (el.get('value')==value || el.getContent()==value) { 1653 el.set('selected', true); 1654 licenseset = true; 1655 } 1656 }); 1657 if (!licenseset) { 1658 // we did not find the value in the list 1659 var recentlicense = this.get_preference('recentlicense'); 1660 node.all('option[selected]').set('selected', false); 1661 node.all('option[value='+recentlicense+']').set('selected', true); 1662 } 1663 }, 1664 create_object_container: function(data) { 1665 var content = this.fpnode.one('.fp-content'); 1666 content.setContent(''); 1667 //var str = '<object data="'+data.src+'" type="'+data.type+'" width="98%" height="98%" id="container_object" class="fp-object-container mdl-align"></object>'; 1668 var container = Y.Node.create('<object/>'). 1669 setAttrs({data:data.src, type:data.type, id:'container_object'}). 1670 addClass('fp-object-container'); 1671 content.setContent('').appendChild(container); 1672 }, 1673 create_upload_form: function(data) { 1674 var client_id = this.options.client_id; 1675 var id = data.upload.id+'_'+client_id; 1676 var content = this.fpnode.one('.fp-content'); 1677 var template_name = 'uploadform_'+this.options.repositories[data.repo_id].type; 1678 var template = M.core_filepicker.templates[template_name] || M.core_filepicker.templates['uploadform']; 1679 content.setContent(template); 1680 1681 content.all('.fp-file,.fp-saveas,.fp-setauthor,.fp-setlicense').each(function (node) { 1682 node.all('label').set('for', node.one('input,select').generateID()); 1683 }); 1684 content.one('form').set('id', id); 1685 content.one('.fp-file input').set('name', 'repo_upload_file'); 1686 if (data.upload.label && content.one('.fp-file label')) { 1687 content.one('.fp-file label').setContent(data.upload.label); 1688 } 1689 content.one('.fp-saveas input').set('name', 'title'); 1690 content.one('.fp-setauthor input').setAttrs({name:'author', value:this.options.author}); 1691 content.one('.fp-setlicense select').set('name', 'license'); 1692 this.populate_licenses_select(content.one('.fp-setlicense select')) 1693 // append hidden inputs to the upload form 1694 content.one('form').appendChild(Y.Node.create('<input/>'). 1695 setAttrs({type:'hidden',name:'itemid',value:this.options.itemid})); 1696 var types = this.options.accepted_types; 1697 for (var i in types) { 1698 content.one('form').appendChild(Y.Node.create('<input/>'). 1699 setAttrs({type:'hidden',name:'accepted_types[]',value:types[i]})); 1700 } 1701 1702 var scope = this; 1703 content.one('.fp-upload-btn').on('click', function(e) { 1704 e.preventDefault(); 1705 var license = content.one('.fp-setlicense select'); 1706 1707 this.set_preference('recentlicense', license.get('value')); 1708 if (!content.one('.fp-file input').get('value')) { 1709 scope.print_msg(M.util.get_string('nofilesattached', 'repository'), 'error'); 1710 return false; 1711 } 1712 this.hide_header(); 1713 scope.request({ 1714 scope: scope, 1715 action:'upload', 1716 client_id: client_id, 1717 params: {'savepath':scope.options.savepath}, 1718 repository_id: scope.active_repo.id, 1719 form: {id: id, upload:true}, 1720 onerror: function(id, o, args) { 1721 scope.create_upload_form(data); 1722 }, 1723 callback: function(id, o, args) { 1724 if (o.event == 'fileexists') { 1725 scope.create_upload_form(data); 1726 scope.process_existing_file(o); 1727 return; 1728 } 1729 if (scope.options.editor_target&&scope.options.env=='editor') { 1730 scope.options.editor_target.value=o.url; 1731 scope.options.editor_target.onchange(); 1732 } 1733 scope.hide(); 1734 o.client_id = client_id; 1735 var formcallback_scope = args.scope.options.magicscope ? args.scope.options.magicscope : args.scope; 1736 scope.options.formcallback.apply(formcallback_scope, [o]); 1737 } 1738 }, true); 1739 }, this); 1740 }, 1741 /** setting handlers and labels for elements in toolbar. Called once during the initial render of filepicker */ 1742 setup_toolbar: function() { 1743 var client_id = this.options.client_id; 1744 var toolbar = this.fpnode.one('.fp-toolbar'); 1745 toolbar.one('.fp-tb-logout').one('a,button').on('click', function(e) { 1746 e.preventDefault(); 1747 if (!this.active_repo.nologin) { 1748 this.hide_header(); 1749 this.request({ 1750 action:'logout', 1751 client_id: this.options.client_id, 1752 repository_id: this.active_repo.id, 1753 path:'', 1754 callback: this.display_response 1755 }, true); 1756 } 1757 if (this.active_repo.logouturl) { 1758 window.open(this.active_repo.logouturl, 'repo_auth', 'location=0,status=0,width=500,height=300,scrollbars=yes'); 1759 } 1760 }, this); 1761 toolbar.one('.fp-tb-refresh').one('a,button').on('click', function(e) { 1762 e.preventDefault(); 1763 if (!this.active_repo.norefresh) { 1764 this.list({ path: this.currentpath }); 1765 } 1766 }, this); 1767 toolbar.one('.fp-tb-search form'). 1768 set('method', 'POST'). 1769 set('id', 'fp-tb-search-'+client_id). 1770 on('submit', function(e) { 1771 e.preventDefault(); 1772 if (!this.active_repo.nosearch) { 1773 this.request({ 1774 scope: this, 1775 action:'search', 1776 client_id: this.options.client_id, 1777 repository_id: this.active_repo.id, 1778 form: {id: 'fp-tb-search-'+client_id, upload:false, useDisabled:true}, 1779 callback: this.display_response 1780 }, true); 1781 } 1782 }, this); 1783 1784 // it does not matter what kind of element is .fp-tb-manage, we create a dummy <a> 1785 // element and use it to open url on click event 1786 var managelnk = Y.Node.create('<a/>'). 1787 setAttrs({id:'fp-tb-manage-'+client_id+'-link', target:'_blank'}). 1788 setStyle('display', 'none'); 1789 toolbar.append(managelnk); 1790 toolbar.one('.fp-tb-manage').one('a,button'). 1791 on('click', function(e) { 1792 e.preventDefault(); 1793 managelnk.simulate('click') 1794 }); 1795 1796 // same with .fp-tb-help 1797 var helplnk = Y.Node.create('<a/>'). 1798 setAttrs({id:'fp-tb-help-'+client_id+'-link', target:'_blank'}). 1799 setStyle('display', 'none'); 1800 toolbar.append(helplnk); 1801 toolbar.one('.fp-tb-help').one('a,button'). 1802 on('click', function(e) { 1803 e.preventDefault(); 1804 helplnk.simulate('click') 1805 }); 1806 }, 1807 hide_header: function() { 1808 if (this.fpnode.one('.fp-toolbar')) { 1809 this.fpnode.one('.fp-toolbar').addClass('empty'); 1810 } 1811 if (this.pathbar) { 1812 this.pathbar.setContent('').addClass('empty'); 1813 } 1814 }, 1815 print_header: function() { 1816 var r = this.active_repo; 1817 var scope = this; 1818 var client_id = this.options.client_id; 1819 this.hide_header(); 1820 this.print_path(); 1821 var toolbar = this.fpnode.one('.fp-toolbar'); 1822 if (!toolbar) { return; } 1823 1824 var enable_tb_control = function(node, enabled) { 1825 if (!node) { return; } 1826 node.addClassIf('disabled', !enabled).addClassIf('enabled', enabled) 1827 if (enabled) { 1828 toolbar.removeClass('empty'); 1829 } 1830 } 1831 1832 // TODO 'back' permanently disabled for now. Note, flickr_public uses 'Logout' for it! 1833 enable_tb_control(toolbar.one('.fp-tb-back'), false); 1834 1835 // search form 1836 enable_tb_control(toolbar.one('.fp-tb-search'), !r.nosearch); 1837 if(!r.nosearch) { 1838 var searchform = toolbar.one('.fp-tb-search form'); 1839 searchform.setContent(''); 1840 this.request({ 1841 scope: this, 1842 action:'searchform', 1843 repository_id: this.active_repo.id, 1844 callback: function(id, obj, args) { 1845 if (obj.repo_id == scope.active_repo.id && obj.form) { 1846 // if we did not jump to another repository meanwhile 1847 searchform.setContent(obj.form); 1848 // Highlight search text when user click for search. 1849 var searchnode = searchform.one('input[name="s"]'); 1850 if (searchnode) { 1851 searchnode.once('click', function(e) { 1852 e.preventDefault(); 1853 this.select(); 1854 }); 1855 } 1856 } 1857 } 1858 }, false); 1859 } 1860 1861 // refresh button 1862 // weather we use cache for this instance, this button will reload listing anyway 1863 enable_tb_control(toolbar.one('.fp-tb-refresh'), !r.norefresh); 1864 1865 // login button 1866 enable_tb_control(toolbar.one('.fp-tb-logout'), !r.nologin); 1867 1868 // manage url 1869 enable_tb_control(toolbar.one('.fp-tb-manage'), r.manage); 1870 Y.one('#fp-tb-manage-'+client_id+'-link').set('href', r.manage); 1871 1872 // help url 1873 enable_tb_control(toolbar.one('.fp-tb-help'), r.help); 1874 Y.one('#fp-tb-help-'+client_id+'-link').set('href', r.help); 1875 1876 // message 1877 enable_tb_control(toolbar.one('.fp-tb-message'), r.message); 1878 toolbar.one('.fp-tb-message').setContent(r.message); 1879 }, 1880 print_path: function() { 1881 if (!this.pathbar) { 1882 return; 1883 } 1884 this.pathbar.setContent('').addClass('empty'); 1885 var p = this.filepath; 1886 if (p && p.length!=0 && this.viewmode != 2) { 1887 for(var i = 0; i < p.length; i++) { 1888 var el = this.pathnode.cloneNode(true); 1889 this.pathbar.appendChild(el); 1890 if (i == 0) { 1891 el.addClass('first'); 1892 } 1893 if (i == p.length-1) { 1894 el.addClass('last'); 1895 } 1896 if (i%2) { 1897 el.addClass('even'); 1898 } else { 1899 el.addClass('odd'); 1900 } 1901 el.all('.fp-path-folder-name').setContent(Y.Escape.html(p[i].name)); 1902 el.on('click', 1903 function(e, path) { 1904 e.preventDefault(); 1905 this.list({'path':path}); 1906 }, 1907 this, p[i].path); 1908 } 1909 this.pathbar.removeClass('empty'); 1910 } 1911 }, 1912 hide: function() { 1913 this.selectui.hide(); 1914 if (this.process_dlg) { 1915 this.process_dlg.hide(); 1916 } 1917 if (this.msg_dlg) { 1918 this.msg_dlg.hide(); 1919 } 1920 this.mainui.hide(); 1921 }, 1922 show: function() { 1923 if (this.fpnode) { 1924 this.hide(); 1925 this.mainui.show(); 1926 this.show_recent_repository(); 1927 } else { 1928 this.launch(); 1929 } 1930 }, 1931 launch: function() { 1932 this.render(); 1933 }, 1934 show_recent_repository: function() { 1935 this.hide_header(); 1936 this.viewbar_set_enabled(false); 1937 var repository_id = this.get_preference('recentrepository'); 1938 this.viewmode = this.get_preference('recentviewmode'); 1939 if (this.viewmode != 2 && this.viewmode != 3) { 1940 this.viewmode = 1; 1941 } 1942 if (this.options.repositories[repository_id]) { 1943 this.list({'repo_id':repository_id}); 1944 } 1945 }, 1946 get_preference: function (name) { 1947 if (this.options.userprefs[name]) { 1948 return this.options.userprefs[name]; 1949 } else { 1950 return false; 1951 } 1952 }, 1953 set_preference: function(name, value) { 1954 if (this.options.userprefs[name] != value) { 1955 M.util.set_user_preference('filepicker_' + name, value); 1956 this.options.userprefs[name] = value; 1957 } 1958 }, 1959 in_iframe: function () { 1960 // If we're not the top window then we're in an iFrame 1961 return window.self !== window.top; 1962 } 1963 }); 1964 var loading = Y.one('#filepicker-loading-'+options.client_id); 1965 if (loading) { 1966 loading.setStyle('display', 'none'); 1967 } 1968 M.core_filepicker.instances[options.client_id] = new FilePickerHelper(options); 1969 };
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |