Allow opening files for editing in new tabs

In a file list files with a default action
have an href that will trigger the action.
This way ctrl-click and middle button click open the default action in a new tab.

In order to achieve this a new param `openfile` was introduced to the files app.
It will make the files app trigger the default action for the file in question.
This also allows linking to file content rather than just the details display.

Introduce fileList.getDefaultActionUrl()
to create a link with that param set.
It's overwritten in the trashbin fileList
so that anchors continue to have `#` as a href.

Fix the link generation for subfolders of public shares:
58a87d0 was the last commit that touched the linkTo function in public.js.
It included the params as arguments to the generateUrl function.
Turns out this completely ignores the dir parameter now.
The inclusion was reverted in other places
so revert it here as well.
Also change `dir` to `path` in the param as that is respected
when following the link.

Add Test for the new link url for files with default action.
Remove test for multiple selects with ctrl-click
as that is not what we are doing anymore.

Signed-off-by: Azul <azul@riseup.net>
This commit is contained in:
Azul 2020-04-06 10:54:07 +02:00
parent d2728cbdc1
commit 43f0d2a3b5
7 changed files with 76 additions and 45 deletions

View File

@ -266,7 +266,7 @@
var mime = this.getCurrentMimeType();
var type = this.getCurrentType();
var permissions = this.getCurrentPermissions();
return this.getDefaultFileAction(mime,type, permissions);
return this.getDefaultFileAction(mime, type, permissions);
},
/**

View File

@ -432,7 +432,7 @@
this.setupUploadEvents(this._uploader);
}
}
this.triedActionOnce = false;
OC.Plugins.attach('OCA.Files.FileList', this);
@ -874,16 +874,12 @@
if ($tr.hasClass('dragging')) {
return;
}
if (this._allowSelection && (event.ctrlKey || event.shiftKey)) {
if (this._allowSelection && event.shiftKey) {
event.preventDefault();
if (event.shiftKey) {
this._selectRange($tr);
} else {
this._selectSingle($tr);
}
this._selectRange($tr);
this._lastChecked = $tr;
this.updateSelectionSummary();
} else {
} else if (!event.ctrlKey) {
// clicked directly on the name
if (!this._detailsView || $(event.target).is('.nametext, .name, .thumbnail') || $(event.target).closest('.nametext').length) {
var filename = $tr.attr('data-file');
@ -1320,6 +1316,31 @@
}, 0);
}
if(!this.triedActionOnce) {
var id = OC.Util.History.parseUrlQuery().openfile;
if (id) {
var $tr = this.$fileList.children().filterAttr('data-id', '' + id);
var filename = $tr.attr('data-file');
this.fileActions.currentFile = $tr.find('td');
var dir = $tr.attr('data-path') || this.getCurrentDirectory();
var spec = this.fileActions.getCurrentDefaultFileAction();
if (spec && spec.action) {
spec.action(filename, {
$file: $tr,
fileList: this,
fileActions: this.fileActions,
dir: dir
});
}
else {
var url = this.getDownloadUrl(filename, dir, true);
OCA.Files.Files.handleDownload(url);
}
}
this.triedActionOnce = true;
}
return newTrs;
},
@ -1524,10 +1545,14 @@
td = $('<td class="filename"></td>');
var spec = this.fileActions.getDefaultFileAction(mime, type, permissions);
// linkUrl
if (mime === 'httpd/unix-directory') {
linkUrl = this.linkTo(path + '/' + name);
}
else if (spec && spec.action) {
linkUrl = this.getDefaultActionUrl(path, fileData.id);
}
else {
linkUrl = this.getDownloadUrl(name, path, type === 'dir');
}
@ -2146,6 +2171,10 @@
return OCA.Files.Files.getDownloadUrl(files, dir || this.getCurrentDirectory(), isDir);
},
getDefaultActionUrl: function(path, id) {
return this.linkTo(path) + "&openfile="+id;
},
getUploadUrl: function(fileName, dir) {
if (_.isUndefined(dir)) {
dir = this.getCurrentDirectory();

View File

@ -239,6 +239,33 @@ describe('OCA.Files.FileList tests', function() {
expect($tr.find('.date').text()).not.toEqual('?');
expect(fileList.findFileEl('testName.txt')[0]).toEqual($tr[0]);
});
it('generates file element with url for default action when one is defined', function() {
var actionStub = sinon.stub();
fileList.setFiles(testFiles);
fileList.fileActions.registerAction({
mime: 'text/plain',
name: 'Test',
type: OCA.Files.FileActions.TYPE_INLINE,
permissions: OC.PERMISSION_ALL,
icon: function() {
// Specify icon for hitory button
return OC.imagePath('core','actions/history');
},
actionHandler: actionStub
});
fileList.fileActions.setDefault('text/plain', 'Test');
var fileData = new FileInfo({
id: 18,
name: 'testName.txt',
mimetype: 'text/plain',
size: 1234,
etag: 'a01234c',
mtime: 123456
});
var $tr = fileList.add(fileData);
expect($tr.find('a.name').attr('href'))
.toEqual(OC.getRootPath() + '/index.php/apps/files?dir=&openfile=18');
});
it('generates dir element with correct attributes when calling add() with dir data', function() {
var fileData = new FileInfo({
id: 19,
@ -1906,36 +1933,6 @@ describe('OCA.Files.FileList tests', function() {
expect($tr.find('input:checkbox').prop('checked')).toEqual(true);
});
it('Selects/deselect a file when clicking on the name while holding Ctrl', function() {
var $tr = fileList.findFileEl('One.txt');
var $tr2 = fileList.findFileEl('Three.pdf');
var e;
expect($tr.find('input:checkbox').prop('checked')).toEqual(false);
expect($tr2.find('input:checkbox').prop('checked')).toEqual(false);
e = new $.Event('click');
e.ctrlKey = true;
$tr.find('td.filename .name').trigger(e);
expect($tr.find('input:checkbox').prop('checked')).toEqual(true);
expect($tr2.find('input:checkbox').prop('checked')).toEqual(false);
// click on second entry, does not clear the selection
e = new $.Event('click');
e.ctrlKey = true;
$tr2.find('td.filename .name').trigger(e);
expect($tr.find('input:checkbox').prop('checked')).toEqual(true);
expect($tr2.find('input:checkbox').prop('checked')).toEqual(true);
expect(_.pluck(fileList.getSelectedFiles(), 'name')).toEqual(['One.txt', 'Three.pdf']);
// deselect now
e = new $.Event('click');
e.ctrlKey = true;
$tr2.find('td.filename .name').trigger(e);
expect($tr.find('input:checkbox').prop('checked')).toEqual(true);
expect($tr2.find('input:checkbox').prop('checked')).toEqual(false);
expect(_.pluck(fileList.getSelectedFiles(), 'name')).toEqual(['One.txt']);
});
it('Selects a range when clicking on one file then Shift clicking on another one', function() {
var $tr = fileList.findFileEl('One.txt');
var $tr2 = fileList.findFileEl('Three.pdf');

View File

@ -113,9 +113,9 @@ OCA.Sharing.PublicApp = {
// Show file preview if previewer is available, images are already handled by the template
if (mimetype.substr(0, mimetype.indexOf('/')) !== 'image' && $('.publicpreview').length === 0) {
// Trigger default action if not download TODO
var action = FileActions.getDefaultFileAction(mimetype, 'file', OC.PERMISSION_READ);
if (action && action.action) {
action($('#filename').val());
var spec = FileActions.getDefaultFileAction(mimetype, 'file', OC.PERMISSION_READ);
if (spec && spec.action) {
spec.action($('#filename').val());
}
}
}
@ -248,7 +248,7 @@ OCA.Sharing.PublicApp = {
};
this.fileList.linkTo = function (dir) {
return OC.generateUrl('/s/' + token + '', {dir: dir});
return OC.generateUrl('/s/' + token + '') + '?' + OC.buildQueryString({path: dir});
};
this.fileList.generatePreviewUrl = function (urlSpec) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -241,6 +241,11 @@
return '#'
},
getDefaultActionUrl: function() {
// no default action
return '#'
},
updateStorageStatistics: function() {
// no op because the trashbin doesn't have
// storage info like free space / used space