Skip to content

Commit e37fa60

Browse files
authored
Merge pull request #7591 from nextcloud/trigger-events-before-and-after-a-file-action-is-executed
Trigger events before and after a file action is executed
2 parents e40d6f6 + c059fbd commit e37fa60

4 files changed

Lines changed: 123 additions & 14 deletions

File tree

apps/files/js/fileactions.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,6 @@
4747
*/
4848
$el: null,
4949

50-
/**
51-
* List of handlers to be notified whenever a register() or
52-
* setDefault() was called.
53-
*
54-
* @member {Function[]}
55-
*/
56-
_updateListeners: {},
57-
5850
_fileActionTriggerTemplate: null,
5951

6052
/**
@@ -142,7 +134,22 @@
142134
var mime = action.mime;
143135
var name = action.name;
144136
var actionSpec = {
145-
action: action.actionHandler,
137+
action: function(fileName, context) {
138+
// Actions registered in one FileAction may be executed on a
139+
// different one (for example, due to the "merge" function),
140+
// so the listeners have to be updated on the FileActions
141+
// from the context instead of on the one in which it was
142+
// originally registered.
143+
if (context && context.fileActions) {
144+
context.fileActions._notifyUpdateListeners('beforeTriggerAction', {action: actionSpec, fileName: fileName, context: context});
145+
}
146+
147+
action.actionHandler(fileName, context);
148+
149+
if (context && context.fileActions) {
150+
context.fileActions._notifyUpdateListeners('afterTriggerAction', {action: actionSpec, fileName: fileName, context: context});
151+
}
152+
},
146153
name: name,
147154
displayName: action.displayName,
148155
mime: mime,
@@ -174,7 +181,6 @@
174181
this.defaults = {};
175182
this.icons = {};
176183
this.currentFile = null;
177-
this._updateListeners = [];
178184
},
179185
/**
180186
* Sets the default action for a given mime type.

apps/files/js/filelist.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,8 +676,25 @@
676676
$(event.target).closest('a').blur();
677677
}
678678
} else {
679-
this._updateDetailsView($tr.attr('data-file'));
679+
// Even if there is no Details action the default event
680+
// handler is prevented for consistency (although there
681+
// should always be a Details action); otherwise the link
682+
// would be downloaded by the browser when the user expected
683+
// the details to be shown.
680684
event.preventDefault();
685+
var filename = $tr.attr('data-file');
686+
var mime = this.fileActions.getCurrentMimeType();
687+
var type = this.fileActions.getCurrentType();
688+
var permissions = this.fileActions.getCurrentPermissions();
689+
var action = this.fileActions.get(mime, type, permissions)['Details'];
690+
if (action) {
691+
action(filename, {
692+
$file: $tr,
693+
fileList: this,
694+
fileActions: this.fileActions,
695+
dir: $tr.attr('data-path') || this.getCurrentDirectory()
696+
});
697+
}
681698
}
682699
}
683700
},

apps/files/tests/js/appSpec.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,22 @@ describe('OCA.Files.App tests', function() {
112112
App.initialize();
113113

114114
var actions = App.fileList.fileActions.actions;
115-
expect(actions.all.OverwriteThis.action).toBe(actionStub);
116-
expect(actions.all.LegacyTest.action).toBe(legacyActionStub);
117-
expect(actions.all.RegularTest.action).toBe(actionStub);
115+
var context = { fileActions: sinon.createStubInstance(OCA.Files.FileActions) };
116+
actions.all.OverwriteThis.action('testFileName', context);
117+
expect(actionStub.calledOnce).toBe(true);
118+
expect(context.fileActions._notifyUpdateListeners.callCount).toBe(2);
119+
expect(context.fileActions._notifyUpdateListeners.getCall(0).calledWith('beforeTriggerAction')).toBe(true);
120+
expect(context.fileActions._notifyUpdateListeners.getCall(1).calledWith('afterTriggerAction')).toBe(true);
121+
actions.all.LegacyTest.action('testFileName', context);
122+
expect(legacyActionStub.calledOnce).toBe(true);
123+
expect(context.fileActions._notifyUpdateListeners.callCount).toBe(4);
124+
expect(context.fileActions._notifyUpdateListeners.getCall(2).calledWith('beforeTriggerAction')).toBe(true);
125+
expect(context.fileActions._notifyUpdateListeners.getCall(3).calledWith('afterTriggerAction')).toBe(true);
126+
actions.all.RegularTest.action('testFileName', context);
127+
expect(actionStub.calledTwice).toBe(true);
128+
expect(context.fileActions._notifyUpdateListeners.callCount).toBe(6);
129+
expect(context.fileActions._notifyUpdateListeners.getCall(4).calledWith('beforeTriggerAction')).toBe(true);
130+
expect(context.fileActions._notifyUpdateListeners.getCall(5).calledWith('afterTriggerAction')).toBe(true);
118131
// default one still there
119132
expect(actions.dir.Open.action).toBeDefined();
120133
});

apps/files/tests/js/fileactionsSpec.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ describe('OCA.Files.FileActions tests', function() {
299299
clock.restore();
300300
});
301301
it('passes context to action handler', function() {
302+
var notifyUpdateListenersSpy = sinon.spy(fileList.fileActions, '_notifyUpdateListeners');
302303
$tr.find('.action-test').click();
303304
expect(actionStub.calledOnce).toEqual(true);
304305
expect(actionStub.getCall(0).args[0]).toEqual('testName.txt');
@@ -309,6 +310,22 @@ describe('OCA.Files.FileActions tests', function() {
309310
expect(context.dir).toEqual('/subdir');
310311
expect(context.fileInfoModel.get('name')).toEqual('testName.txt');
311312

313+
expect(notifyUpdateListenersSpy.calledTwice).toEqual(true);
314+
expect(notifyUpdateListenersSpy.calledBefore(actionStub)).toEqual(true);
315+
expect(notifyUpdateListenersSpy.calledAfter(actionStub)).toEqual(true);
316+
expect(notifyUpdateListenersSpy.getCall(0).args[0]).toEqual('beforeTriggerAction');
317+
expect(notifyUpdateListenersSpy.getCall(0).args[1]).toEqual({
318+
action: fileActions.getActions('all', OCA.Files.FileActions.TYPE_INLINE, OC.PERMISSION_READ)['Test'],
319+
fileName: 'testName.txt',
320+
context: context
321+
});
322+
expect(notifyUpdateListenersSpy.getCall(1).args[0]).toEqual('afterTriggerAction');
323+
expect(notifyUpdateListenersSpy.getCall(1).args[1]).toEqual({
324+
action: fileActions.getActions('all', OCA.Files.FileActions.TYPE_INLINE, OC.PERMISSION_READ)['Test'],
325+
fileName: 'testName.txt',
326+
context: context
327+
});
328+
312329
// when data-path is defined
313330
actionStub.reset();
314331
$tr.attr('data-path', '/somepath');
@@ -317,6 +334,7 @@ describe('OCA.Files.FileActions tests', function() {
317334
expect(context.dir).toEqual('/somepath');
318335
});
319336
it('also triggers action handler when calling triggerAction()', function() {
337+
var notifyUpdateListenersSpy = sinon.spy(fileList.fileActions, '_notifyUpdateListeners');
320338
var model = new OCA.Files.FileInfoModel({
321339
id: 1,
322340
name: 'Test.txt',
@@ -331,7 +349,62 @@ describe('OCA.Files.FileActions tests', function() {
331349
expect(actionStub.getCall(0).args[1].fileList).toEqual(fileList);
332350
expect(actionStub.getCall(0).args[1].fileActions).toEqual(fileActions);
333351
expect(actionStub.getCall(0).args[1].fileInfoModel).toEqual(model);
352+
353+
expect(notifyUpdateListenersSpy.calledTwice).toEqual(true);
354+
expect(notifyUpdateListenersSpy.calledBefore(actionStub)).toEqual(true);
355+
expect(notifyUpdateListenersSpy.calledAfter(actionStub)).toEqual(true);
356+
expect(notifyUpdateListenersSpy.getCall(0).args[0]).toEqual('beforeTriggerAction');
357+
expect(notifyUpdateListenersSpy.getCall(0).args[1]).toEqual({
358+
action: fileActions.getActions('all', OCA.Files.FileActions.TYPE_INLINE, OC.PERMISSION_READ)['Test'],
359+
fileName: 'Test.txt',
360+
context: {
361+
fileActions: fileActions,
362+
fileInfoModel: model,
363+
dir: '/subdir',
364+
fileList: fileList,
365+
$file: fileList.findFileEl('Test.txt')
366+
}
367+
});
368+
expect(notifyUpdateListenersSpy.getCall(1).args[0]).toEqual('afterTriggerAction');
369+
expect(notifyUpdateListenersSpy.getCall(1).args[1]).toEqual({
370+
action: fileActions.getActions('all', OCA.Files.FileActions.TYPE_INLINE, OC.PERMISSION_READ)['Test'],
371+
fileName: 'Test.txt',
372+
context: {
373+
fileActions: fileActions,
374+
fileInfoModel: model,
375+
dir: '/subdir',
376+
fileList: fileList,
377+
$file: fileList.findFileEl('Test.txt')
378+
}
379+
});
334380
});
381+
it('triggers listener events when invoked directly', function() {
382+
var context = {fileActions: new OCA.Files.FileActions()}
383+
var notifyUpdateListenersSpy = sinon.spy(context.fileActions, '_notifyUpdateListeners');
384+
var testAction = fileActions.get('all', OCA.Files.FileActions.TYPE_INLINE, OC.PERMISSION_READ)['Test'];
385+
386+
testAction('Test.txt', context);
387+
388+
expect(actionStub.calledOnce).toEqual(true);
389+
expect(actionStub.getCall(0).args[0]).toEqual('Test.txt');
390+
expect(actionStub.getCall(0).args[1]).toBe(context);
391+
392+
expect(notifyUpdateListenersSpy.calledTwice).toEqual(true);
393+
expect(notifyUpdateListenersSpy.calledBefore(actionStub)).toEqual(true);
394+
expect(notifyUpdateListenersSpy.calledAfter(actionStub)).toEqual(true);
395+
expect(notifyUpdateListenersSpy.getCall(0).args[0]).toEqual('beforeTriggerAction');
396+
expect(notifyUpdateListenersSpy.getCall(0).args[1]).toEqual({
397+
action: fileActions.getActions('all', OCA.Files.FileActions.TYPE_INLINE, OC.PERMISSION_READ)['Test'],
398+
fileName: 'Test.txt',
399+
context: context
400+
});
401+
expect(notifyUpdateListenersSpy.getCall(1).args[0]).toEqual('afterTriggerAction');
402+
expect(notifyUpdateListenersSpy.getCall(1).args[1]).toEqual({
403+
action: fileActions.getActions('all', OCA.Files.FileActions.TYPE_INLINE, OC.PERMISSION_READ)['Test'],
404+
fileName: 'Test.txt',
405+
context: context
406+
});
407+
}),
335408
describe('actions menu', function() {
336409
it('shows actions menu inside row when clicking the menu trigger', function() {
337410
expect($tr.find('td.filename .fileActionsMenu').length).toEqual(0);

0 commit comments

Comments
 (0)