MDL-31901: Changing interface of file picker, use renderers:

- Filepicker window is now resizable and draggable;
- filepicker&renderer: removed id substitution from renderer, replaced it with classes (better readability);
- filepicker: allowed tree and table view for search results;
- filepicker: fixed small bug with displaying external link checkbox
- filepicker: display additional information about file in select window, repository returns more formatted information
This commit is contained in:
Marina Glancy
2012-05-21 11:57:51 +08:00
parent 5bdf63cce0
commit b92241f280
5 changed files with 262 additions and 217 deletions
+2
View File
@@ -74,9 +74,11 @@ $string['createinstance'] = 'Create a repository instance';
$string['createrepository'] = 'Create a repository instance';
$string['createxxinstance'] = 'Create "{$a}" instance';
$string['date'] = 'Date';
$string['datecreated'] = 'Created';
$string['deleted'] = 'Repository deleted';
$string['deleterepository'] = 'Delete this repository';
$string['detailview'] = 'View details';
$string['dimensions'] = 'Dimensions';
$string['disabled'] = 'Disabled';
$string['download'] = 'Download';
$string['downloadfolder'] = 'Download all';
+1 -1
View File
@@ -439,7 +439,7 @@ class page_requirements_manager {
case 'core_filepicker':
$module = array('name' => 'core_filepicker',
'fullpath' => '/repository/filepicker.js',
'requires' => array('base', 'node', 'node-event-simulate', 'json', 'async-queue', 'io-base', 'io-upload-iframe', 'io-form', 'yui2-menu', 'yui2-treeview', 'yui2-dragdrop', 'panel', 'cookie', 'datatable', 'datatable-sort'),
'requires' => array('base', 'node', 'node-event-simulate', 'json', 'async-queue', 'io-base', 'io-upload-iframe', 'io-form', 'yui2-menu', 'yui2-treeview', 'yui2-dragdrop', 'panel', 'cookie', 'datatable', 'datatable-sort', 'resize-plugin', 'dd-plugin', 'resize-constrain'),
// TODO check if those all are really required
'strings' => array(array('add', 'repository'), array('back', 'repository'), array('cancel', 'moodle'), array('close', 'repository'),
array('cleancache', 'repository'), array('copying', 'repository'), array('date', 'repository'), array('downloadsucc', 'repository'),
+155 -128
View File
@@ -65,10 +65,34 @@ M.core_filepicker.show = function(Y, options) {
M.core_filepicker.instances[options.client_id].show();
};
/**
* Add new file picker to current instances
*/
M.core_filepicker.init = function(Y, options) {
/** 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;
}
if (options.templates);
for (var templid in options.templates) {
this.templates[templid] = options.templates[templid];
@@ -377,20 +401,14 @@ M.core_filepicker.init = function(Y, options) {
}
},
view_files: function() {
if (this.active_repo.issearchresult) {
// list view is desiged to display treeview
// it is not working well with search result
this.view_as_icons();
this.viewbar_set_enabled(true);
this.print_path();
if (this.viewmode == 2) {
this.view_as_list();
} else if (this.viewmode == 3) {
this.view_as_table();
} else {
this.viewbar_set_enabled(true);
this.print_path();
if (this.viewmode == 2) {
this.view_as_list();
} else if (this.viewmode == 3) {
this.view_as_table();
} else {
this.view_as_icons();
}
this.view_as_icons();
}
},
treeview_dynload: function(node, cb) {
@@ -541,18 +559,10 @@ M.core_filepicker.init = function(Y, options) {
filenamediv.setContent(filename);
var imgdiv = element.one('.fp-thumbnail');
var set_width = function(node, width) {
var widthmatches = node.getStyle('minWidth').match(/^(\d+)px$/)
if (widthmatches && parseInt(widthmatches[1])>width) {
width = parseInt(widthmatches[1]);
}
node.setStyle('width', '' + width + 'px')
node.setStyle('width', '' + Math.max(width, node.getStylePx('minWidth')) + 'px')
}
var set_height = function(node, height) {
var heightmatches = node.getStyle('minHeight').match(/^(\d+)px$/)
if (heightmatches && parseInt(heightmatches[1])>height) {
height = parseInt(heightmatches[1]);
}
node.setStyle('height', '' + height + 'px')
node.setStyle('height', '' + Math.max(height, node.getStylePx('minHeight')) + 'px')
}
var width = node.thumbnail_width ? node.thumbnail_width : 90;
var height = node.thumbnail_height ? node.thumbnail_height : 90;
@@ -656,75 +666,90 @@ M.core_filepicker.init = function(Y, options) {
this.selectui.show();
var client_id = this.options.client_id;
var selectnode = this.fpnode.one('.fp-select');
var return_types = this.options.repositories[this.active_repo.id].return_types;
selectnode.removeClass('loading');
selectnode.one('#newname-'+client_id).set('value', args.title);
selectnode.one('#text-author-'+client_id).set('value', this.options.author);
selectnode.one('.fp-saveas input').set('value', args.title);
selectnode.one('.fp-setauthor input').set('value', this.options.author);
var imgnode = Y.Node.create('<img/>').set('src', args.thumbnail)
selectnode.one('#img-'+client_id).setContent('').appendChild(imgnode);
selectnode.one('.fp-thumbnail').setContent('').appendChild(imgnode);
selectnode.one('#linkexternal-'+client_id).set('checked', ''); // default to unchecked
if ((this.options.externallink && this.options.env == 'editor' && this.options.return_types != 1)) {
// enable checkbox 'Link external'
selectnode.one('#linkexternal-'+client_id).set('disabled', '');
selectnode.all('#linkexternal-'+client_id+',#wrap-linkexternal-'+client_id).removeClass('uneditable')
selectnode.one('.fp-linkexternal input').set('checked', ''); // default to unchecked
if ((this.options.externallink && this.options.env == 'editor' && return_types == 3)) {
// support both internal and external links, enable checkbox 'Link external'
selectnode.one('.fp-linkexternal input').set('disabled', '');
selectnode.all('.fp-linkexternal').removeClass('uneditable')
} else {
// disable checkbox 'Link external'
selectnode.one('#linkexternal-'+client_id).set('disabled', 'disabled');
selectnode.all('#linkexternal-'+client_id+',#wrap-linkexternal-'+client_id).addClass('uneditable')
if (this.options.return_types == 1) {
selectnode.one('.fp-linkexternal input').set('disabled', 'disabled');
selectnode.all('.fp-linkexternal').addClass('uneditable')
if (return_types == 1) {
// support external links only
selectnode.one('#linkexternal-'+client_id).set('checked', 'checked');
selectnode.one('.fp-linkexternal input').set('checked', 'checked');
}
}
if (args.hasauthor) {
selectnode.one('#text-author-'+client_id).set('disabled', 'disabled');
selectnode.all('#text-author-'+client_id+',#wrap-text-author-'+client_id).addClass('uneditable')
selectnode.one('.fp-setauthor input').set('disabled', 'disabled');
selectnode.all('.fp-setauthor').addClass('uneditable')
} else {
selectnode.one('#text-author-'+client_id).set('disabled', '');
selectnode.all('#text-author-'+client_id+',#wrap-text-author-'+client_id).removeClass('uneditable')
selectnode.one('.fp-setauthor input').set('disabled', '');
selectnode.all('.fp-setauthor').removeClass('uneditable')
}
if (!args.haslicense) {
// the license of the file
this.populate_licenses_select(selectnode.one('#select-license-'+client_id));
selectnode.one('#wrap-select-license-'+client_id).set('disabled', '');
selectnode.all('#select-license-'+client_id+'#wrap-select-license-'+client_id).removeClass('uneditable');
selectnode.one('.fp-setlicense select').set('disabled', '');
selectnode.one('.fp-setlicense').removeClass('uneditable');
} else {
selectnode.one('#wrap-select-license-'+client_id).set('disabled', 'disabled');
selectnode.all('#select-license-'+client_id+'#wrap-select-license-'+client_id).addClass('uneditable');
selectnode.one('.fp-setlicense select').set('disabled', 'disabled');
selectnode.one('.fp-setlicense').addClass('uneditable');
}
selectnode.one('form #filesource-'+client_id).set('value', args.source);
// 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(value);
}
}
},
setup_select_file: function() {
var client_id = this.options.client_id;
var selectnode = this.fpnode.one('.fp-select');
var getfile = selectnode.one('#fp-confirm-'+client_id);
var getfile = selectnode.one('.fp-select-confirm');
// bind labels with corresponding inputs
selectnode.all('.fp-saveas,.fp-linkexternal,.fp-setauthor,.fp-setlicense').each(function (node) {
node.all('label').set('for', node.one('input,select').generateID());
});
this.populate_licenses_select(selectnode.one('.fp-setlicense select'));
// 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('#newname-'+client_id).get('value');
var title = selectnode.one('.fp-saveas input').get('value');
var filesource = selectnode.one('form #filesource-'+client_id).get('value');
var params = {'title':title, 'source':filesource, 'savepath': this.options.savepath};
var license = selectnode.one('#select-license-'+client_id);
var license = selectnode.one('.fp-setlicense select');
if (license) {
params['license'] = license.get('value');
Y.Cookie.set('recentlicense', license.get('value'));
}
var author = selectnode.one('#text-author-'+client_id);
if (author){
params['author'] = author.get('value');
}
params['author'] = selectnode.one('.fp-setauthor input').get('value');
if (this.options.externallink && this.options.env == 'editor') {
// in editor, images are stored in '/' only
params.savepath = '/';
// when image or media button is clicked
if ( this.options.return_types != 1 ) {
var linkexternal = selectnode.one('#linkexternal-'+client_id);
var return_types = this.options.repositories[this.active_repo.id].return_types;
if ( return_types != 1 ) {
var linkexternal = selectnode.one('.fp-linkexternal input');
if (linkexternal && linkexternal.get('checked')) {
params['linkexternal'] = 'yes';
}
@@ -775,7 +800,7 @@ M.core_filepicker.init = function(Y, options) {
e.preventDefault();
}
}, this);
var cancel = selectnode.one('#fp-cancel-'+client_id);
var cancel = selectnode.one('.fp-select-cancel');
cancel.on('click', function(e) {
e.preventDefault();
this.selectui.hide();
@@ -815,24 +840,9 @@ M.core_filepicker.init = function(Y, options) {
},
render: function() {
var client_id = this.options.client_id;
var nodecontent = M.core_filepicker.templates.generallayout.
replace(/\{TOOLBARID}/g, 'fp-tb-'+client_id).
replace(/\{TOOLBACKID}/g, 'fp-tb-back-'+client_id).
replace(/\{TOOLSEARCHID}/g, 'fp-tb-search-'+client_id).
replace(/\{TOOLREFRESHID}/g, 'fp-tb-refresh-'+client_id).
replace(/\{TOOLLOGOUTID}/g, 'fp-tb-logout-'+client_id).
replace(/\{TOOLMANAGEID}/g, 'fp-tb-manage-'+client_id).
replace(/\{TOOLHELPID}/g, 'fp-tb-help-'+client_id);
this.fpnode = Y.Node.create(nodecontent).set('id', 'filepicker-'+client_id);
var fpselectnode = Y.Node.create(M.core_filepicker.templates.selectlayout.
replace(/\{IMGID}/g, 'img-'+client_id).
replace(/\{NEWNAMEID}/g, 'newname-'+client_id).
replace(/\{LINKEXTID}/g, 'linkexternal-'+client_id).
replace(/\{AUTHORID}/g, 'text-author-'+client_id).
replace(/\{LICENSEID}/g, 'select-license-'+client_id).
replace(/\{BUTCONFIRMID}/g, 'fp-confirm-'+client_id).
replace(/\{BUTCANCELID}/g, 'fp-cancel-'+client_id)
);
this.fpnode = Y.Node.create(M.core_filepicker.templates.generallayout).
set('id', 'filepicker-'+client_id);
var fpselectnode = Y.Node.create(M.core_filepicker.templates.selectlayout);
Y.one(document.body).appendChild(this.fpnode);
this.fpnode.appendChild(fpselectnode);
this.mainui = new Y.Panel({
@@ -842,10 +852,25 @@ M.core_filepicker.init = function(Y, options) {
centered : true,
modal : true,
visible : false,
render : true,
plugins : [Y.Plugin.Drag]
render : true
});
// allow to move the panel dragging it by it's header:
this.mainui.plug(Y.Plugin.Drag,{handles:['.yui3-widget-hd']});
// Check if CSS for the node sets min-max width/height and therefore if panel shall be resizable:
var resizeconstraints = {
minWidth: this.fpnode.getStylePx('minWidth')?this.fpnode.getStylePx('minWidth'):this.fpnode.getStylePx('width'),
minHeight: this.fpnode.getStylePx('minHeight')?this.fpnode.getStylePx('minHeight'):this.fpnode.getStylePx('height'),
maxWidth: this.fpnode.getStylePx('maxWidth')?this.fpnode.getStylePx('maxWidth'):this.fpnode.getStylePx('width'),
maxHeight: this.fpnode.getStylePx('maxHeight')?this.fpnode.getStylePx('maxHeight'):this.fpnode.getStylePx('height'),
preserveRatio: false
};
if (resizeconstraints.minWidth < resizeconstraints.maxWidth ||
resizeconstraints.minHeight < resizeconstraints.maxHeight) {
this.mainui.plug(Y.Plugin.Resize)
this.mainui.resize.plug(Y.Plugin.ResizeConstrained, resizeconstraints);
}
this.mainui.show();
// create panel for selecting a file (initially hidden)
this.selectui = new Y.Panel({
srcNode : fpselectnode,
zIndex : 600000,
@@ -1121,35 +1146,33 @@ M.core_filepicker.init = function(Y, options) {
create_upload_form: function(data) {
var client_id = this.options.client_id;
var id = data.upload.id+'_'+client_id;
var str = M.core_filepicker.templates.uploadform.
replace(/\{UPLOADFORMID}/g, id).
replace(/\{INPUTFILEID}/g, id+'_file').
replace(/\{NEWNAMEID}/g, 'newname-'+client_id).
replace(/\{AUTHORID}/g, 'author-'+client_id).
replace(/\{LICENSEID}/g, 'license-'+client_id).
replace(/\{BUTUPLOADID}/g, id+'_action');
this.fpnode.one('.fp-content').setContent(str);
var content = this.fpnode.one('.fp-content');
content.setContent(M.core_filepicker.templates.uploadform);
Y.all('#'+id+'_file').set('name', 'repo_upload_file');
Y.all('#'+'newname-'+client_id).set('name', 'title');
Y.all('#'+'author-'+client_id).set('name', 'author');
Y.all('#'+'author-'+client_id).set('value', this.options.author);
Y.all('#'+'license-'+client_id).set('name', 'license');
this.populate_licenses_select(Y.one('#'+'license-'+client_id))
Y.one('#'+id).appendChild(Y.Node.create('<input/>').
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');
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.populate_licenses_select(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) {
Y.one('#'+id).appendChild(Y.Node.create('<input/>').
content.one('form').appendChild(Y.Node.create('<input/>').
setAttrs({type:'hidden',name:'accepted_types[]',value:types[i]}));
}
var scope = this;
Y.one('#'+id+'_action').on('click', function(e) {
content.one('.fp-upload-btn').on('click', function(e) {
e.preventDefault();
var license = Y.one('#license-'+client_id);
var license = content.one('.fp-setlicense select');
Y.Cookie.set('recentlicense', license.get('value'));
if (!Y.one('#'+id+'_file').get('value')) {
if (!content.one('.fp-file input').get('value')) {
scope.print_msg(M.str.repository.nofilesattached, 'error');
return false;
}
@@ -1185,7 +1208,8 @@ M.core_filepicker.init = function(Y, options) {
/** 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;
Y.one('#fp-tb-logout-'+client_id).on('click', function(e) {
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();
@@ -1198,14 +1222,15 @@ M.core_filepicker.init = function(Y, options) {
}, true);
}
}, this);
Y.one('#fp-tb-refresh-'+client_id).on('click', function(e) {
toolbar.one('.fp-tb-refresh').one('a,button').on('click', function(e) {
e.preventDefault();
if (!this.active_repo.norefresh) {
this.list();
}
}, this);
Y.one('#fp-tb-search-'+client_id).
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) {
@@ -1220,31 +1245,32 @@ M.core_filepicker.init = function(Y, options) {
}
}, this);
// it does not matter what kind of element is {TOOLMANAGEID}, we create a dummy <a>
// 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');
Y.one('#fp-tb-'+client_id).append(managelnk);
Y.one('#fp-tb-manage-'+client_id).on('click', function(e) {
e.preventDefault();
managelnk.simulate('click')
});
toolbar.append(managelnk);
toolbar.one('.fp-tb-manage').one('a,button').
on('click', function(e) {
e.preventDefault();
managelnk.simulate('click')
});
// same with {TOOLHELPID}
// same with .fp-tb-help
var helplnk = Y.Node.create('<a/>').
setAttrs({id:'fp-tb-help-'+client_id+'-link', target:'_blank'}).
setStyle('display', 'none');
Y.one('#fp-tb-'+client_id).append(helplnk);
Y.one('#fp-tb-help-'+client_id).on('click', function(e) {
e.preventDefault();
helplnk.simulate('click')
});
toolbar.append(helplnk);
toolbar.one('.fp-tb-manage').one('a,button').
on('click', function(e) {
e.preventDefault();
helplnk.simulate('click')
});
},
hide_header: function() {
var client_id = this.options.client_id;
if (Y.one('#fp-tb-'+client_id)) {
Y.one('#fp-tb-'+client_id).addClass('empty');
if (this.fpnode.one('.fp-toolbar')) {
this.fpnode.one('.fp-toolbar').addClass('empty');
}
if (this.pathbar) {
this.pathbar.setContent('').addClass('empty');
@@ -1259,23 +1285,26 @@ M.core_filepicker.init = function(Y, options) {
var client_id = this.options.client_id;
this.hide_header();
this.print_paging();
this.print_path();
var toolbar = this.fpnode.one('.fp-toolbar');
if (!toolbar) { return; }
var enable_tb_control = function(elementid, enabled) {
if (!enabled) {
Y.all('#'+elementid+',#wrap-'+elementid).addClass('disabled').removeClass('enabled')
} else {
Y.all('#'+elementid+',#wrap-'+elementid).removeClass('disabled').addClass('enabled')
Y.one('#fp-tb-'+client_id).removeClass('empty');
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('fp-tb-back-'+client_id, false);
enable_tb_control(toolbar.one('.fp-tb-back'), false);
// search form
enable_tb_control('fp-tb-search-'+client_id, !r.nosearch);
enable_tb_control(toolbar.one('.fp-tb-search'), !r.nosearch);
if(!r.nosearch) {
Y.all('#fp-tb-search-'+client_id).setContent('');
var searchform = toolbar.one('.fp-tb-search form');
searchform.setContent('');
this.request({
scope: this,
action:'searchform',
@@ -1283,7 +1312,7 @@ M.core_filepicker.init = function(Y, options) {
callback: function(id, obj, args) {
if (obj.repo_id == scope.active_repo.id && obj.form) {
// if we did not jump to another repository meanwhile
Y.all('#fp-tb-search-'+scope.options.client_id).setContent(obj.form);
searchform.setContent(obj.form);
}
}
}, false);
@@ -1291,24 +1320,22 @@ M.core_filepicker.init = function(Y, options) {
// refresh button
// weather we use cache for this instance, this button will reload listing anyway
enable_tb_control('fp-tb-refresh-'+client_id, !r.norefresh);
enable_tb_control(toolbar.one('.fp-tb-refresh'), !r.norefresh);
// login button
enable_tb_control('fp-tb-logout-'+client_id, !r.nologin);
enable_tb_control(toolbar.one('.fp-tb-logout'), !r.nologin);
if(!r.nologin) {
var label = r.logouttext?r.logouttext:M.str.repository.logout;
Y.one('#fp-tb-logout-'+client_id).setContent(label)
toolbar.one('.fp-tb-logout').one('a,button').setContent(label)
}
// manage url
enable_tb_control('fp-tb-manage-'+client_id, r.manage);
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('fp-tb-help-'+client_id, r.help);
enable_tb_control(toolbar.one('.fp-tb-help'), r.help);
Y.one('#fp-tb-help-'+client_id+'-link').set('href', r.help);
this.print_path();
},
get_page_button: function(page) {
var r = this.active_repo;
+26 -18
View File
@@ -1793,37 +1793,45 @@ abstract class repository {
}
$len = count($listing['list']);
for ($i=0; $i<$len; $i++) {
if (isset($listing['list'][$i]['size'])) {
$listing['list'][$i]['size'] = (int)$listing['list'][$i]['size'];
$listing['list'][$i]['size_f'] = display_size($listing['list'][$i]['size']);
$file = & $listing['list'][$i];
if (isset($file['size'])) {
$file['size'] = (int)$file['size'];
$file['size_f'] = display_size($file['size']);
}
if (isset($file['license']) &&
get_string_manager()->string_exists($file['license'], 'license')) {
$file['license_f'] = get_string($file['license'], 'license');
}
if (isset($file['image_width']) && isset($file['image_height'])) {
$file['dimensions'] = $file['image_width'].'x'.$file['image_height'];
}
foreach (array('date', 'datemodified', 'datecreated') as $key) {
if (!isset($listing['list'][$i][$key]) && isset($listing['list'][$i]['date'])) {
$listing['list'][$i][$key] = $listing['list'][$i]['date'];
if (!isset($file[$key]) && isset($file['date'])) {
$file[$key] = $file['date'];
}
if (isset($listing['list'][$i][$key])) {
if (isset($file[$key])) {
// must be UNIX timestamp
$listing['list'][$i][$key] = (int)$listing['list'][$i][$key];
if (!$listing['list'][$i][$key]) {
unset($listing['list'][$i][$key]);
$file[$key] = (int)$file[$key];
if (!$file[$key]) {
unset($file[$key]);
} else {
$listing['list'][$i][$key.'_f'] = userdate($listing['list'][$i][$key], get_string('strftimedatetime', 'langconfig'));
$listing['list'][$i][$key.'_f_s'] = userdate($listing['list'][$i][$key], get_string('strftimedatetimeshort', 'langconfig'));
$file[$key.'_f'] = userdate($file[$key], get_string('strftimedatetime', 'langconfig'));
$file[$key.'_f_s'] = userdate($file[$key], get_string('strftimedatetimeshort', 'langconfig'));
}
}
}
if (!isset($listing['list'][$i]['type']) && !array_key_exists('children', $listing['list'][$i]) && isset($listing['list'][$i]['title'])) {
$mimetype = mimeinfo('type', $listing['list'][$i]['title']);
if (!isset($file['type']) && !array_key_exists('children', $file) && isset($file['title'])) {
$mimetype = mimeinfo('type', $file['title']);
if (get_string_manager()->string_exists($mimetype, 'mimetypes')) {
$mimetype = get_string($mimetype, 'mimetypes');
}
$listing['list'][$i]['type'] = $mimetype;
$file['type'] = $mimetype;
}
if (!isset($listing['list'][$i]['icon']) && isset($listing['list'][$i]['title'])) {
if (array_key_exists('children', $listing['list'][$i])) {
$listing['list'][$i]['icon'] = $OUTPUT->pix_url('f/folder')->out(false);
if (!isset($file['icon']) && isset($file['title'])) {
if (array_key_exists('children', $file)) {
$file['icon'] = $OUTPUT->pix_url('f/folder')->out(false);
} else {
$listing['list'][$i]['icon'] = $OUTPUT->pix_url('f/'.mimeinfo('icon', $listing['list'][$i]['title']))->out(false);
$file['icon'] = $OUTPUT->pix_url('f/'.mimeinfo('icon', $file['title']))->out(false);
}
}
}
+78 -70
View File
@@ -36,7 +36,9 @@ class core_repository_renderer extends plugin_renderer_base {
* Template for FilePicker with general layout (not QuickUpload).
*
* Must have one top element containing everything else (recommended <div class="file-picker">),
* CSS for this element must define width and height of the filepicker window;
* CSS for this element must define width and height of the filepicker window. Or CSS must
* define min-width, max-width, min-height and max-height and in this case the filepicker
* window will be resizeable;
*
* Element with class 'fp-viewbar' will have the class 'enabled' or 'disabled' when view mode
* can be changed or not;
@@ -59,23 +61,18 @@ class core_repository_renderer extends plugin_renderer_base {
* The content of element with class 'fp-path-folder-name' will be substituted with folder name;
* Parent element will receive class 'empty' when there are no folders to be displayed;
*
* Element with id {TOOLBARID} will have class 'empty' if all 'Search', 'Login', 'Refresh' and
* 'Logout' are unavailable for this repo;
* Element with id {TOOLBACKID} will hold the click event for going back to Login form;
* Element (<form>!) with id {TOOLSEARCHID} is responsible for search inside the repo (if
* repository provides this functionality), it must have one input-text field;
* Element with id {TOOLREFRESHID} will hold the click event for refreshing current view;
* Element with id {TOOLLOGOUTID} will hold the click event for logout (the content of the
* element will be substituted with logout string provided by repository or default
* M.str.repository.logout if not specified);
* Element with id {TOOLMANAGEID} will hold the click event for opening new window to manage
* repository files;
* Element with id {TOOLHELPID} will hold the click event for opening new window for help;
* Elements with ids {TOOLBACKID}, {TOOLSEARCHID}, {TOOLREFRESHID}, {TOOLLOGOUTID},
* {TOOLMANAGEID}, {TOOLHELPID} and also optional elements width ids wrap-{TOOLBACKID},
* wrap-{TOOLSEARCHID}, wrap-{TOOLREFRESHID}, wrap-{TOOLLOGOUTID}, wrap-{TOOLMANAGEID} and
* wrap-{TOOLHELPID} will have class 'enabled' or 'disabled' when applicable or not for
* the current repository view;
* Element with class 'fp-toolbar' will have class 'empty' if all 'Back', 'Search', 'Refresh',
* 'Logout', 'Manage' and 'Help' are unavailable for this repo;
*
* Inside fp-toolbar there are expected elements with classes fp-tb-back, fp-tb-search,
* fp-tb-refresh, fp-tb-logout, fp-tb-manage and fp-tb-help. Each of them will have
* class 'enabled' or 'disabled' if particular repository has this functionality.
* Element with class 'fp-tb-search' must contain empty form inside, it's contents will
* be substituted with the search form returned by repository (in the most cases it
* is generated with template core_repository_renderer::repository_default_searchform);
* Other elements must have either <a> or <button> element inside, it will hold onclick
* event for corresponding action; labels for fp-tb-back and fp-tb-logout may be
* replaced with those specified by repository;
*
* @return string
*/
@@ -96,16 +93,16 @@ class core_repository_renderer extends plugin_renderer_base {
</ul>
</div>
<div style="width:480px;height:400px;display:inline-block;vertical-align:top;">
<div class="fp-toolbar" id="{TOOLBARID}" style="background:yellow">
<div id="wrap-{TOOLBACKID}"><a id="{TOOLBACKID}">'.get_string('back', 'repository').'</a></div>
<div id="wrap-{TOOLSEARCHID}">
<div class="{!}fp-toolbar">
<div class="{!}fp-tb-back"><a>'.get_string('back', 'repository').'</a></div>
<div class="{!}fp-tb-search">
<img src="'.$this->pix_url('a/search').'" />
<form id="{TOOLSEARCHID}"></form>
<form/>
</div>
<div id="wrap-{TOOLREFRESHID}"><a id="{TOOLREFRESHID}"><img src="'.$this->pix_url('a/refresh').'" />'.get_string('refresh', 'repository').'</a></div>
<div id="wrap-{TOOLLOGOUTID}"><img src="'.$this->pix_url('a/logout').'" /><a id="{TOOLLOGOUTID}"></a></div>
<div id="wrap-{TOOLMANAGEID}"><a id="{TOOLMANAGEID}"><img src="'.$this->pix_url('a/setting').'" /> '.get_string('manageurl', 'repository').'</a></div>
<div id="wrap-{TOOLHELPID}"><a id="{TOOLHELPID}"><img src="'.$this->pix_url('a/help').'" /> '.get_string('help').'</a></div>
<div class="{!}fp-tb-refresh"><a><img src="'.$this->pix_url('a/refresh').'" />'.get_string('refresh', 'repository').'</a></div>
<div class="{!}fp-tb-logout"><img src="'.$this->pix_url('a/logout').'" /><a></a></div>
<div class="{!}fp-tb-manage"><a><img src="'.$this->pix_url('a/setting').'" /> '.get_string('manageurl', 'repository').'</a></div>
<div class="{!}fp-tb-help"><a><img src="'.$this->pix_url('a/help').'" /> '.get_string('help').'</a></div>
</div>
<div class="{!}fp-paging" style="background:pink"></div>
<div class="fp-pathbar" style="background:#ddffdd">
@@ -169,18 +166,21 @@ class core_repository_renderer extends plugin_renderer_base {
* All content must be enclosed in an element with class 'fp-select', CSS for this class
* must define width and height of the window;
*
* Image will be added as content to the element with id {IMGID};
* Thumbnail image will be added as content to the element with class 'fp-thumbnail';
*
* Inside the window <form> element must be present and contain followng input fields:
* {NEWNAMEID} (input-text)
* {LINKEXTID} (input-checkbox)
* {AUTHORID} (input-text)
* {LICENSEID} (select, will be populated with available options)
* {BUTCONFIRMID} (will hold onclick event)
* {BUTCANCELID} (will hold onclick event)
* Inside the window the elements with the following classnames must be present:
* 'fp-saveas', 'fp-linkexternal', 'fp-setauthor', 'fp-setlicense'. Inside each of them must have
* one input element (or select in case of fp-setlicense). They may also have labels.
* The elements will be assign with class 'uneditable' and input/select element will become
* disabled if they are not applicable for the particular file;
*
* Elements with ids 'wrap-{LINKEXTID}', 'wrap-{AUTHORID}' and 'wrap-{LICENSEID}' may be
* assigned with class 'uneditable' if not applicable for particular repository;
* There may be present elements with classes 'fp-datemodified', 'fp-datecreated', 'fp-size',
* 'fp-license', 'fp-author'. They will receive additional class 'fp-unknown' if information
* is unavailable. If there is information available, the content of embedded element
* with class 'fp-value' will be substituted with the value;
*
* Elements with classes 'fp-select-confirm' and 'fp-select-cancel' will hold corresponding
* onclick events;
*
* When confirm button is pressed and file is being selected, the top element receives
* additional class 'loading'. It is removed when response from server is received.
@@ -194,20 +194,27 @@ class core_repository_renderer extends plugin_renderer_base {
<p>'.get_string('loading', 'repository').'</p>
</div>
<form>
<p id="{IMGID}"></p>
<p class="{!}fp-thumbnail"></p>
<table width="100%">
<tr><td class="mdl-right"><label for="{NEWNAMEID}">'.get_string('saveas', 'repository').'</label>:</td>
<td class="mdl-left"><input type="text" id="{NEWNAMEID}" /></td></tr>
<tr id="wrap-{LINKEXTID}"><td></td>
<td class="mdl-left"><input type="checkbox" id="{LINKEXTID}" value="" /><label for="{LINKEXTID}">'.get_string('linkexternal', 'repository').'</label></td></tr>
<tr id="wrap-{AUTHORID}"><td class="mdl-right"><label for="{AUTHORID}">'.get_string('author', 'repository').'</label>:</td>
<td class="mdl-left"><input id="{AUTHORID}" type="text" /></td></tr>
<tr id="wrap-{LICENSEID}"><td class="mdl-right"><label for="{LICENSEID}">'.get_string('chooselicense', 'repository').'</label>:</td>
<td class="mdl-left"><select id="{LICENSEID}"></select></td></tr>
<tr class="{!}fp-saveas"><td class="mdl-right"><label>'.get_string('saveas', 'repository').'</label>:</td>
<td class="mdl-left"><input type="text"/></td></tr>
<tr class="{!}fp-linkexternal"><td></td>
<td class="mdl-left"><input type="checkbox"/><label>'.get_string('linkexternal', 'repository').'</label></td></tr>
<tr class="{!}fp-setauthor"><td class="mdl-right"><label>'.get_string('author', 'repository').'</label>:</td>
<td class="mdl-left"><input type="text" /></td></tr>
<tr class="{!}fp-setlicense"><td class="mdl-right"><label>'.get_string('chooselicense', 'repository').'</label>:</td>
<td class="mdl-left"><select></select></td></tr>
</table>
<p><button id="{BUTCONFIRMID}" >'.get_string('getfile', 'repository').'</button>
<button id="{BUTCANCELID}" >'.get_string('cancel').'</button></p>
</form></div>';
<p><button class="{!}fp-select-confirm" >'.get_string('getfile', 'repository').'</button>
<button class="{!}fp-select-cancel" >'.get_string('cancel').'</button></p>
</form>
<div class="{!}fp-datemodified">'.get_string('lastmodified', 'moodle').': <span class="fp-value"/></div>
<div class="{!}fp-datecreated">'.get_string('datecreated', 'repository').': <span class="fp-value"/></div>
<div class="{!}fp-size">'.get_string('size', 'repository').': <span class="fp-value"/></div>
<div class="{!}fp-license">'.get_string('license', 'moodle').': <span class="fp-value"/></div>
<div class="{!}fp-author">'.get_string('author', 'repository').': <span class="fp-value"/></div>
<div class="{!}fp-dimensions">'.get_string('dimensions', 'repository').': <span class="fp-value"/></div>
</div>';
return preg_replace('/\{\!\}/', '', $rv);
}
@@ -215,42 +222,43 @@ class core_repository_renderer extends plugin_renderer_base {
* Content to display when user chooses 'Upload file' repository (will be nested inside
* element with class 'fp-content').
*
* Must contain form (enctype="multipart/form-data" method="POST") with id {UPLOADFORMID}
* The elements with the following ids are obligatory:
* {INPUTFILEID} (input-file)
* {NEWNAMEID} (input-text)
* {AUTHORID} (input-text)
* {LICENSEID} (select, will be populated with available options)
* {BUTUPLOADID} (any element type, will hold onclick event)
* Must contain form (enctype="multipart/form-data" method="POST")
*
* The elements with the following classnames must be present:
* 'fp-file', 'fp-saveas', 'fp-setauthor', 'fp-setlicense'. Inside each of them must have
* one input element (or select in case of fp-setlicense). They may also have labels.
*
* Element with class 'fp-upload-btn' will hold onclick event for uploading the file;
*
* Please note that some fields may be hidden using CSS if this is part of quickupload form
*
* @return string
*/
public function js_template_uploadform() {
return '<div class="fp-upload-form mdl-align">
<form id="{UPLOADFORMID}" enctype="multipart/form-data" method="POST">
$rv = '<div class="fp-upload-form mdl-align">
<form enctype="multipart/form-data" method="POST">
<table width="100%">
<tr>
<td class="mdl-right"><label for="{INPUTFILEID}">'.get_string('attachment', 'repository').'</label>:</td>
<td class="mdl-left"><input type="file" id="{INPUTFILEID}" /></td>
<tr class="{!}fp-file">
<td class="mdl-right"><label>'.get_string('attachment', 'repository').'</label>:</td>
<td class="mdl-left"><input type="file"/></td>
</tr>
<tr>
<td class="mdl-right"><label for="{NEWNAMEID}">'.get_string('saveas', 'repository').'</label>:</td>
<td class="mdl-left"><input type="text" id="{NEWNAMEID}" /></td>
<tr class="{!}fp-saveas">
<td class="mdl-right"><label>'.get_string('saveas', 'repository').'</label>:</td>
<td class="mdl-left"><input type="text"/></td>
</tr>
<tr>
<td class="mdl-right"><label for="{AUTHORID}">'.get_string('author', 'repository').'</label>:</td>
<td class="mdl-left"><input type="text" id="{AUTHORID}" /></td>
<tr class="{!}fp-setauthor">
<td class="mdl-right"><label>'.get_string('author', 'repository').'</label>:</td>
<td class="mdl-left"><input type="text"/></td>
</tr>
<tr>
<td class="mdl-right"><label for="{LICENSEID}">'.get_string('chooselicense', 'repository').'</label>:</td>
<td class="mdl-left"><select id="{LICENSEID}" /></td>
<tr class="{!}fp-setlicense">
<td class="mdl-right"><label>'.get_string('chooselicense', 'repository').'</label>:</td>
<td class="mdl-left"><select/></td>
</tr>
</table>
</form>
<div class="fp-upload-btn"><button id="{BUTUPLOADID}">'.get_string('upload', 'repository').'</button></div>
<div><button class="{!}fp-upload-btn">'.get_string('upload', 'repository').'</button></div>
</div> ';
return preg_replace('/\{\!\}/', '', $rv);
}
/**