[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 // YUI3 File Picker module for moodle 2 // Author: Dongsheng Cai <[email protected]> 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.str.moodle.name, allowHTML: true, formatter: formatTitle, 335 sortable: true, sortFn: sortFoldersFirst}, 336 {key: "datemodified", label: M.str.moodle.lastmodified, allowHTML: true, formatter: formatValue, 337 sortable: true, sortFn: sortFoldersFirst}, 338 {key: "size", label: M.str.repository.size, allowHTML: true, formatter: formatValue, 339 sortable: true, sortFn: sortFoldersFirst}, 340 {key: "mimetype", label: M.str.repository.type, 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.str.repository.fileexistsdialogheader, 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.str.repository.fileexistsdialog_editor); 736 } else { 737 node.one('.fp-dlg-text').setContent(M.str.repository.fileexistsdialog_filemanager); 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.str.moodle.error; 755 if (type != 'error') { 756 type = 'info'; // one of only two types excepted 757 header = M.str.moodle.info; 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.str.repository.nofilesavailable, '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.str.repository.nofilesavailable, '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.str.repository.nofilesavailable, '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.str.repository.nofilesavailable, '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.str.repository.select+' '+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 this.fpnode = Y.Node.createWithFilesSkin(M.core_filepicker.templates.generallayout). 1303 set('id', 'filepicker-'+client_id).set('aria-labelledby', labelid); 1304 this.mainui = new M.core.dialogue({ 1305 extraClasses : ['filepicker'], 1306 draggable : true, 1307 bodyContent : this.fpnode, 1308 headerContent: '<h3 id="'+ labelid +'">'+ M.str.repository.filepicker +'</h3>', 1309 centered : true, 1310 modal : true, 1311 visible : false, 1312 width : '873px', 1313 responsiveWidth : 873, 1314 height : '558px', 1315 zIndex : this.options.zIndex 1316 }); 1317 1318 // create panel for selecting a file (initially hidden) 1319 this.selectnode = Y.Node.createWithFilesSkin(M.core_filepicker.templates.selectlayout). 1320 set('id', 'filepicker-select-'+client_id). 1321 set('aria-live', 'assertive'). 1322 set('role', 'dialog'); 1323 1324 var fplabel = 'fp-file_label_'+ client_id; 1325 this.selectui = new M.core.dialogue({ 1326 headerContent: '<h3 id="' + fplabel +'">'+M.str.repository.select+'</h3>', 1327 draggable : true, 1328 width : '450px', 1329 bodyContent : this.selectnode, 1330 centered : true, 1331 modal : true, 1332 visible : false, 1333 zIndex : this.options.zIndex 1334 }); 1335 Y.one('#'+this.selectnode.get('id')).setAttribute('aria-labelledby', fplabel); 1336 // event handler for lazy loading of thumbnails and next page 1337 this.fpnode.one('.fp-content').on(['scroll','resize'], this.content_scrolled, this); 1338 // save template for one path element and location of path bar 1339 if (this.fpnode.one('.fp-path-folder')) { 1340 this.pathnode = this.fpnode.one('.fp-path-folder'); 1341 this.pathbar = this.pathnode.get('parentNode'); 1342 this.pathbar.removeChild(this.pathnode); 1343 } 1344 // assign callbacks for view mode switch buttons 1345 this.fpnode.one('.fp-vb-icons').on('click', this.viewbar_clicked, this); 1346 this.fpnode.one('.fp-vb-tree').on('click', this.viewbar_clicked, this); 1347 this.fpnode.one('.fp-vb-details').on('click', this.viewbar_clicked, this); 1348 1349 // assign callbacks for toolbar links 1350 this.setup_toolbar(); 1351 this.setup_select_file(); 1352 this.hide_header(); 1353 1354 // processing repository listing 1355 // Resort the repositories by sortorder 1356 var sorted_repositories = []; 1357 for (var i in this.options.repositories) { 1358 sorted_repositories[i] = this.options.repositories[i]; 1359 } 1360 sorted_repositories.sort(function(a,b){return a.sortorder-b.sortorder}); 1361 // extract one repository template and repeat it for all repositories available, 1362 // set name and icon and assign callbacks 1363 var reponode = this.fpnode.one('.fp-repo'); 1364 if (reponode) { 1365 var list = reponode.get('parentNode'); 1366 list.removeChild(reponode); 1367 for (i in sorted_repositories) { 1368 var repository = sorted_repositories[i]; 1369 var node = reponode.cloneNode(true); 1370 list.appendChild(node); 1371 node. 1372 set('id', 'fp-repo-'+client_id+'-'+repository.id). 1373 on('click', function(e, repository_id) { 1374 e.preventDefault(); 1375 this.set_preference('recentrepository', repository_id); 1376 this.hide_header(); 1377 this.list({'repo_id':repository_id}); 1378 }, this /*handler running scope*/, repository.id/*second argument of handler*/); 1379 node.one('.fp-repo-name').setContent(Y.Escape.html(repository.name)); 1380 node.one('.fp-repo-icon').set('src', repository.icon); 1381 if (i==0) { 1382 node.addClass('first'); 1383 } 1384 if (i==sorted_repositories.length-1) { 1385 node.addClass('last'); 1386 } 1387 if (i%2) { 1388 node.addClass('even'); 1389 } else { 1390 node.addClass('odd'); 1391 } 1392 } 1393 } 1394 // display error if no repositories found 1395 if (sorted_repositories.length==0) { 1396 this.display_error(M.str.repository.norepositoriesavailable, 'norepositoriesavailable') 1397 } 1398 // display repository that was used last time 1399 this.mainui.show(); 1400 this.show_recent_repository(); 1401 }, 1402 parse_repository_options: function(data, appendtolist) { 1403 if (appendtolist) { 1404 if (data.list) { 1405 if (!this.filelist) { 1406 this.filelist = []; 1407 } 1408 for (var i in data.list) { 1409 this.filelist[this.filelist.length] = data.list[i]; 1410 } 1411 } 1412 } else { 1413 this.filelist = data.list?data.list:null; 1414 this.lazyloading = {}; 1415 } 1416 this.filepath = data.path?data.path:null; 1417 this.objecttag = data.object?data.object:null; 1418 this.active_repo = {}; 1419 this.active_repo.issearchresult = data.issearchresult ? true : false; 1420 this.active_repo.dynload = data.dynload?data.dynload:false; 1421 this.active_repo.pages = Number(data.pages?data.pages:null); 1422 this.active_repo.page = Number(data.page?data.page:null); 1423 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)) 1424 this.active_repo.id = data.repo_id?data.repo_id:null; 1425 this.active_repo.nosearch = (data.login || data.nosearch); // this is either login form or 'nosearch' attribute set 1426 this.active_repo.norefresh = (data.login || data.norefresh); // this is either login form or 'norefresh' attribute set 1427 this.active_repo.nologin = (data.login || data.nologin); // this is either login form or 'nologin' attribute is set 1428 this.active_repo.logouttext = data.logouttext?data.logouttext:null; 1429 this.active_repo.logouturl = (data.logouturl || ''); 1430 this.active_repo.message = (data.message || ''); 1431 this.active_repo.help = data.help?data.help:null; 1432 this.active_repo.manage = data.manage?data.manage:null; 1433 this.print_header(); 1434 }, 1435 print_login: function(data) { 1436 this.parse_repository_options(data); 1437 var client_id = this.options.client_id; 1438 var repository_id = data.repo_id; 1439 var l = this.logindata = data.login; 1440 var loginurl = ''; 1441 var action = data['login_btn_action'] ? data['login_btn_action'] : 'login'; 1442 var form_id = 'fp-form-'+client_id; 1443 1444 var loginform_node = Y.Node.create(M.core_filepicker.templates.loginform); 1445 loginform_node.one('form').set('id', form_id); 1446 this.fpnode.one('.fp-content').setContent('').appendChild(loginform_node); 1447 var templates = { 1448 'popup' : loginform_node.one('.fp-login-popup'), 1449 'textarea' : loginform_node.one('.fp-login-textarea'), 1450 'select' : loginform_node.one('.fp-login-select'), 1451 'text' : loginform_node.one('.fp-login-text'), 1452 'radio' : loginform_node.one('.fp-login-radiogroup'), 1453 'checkbox' : loginform_node.one('.fp-login-checkbox'), 1454 'input' : loginform_node.one('.fp-login-input') 1455 }; 1456 var container; 1457 for (var i in templates) { 1458 if (templates[i]) { 1459 container = templates[i].get('parentNode'); 1460 container.removeChild(templates[i]); 1461 } 1462 } 1463 1464 for(var k in l) { 1465 if (templates[l[k].type]) { 1466 var node = templates[l[k].type].cloneNode(true); 1467 } else { 1468 node = templates['input'].cloneNode(true); 1469 } 1470 if (l[k].type == 'popup') { 1471 // submit button 1472 loginurl = l[k].url; 1473 var popupbutton = node.one('button'); 1474 popupbutton.on('click', function(e){ 1475 M.core_filepicker.active_filepicker = this; 1476 window.open(loginurl, 'repo_auth', 'location=0,status=0,width=500,height=300,scrollbars=yes'); 1477 e.preventDefault(); 1478 }, this); 1479 loginform_node.one('form').on('keydown', function(e) { 1480 if (e.keyCode == 13) { 1481 popupbutton.simulate('click'); 1482 e.preventDefault(); 1483 } 1484 }, this); 1485 loginform_node.all('.fp-login-submit').remove(); 1486 action = 'popup'; 1487 } else if(l[k].type=='textarea') { 1488 // textarea element 1489 if (node.one('label')) { 1490 node.one('label').set('for', l[k].id).setContent(l[k].label); 1491 } 1492 node.one('textarea').setAttrs({id:l[k].id, name:l[k].name}); 1493 } else if(l[k].type=='select') { 1494 // select element 1495 if (node.one('label')) { 1496 node.one('label').set('for', l[k].id).setContent(l[k].label); 1497 } 1498 node.one('select').setAttrs({id:l[k].id, name:l[k].name}).setContent(''); 1499 for (i in l[k].options) { 1500 node.one('select').appendChild( 1501 Y.Node.create('<option/>'). 1502 set('value', l[k].options[i].value). 1503 setContent(l[k].options[i].label)); 1504 } 1505 } else if(l[k].type=='radio') { 1506 // radio input element 1507 node.all('label').setContent(l[k].label); 1508 var list = l[k].value.split('|'); 1509 var labels = l[k].value_label.split('|'); 1510 var radionode = null; 1511 for(var item in list) { 1512 if (radionode == null) { 1513 radionode = node.one('.fp-login-radio'); 1514 radionode.one('input').set('checked', 'checked'); 1515 } else { 1516 var x = radionode.cloneNode(true); 1517 radionode.insert(x, 'after'); 1518 radionode = x; 1519 radionode.one('input').set('checked', ''); 1520 } 1521 radionode.one('input').setAttrs({id:''+l[k].id+item, name:l[k].name, 1522 type:l[k].type, value:list[item]}); 1523 radionode.all('label').setContent(labels[item]).set('for', ''+l[k].id+item) 1524 } 1525 if (radionode == null) { 1526 node.one('.fp-login-radio').remove(); 1527 } 1528 } else { 1529 // input element 1530 if (node.one('label')) { node.one('label').set('for', l[k].id).setContent(l[k].label) } 1531 node.one('input'). 1532 set('type', l[k].type). 1533 set('id', l[k].id). 1534 set('name', l[k].name). 1535 set('value', l[k].value?l[k].value:'') 1536 } 1537 container.appendChild(node); 1538 } 1539 // custom label text for submit button 1540 if (data['login_btn_label']) { 1541 loginform_node.all('.fp-login-submit').setContent(data['login_btn_label']) 1542 } 1543 // register button action for login and search 1544 if (action == 'login' || action == 'search') { 1545 loginform_node.one('.fp-login-submit').on('click', function(e){ 1546 e.preventDefault(); 1547 this.hide_header(); 1548 this.request({ 1549 'scope': this, 1550 'action':(action == 'search') ? 'search' : 'signin', 1551 'path': '', 1552 'client_id': client_id, 1553 'repository_id': repository_id, 1554 'form': {id:form_id, upload:false, useDisabled:true}, 1555 'callback': this.display_response 1556 }, true); 1557 }, this); 1558 } 1559 // if 'Enter' is pressed in the form, simulate the button click 1560 if (loginform_node.one('.fp-login-submit')) { 1561 loginform_node.one('form').on('keydown', function(e) { 1562 if (e.keyCode == 13) { 1563 loginform_node.one('.fp-login-submit').simulate('click') 1564 e.preventDefault(); 1565 } 1566 }, this); 1567 } 1568 }, 1569 display_response: function(id, obj, args) { 1570 var scope = args.scope; 1571 // highlight the current repository in repositories list 1572 scope.fpnode.all('.fp-repo.active').removeClass('active'); 1573 scope.fpnode.all('#fp-repo-'+scope.options.client_id+'-'+obj.repo_id).addClass('active') 1574 // add class repository_REPTYPE to the filepicker (for repository-specific styles) 1575 for (var i in scope.options.repositories) { 1576 scope.fpnode.removeClass('repository_'+scope.options.repositories[i].type) 1577 } 1578 if (obj.repo_id && scope.options.repositories[obj.repo_id]) { 1579 scope.fpnode.addClass('repository_'+scope.options.repositories[obj.repo_id].type) 1580 } 1581 Y.one('.file-picker .fp-repo-items').focus(); 1582 1583 // display response 1584 if (obj.login) { 1585 scope.viewbar_set_enabled(false); 1586 scope.print_login(obj); 1587 } else if (obj.upload) { 1588 scope.viewbar_set_enabled(false); 1589 scope.parse_repository_options(obj); 1590 scope.create_upload_form(obj); 1591 } else if (obj.object) { 1592 M.core_filepicker.active_filepicker = scope; 1593 scope.viewbar_set_enabled(false); 1594 scope.parse_repository_options(obj); 1595 scope.create_object_container(obj.object); 1596 } else if (obj.list) { 1597 scope.viewbar_set_enabled(true); 1598 scope.parse_repository_options(obj); 1599 scope.view_files(); 1600 } 1601 }, 1602 list: function(args) { 1603 if (!args) { 1604 args = {}; 1605 } 1606 if (!args.repo_id) { 1607 args.repo_id = this.active_repo.id; 1608 } 1609 if (!args.path) { 1610 args.path = ''; 1611 } 1612 this.currentpath = args.path; 1613 this.request({ 1614 action: 'list', 1615 client_id: this.options.client_id, 1616 repository_id: args.repo_id, 1617 path: args.path, 1618 page: args.page, 1619 scope: this, 1620 callback: this.display_response 1621 }, true); 1622 }, 1623 populate_licenses_select: function(node) { 1624 if (!node) { 1625 return; 1626 } 1627 node.setContent(''); 1628 var licenses = this.options.licenses; 1629 var recentlicense = this.get_preference('recentlicense'); 1630 if (recentlicense) { 1631 this.options.defaultlicense=recentlicense; 1632 } 1633 for (var i in licenses) { 1634 var option = Y.Node.create('<option/>'). 1635 set('selected', (this.options.defaultlicense==licenses[i].shortname)). 1636 set('value', licenses[i].shortname). 1637 setContent(Y.Escape.html(licenses[i].fullname)); 1638 node.appendChild(option) 1639 } 1640 }, 1641 set_selected_license: function(node, value) { 1642 var licenseset = false; 1643 node.all('option').each(function(el) { 1644 if (el.get('value')==value || el.getContent()==value) { 1645 el.set('selected', true); 1646 licenseset = true; 1647 } 1648 }); 1649 if (!licenseset) { 1650 // we did not find the value in the list 1651 var recentlicense = this.get_preference('recentlicense'); 1652 node.all('option[selected]').set('selected', false); 1653 node.all('option[value='+recentlicense+']').set('selected', true); 1654 } 1655 }, 1656 create_object_container: function(data) { 1657 var content = this.fpnode.one('.fp-content'); 1658 content.setContent(''); 1659 //var str = '<object data="'+data.src+'" type="'+data.type+'" width="98%" height="98%" id="container_object" class="fp-object-container mdl-align"></object>'; 1660 var container = Y.Node.create('<object/>'). 1661 setAttrs({data:data.src, type:data.type, id:'container_object'}). 1662 addClass('fp-object-container'); 1663 content.setContent('').appendChild(container); 1664 }, 1665 create_upload_form: function(data) { 1666 var client_id = this.options.client_id; 1667 var id = data.upload.id+'_'+client_id; 1668 var content = this.fpnode.one('.fp-content'); 1669 var template_name = 'uploadform_'+this.options.repositories[data.repo_id].type; 1670 var template = M.core_filepicker.templates[template_name] || M.core_filepicker.templates['uploadform']; 1671 content.setContent(template); 1672 1673 content.all('.fp-file,.fp-saveas,.fp-setauthor,.fp-setlicense').each(function (node) { 1674 node.all('label').set('for', node.one('input,select').generateID()); 1675 }); 1676 content.one('form').set('id', id); 1677 content.one('.fp-file input').set('name', 'repo_upload_file'); 1678 if (data.upload.label && content.one('.fp-file label')) { 1679 content.one('.fp-file label').setContent(data.upload.label); 1680 } 1681 content.one('.fp-saveas input').set('name', 'title'); 1682 content.one('.fp-setauthor input').setAttrs({name:'author', value:this.options.author}); 1683 content.one('.fp-setlicense select').set('name', 'license'); 1684 this.populate_licenses_select(content.one('.fp-setlicense select')) 1685 // append hidden inputs to the upload form 1686 content.one('form').appendChild(Y.Node.create('<input/>'). 1687 setAttrs({type:'hidden',name:'itemid',value:this.options.itemid})); 1688 var types = this.options.accepted_types; 1689 for (var i in types) { 1690 content.one('form').appendChild(Y.Node.create('<input/>'). 1691 setAttrs({type:'hidden',name:'accepted_types[]',value:types[i]})); 1692 } 1693 1694 var scope = this; 1695 content.one('.fp-upload-btn').on('click', function(e) { 1696 e.preventDefault(); 1697 var license = content.one('.fp-setlicense select'); 1698 1699 this.set_preference('recentlicense', license.get('value')); 1700 if (!content.one('.fp-file input').get('value')) { 1701 scope.print_msg(M.str.repository.nofilesattached, 'error'); 1702 return false; 1703 } 1704 this.hide_header(); 1705 scope.request({ 1706 scope: scope, 1707 action:'upload', 1708 client_id: client_id, 1709 params: {'savepath':scope.options.savepath}, 1710 repository_id: scope.active_repo.id, 1711 form: {id: id, upload:true}, 1712 onerror: function(id, o, args) { 1713 scope.create_upload_form(data); 1714 }, 1715 callback: function(id, o, args) { 1716 if (o.event == 'fileexists') { 1717 scope.create_upload_form(data); 1718 scope.process_existing_file(o); 1719 return; 1720 } 1721 if (scope.options.editor_target&&scope.options.env=='editor') { 1722 scope.options.editor_target.value=o.url; 1723 scope.options.editor_target.onchange(); 1724 } 1725 scope.hide(); 1726 o.client_id = client_id; 1727 var formcallback_scope = args.scope.options.magicscope ? args.scope.options.magicscope : args.scope; 1728 scope.options.formcallback.apply(formcallback_scope, [o]); 1729 } 1730 }, true); 1731 }, this); 1732 }, 1733 /** setting handlers and labels for elements in toolbar. Called once during the initial render of filepicker */ 1734 setup_toolbar: function() { 1735 var client_id = this.options.client_id; 1736 var toolbar = this.fpnode.one('.fp-toolbar'); 1737 toolbar.one('.fp-tb-logout').one('a,button').on('click', function(e) { 1738 e.preventDefault(); 1739 if (!this.active_repo.nologin) { 1740 this.hide_header(); 1741 this.request({ 1742 action:'logout', 1743 client_id: this.options.client_id, 1744 repository_id: this.active_repo.id, 1745 path:'', 1746 callback: this.display_response 1747 }, true); 1748 } 1749 if (this.active_repo.logouturl) { 1750 window.open(this.active_repo.logouturl, 'repo_auth', 'location=0,status=0,width=500,height=300,scrollbars=yes'); 1751 } 1752 }, this); 1753 toolbar.one('.fp-tb-refresh').one('a,button').on('click', function(e) { 1754 e.preventDefault(); 1755 if (!this.active_repo.norefresh) { 1756 this.list({ path: this.currentpath }); 1757 } 1758 }, this); 1759 toolbar.one('.fp-tb-search form'). 1760 set('method', 'POST'). 1761 set('id', 'fp-tb-search-'+client_id). 1762 on('submit', function(e) { 1763 e.preventDefault(); 1764 if (!this.active_repo.nosearch) { 1765 this.request({ 1766 scope: this, 1767 action:'search', 1768 client_id: this.options.client_id, 1769 repository_id: this.active_repo.id, 1770 form: {id: 'fp-tb-search-'+client_id, upload:false, useDisabled:true}, 1771 callback: this.display_response 1772 }, true); 1773 } 1774 }, this); 1775 1776 // it does not matter what kind of element is .fp-tb-manage, we create a dummy <a> 1777 // element and use it to open url on click event 1778 var managelnk = Y.Node.create('<a/>'). 1779 setAttrs({id:'fp-tb-manage-'+client_id+'-link', target:'_blank'}). 1780 setStyle('display', 'none'); 1781 toolbar.append(managelnk); 1782 toolbar.one('.fp-tb-manage').one('a,button'). 1783 on('click', function(e) { 1784 e.preventDefault(); 1785 managelnk.simulate('click') 1786 }); 1787 1788 // same with .fp-tb-help 1789 var helplnk = Y.Node.create('<a/>'). 1790 setAttrs({id:'fp-tb-help-'+client_id+'-link', target:'_blank'}). 1791 setStyle('display', 'none'); 1792 toolbar.append(helplnk); 1793 toolbar.one('.fp-tb-help').one('a,button'). 1794 on('click', function(e) { 1795 e.preventDefault(); 1796 helplnk.simulate('click') 1797 }); 1798 }, 1799 hide_header: function() { 1800 if (this.fpnode.one('.fp-toolbar')) { 1801 this.fpnode.one('.fp-toolbar').addClass('empty'); 1802 } 1803 if (this.pathbar) { 1804 this.pathbar.setContent('').addClass('empty'); 1805 } 1806 }, 1807 print_header: function() { 1808 var r = this.active_repo; 1809 var scope = this; 1810 var client_id = this.options.client_id; 1811 this.hide_header(); 1812 this.print_path(); 1813 var toolbar = this.fpnode.one('.fp-toolbar'); 1814 if (!toolbar) { return; } 1815 1816 var enable_tb_control = function(node, enabled) { 1817 if (!node) { return; } 1818 node.addClassIf('disabled', !enabled).addClassIf('enabled', enabled) 1819 if (enabled) { 1820 toolbar.removeClass('empty'); 1821 } 1822 } 1823 1824 // TODO 'back' permanently disabled for now. Note, flickr_public uses 'Logout' for it! 1825 enable_tb_control(toolbar.one('.fp-tb-back'), false); 1826 1827 // search form 1828 enable_tb_control(toolbar.one('.fp-tb-search'), !r.nosearch); 1829 if(!r.nosearch) { 1830 var searchform = toolbar.one('.fp-tb-search form'); 1831 searchform.setContent(''); 1832 this.request({ 1833 scope: this, 1834 action:'searchform', 1835 repository_id: this.active_repo.id, 1836 callback: function(id, obj, args) { 1837 if (obj.repo_id == scope.active_repo.id && obj.form) { 1838 // if we did not jump to another repository meanwhile 1839 searchform.setContent(obj.form); 1840 // Highlight search text when user click for search. 1841 var searchnode = searchform.one('input[name="s"]'); 1842 if (searchnode) { 1843 searchnode.once('click', function(e) { 1844 e.preventDefault(); 1845 this.select(); 1846 }); 1847 } 1848 } 1849 } 1850 }, false); 1851 } 1852 1853 // refresh button 1854 // weather we use cache for this instance, this button will reload listing anyway 1855 enable_tb_control(toolbar.one('.fp-tb-refresh'), !r.norefresh); 1856 1857 // login button 1858 enable_tb_control(toolbar.one('.fp-tb-logout'), !r.nologin); 1859 1860 // manage url 1861 enable_tb_control(toolbar.one('.fp-tb-manage'), r.manage); 1862 Y.one('#fp-tb-manage-'+client_id+'-link').set('href', r.manage); 1863 1864 // help url 1865 enable_tb_control(toolbar.one('.fp-tb-help'), r.help); 1866 Y.one('#fp-tb-help-'+client_id+'-link').set('href', r.help); 1867 1868 // message 1869 enable_tb_control(toolbar.one('.fp-tb-message'), r.message); 1870 toolbar.one('.fp-tb-message').setContent(r.message); 1871 }, 1872 print_path: function() { 1873 if (!this.pathbar) { 1874 return; 1875 } 1876 this.pathbar.setContent('').addClass('empty'); 1877 var p = this.filepath; 1878 if (p && p.length!=0 && this.viewmode != 2) { 1879 for(var i = 0; i < p.length; i++) { 1880 var el = this.pathnode.cloneNode(true); 1881 this.pathbar.appendChild(el); 1882 if (i == 0) { 1883 el.addClass('first'); 1884 } 1885 if (i == p.length-1) { 1886 el.addClass('last'); 1887 } 1888 if (i%2) { 1889 el.addClass('even'); 1890 } else { 1891 el.addClass('odd'); 1892 } 1893 el.all('.fp-path-folder-name').setContent(Y.Escape.html(p[i].name)); 1894 el.on('click', 1895 function(e, path) { 1896 e.preventDefault(); 1897 this.list({'path':path}); 1898 }, 1899 this, p[i].path); 1900 } 1901 this.pathbar.removeClass('empty'); 1902 } 1903 }, 1904 hide: function() { 1905 this.selectui.hide(); 1906 if (this.process_dlg) { 1907 this.process_dlg.hide(); 1908 } 1909 if (this.msg_dlg) { 1910 this.msg_dlg.hide(); 1911 } 1912 this.mainui.hide(); 1913 }, 1914 show: function() { 1915 if (this.fpnode) { 1916 this.hide(); 1917 this.mainui.show(); 1918 this.show_recent_repository(); 1919 } else { 1920 this.launch(); 1921 } 1922 }, 1923 launch: function() { 1924 this.render(); 1925 }, 1926 show_recent_repository: function() { 1927 this.hide_header(); 1928 this.viewbar_set_enabled(false); 1929 var repository_id = this.get_preference('recentrepository'); 1930 this.viewmode = this.get_preference('recentviewmode'); 1931 if (this.viewmode != 2 && this.viewmode != 3) { 1932 this.viewmode = 1; 1933 } 1934 if (this.options.repositories[repository_id]) { 1935 this.list({'repo_id':repository_id}); 1936 } 1937 }, 1938 get_preference: function (name) { 1939 if (this.options.userprefs[name]) { 1940 return this.options.userprefs[name]; 1941 } else { 1942 return false; 1943 } 1944 }, 1945 set_preference: function(name, value) { 1946 if (this.options.userprefs[name] != value) { 1947 M.util.set_user_preference('filepicker_' + name, value); 1948 this.options.userprefs[name] = value; 1949 } 1950 } 1951 }); 1952 var loading = Y.one('#filepicker-loading-'+options.client_id); 1953 if (loading) { 1954 loading.setStyle('display', 'none'); 1955 } 1956 M.core_filepicker.instances[options.client_id] = new FilePickerHelper(options); 1957 };
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |