moodle/repository/filepicker.js
Tim Hunt adf336cbf2 MDL-82177 file upload: default to path '/'when things go wrong
This 'fix' is basically a work-around, but one that is already used in
some places. Now it is used in all similar places.

Exactly what causes the current file path in a file manager to become
unset is still unclear to me, but it seems to be an obscure race
condition that is very hard to reproduce.

However, when it happens, currently we are effectively defaulting to
path '/undefined/'. Using '/' is never worse, and is infinitely better
in the case where the filepicker does not allow folders to be used
(which includes important cases like essay questions in a quiz, which
some people use for exams!). In that case, falling back to non-top-level
path leads to dataloss.

Also, this is all historic JavaScript which will get replaced in the
grand de-YUI-fication, so I think a pragmatic fix is justified here.
2024-07-30 15:07:02 +01:00

2149 lines
102 KiB
JavaScript

// YUI3 File Picker module for moodle
// Author: Dongsheng Cai <dongsheng@moodle.com>
/**
*
* File Picker UI
* =====
* this.fpnode, contains reference to filepicker Node, non-empty if and only if rendered
* this.api, stores the URL to make ajax request
* this.mainui, YUI Panel
* this.selectnode, contains reference to select-file Node
* this.selectui, YUI Panel for selecting particular file
* this.msg_dlg, YUI Panel for error or info message
* this.process_dlg, YUI Panel for processing existing filename
* this.treeview, YUI Treeview
* this.viewmode, store current view mode
* this.pathbar, reference to the Node with path bar
* this.pathnode, a Node element representing one folder in a path bar (not attached anywhere, just used for template)
* this.currentpath, the current path in the repository (or last requested path)
*
* Filepicker options:
* =====
* this.options.client_id, the instance id
* this.options.contextid
* this.options.itemid
* this.options.repositories, stores all repositories displayed in file picker
* this.options.formcallback
*
* Active repository options
* =====
* this.active_repo.id
* this.active_repo.defaultreturntype
* this.active_repo.nosearch
* this.active_repo.norefresh
* this.active_repo.nologin
* this.active_repo.help
* this.active_repo.manage
*
* Server responses
* =====
* this.filelist, cached filelist
* this.pages
* this.page
* this.filepath, current path (each element of the array is a part of the breadcrumb)
* this.logindata, cached login form
*/
YUI.add('moodle-core_filepicker', function(Y) {
/** help function to extract width/height style as a number, not as a string */
Y.Node.prototype.getStylePx = function(attr) {
var style = this.getStyle(attr);
if (''+style == '0' || ''+style == '0px') {
return 0;
}
var matches = style.match(/^([\d\.]+)px$/)
if (matches && parseFloat(matches[1])) {
return parseFloat(matches[1]);
}
return null;
}
/** if condition is met, the class is added to the node, otherwise - removed */
Y.Node.prototype.addClassIf = function(className, condition) {
if (condition) {
this.addClass(className);
} else {
this.removeClass(className);
}
return this;
}
/** sets the width(height) of the node considering existing minWidth(minHeight) */
Y.Node.prototype.setStyleAdv = function(stylename, value) {
var stylenameCap = stylename.substr(0,1).toUpperCase() + stylename.substr(1, stylename.length-1).toLowerCase();
this.setStyle(stylename, '' + Math.max(value, this.getStylePx('min'+stylenameCap)) + 'px')
return this;
}
/** set image source to src, if there is preview, remember it in lazyloading.
* If there is a preview and it was already loaded, use it. */
Y.Node.prototype.setImgSrc = function(src, realsrc, lazyloading) {
if (realsrc) {
if (M.core_filepicker.loadedpreviews[realsrc]) {
this.set('src', realsrc).addClass('realpreview');
return this;
} else {
if (!this.get('id')) {
this.generateID();
}
lazyloading[this.get('id')] = realsrc;
}
}
this.set('src', src);
return this;
}
/**
* Replaces the image source with preview. If the image is inside the treeview, we need
* also to update the html property of corresponding YAHOO.widget.HTMLNode
* @param array lazyloading array containing associations of imgnodeid->realsrc
*/
Y.Node.prototype.setImgRealSrc = function(lazyloading) {
if (this.get('id') && lazyloading[this.get('id')]) {
var newsrc = lazyloading[this.get('id')];
M.core_filepicker.loadedpreviews[newsrc] = true;
this.set('src', newsrc).addClass('realpreview');
delete lazyloading[this.get('id')];
var treenode = this.ancestor('.fp-treeview')
if (treenode && treenode.get('parentNode').treeview) {
treenode.get('parentNode').treeview.getRoot().refreshPreviews(this.get('id'), newsrc);
}
}
return this;
}
/** scan TreeView to find which node contains image with id=imgid and replace it's html
* with the new image source. */
Y.YUI2.widget.Node.prototype.refreshPreviews = function(imgid, newsrc, regex) {
if (!regex) {
regex = new RegExp("<img\\s[^>]*id=\""+imgid+"\"[^>]*?(/?)>", "im");
}
if (this.expanded || this.isLeaf) {
var html = this.getContentHtml();
if (html && this.setHtml && regex.test(html)) {
var newhtml = this.html.replace(regex, "<img id=\""+imgid+"\" src=\""+newsrc+"\" class=\"realpreview\"$1>", html);
this.setHtml(newhtml);
return true;
}
if (!this.isLeaf && this.children) {
for(var c in this.children) {
if (this.children[c].refreshPreviews(imgid, newsrc, regex)) {
return true;
}
}
}
}
return false;
}
/**
* Displays a list of files (used by filepicker, filemanager) inside the Node
*
* @param array options
* viewmode : 1 - icons, 2 - tree, 3 - table
* appendonly : whether fileslist need to be appended instead of replacing the existing content
* filenode : Node element that contains template for displaying one file
* callback : On click callback. The element of the fileslist array will be passed as argument
* rightclickcallback : On right click callback (optional).
* callbackcontext : context where callbacks are executed
* sortable : whether content may be sortable (in table mode)
* dynload : allow dynamic load for tree view
* filepath : for pre-building of tree view - the path to the current directory in filepicker format
* treeview_dynload : callback to function to dynamically load the folder in tree view
* classnamecallback : callback to function that returns the class name for an element
* @param array fileslist array of files to show, each array element may have attributes:
* title or fullname : file name
* shorttitle (optional) : display file name
* thumbnail : url of image
* icon : url of icon image
* thumbnail_width : width of thumbnail, default 90
* thumbnail_height : height of thumbnail, default 90
* thumbnail_alt : TODO not needed!
* description or thumbnail_title : alt text
* @param array lazyloading : reference to the array with lazy loading images
*/
Y.Node.prototype.fp_display_filelist = function(options, fileslist, lazyloading) {
var viewmodeclassnames = {1:'fp-iconview', 2:'fp-treeview', 3:'fp-tableview'};
var classname = viewmodeclassnames[options.viewmode];
var scope = this;
/** return whether file is a folder (different attributes in FileManager and FilePicker) */
var file_is_folder = function(node) {
if (node.children) {return true;}
if (node.type && node.type == 'folder') {return true;}
return false;
};
/** return the name of the file (different attributes in FileManager and FilePicker) */
var file_get_filename = function(node) {
return node.title ? node.title : node.fullname;
};
/** return display name of the file (different attributes in FileManager and FilePicker) */
var file_get_displayname = function(node) {
var displayname = node.shorttitle ? node.shorttitle : file_get_filename(node);
return Y.Escape.html(displayname);
};
/** return file description (different attributes in FileManager and FilePicker) */
var file_get_description = function(node) {
var description = '';
if (node.description) {
description = node.description;
} else if (node.thumbnail_title) {
description = node.thumbnail_title;
} else {
description = file_get_filename(node);
}
return Y.Escape.html(description);
};
/** help funciton for tree view */
var build_tree = function(node, level) {
// prepare file name with icon
var el = Y.Node.create('<div/>');
el.appendChild(options.filenode.cloneNode(true));
el.one('.fp-filename').setContent(file_get_displayname(node));
// TODO add tooltip with node.title or node.thumbnail_title
var tmpnodedata = {className:options.classnamecallback(node)};
el.get('children').addClass(tmpnodedata.className);
if (node.icon) {
el.one('.fp-icon').appendChild(Y.Node.create('<img/>'));
el.one('.fp-icon img').setImgSrc(node.icon, node.realicon, lazyloading);
}
// create node
tmpnodedata.html = el.getContent();
var tmpNode = new Y.YUI2.widget.HTMLNode(tmpnodedata, level, false);
if (node.dynamicLoadComplete) {
tmpNode.dynamicLoadComplete = true;
}
tmpNode.fileinfo = node;
tmpNode.isLeaf = !file_is_folder(node);
if (!tmpNode.isLeaf) {
if(node.expanded) {
tmpNode.expand();
}
tmpNode.path = node.path ? node.path : (node.filepath ? node.filepath : '');
for(var c in node.children) {
build_tree(node.children[c], tmpNode);
}
}
};
/** initialize tree view */
var initialize_tree_view = function() {
var parentid = scope.one('.'+classname).get('id');
// TODO MDL-32736 use YUI3 gallery TreeView
scope.treeview = new Y.YUI2.widget.TreeView(parentid);
if (options.dynload) {
scope.treeview.setDynamicLoad(Y.bind(options.treeview_dynload, options.callbackcontext), 1);
}
scope.treeview.singleNodeHighlight = true;
if (options.filepath && options.filepath.length) {
// we just jumped from icon/details view, we need to show all parents
// we extract as much information as possible from filepath and filelist
// and send additional requests to retrieve siblings for parent folders
var mytree = {};
var mytreeel = null;
for (var i in options.filepath) {
if (mytreeel == null) {
mytreeel = mytree;
} else {
mytreeel.children = [{}];
mytreeel = mytreeel.children[0];
}
var pathelement = options.filepath[i];
mytreeel.path = pathelement.path;
mytreeel.title = pathelement.name;
mytreeel.icon = pathelement.icon;
mytreeel.dynamicLoadComplete = true; // we will call it manually
mytreeel.expanded = true;
}
mytreeel.children = fileslist;
build_tree(mytree, scope.treeview.getRoot());
// manually call dynload for parent elements in the tree so we can load other siblings
if (options.dynload) {
var root = scope.treeview.getRoot();
// Whether search results are currently displayed in the active repository in the filepicker.
// We do not want to load siblings of parent elements when displaying search tree results.
var isSearchResult = typeof options.callbackcontext.active_repo !== 'undefined' &&
options.callbackcontext.active_repo.issearchresult;
while (root && root.children && root.children.length) {
root = root.children[0];
if (root.path == mytreeel.path) {
root.origpath = options.filepath;
root.origlist = fileslist;
} else if (!root.isLeaf && root.expanded && !isSearchResult) {
Y.bind(options.treeview_dynload, options.callbackcontext)(root, null);
}
}
}
} else {
// there is no path information, just display all elements as a list, without hierarchy
for(k in fileslist) {
build_tree(fileslist[k], scope.treeview.getRoot());
}
}
scope.treeview.subscribe('clickEvent', function(e){
e.node.highlight(false);
var callback = options.callback;
if (options.rightclickcallback && e.event.target &&
Y.Node(e.event.target).ancestor('.fp-treeview .fp-contextmenu', true)) {
callback = options.rightclickcallback;
}
Y.bind(callback, options.callbackcontext)(e, e.node.fileinfo);
Y.YUI2.util.Event.stopEvent(e.event)
});
// Simulate click on file not folder.
scope.treeview.subscribe('enterKeyPressed', function(node) {
if (node.children.length === 0) {
Y.one(node.getContentEl()).one('a').simulate('click');
}
});
// TODO MDL-32736 support right click
/*if (options.rightclickcallback) {
scope.treeview.subscribe('dblClickEvent', function(e){
e.node.highlight(false);
Y.bind(options.rightclickcallback, options.callbackcontext)(e, e.node.fileinfo);
});
}*/
scope.treeview.draw();
};
/** formatting function for table view */
var formatValue = function (o){
if (o.data[''+o.column.key+'_f_s']) {return o.data[''+o.column.key+'_f_s'];}
else if (o.data[''+o.column.key+'_f']) {return o.data[''+o.column.key+'_f'];}
else if (o.value) {return o.value;}
else {return '';}
};
/** formatting function for table view */
var formatTitle = function(o) {
var el = Y.Node.create('<div/>');
el.appendChild(options.filenode.cloneNode(true)); // TODO not node but string!
el.get('children').addClass(o.data['classname']);
el.one('.fp-filename').setContent(o.value);
if (o.data['icon']) {
el.one('.fp-icon').appendChild(Y.Node.create('<img/>'));
el.one('.fp-icon img').setImgSrc(o.data['icon'], o.data['realicon'], lazyloading);
}
if (options.rightclickcallback) {
el.get('children').addClass('fp-hascontextmenu');
}
// TODO add tooltip with o.data['title'] (o.value) or o.data['thumbnail_title']
return el.getContent();
}
/**
* Generate slave checkboxes based on toggleall's specification
* @param {object} o An object reprsenting the record for the current row.
* @return {html} The checkbox html
*/
var formatCheckbox = function(o) {
var el = Y.Node.create('<div/>');
var parentid = scope.one('.' + classname).get('id');
var checkbox = Y.Node.create('<input/>')
.setAttribute('type', 'checkbox')
.setAttribute('data-fieldtype', 'checkbox')
.setAttribute('data-fullname', o.data.fullname)
.setAttribute('data-action', 'toggle')
.setAttribute('data-toggle', 'slave')
.setAttribute('data-togglegroup', 'file-selections-' + parentid);
var checkboxLabel = Y.Node.create('<label>')
.setHTML("Select file '" + o.data.fullname + "'")
.addClass('sr-only')
.setAttrs({
for: checkbox.generateID(),
});
el.appendChild(checkbox);
el.appendChild(checkboxLabel);
return el.getContent();
};
/** sorting function for table view */
var sortFoldersFirst = function(a, b, desc) {
if (a.get('isfolder') && !b.get('isfolder')) {
return -1;
}
if (!a.get('isfolder') && b.get('isfolder')) {
return 1;
}
var aa = a.get(this.key), bb = b.get(this.key), dir = desc ? -1 : 1;
return (aa > bb) ? dir : ((aa < bb) ? -dir : 0);
}
/** initialize table view */
var initialize_table_view = function() {
var cols = [
{key: "displayname", label: M.util.get_string('name', 'moodle'), allowHTML: true, formatter: formatTitle,
sortable: true, sortFn: sortFoldersFirst},
{key: "datemodified", label: M.util.get_string('lastmodified', 'moodle'), allowHTML: true, formatter: formatValue,
sortable: true, sortFn: sortFoldersFirst},
{key: "size", label: M.util.get_string('size', 'repository'), allowHTML: true, formatter: formatValue,
sortable: true, sortFn: sortFoldersFirst},
{key: "mimetype", label: M.util.get_string('type', 'repository'), allowHTML: true,
sortable: true, sortFn: sortFoldersFirst}
];
// Generate a checkbox based on toggleall's specification
var div = Y.Node.create('<div/>');
var parentid = scope.one('.' + classname).get('id');
var checkbox = Y.Node.create('<input/>')
.setAttribute('type', 'checkbox')
// .setAttribute('title', M.util.get_string('selectallornone', 'form'))
.setAttribute('data-action', 'toggle')
.setAttribute('data-toggle', 'master')
.setAttribute('data-togglegroup', 'file-selections-' + parentid);
var checkboxLabel = Y.Node.create('<label>')
.setHTML(M.util.get_string('selectallornone', 'form'))
.addClass('sr-only')
.setAttrs({
for: checkbox.generateID(),
});
div.appendChild(checkboxLabel);
div.appendChild(checkbox);
// Define the selector for the click event handler.
var clickEventSelector = 'tr';
// Enable the selectable checkboxes
if (options.disablecheckboxes != undefined && !options.disablecheckboxes) {
clickEventSelector = 'tr td:not(:first-child)';
cols.unshift({
key: "",
label: div.getContent(),
allowHTML: true,
formatter: formatCheckbox,
sortable: false
});
}
scope.tableview = new Y.DataTable({columns: cols, data: fileslist});
scope.tableview.delegate('click', function (e, tableview) {
var record = tableview.getRecord(e.currentTarget.get('id'));
if (record) {
var callback = options.callback;
if (options.rightclickcallback && e.target.ancestor('.fp-tableview .fp-contextmenu', true)) {
callback = options.rightclickcallback;
}
Y.bind(callback, this)(e, record.getAttrs());
}
}, clickEventSelector, options.callbackcontext, scope.tableview);
if (options.rightclickcallback) {
scope.tableview.delegate('contextmenu', function (e, tableview) {
var record = tableview.getRecord(e.currentTarget.get('id'));
if (record) { Y.bind(options.rightclickcallback, this)(e, record.getAttrs()); }
}, 'tr', options.callbackcontext, scope.tableview);
}
}
/** append items in table view mode */
var append_files_table = function() {
if (options.appendonly) {
fileslist.forEach(function(el) {
this.tableview.data.add(el);
},scope);
}
scope.tableview.render(scope.one('.'+classname));
scope.tableview.sortable = options.sortable ? true : false;
};
/** append items in tree view mode */
var append_files_tree = function() {
if (options.appendonly) {
var parentnode = scope.treeview.getRoot();
if (scope.treeview.getHighlightedNode()) {
parentnode = scope.treeview.getHighlightedNode();
if (parentnode.isLeaf) {parentnode = parentnode.parent;}
}
for (var k in fileslist) {
build_tree(fileslist[k], parentnode);
}
scope.treeview.draw();
} else {
// otherwise files were already added in initialize_tree_view()
}
}
/** append items in icon view mode */
var append_files_icons = function() {
parent = scope.one('.'+classname);
for (var k in fileslist) {
var node = fileslist[k];
var element = options.filenode.cloneNode(true);
parent.appendChild(element);
element.addClass(options.classnamecallback(node));
var filenamediv = element.one('.fp-filename');
filenamediv.setContent(file_get_displayname(node));
var imgdiv = element.one('.fp-thumbnail'), width, height, src;
if (node.thumbnail) {
width = node.thumbnail_width ? node.thumbnail_width : 90;
height = node.thumbnail_height ? node.thumbnail_height : 90;
src = node.thumbnail;
} else {
width = 16;
height = 16;
src = node.icon;
}
filenamediv.setStyleAdv('width', width);
imgdiv.setStyleAdv('width', width).setStyleAdv('height', height);
var img = Y.Node.create('<img/>').setAttrs({
title: file_get_description(node),
alt: Y.Escape.html(node.thumbnail_alt ? node.thumbnail_alt : file_get_filename(node))}).
setStyle('maxWidth', ''+width+'px').
setStyle('maxHeight', ''+height+'px');
img.setImgSrc(src, node.realthumbnail, lazyloading);
imgdiv.appendChild(img);
element.on('click', function(e, nd) {
if (options.rightclickcallback && e.target.ancestor('.fp-iconview .fp-contextmenu', true)) {
Y.bind(options.rightclickcallback, this)(e, nd);
} else {
Y.bind(options.callback, this)(e, nd);
}
}, options.callbackcontext, node);
if (options.rightclickcallback) {
element.on('contextmenu', options.rightclickcallback, options.callbackcontext, node);
}
}
}
// Notify the user if any of the files has a problem status.
var problemFiles = [];
fileslist.forEach(function(file) {
if (!file_is_folder(file) && file.hasOwnProperty('status') && file.status != 0) {
problemFiles.push(file);
}
});
if (problemFiles.length > 0) {
require(["core/notification", "core/str"], function(Notification, Str) {
problemFiles.forEach(function(problemFile) {
Str.get_string('storedfilecannotreadfile', 'error', problemFile.fullname).then(function(string) {
Notification.addNotification({
message: string,
type: "error"
});
return;
}).catch(Notification.exception);
});
});
}
// If table view, need some additional properties
// before passing fileslist to the YUI tableview
if (options.viewmode == 3) {
fileslist.forEach(function(el) {
el.displayname = file_get_displayname(el);
el.isfolder = file_is_folder(el);
el.classname = options.classnamecallback(el);
}, scope);
}
// initialize files view
if (!options.appendonly) {
var parent = Y.Node.create('<div/>').addClass(classname);
this.setContent('').appendChild(parent);
parent.generateID();
if (options.viewmode == 2) {
initialize_tree_view();
} else if (options.viewmode == 3) {
initialize_table_view();
} else {
// nothing to initialize for icon view
}
}
// append files to the list
if (options.viewmode == 2) {
append_files_tree();
} else if (options.viewmode == 3) {
append_files_table();
} else {
append_files_icons();
}
}
}, '@VERSION@', {
requires:['base', 'node', 'yui2-treeview', 'panel', 'cookie', 'datatable', 'datatable-sort']
});
M.core_filepicker = M.core_filepicker || {};
/**
* instances of file pickers used on page
*/
M.core_filepicker.instances = M.core_filepicker.instances || {};
M.core_filepicker.active_filepicker = null;
/**
* HTML Templates to use in FilePicker
*/
M.core_filepicker.templates = M.core_filepicker.templates || {};
/**
* Array of image sources for real previews (realicon or realthumbnail) that are already loaded
*/
M.core_filepicker.loadedpreviews = M.core_filepicker.loadedpreviews || {};
/**
* Set selected file info
*
* @param object file info
*/
M.core_filepicker.select_file = function(file) {
M.core_filepicker.active_filepicker.select_file(file);
}
/**
* Init and show file picker
*/
M.core_filepicker.show = function(Y, options) {
if (!M.core_filepicker.instances[options.client_id]) {
M.core_filepicker.init(Y, options);
}
M.core_filepicker.instances[options.client_id].options.formcallback = options.formcallback;
M.core_filepicker.instances[options.client_id].show();
};
M.core_filepicker.set_templates = function(Y, templates) {
for (var templid in templates) {
M.core_filepicker.templates[templid] = templates[templid];
}
}
/**
* Add new file picker to current instances
*/
M.core_filepicker.init = function(Y, options) {
var FilePickerHelper = function(options) {
FilePickerHelper.superclass.constructor.apply(this, arguments);
};
FilePickerHelper.NAME = "FilePickerHelper";
FilePickerHelper.ATTRS = {
options: {},
lang: {}
};
Y.extend(FilePickerHelper, Y.Base, {
api: M.cfg.wwwroot+'/repository/repository_ajax.php',
cached_responses: {},
waitinterval : null, // When the loading template is being displayed and its animation is running this will be an interval instance.
initializer: function(options) {
this.options = options;
if (!this.options.savepath) {
this.options.savepath = '/';
}
},
destructor: function() {
},
request: function(args, redraw) {
var api = (args.api ? args.api : this.api) + '?action='+args.action;
var params = {};
var scope = args['scope'] ? args['scope'] : this;
params['repo_id']=args.repository_id;
params['p'] = args.path?args.path:'';
params['page'] = args.page?args.page:'';
params['env']=this.options.env;
// the form element only accept certain file types
params['accepted_types']=this.options.accepted_types;
params['sesskey'] = M.cfg.sesskey;
params['client_id'] = args.client_id;
params['itemid'] = this.options.itemid?this.options.itemid:0;
params['maxbytes'] = this.options.maxbytes?this.options.maxbytes:-1;
// The unlimited value of areamaxbytes is -1, it is defined by FILE_AREA_MAX_BYTES_UNLIMITED.
params['areamaxbytes'] = this.options.areamaxbytes ? this.options.areamaxbytes : -1;
if (this.options.context && this.options.context.id) {
params['ctx_id'] = this.options.context.id;
}
if (args['params']) {
for (i in args['params']) {
params[i] = args['params'][i];
}
}
if (args.action == 'upload') {
var list = [];
for(var k in params) {
var value = params[k];
if(value instanceof Array) {
for(var i in value) {
list.push(k+'[]='+value[i]);
}
} else {
list.push(k+'='+value);
}
}
params = list.join('&');
} else {
params = build_querystring(params);
}
var cfg = {
method: 'POST',
on: {
complete: function(id,o,p) {
var data = null;
try {
data = Y.JSON.parse(o.responseText);
} catch(e) {
if (o && o.status && o.status > 0) {
Y.use('moodle-core-notification-exception', function() {
return new M.core.exception(e);
});
return;
}
}
// error checking
if (data && data.error) {
Y.use('moodle-core-notification-ajaxexception', function () {
return new M.core.ajaxException(data);
});
this.fpnode.one('.fp-content').setContent('');
return;
} else {
if (data.msg) {
scope.print_msg(data.msg, 'info');
}
// cache result if applicable
if (args.action != 'upload' && data.allowcaching) {
scope.cached_responses[params] = data;
}
// invoke callback
args.callback(id,data,p);
}
}
},
arguments: {
scope: scope
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
data: params,
context: this
};
if (args.form) {
cfg.form = args.form;
}
// check if result of the same request has been already cached. If not, request it
// (never applicable in case of form submission and/or upload action):
if (!args.form && args.action != 'upload' && scope.cached_responses[params]) {
args.callback(null, scope.cached_responses[params], {scope: scope})
} else {
Y.io(api, cfg);
if (redraw) {
this.wait();
}
}
},
/** displays the dialog and processes rename/overwrite if there is a file with the same name in the same filearea*/
process_existing_file: function(data) {
var scope = this;
var handleOverwrite = function(e) {
// overwrite
e.preventDefault();
var data = this.process_dlg.dialogdata;
var params = {}
params['existingfilename'] = data.existingfile.filename;
params['existingfilepath'] = data.existingfile.filepath;
params['newfilename'] = data.newfile.filename;
params['newfilepath'] = data.newfile.filepath;
this.hide_header();
this.request({
'params': params,
'scope': this,
'action':'overwrite',
'path': '',
'client_id': this.options.client_id,
'repository_id': this.active_repo.id,
'callback': function(id, o, args) {
scope.hide();
// Add an arbitrary parameter to the URL to force browsers to re-load the new image even
// if the file name has not changed.
var urlimage = data.existingfile.url + "?time=" + (new Date()).getTime();
if (scope.options.editor_target && scope.options.env == 'editor') {
// editor needs to update url
scope.options.editor_target.value = urlimage;
scope.options.editor_target.dispatchEvent(new Event('change'), {'bubbles': true});
}
var fileinfo = {'client_id':scope.options.client_id,
'url': urlimage,
'file': data.existingfile.filename};
var formcallback_scope = scope.options.magicscope ? scope.options.magicscope : scope;
scope.options.formcallback.apply(formcallback_scope, [fileinfo]);
}
}, true);
}
var handleRename = function(e) {
// inserts file with the new name
e.preventDefault();
var scope = this;
var data = this.process_dlg.dialogdata;
if (scope.options.editor_target && scope.options.env == 'editor') {
scope.options.editor_target.value = data.newfile.url;
scope.options.editor_target.dispatchEvent(new Event('change'), {'bubbles': true});
}
scope.hide();
var formcallback_scope = scope.options.magicscope ? scope.options.magicscope : scope;
var fileinfo = {'client_id':scope.options.client_id,
'url':data.newfile.url,
'file':data.newfile.filename};
scope.options.formcallback.apply(formcallback_scope, [fileinfo]);
}
var handleCancel = function(e) {
// Delete tmp file
e.preventDefault();
var params = {};
params['newfilename'] = this.process_dlg.dialogdata.newfile.filename;
params['newfilepath'] = this.process_dlg.dialogdata.newfile.filepath;
this.request({
'params': params,
'scope': this,
'action':'deletetmpfile',
'path': '',
'client_id': this.options.client_id,
'repository_id': this.active_repo.id,
'callback': function(id, o, args) {
// let it be in background, from user point of view nothing is happenning
}
}, false);
this.process_dlg.hide();
this.selectui.hide();
}
if (!this.process_dlg) {
this.process_dlg_node = Y.Node.create(M.core_filepicker.templates.processexistingfile);
var node = this.process_dlg_node;
node.generateID();
this.process_dlg = new M.core.dialogue({
draggable : true,
bodyContent : node,
headerContent: M.util.get_string('fileexistsdialogheader', 'repository'),
centered : true,
modal : true,
visible : false,
zIndex : this.options.zIndex
});
node.one('.fp-dlg-butoverwrite').on('click', handleOverwrite, this);
node.one('.fp-dlg-butrename').on('click', handleRename, this);
node.one('.fp-dlg-butcancel').on('click', handleCancel, this);
if (this.options.env == 'editor') {
node.one('.fp-dlg-text').setContent(M.util.get_string('fileexistsdialog_editor', 'repository'));
} else {
node.one('.fp-dlg-text').setContent(M.util.get_string('fileexistsdialog_filemanager', 'repository'));
}
}
this.selectnode.removeClass('loading');
this.process_dlg.dialogdata = data;
this.process_dlg_node.one('.fp-dlg-butrename').setContent(M.util.get_string('renameto', 'repository', data.newfile.filename));
this.process_dlg.show();
},
/** displays error instead of filepicker contents */
display_error: function(errortext, errorcode) {
this.fpnode.one('.fp-content').setContent(M.core_filepicker.templates.error);
this.fpnode.one('.fp-content .fp-error').
addClass(errorcode).
setContent(Y.Escape.html(errortext));
},
/** displays message in a popup */
print_msg: function(msg, type) {
var header = M.util.get_string('error', 'moodle');
if (type != 'error') {
type = 'info'; // one of only two types excepted
header = M.util.get_string('info', 'moodle');
}
if (!this.msg_dlg) {
this.msg_dlg_node = Y.Node.create(M.core_filepicker.templates.message);
this.msg_dlg_node.generateID();
this.msg_dlg = new M.core.dialogue({
draggable : true,
bodyContent : this.msg_dlg_node,
centered : true,
modal : true,
visible : false,
zIndex : this.options.zIndex
});
this.msg_dlg_node.one('.fp-msg-butok').on('click', function(e) {
e.preventDefault();
this.msg_dlg.hide();
}, this);
}
this.msg_dlg.set('headerContent', header);
this.msg_dlg_node.removeClass('fp-msg-info').removeClass('fp-msg-error').addClass('fp-msg-'+type)
this.msg_dlg_node.one('.fp-msg-text').setContent(Y.Escape.html(msg));
this.msg_dlg.show();
},
view_files: function(appenditems) {
this.viewbar_set_enabled(true);
this.print_path();
/*if ((appenditems == null) && (!this.filelist || !this.filelist.length) && !this.active_repo.hasmorepages) {
// TODO do it via classes and adjust for each view mode!
// If there are no items and no next page, just display status message and quit
this.display_error(M.util.get_string('nofilesavailable', 'repository'), 'nofilesavailable');
return;
}*/
if (this.viewmode == 2) {
this.view_as_list(appenditems);
} else if (this.viewmode == 3) {
this.view_as_table(appenditems);
} else {
this.view_as_icons(appenditems);
}
this.fpnode.one('.fp-content').setAttribute('tabindex', '0');
this.fpnode.one('.fp-content').focus();
// display/hide the link for requesting next page
if (!appenditems && this.active_repo.hasmorepages) {
if (!this.fpnode.one('.fp-content .fp-nextpage')) {
this.fpnode.one('.fp-content').append(M.core_filepicker.templates.nextpage);
}
this.fpnode.one('.fp-content .fp-nextpage').one('a,button').on('click', function(e) {
e.preventDefault();
this.fpnode.one('.fp-content .fp-nextpage').addClass('loading');
this.request_next_page();
}, this);
}
if (!this.active_repo.hasmorepages && this.fpnode.one('.fp-content .fp-nextpage')) {
this.fpnode.one('.fp-content .fp-nextpage').remove();
}
if (this.fpnode.one('.fp-content .fp-nextpage')) {
this.fpnode.one('.fp-content .fp-nextpage').removeClass('loading');
}
this.content_scrolled();
},
content_scrolled: function(e) {
setTimeout(Y.bind(function() {
if (this.processingimages) {
return;
}
this.processingimages = true;
var scope = this,
fpcontent = this.fpnode.one('.fp-content'),
fpcontenty = fpcontent.getY(),
fpcontentheight = fpcontent.getStylePx('height'),
nextpage = fpcontent.one('.fp-nextpage'),
is_node_visible = function(node) {
var offset = node.getY()-fpcontenty;
if (offset <= fpcontentheight && (offset >=0 || offset+node.getStylePx('height')>=0)) {
return true;
}
return false;
};
// automatically load next page when 'more' link becomes visible
if (nextpage && !nextpage.hasClass('loading') && is_node_visible(nextpage)) {
nextpage.one('a,button').simulate('click');
}
// replace src for visible images that need to be lazy-loaded
if (scope.lazyloading) {
fpcontent.all('img').each( function(node) {
if (node.get('id') && scope.lazyloading[node.get('id')] && is_node_visible(node)) {
node.setImgRealSrc(scope.lazyloading);
}
});
}
this.processingimages = false;
}, this), 200)
},
treeview_dynload: function(node, cb) {
var retrieved_children = {};
if (node.children) {
for (var i in node.children) {
retrieved_children[node.children[i].path] = node.children[i];
}
}
this.request({
action:'list',
client_id: this.options.client_id,
repository_id: this.active_repo.id,
path:node.path?node.path:'',
page:node.page?args.page:'',
scope:this,
callback: function(id, obj, args) {
var list = obj.list;
var scope = args.scope;
// check that user did not leave the view mode before recieving this response
if (!(scope.active_repo.id == obj.repo_id && scope.viewmode == 2 && node && node.getChildrenEl())) {
return;
}
if (cb != null) { // (in manual mode do not update current path)
scope.viewbar_set_enabled(true);
scope.parse_repository_options(obj);
}
node.highlight(false);
node.origlist = obj.list ? obj.list : null;
node.origpath = obj.path ? obj.path : null;
node.children = [];
for(k in list) {
if (list[k].children && retrieved_children[list[k].path]) {
// if this child is a folder and has already been retrieved
node.children[node.children.length] = retrieved_children[list[k].path];
} else {
// append new file to the list
scope.view_as_list([list[k]]);
}
}
if (cb == null) {
node.refresh();
} else {
// invoke callback requested by TreeView component
cb();
}
scope.content_scrolled();
}
}, false);
},
classnamecallback : function(node) {
var classname = '';
if (node.children) {
classname = classname + ' fp-folder';
}
if (node.isref) {
classname = classname + ' fp-isreference';
}
if (node.iscontrolledlink) {
classname = classname + ' fp-iscontrolledlink';
}
if (node.refcount) {
classname = classname + ' fp-hasreferences';
}
if (node.originalmissing) {
classname = classname + ' fp-originalmissing';
}
return Y.Lang.trim(classname);
},
/** displays list of files in tree (list) view mode. If param appenditems is specified,
* appends those items to the end of the list. Otherwise (default behaviour)
* clears the contents and displays the items from this.filelist */
view_as_list: function(appenditems) {
var list = (appenditems != null) ? appenditems : this.filelist;
this.viewmode = 2;
if (!this.filelist || this.filelist.length==0 && (!this.filepath || !this.filepath.length)) {
this.display_error(M.util.get_string('nofilesavailable', 'repository'), 'nofilesavailable');
return;
}
var element_template = Y.Node.create(M.core_filepicker.templates.listfilename);
var options = {
viewmode : this.viewmode,
appendonly : (appenditems != null),
filenode : element_template,
callbackcontext : this,
callback : function(e, node) {
// TODO MDL-32736 e is not an event here but an object with properties 'event' and 'node'
if (!node.children) {
if (e.node.parent && e.node.parent.origpath) {
// set the current path
this.filepath = e.node.parent.origpath;
this.filelist = e.node.parent.origlist;
this.print_path();
}
this.select_file(node);
} else {
// save current path and filelist (in case we want to jump to other viewmode)
this.filepath = e.node.origpath;
this.filelist = e.node.origlist;
this.currentpath = e.node.path;
this.print_path();
this.content_scrolled();
}
},
classnamecallback : this.classnamecallback,
dynload : this.active_repo.dynload,
filepath : this.filepath,
treeview_dynload : this.treeview_dynload
};
this.fpnode.one('.fp-content').fp_display_filelist(options, list, this.lazyloading);
},
/** displays list of files in icon view mode. If param appenditems is specified,
* appends those items to the end of the list. Otherwise (default behaviour)
* clears the contents and displays the items from this.filelist */
view_as_icons: function(appenditems) {
this.viewmode = 1;
var list = (appenditems != null) ? appenditems : this.filelist;
var element_template = Y.Node.create(M.core_filepicker.templates.iconfilename);
if ((appenditems == null) && (!this.filelist || !this.filelist.length)) {
this.display_error(M.util.get_string('nofilesavailable', 'repository'), 'nofilesavailable');
return;
}
var options = {
viewmode : this.viewmode,
appendonly : (appenditems != null),
filenode : element_template,
callbackcontext : this,
callback : function(e, node) {
if (e.preventDefault) {
e.preventDefault();
}
if(node.children) {
if (this.active_repo.dynload) {
this.list({'path':node.path});
} else {
this.filelist = node.children;
this.view_files();
}
} else {
this.select_file(node);
}
},
classnamecallback : this.classnamecallback
};
this.fpnode.one('.fp-content').fp_display_filelist(options, list, this.lazyloading);
},
/** displays list of files in table view mode. If param appenditems is specified,
* appends those items to the end of the list. Otherwise (default behaviour)
* clears the contents and displays the items from this.filelist */
view_as_table: function(appenditems) {
this.viewmode = 3;
var list = (appenditems != null) ? appenditems : this.filelist;
if (!appenditems && (!this.filelist || this.filelist.length==0) && !this.active_repo.hasmorepages) {
this.display_error(M.util.get_string('nofilesavailable', 'repository'), 'nofilesavailable');
return;
}
var element_template = Y.Node.create(M.core_filepicker.templates.listfilename);
var options = {
viewmode : this.viewmode,
appendonly : (appenditems != null),
filenode : element_template,
callbackcontext : this,
sortable : !this.active_repo.hasmorepages,
callback : function(e, node) {
if (e.preventDefault) {e.preventDefault();}
if (node.children) {
if (this.active_repo.dynload) {
this.list({'path':node.path});
} else {
this.filelist = node.children;
this.view_files();
}
} else {
this.select_file(node);
}
},
classnamecallback : this.classnamecallback
};
this.fpnode.one('.fp-content').fp_display_filelist(options, list, this.lazyloading);
},
/** If more than one page available, requests and displays the files from the next page */
request_next_page: function() {
if (!this.active_repo.hasmorepages || this.active_repo.nextpagerequested) {
// nothing to load
return;
}
this.active_repo.nextpagerequested = true;
var nextpage = this.active_repo.page+1;
var args = {
page: nextpage,
repo_id: this.active_repo.id
};
var action = this.active_repo.issearchresult ? 'search' : 'list';
this.request({
path: this.currentpath,
scope: this,
action: action,
client_id: this.options.client_id,
repository_id: args.repo_id,
params: args,
callback: function(id, obj, args) {
var scope = args.scope;
// Check that we are still in the same repository and are expecting this page. We have no way
// to compare the requested page and the one returned, so we assume that if the last chunk
// of the breadcrumb is similar, then we probably are on the same page.
var samepage = true;
if (obj.path && scope.filepath) {
var pathbefore = scope.filepath[scope.filepath.length-1];
var pathafter = obj.path[obj.path.length-1];
if (pathbefore.path != pathafter.path) {
samepage = false;
}
}
if (scope.active_repo.hasmorepages && obj.list && obj.page &&
obj.repo_id == scope.active_repo.id &&
obj.page == scope.active_repo.page+1 && samepage) {
scope.parse_repository_options(obj, true);
scope.view_files(obj.list)
}
}
}, false);
},
select_file: function(args) {
var argstitle = args.shorttitle ? args.shorttitle : args.title;
// Limit the string length so it fits nicely on mobile devices
var titlelength = 30;
if (argstitle.length > titlelength) {
argstitle = argstitle.substring(0, titlelength) + '...';
}
Y.one('#fp-file_label_'+this.options.client_id).setContent(Y.Escape.html(M.util.get_string('select', 'repository')+' '+argstitle));
this.selectui.show();
Y.one('#'+this.selectnode.get('id')).focus();
var client_id = this.options.client_id;
var selectnode = this.selectnode;
var return_types = this.options.repositories[this.active_repo.id].return_types;
selectnode.removeClass('loading');
selectnode.one('.fp-saveas input').set('value', args.title);
var imgnode = Y.Node.create('<img/>').
set('src', args.realthumbnail ? args.realthumbnail : args.thumbnail).
setStyle('maxHeight', ''+(args.thumbnail_height ? args.thumbnail_height : 90)+'px').
setStyle('maxWidth', ''+(args.thumbnail_width ? args.thumbnail_width : 90)+'px');
selectnode.one('.fp-thumbnail').setContent('').appendChild(imgnode);
// filelink is the array of file-link-types available for this repository in this env
var filelinktypes = [2/*FILE_INTERNAL*/,1/*FILE_EXTERNAL*/,4/*FILE_REFERENCE*/,8/*FILE_CONTROLLED_LINK*/];
var filelink = {}, firstfilelink = null, filelinkcount = 0;
for (var i in filelinktypes) {
var allowed = (return_types & filelinktypes[i]) &&
(this.options.return_types & filelinktypes[i]);
if (filelinktypes[i] == 1/*FILE_EXTERNAL*/ && !this.options.externallink && this.options.env == 'editor') {
// special configuration setting 'repositoryallowexternallinks' may prevent
// using external links in editor environment
allowed = false;
}
filelink[filelinktypes[i]] = allowed;
firstfilelink = (firstfilelink==null && allowed) ? filelinktypes[i] : firstfilelink;
filelinkcount += allowed ? 1 : 0;
}
var defaultreturntype = this.options.repositories[this.active_repo.id].defaultreturntype;
if (defaultreturntype) {
if (filelink[defaultreturntype]) {
firstfilelink = defaultreturntype;
}
}
// make radio buttons enabled if this file-link-type is available and only if there are more than one file-link-type option
// check the first available file-link-type option
for (var linktype in filelink) {
var el = selectnode.one('.fp-linktype-'+linktype);
el.addClassIf('uneditable', !(filelink[linktype] && filelinkcount>1));
el.one('input').set('checked', (firstfilelink == linktype) ? 'checked' : '').simulate('change');
}
// TODO MDL-32532: attributes 'hasauthor' and 'haslicense' need to be obsolete,
selectnode.one('.fp-setauthor input').set('value', args.author ? args.author : this.options.author);
this.populateLicensesSelect(selectnode.one('.fp-setlicense select'), args);
selectnode.one('form #filesource-'+client_id).set('value', args.source);
selectnode.one('form #filesourcekey-'+client_id).set('value', args.sourcekey);
// display static information about a file (when known)
var attrs = ['datemodified','datecreated','size','license','author','dimensions'];
for (var i in attrs) {
if (selectnode.one('.fp-'+attrs[i])) {
var value = (args[attrs[i]+'_f']) ? args[attrs[i]+'_f'] : (args[attrs[i]] ? args[attrs[i]] : '');
selectnode.one('.fp-'+attrs[i]).addClassIf('fp-unknown', ''+value == '')
.one('.fp-value').setContent(Y.Escape.html(value));
}
}
},
setup_select_file: function() {
var client_id = this.options.client_id;
var selectnode = this.selectnode;
var getfile = selectnode.one('.fp-select-confirm');
var filePickerHelper = this;
// bind labels with corresponding inputs
selectnode.all('.fp-saveas,.fp-linktype-2,.fp-linktype-1,.fp-linktype-4,fp-linktype-8,.fp-setauthor,.fp-setlicense').each(function (node) {
node.all('label').set('for', node.one('input,select').generateID());
});
selectnode.one('.fp-linktype-2 input').setAttrs({value: 2, name: 'linktype'});
selectnode.one('.fp-linktype-1 input').setAttrs({value: 1, name: 'linktype'});
selectnode.one('.fp-linktype-4 input').setAttrs({value: 4, name: 'linktype'});
selectnode.one('.fp-linktype-8 input').setAttrs({value: 8, name: 'linktype'});
var changelinktype = function(e) {
if (e.currentTarget.get('checked')) {
var allowinputs = e.currentTarget.get('value') != 1/*FILE_EXTERNAL*/;
selectnode.all('.fp-setauthor,.fp-setlicense,.fp-saveas').each(function(node){
node.addClassIf('uneditable', !allowinputs);
node.all('input,select').set('disabled', allowinputs?'':'disabled');
});
// If the link to the file is selected, only then.
// Remember: this is not to be done for all repos.
// Only for those repos where the filereferencewarning is set.
// The value 4 represents FILE_REFERENCE here.
if (e.currentTarget.get('value') === '4') {
var filereferencewarning = filePickerHelper.active_repo.filereferencewarning;
if (filereferencewarning) {
var fileReferenceNode = e.currentTarget.ancestor('.fp-linktype-4');
var fileReferenceWarningNode = Y.Node.create('<div/>').
addClass('alert alert-warning px-3 py-1 my-1 small').
setAttrs({role: 'alert'}).
setContent(filereferencewarning);
fileReferenceNode.append(fileReferenceWarningNode);
}
} else {
var fileReferenceInput = selectnode.one('.fp-linktype-4 input');
var fileReferenceWarningNode = fileReferenceInput.ancestor('.fp-linktype-4').one('.alert-warning');
if (fileReferenceWarningNode) {
fileReferenceWarningNode.remove();
}
}
}
};
selectnode.all('.fp-linktype-2,.fp-linktype-1,.fp-linktype-4,.fp-linktype-8').each(function (node) {
node.one('input').on('change', changelinktype, this);
});
// register event on clicking submit button
getfile.on('click', function(e) {
e.preventDefault();
var client_id = this.options.client_id;
var scope = this;
var repository_id = this.active_repo.id;
var title = selectnode.one('.fp-saveas input').get('value');
var filesource = selectnode.one('form #filesource-'+client_id).get('value');
var filesourcekey = selectnode.one('form #filesourcekey-'+client_id).get('value');
var params = {
'title': title,
'source': filesource,
'savepath': this.options.savepath || '/',
'sourcekey': filesourcekey,
};
var license = selectnode.one('.fp-setlicense select');
if (license) {
params['license'] = license.get('value');
var origlicense = selectnode.one('.fp-license .fp-value');
if (origlicense) {
origlicense = origlicense.getContent();
}
if (this.options.rememberuserlicensepref) {
this.set_preference('recentlicense', license.get('value'));
}
}
params['author'] = selectnode.one('.fp-setauthor input').get('value');
var return_types = this.options.repositories[this.active_repo.id].return_types;
if (this.options.env == 'editor') {
// in editor, images are stored in '/' only
params.savepath = '/';
}
if ((this.options.externallink || this.options.env != 'editor') &&
(return_types & 1/*FILE_EXTERNAL*/) &&
(this.options.return_types & 1/*FILE_EXTERNAL*/) &&
selectnode.one('.fp-linktype-1 input').get('checked')) {
params['linkexternal'] = 'yes';
} else if ((return_types & 4/*FILE_REFERENCE*/) &&
(this.options.return_types & 4/*FILE_REFERENCE*/) &&
selectnode.one('.fp-linktype-4 input').get('checked')) {
params['usefilereference'] = '1';
} else if ((return_types & 8/*FILE_CONTROLLED_LINK*/) &&
(this.options.return_types & 8/*FILE_CONTROLLED_LINK*/) &&
selectnode.one('.fp-linktype-8 input').get('checked')) {
params['usecontrolledlink'] = '1';
}
selectnode.addClass('loading');
this.request({
action:'download',
client_id: client_id,
repository_id: repository_id,
'params': params,
onerror: function(id, obj, args) {
selectnode.removeClass('loading');
scope.selectui.hide();
},
callback: function(id, obj, args) {
selectnode.removeClass('loading');
if (obj.event == 'fileexists') {
scope.process_existing_file(obj);
return;
}
if (scope.options.editor_target && scope.options.env=='editor') {
scope.options.editor_target.value=obj.url;
scope.options.editor_target.dispatchEvent(new Event('change'), {'bubbles': true});
}
scope.hide();
obj.client_id = client_id;
var formcallback_scope = args.scope.options.magicscope ? args.scope.options.magicscope : args.scope;
scope.options.formcallback.apply(formcallback_scope, [obj]);
}
}, false);
}, this);
var elform = selectnode.one('form');
elform.appendChild(Y.Node.create('<input/>').
setAttrs({type:'hidden',id:'filesource-'+client_id}));
elform.appendChild(Y.Node.create('<input/>').
setAttrs({type:'hidden',id:'filesourcekey-'+client_id}));
elform.on('keydown', function(e) {
if (e.keyCode == 13) {
getfile.simulate('click');
e.preventDefault();
}
}, this);
var cancel = selectnode.one('.fp-select-cancel');
cancel.on('click', function(e) {
e.preventDefault();
this.selectui.hide();
}, this);
},
wait: function() {
// First check there isn't already an interval in play, and if there is kill it now.
if (this.waitinterval != null) {
clearInterval(this.waitinterval);
}
// Prepare the root node we will set content for and the loading template we want to display as a YUI node.
var root = this.fpnode.one('.fp-content');
var content = Y.Node.create(M.core_filepicker.templates.loading).addClass('fp-content-hidden').setStyle('opacity', 0);
var count = 0;
// Initiate an interval, we will have a count which will increment every 100 milliseconds.
// Count 0 - the loading icon will have visibility set to hidden (invisible) and have an opacity of 0 (invisible also)
// Count 5 - the visiblity will be switched to visible but opacity will still be at 0 (inivisible)
// Counts 6 - 15 opacity will be increased by 0.1 making the loading icon visible over the period of a second
// Count 16 - The interval will be cancelled.
var interval = setInterval(function(){
if (!content || !root.contains(content) || count >= 15) {
clearInterval(interval);
return true;
}
if (count == 5) {
content.removeClass('fp-content-hidden');
} else if (count > 5) {
var opacity = parseFloat(content.getStyle('opacity'));
content.setStyle('opacity', opacity + 0.1);
}
count++;
return false;
}, 100);
// Store the wait interval so that we can check it in the future.
this.waitinterval = interval;
// Set the content to the loading template.
root.setContent(content);
},
viewbar_set_enabled: function(mode) {
var viewbar = this.fpnode.one('.fp-viewbar')
if (viewbar) {
if (mode) {
viewbar.addClass('enabled').removeClass('disabled');
this.fpnode.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').setAttribute("aria-disabled", "false");
this.fpnode.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').setAttribute("tabindex", "");
} else {
viewbar.removeClass('enabled').addClass('disabled');
this.fpnode.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').setAttribute("aria-disabled", "true");
this.fpnode.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').setAttribute("tabindex", "-1");
}
}
this.fpnode.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').removeClass('checked');
var modes = {1:'icons', 2:'tree', 3:'details'};
this.fpnode.all('.fp-vb-'+modes[this.viewmode]).addClass('checked');
},
viewbar_clicked: function(e) {
e.preventDefault();
var viewbar = this.fpnode.one('.fp-viewbar')
if (!viewbar || !viewbar.hasClass('disabled')) {
if (e.currentTarget.hasClass('fp-vb-tree')) {
this.viewmode = 2;
} else if (e.currentTarget.hasClass('fp-vb-details')) {
this.viewmode = 3;
} else {
this.viewmode = 1;
}
this.viewbar_set_enabled(true)
this.view_files();
this.set_preference('recentviewmode', this.viewmode);
}
},
render: function() {
var client_id = this.options.client_id;
var fpid = "filepicker-"+ client_id;
var labelid = 'fp-dialog-label_'+ client_id;
var width = 873;
var draggable = true;
this.fpnode = Y.Node.create(M.core_filepicker.templates.generallayout).
set('id', 'filepicker-'+client_id).set('aria-labelledby', labelid);
if (this.in_iframe()) {
width = Math.floor(window.innerWidth * 0.95);
draggable = false;
}
this.mainui = new M.core.dialogue({
extraClasses : ['filepicker'],
draggable : draggable,
bodyContent : this.fpnode,
headerContent: '<h3 id="'+ labelid +'">'+ M.util.get_string('filepicker', 'repository') +'</h3>',
centered : true,
modal : true,
visible : false,
width : width+'px',
responsiveWidth : 768,
height : '558px',
zIndex : this.options.zIndex,
focusOnPreviousTargetAfterHide: true,
focusAfterHide: this.options.previousActiveElement
});
// create panel for selecting a file (initially hidden)
this.selectnode = Y.Node.create(M.core_filepicker.templates.selectlayout).
set('id', 'filepicker-select-'+client_id).
set('aria-live', 'assertive').
set('role', 'dialog');
var fplabel = 'fp-file_label_'+ client_id;
this.selectui = new M.core.dialogue({
headerContent: '<h3 id="' + fplabel +'">'+M.util.get_string('select', 'repository')+'</h3>',
draggable : true,
width : '450px',
bodyContent : this.selectnode,
centered : true,
modal : true,
visible : false,
zIndex : this.options.zIndex
});
Y.one('#'+this.selectnode.get('id')).setAttribute('aria-labelledby', fplabel);
// event handler for lazy loading of thumbnails and next page
this.fpnode.one('.fp-content').on(['scroll','resize'], this.content_scrolled, this);
// save template for one path element and location of path bar
if (this.fpnode.one('.fp-path-folder')) {
this.pathnode = this.fpnode.one('.fp-path-folder');
this.pathbar = this.pathnode.get('parentNode');
this.pathbar.removeChild(this.pathnode);
}
// assign callbacks for view mode switch buttons
this.fpnode.one('.fp-vb-icons').on('click', this.viewbar_clicked, this);
this.fpnode.one('.fp-vb-tree').on('click', this.viewbar_clicked, this);
this.fpnode.one('.fp-vb-details').on('click', this.viewbar_clicked, this);
// assign callbacks for toolbar links
this.setup_toolbar();
this.setup_select_file();
this.hide_header();
// processing repository listing
// Resort the repositories by sortorder
var sorted_repositories = [];
var i;
for (i in this.options.repositories) {
sorted_repositories[i] = this.options.repositories[i];
}
sorted_repositories.sort(function(a,b){return a.sortorder-b.sortorder});
// extract one repository template and repeat it for all repositories available,
// set name and icon and assign callbacks
var reponode = this.fpnode.one('.fp-repo');
if (reponode) {
var list = reponode.get('parentNode');
list.removeChild(reponode);
for (i in sorted_repositories) {
var repository = sorted_repositories[i];
var h = (parseInt(i) == 0) ? parseInt(i) : parseInt(i) - 1,
j = (parseInt(i) == Object.keys(sorted_repositories).length - 1) ? parseInt(i) : parseInt(i) + 1;
var previousrepository = sorted_repositories[h];
var nextrepository = sorted_repositories[j];
var node = reponode.cloneNode(true);
list.appendChild(node);
node.
set('id', 'fp-repo-'+client_id+'-'+repository.id).
on('click', function(e, repository_id) {
e.preventDefault();
this.set_preference('recentrepository', repository_id);
this.hide_header();
this.list({'repo_id':repository_id});
}, this /*handler running scope*/, repository.id/*second argument of handler*/);
node.on('key', function(e, previousrepositoryid, nextrepositoryid, clientid, repositoryid) {
this.changeHighlightedRepository(e, clientid, repositoryid, previousrepositoryid, nextrepositoryid);
}, 'down:38,40', this, previousrepository.id, nextrepository.id, client_id, repository.id);
node.on('key', function(e, repositoryid) {
e.preventDefault();
this.set_preference('recentrepository', repositoryid);
this.hide_header();
this.list({'repo_id': repositoryid});
}, 'enter', this, repository.id);
node.one('.fp-repo-name').setContent(Y.Escape.html(repository.name));
node.one('.fp-repo-icon').set('src', repository.icon);
if (i==0) {
node.addClass('first');
}
if (i==sorted_repositories.length-1) {
node.addClass('last');
}
if (i%2) {
node.addClass('even');
} else {
node.addClass('odd');
}
}
}
// display error if no repositories found
if (sorted_repositories.length==0) {
this.display_error(M.util.get_string('norepositoriesavailable', 'repository'), 'norepositoriesavailable')
}
// display repository that was used last time
this.mainui.show();
this.show_recent_repository();
},
/**
* Change the highlighted repository to a new one.
*
* @param {object} event The key event
* @param {integer} clientid The client id to identify the repo class.
* @param {integer} oldrepositoryid The repository id that we are removing the highlight for
* @param {integer} previousrepositoryid The previous repository id.
* @param {integer} nextrepositoryid The next repository id.
*/
changeHighlightedRepository: function(event, clientid, oldrepositoryid, previousrepositoryid, nextrepositoryid) {
event.preventDefault();
var newrepositoryid = (event.keyCode == '40') ? nextrepositoryid : previousrepositoryid;
this.fpnode.one('#fp-repo-' + clientid + '-' + oldrepositoryid).setAttribute('tabindex', '-1');
this.fpnode.one('#fp-repo-' + clientid + '-' + newrepositoryid)
.setAttribute('tabindex', '0')
.focus();
},
parse_repository_options: function(data, appendtolist) {
if (appendtolist) {
if (data.list) {
if (!this.filelist) {
this.filelist = [];
}
for (var i in data.list) {
this.filelist[this.filelist.length] = data.list[i];
}
}
} else {
this.filelist = data.list?data.list:null;
this.lazyloading = {};
}
this.filepath = data.path?data.path:null;
this.objecttag = data.object?data.object:null;
this.active_repo = {};
this.active_repo.issearchresult = data.issearchresult ? true : false;
this.active_repo.defaultreturntype = data.defaultreturntype?data.defaultreturntype:null;
this.active_repo.dynload = data.dynload?data.dynload:false;
this.active_repo.pages = Number(data.pages?data.pages:null);
this.active_repo.page = Number(data.page?data.page:null);
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))
this.active_repo.id = data.repo_id?data.repo_id:null;
this.active_repo.nosearch = (data.login || data.nosearch); // this is either login form or 'nosearch' attribute set
this.active_repo.norefresh = (data.login || data.norefresh); // this is either login form or 'norefresh' attribute set
this.active_repo.nologin = (data.login || data.nologin); // this is either login form or 'nologin' attribute is set
this.active_repo.logouttext = data.logouttext?data.logouttext:null;
this.active_repo.logouturl = (data.logouturl || '');
this.active_repo.message = (data.message || '');
this.active_repo.help = data.help?data.help:null;
this.active_repo.manage = data.manage?data.manage:null;
// Warning message related to the file reference option, if applicable to the given repository.
this.active_repo.filereferencewarning = data.filereferencewarning ? data.filereferencewarning : null;
this.print_header();
},
print_login: function(data) {
this.parse_repository_options(data);
var client_id = this.options.client_id;
var repository_id = data.repo_id;
var l = this.logindata = data.login;
var loginurl = '';
var action = data['login_btn_action'] ? data['login_btn_action'] : 'login';
var form_id = 'fp-form-'+client_id;
var loginform_node = Y.Node.create(M.core_filepicker.templates.loginform);
loginform_node.one('form').set('id', form_id);
this.fpnode.one('.fp-content').setContent('').appendChild(loginform_node);
var templates = {
'popup' : loginform_node.one('.fp-login-popup'),
'textarea' : loginform_node.one('.fp-login-textarea'),
'select' : loginform_node.one('.fp-login-select'),
'text' : loginform_node.one('.fp-login-text'),
'radio' : loginform_node.one('.fp-login-radiogroup'),
'checkbox' : loginform_node.one('.fp-login-checkbox'),
'input' : loginform_node.one('.fp-login-input')
};
var container;
for (var i in templates) {
if (templates[i]) {
container = templates[i].get('parentNode');
container.removeChild(templates[i]);
}
}
for(var k in l) {
if (templates[l[k].type]) {
var node = templates[l[k].type].cloneNode(true);
} else {
node = templates['input'].cloneNode(true);
}
if (l[k].type == 'popup') {
// submit button
loginurl = l[k].url;
var popupbutton = node.one('button');
popupbutton.on('click', function(e){
M.core_filepicker.active_filepicker = this;
window.open(loginurl, 'repo_auth', 'location=0,status=0,width=500,height=300,scrollbars=yes');
e.preventDefault();
}, this);
loginform_node.one('form').on('keydown', function(e) {
if (e.keyCode == 13) {
popupbutton.simulate('click');
e.preventDefault();
}
}, this);
loginform_node.all('.fp-login-submit').remove();
action = 'popup';
} else if(l[k].type=='textarea') {
// textarea element
if (node.one('label')) {
node.one('label').set('for', l[k].id).setContent(l[k].label);
}
node.one('textarea').setAttrs({id:l[k].id, name:l[k].name});
} else if(l[k].type=='select') {
// select element
if (node.one('label')) {
node.one('label').set('for', l[k].id).setContent(l[k].label);
}
node.one('select').setAttrs({id:l[k].id, name:l[k].name}).setContent('');
for (i in l[k].options) {
node.one('select').appendChild(
Y.Node.create('<option/>').
set('value', l[k].options[i].value).
setContent(l[k].options[i].label));
}
} else if(l[k].type=='radio') {
// radio input element
node.all('label').setContent(l[k].label);
var list = l[k].value.split('|');
var labels = l[k].value_label.split('|');
var radionode = null;
for(var item in list) {
if (radionode == null) {
radionode = node.one('.fp-login-radio');
radionode.one('input').set('checked', 'checked');
} else {
var x = radionode.cloneNode(true);
radionode.insert(x, 'after');
radionode = x;
radionode.one('input').set('checked', '');
}
radionode.one('input').setAttrs({id:''+l[k].id+item, name:l[k].name,
type:l[k].type, value:list[item]});
radionode.all('label').setContent(labels[item]).set('for', ''+l[k].id+item)
}
if (radionode == null) {
node.one('.fp-login-radio').remove();
}
} else {
// input element
if (node.one('label')) { node.one('label').set('for', l[k].id).setContent(l[k].label) }
node.one('input').
set('type', l[k].type).
set('id', l[k].id).
set('name', l[k].name).
set('value', l[k].value?l[k].value:'')
}
container.appendChild(node);
}
// custom label text for submit button
if (data['login_btn_label']) {
loginform_node.all('.fp-login-submit').setContent(data['login_btn_label'])
}
// register button action for login and search
if (action == 'login' || action == 'search') {
loginform_node.one('.fp-login-submit').on('click', function(e){
e.preventDefault();
this.hide_header();
this.request({
'scope': this,
'action':(action == 'search') ? 'search' : 'signin',
'path': '',
'client_id': client_id,
'repository_id': repository_id,
'form': {id:form_id, upload:false, useDisabled:true},
'callback': this.display_response
}, true);
}, this);
}
// if 'Enter' is pressed in the form, simulate the button click
if (loginform_node.one('.fp-login-submit')) {
loginform_node.one('form').on('keydown', function(e) {
if (e.keyCode == 13) {
loginform_node.one('.fp-login-submit').simulate('click')
e.preventDefault();
}
}, this);
}
},
display_response: function(id, obj, args) {
var scope = args.scope;
// highlight the current repository in repositories list
scope.fpnode.all('.fp-repo.active')
.removeClass('active')
.setAttribute('aria-selected', 'false')
.setAttribute('tabindex', '-1');
scope.fpnode.all('.nav-link')
.removeClass('active')
.setAttribute('aria-selected', 'false')
.setAttribute('tabindex', '-1');
var activenode = scope.fpnode.one('#fp-repo-' + scope.options.client_id + '-' + obj.repo_id);
activenode.addClass('active')
.setAttribute('aria-selected', 'true')
.setAttribute('tabindex', '0');
activenode.all('.nav-link').addClass('active');
// add class repository_REPTYPE to the filepicker (for repository-specific styles)
for (var i in scope.options.repositories) {
scope.fpnode.removeClass('repository_'+scope.options.repositories[i].type)
}
if (obj.repo_id && scope.options.repositories[obj.repo_id]) {
scope.fpnode.addClass('repository_'+scope.options.repositories[obj.repo_id].type)
}
Y.one('.file-picker .fp-repo-items').focus();
// display response
if (obj.login) {
scope.viewbar_set_enabled(false);
scope.print_login(obj);
} else if (obj.upload) {
scope.viewbar_set_enabled(false);
scope.parse_repository_options(obj);
scope.create_upload_form(obj);
} else if (obj.object) {
M.core_filepicker.active_filepicker = scope;
scope.viewbar_set_enabled(false);
scope.parse_repository_options(obj);
scope.create_object_container(obj.object);
} else if (obj.list) {
scope.viewbar_set_enabled(true);
scope.parse_repository_options(obj);
scope.view_files();
}
},
list: function(args) {
if (!args) {
args = {};
}
if (!args.repo_id) {
args.repo_id = this.active_repo.id;
}
if (!args.path) {
args.path = '';
}
this.currentpath = args.path;
this.request({
action: 'list',
client_id: this.options.client_id,
repository_id: args.repo_id,
path: args.path,
page: args.page,
scope: this,
callback: this.display_response
}, true);
},
populateLicensesSelect: function(licensenode, filenode) {
if (!licensenode) {
return;
}
licensenode.setContent('');
var selectedlicense = this.options.defaultlicense;
if (filenode) {
// File has a license already, use it.
selectedlicense = filenode.license;
} else if (this.options.rememberuserlicensepref && this.get_preference('recentlicense')) {
// When 'Remember user licence preference' is enabled use the last license selected by the user, if any.
selectedlicense = this.get_preference('recentlicense');
}
var licenses = this.options.licenses;
for (var i in licenses) {
// Include the file's current license, even if not enabled, to prevent displaying
// misleading information about which license the file currently has assigned to it.
if (licenses[i].enabled == true || (filenode !== undefined && licenses[i].shortname === filenode.license)) {
var option = Y.Node.create('<option/>').
set('selected', (licenses[i].shortname == selectedlicense)).
set('value', licenses[i].shortname).
setContent(Y.Escape.html(licenses[i].fullname));
licensenode.appendChild(option);
}
}
},
create_object_container: function(data) {
var content = this.fpnode.one('.fp-content');
content.setContent('');
//var str = '<object data="'+data.src+'" type="'+data.type+'" width="98%" height="98%" id="container_object" class="fp-object-container mdl-align"></object>';
var container = Y.Node.create('<object/>').
setAttrs({data:data.src, type:data.type, id:'container_object'}).
addClass('fp-object-container');
content.setContent('').appendChild(container);
},
create_upload_form: function(data) {
var client_id = this.options.client_id;
var id = data.upload.id+'_'+client_id;
var content = this.fpnode.one('.fp-content');
var template_name = 'uploadform_'+this.options.repositories[data.repo_id].type;
var template = M.core_filepicker.templates[template_name] || M.core_filepicker.templates['uploadform'];
content.setContent(template);
content.all('.fp-file,.fp-saveas,.fp-setauthor,.fp-setlicense').each(function (node) {
node.all('label').set('for', node.one('input,select').generateID());
});
content.one('form').set('id', id);
content.one('.fp-file input').set('name', 'repo_upload_file');
if (data.upload.label && content.one('.fp-file label')) {
content.one('.fp-file label').setContent(data.upload.label);
}
content.one('.fp-saveas input').set('name', 'title');
content.one('.fp-setauthor input').setAttrs({name:'author', value:this.options.author});
content.one('.fp-setlicense select').set('name', 'license');
this.populateLicensesSelect(content.one('.fp-setlicense select'));
// append hidden inputs to the upload form
content.one('form').appendChild(Y.Node.create('<input/>').
setAttrs({type:'hidden',name:'itemid',value:this.options.itemid}));
var types = this.options.accepted_types;
for (var i in types) {
content.one('form').appendChild(Y.Node.create('<input/>').
setAttrs({type:'hidden',name:'accepted_types[]',value:types[i]}));
}
var scope = this;
content.one('.fp-upload-btn').on('click', function(e) {
e.preventDefault();
var license = content.one('.fp-setlicense select');
if (this.options.rememberuserlicensepref) {
this.set_preference('recentlicense', license.get('value'));
}
if (!content.one('.fp-file input').get('value')) {
scope.print_msg(M.util.get_string('nofilesattached', 'repository'), 'error');
return false;
}
this.hide_header();
scope.request({
scope: scope,
action:'upload',
client_id: client_id,
params: {'savepath': scope.options.savepath || '/'},
repository_id: scope.active_repo.id,
form: {id: id, upload:true},
onerror: function(id, o, args) {
scope.create_upload_form(data);
},
callback: function(id, o, args) {
if (o.event == 'fileexists') {
scope.create_upload_form(data);
scope.process_existing_file(o);
return;
}
if (scope.options.editor_target&&scope.options.env=='editor') {
scope.options.editor_target.value=o.url;
scope.options.editor_target.dispatchEvent(new Event('change'), {'bubbles': true});
}
scope.hide();
o.client_id = client_id;
var formcallback_scope = args.scope.options.magicscope ? args.scope.options.magicscope : args.scope;
scope.options.formcallback.apply(formcallback_scope, [o]);
}
}, true);
}, this);
},
/** setting handlers and labels for elements in toolbar. Called once during the initial render of filepicker */
setup_toolbar: function() {
var client_id = this.options.client_id;
var toolbar = this.fpnode.one('.fp-toolbar');
toolbar.one('.fp-tb-logout').one('a,button').on('click', function(e) {
e.preventDefault();
if (!this.active_repo.nologin) {
this.hide_header();
this.request({
action:'logout',
client_id: this.options.client_id,
repository_id: this.active_repo.id,
path:'',
callback: this.display_response
}, true);
}
if (this.active_repo.logouturl) {
window.open(this.active_repo.logouturl, 'repo_auth', 'location=0,status=0,width=500,height=300,scrollbars=yes');
}
}, this);
toolbar.one('.fp-tb-refresh').one('a,button').on('click', function(e) {
e.preventDefault();
if (!this.active_repo.norefresh) {
this.list({ path: this.currentpath });
}
}, this);
toolbar.one('.fp-tb-search form').
set('method', 'POST').
set('id', 'fp-tb-search-'+client_id).
on('submit', function(e) {
e.preventDefault();
if (!this.active_repo.nosearch) {
this.request({
scope: this,
action:'search',
client_id: this.options.client_id,
repository_id: this.active_repo.id,
form: {id: 'fp-tb-search-'+client_id, upload:false, useDisabled:true},
callback: this.display_response
}, true);
}
}, this);
// it does not matter what kind of element is .fp-tb-manage, we create a dummy <a>
// element and use it to open url on click event
var managelnk = Y.Node.create('<a/>').
setAttrs({id:'fp-tb-manage-'+client_id+'-link', target:'_blank'}).
setStyle('display', 'none');
toolbar.append(managelnk);
toolbar.one('.fp-tb-manage').one('a,button').
on('click', function(e) {
e.preventDefault();
managelnk.simulate('click')
});
// same with .fp-tb-help
var helplnk = Y.Node.create('<a/>').
setAttrs({id:'fp-tb-help-'+client_id+'-link', target:'_blank'}).
setStyle('display', 'none');
toolbar.append(helplnk);
toolbar.one('.fp-tb-help').one('a,button').
on('click', function(e) {
e.preventDefault();
helplnk.simulate('click')
});
},
hide_header: function() {
if (this.fpnode.one('.fp-toolbar')) {
this.fpnode.one('.fp-toolbar').addClass('empty');
}
if (this.pathbar) {
this.pathbar.setContent('').addClass('empty');
}
},
print_header: function() {
var r = this.active_repo;
var scope = this;
var client_id = this.options.client_id;
this.hide_header();
this.print_path();
var toolbar = this.fpnode.one('.fp-toolbar');
if (!toolbar) { return; }
var enable_tb_control = function(node, enabled) {
if (!node) { return; }
node.addClassIf('disabled', !enabled).addClassIf('enabled', enabled)
if (enabled) {
toolbar.removeClass('empty');
}
}
// TODO 'back' permanently disabled for now. Note, flickr_public uses 'Logout' for it!
enable_tb_control(toolbar.one('.fp-tb-back'), false);
// search form
enable_tb_control(toolbar.one('.fp-tb-search'), !r.nosearch);
if(!r.nosearch) {
var searchform = toolbar.one('.fp-tb-search form');
searchform.setContent('');
this.request({
scope: this,
action:'searchform',
repository_id: this.active_repo.id,
callback: function(id, obj, args) {
if (obj.repo_id == scope.active_repo.id && obj.form) {
// if we did not jump to another repository meanwhile
searchform.setContent(obj.form);
// Highlight search text when user click for search.
var searchnode = searchform.one('input[name="s"]');
if (searchnode) {
searchnode.once('click', function(e) {
e.preventDefault();
this.select();
});
}
}
}
}, false);
}
// refresh button
// weather we use cache for this instance, this button will reload listing anyway
enable_tb_control(toolbar.one('.fp-tb-refresh'), !r.norefresh);
// login button
enable_tb_control(toolbar.one('.fp-tb-logout'), !r.nologin);
// manage url
enable_tb_control(toolbar.one('.fp-tb-manage'), r.manage);
Y.one('#fp-tb-manage-'+client_id+'-link').set('href', r.manage);
// help url
enable_tb_control(toolbar.one('.fp-tb-help'), r.help);
Y.one('#fp-tb-help-'+client_id+'-link').set('href', r.help);
// message
enable_tb_control(toolbar.one('.fp-tb-message'), r.message);
toolbar.one('.fp-tb-message').setContent(r.message);
},
print_path: function() {
if (!this.pathbar) {
return;
}
this.pathbar.setContent('').addClass('empty');
var p = this.filepath;
if (p && p.length!=0 && this.viewmode != 2) {
for(var i = 0; i < p.length; i++) {
var el = this.pathnode.cloneNode(true);
this.pathbar.appendChild(el);
if (i == 0) {
el.addClass('first');
}
if (i == p.length-1) {
el.addClass('last');
}
if (i%2) {
el.addClass('even');
} else {
el.addClass('odd');
}
el.all('.fp-path-folder-name').setContent(Y.Escape.html(p[i].name));
el.on('click',
function(e, path) {
e.preventDefault();
this.list({'path':path});
},
this, p[i].path);
}
this.pathbar.removeClass('empty');
}
},
hide: function() {
this.selectui.hide();
if (this.process_dlg) {
this.process_dlg.hide();
}
if (this.msg_dlg) {
this.msg_dlg.hide();
}
this.mainui.hide();
},
show: function() {
if (this.fpnode) {
this.hide();
this.mainui.show();
this.show_recent_repository();
} else {
this.launch();
}
},
launch: function() {
this.render();
},
show_recent_repository: function() {
this.hide_header();
this.viewbar_set_enabled(false);
var repository_id = this.get_preference('recentrepository');
this.viewmode = this.get_preference('recentviewmode');
if (this.viewmode != 2 && this.viewmode != 3) {
this.viewmode = 1;
}
if (this.options.repositories[repository_id]) {
this.list({'repo_id':repository_id});
}
},
get_preference: function (name) {
if (this.options.userprefs[name]) {
return this.options.userprefs[name];
} else {
return false;
}
},
set_preference: function(name, value) {
if (this.options.userprefs[name] != value) {
require(['core_user/repository'], function(UserRepository) {
UserRepository.setUserPreference('filepicker_' + name, value);
this.options.userprefs[name] = value;
}.bind(this));
}
},
in_iframe: function () {
// If we're not the top window then we're in an iFrame
return window.self !== window.top;
}
});
var loading = Y.one('#filepicker-loading-'+options.client_id);
if (loading) {
loading.setStyle('display', 'none');
}
M.core_filepicker.instances[options.client_id] = new FilePickerHelper(options);
};