Merge pull request #9538 from owncloud/fileactions-cleanup

Propagate file action changes to the file lists
This commit is contained in:
Vincent Petry 2014-07-10 16:15:23 +02:00
commit e391108ebc
7 changed files with 137 additions and 43 deletions

View file

@ -32,9 +32,11 @@
// regular actions // regular actions
fileActions.merge(OCA.Files.fileActions); fileActions.merge(OCA.Files.fileActions);
// in case apps would decide to register file actions later, this._onActionsUpdated = _.bind(this._onActionsUpdated, this);
// replace the global object with this one OCA.Files.fileActions.on('setDefault.app-files', this._onActionsUpdated);
OCA.Files.fileActions = fileActions; OCA.Files.fileActions.on('registerAction.app-files', this._onActionsUpdated);
window.FileActions.on('setDefault.app-files', this._onActionsUpdated);
window.FileActions.on('registerAction.app-files', this._onActionsUpdated);
this.files = OCA.Files.Files; this.files = OCA.Files.Files;
@ -59,6 +61,32 @@
this._onPopState(OC.Util.History.parseUrlQuery()); this._onPopState(OC.Util.History.parseUrlQuery());
}, },
/**
* Destroy the app
*/
destroy: function() {
this.navigation = null;
this.fileList.destroy();
this.fileList = null;
this.files = null;
OCA.Files.fileActions.off('setDefault.app-files', this._onActionsUpdated);
OCA.Files.fileActions.off('registerAction.app-files', this._onActionsUpdated);
window.FileActions.off('setDefault.app-files', this._onActionsUpdated);
window.FileActions.off('registerAction.app-files', this._onActionsUpdated);
},
_onActionsUpdated: function(ev, newAction) {
// forward new action to the file list
if (ev.action) {
this.fileList.fileActions.registerAction(ev.action);
} else if (ev.defaultAction) {
this.fileList.fileActions.setDefault(
ev.defaultAction.mime,
ev.defaultAction.name
);
}
},
/** /**
* Returns the container of the currently visible app. * Returns the container of the currently visible app.
* *

View file

@ -23,48 +23,52 @@
icons: {}, icons: {},
currentFile: null, currentFile: null,
/**
* Dummy jquery element, for events
*/
$el: null,
/** /**
* List of handlers to be notified whenever a register() or * List of handlers to be notified whenever a register() or
* setDefault() was called. * setDefault() was called.
*/ */
_updateListeners: [], _updateListeners: {},
initialize: function() { initialize: function() {
this.clear(); this.clear();
// abusing jquery for events until we get a real event lib
this.$el = $('<div class="dummy-fileactions hidden"></div>');
$('body').append(this.$el);
}, },
/** /**
* Adds an update listener to be notified whenever register() * Adds an event handler
* or setDefault() has been called.
* *
* @param {String} eventName event name
* @param Function callback * @param Function callback
*/ */
addUpdateListener: function(callback) { on: function(eventName, callback) {
if (!_.isFunction(callback)) { this.$el.on(eventName, callback);
throw 'Argument passed to FileActions.addUpdateListener must be a function';
}
this._updateListeners.push(callback);
}, },
/** /**
* Removes an update listener. * Removes an event handler
* *
* @param {String} eventName event name
* @param Function callback * @param Function callback
*/ */
removeUpdateListener: function(callback) { off: function(eventName, callback) {
if (!_.isFunction(callback)) { this.$el.off(eventName, callback);
throw 'Argument passed to FileActions.removeUpdateListener must be a function';
}
this._updateListeners = _.without(this._updateListeners, callback);
}, },
/** /**
* Notifies the registered update listeners * Notifies the event handlers
*
* @param {String} eventName event name
* @param {Object} data data
*/ */
_notifyUpdateListeners: function() { _notifyUpdateListeners: function(eventName, data) {
for (var i = 0; i < this._updateListeners.length; i++) { this.$el.trigger(new $.Event(eventName, data));
this._updateListeners[i](this);
}
}, },
/** /**
@ -87,17 +91,44 @@
this.defaults = _.extend(this.defaults, fileActions.defaults); this.defaults = _.extend(this.defaults, fileActions.defaults);
this.icons = _.extend(this.icons, fileActions.icons); this.icons = _.extend(this.icons, fileActions.icons);
}, },
register: function (mime, name, permissions, icon, action, displayName) { /**
* @deprecated use #registerAction() instead
*/
register: function(mime, name, permissions, icon, action, displayName) {
return this.registerAction({
name: name,
mime: mime,
permissions: permissions,
icon: icon,
actionHandler: action,
displayName: displayName
});
},
/**
* Register action
*
* @param {Object} action action object
* @param {String} action.name identifier of the action
* @param {String} action.displayName display name of the action, defaults
* to the name given in action.name
* @param {String} action.mime mime type
* @param {int} action.permissions permissions
* @param {(Function|String)} action.icon icon
* @param {Function} action.actionHandler function that performs the action
*/
registerAction: function (action) {
var mime = action.mime;
var name = action.name;
if (!this.actions[mime]) { if (!this.actions[mime]) {
this.actions[mime] = {}; this.actions[mime] = {};
} }
this.actions[mime][name] = { this.actions[mime][name] = {
action: action, action: action.actionHandler,
permissions: permissions, permissions: action.permissions,
displayName: displayName || t('files', name) displayName: action.displayName || t('files', name)
}; };
this.icons[name] = icon; this.icons[name] = action.icon;
this._notifyUpdateListeners(); this._notifyUpdateListeners('registerAction', {action: action});
}, },
clear: function() { clear: function() {
this.actions = {}; this.actions = {};
@ -108,7 +139,7 @@
}, },
setDefault: function (mime, name) { setDefault: function (mime, name) {
this.defaults[mime] = name; this.defaults[mime] = name;
this._notifyUpdateListeners(); this._notifyUpdateListeners('setDefault', {defaultAction: {mime: mime, name: name}});
}, },
get: function (mime, type, permissions) { get: function (mime, type, permissions) {
var actions = this.getActions(mime, type, permissions); var actions = this.getActions(mime, type, permissions);

View file

@ -172,7 +172,8 @@
*/ */
destroy: function() { destroy: function() {
// TODO: also unregister other event handlers // TODO: also unregister other event handlers
this.fileActions.removeUpdateListener(this._onFileActionsUpdated); this.fileActions.off('registerAction', this._onFileActionsUpdated);
this.fileActions.off('setDefault', this._onFileActionsUpdated);
}, },
_initFileActions: function(fileActions) { _initFileActions: function(fileActions) {
@ -182,7 +183,8 @@
this.fileActions.registerDefaultActions(); this.fileActions.registerDefaultActions();
} }
this._onFileActionsUpdated = _.debounce(_.bind(this._onFileActionsUpdated, this), 100); this._onFileActionsUpdated = _.debounce(_.bind(this._onFileActionsUpdated, this), 100);
this.fileActions.addUpdateListener(this._onFileActionsUpdated); this.fileActions.on('registerAction', this._onFileActionsUpdated);
this.fileActions.on('setDefault', this._onFileActionsUpdated);
}, },
/** /**

View file

@ -52,9 +52,7 @@ describe('OCA.Files.App tests', function() {
App.initialize(); App.initialize();
}); });
afterEach(function() { afterEach(function() {
App.navigation = null; App.destroy();
App.fileList = null;
App.files = null;
pushStateStub.restore(); pushStateStub.restore();
parseUrlQueryStub.restore(); parseUrlQueryStub.restore();

View file

@ -354,7 +354,7 @@ describe('OCA.Files.FileActions tests', function() {
it('notifies update event handlers once after multiple changes', function() { it('notifies update event handlers once after multiple changes', function() {
var actionStub = sinon.stub(); var actionStub = sinon.stub();
var handler = sinon.stub(); var handler = sinon.stub();
FileActions.addUpdateListener(handler); FileActions.on('registerAction', handler);
FileActions.register( FileActions.register(
'all', 'all',
'Test', 'Test',
@ -374,8 +374,8 @@ describe('OCA.Files.FileActions tests', function() {
it('does not notifies update event handlers after unregistering', function() { it('does not notifies update event handlers after unregistering', function() {
var actionStub = sinon.stub(); var actionStub = sinon.stub();
var handler = sinon.stub(); var handler = sinon.stub();
FileActions.addUpdateListener(handler); FileActions.on('registerAction', handler);
FileActions.removeUpdateListener(handler); FileActions.off('registerAction', handler);
FileActions.register( FileActions.register(
'all', 'all',
'Test', 'Test',

View file

@ -92,6 +92,21 @@ OCA.Sharing.App = {
} }
}, },
/**
* Destroy the app
*/
destroy: function() {
OCA.Files.fileActions.off('setDefault.app-sharing', this._onActionsUpdated);
OCA.Files.fileActions.off('registerAction.app-sharing', this._onActionsUpdated);
this.removeSharingIn();
this.removeSharingOut();
this.removeSharingLinks();
this._inFileList = null;
this._outFileList = null;
this._linkFileList = null;
delete this._globalActionsInitialized;
},
_createFileActions: function() { _createFileActions: function() {
// inherit file actions from the files app // inherit file actions from the files app
var fileActions = new OCA.Files.FileActions(); var fileActions = new OCA.Files.FileActions();
@ -100,6 +115,14 @@ OCA.Sharing.App = {
fileActions.registerDefaultActions(); fileActions.registerDefaultActions();
fileActions.merge(OCA.Files.fileActions); fileActions.merge(OCA.Files.fileActions);
if (!this._globalActionsInitialized) {
// in case actions are registered later
this._onActionsUpdated = _.bind(this._onActionsUpdated, this);
OCA.Files.fileActions.on('setDefault.app-sharing', this._onActionsUpdated);
OCA.Files.fileActions.on('registerAction.app-sharing', this._onActionsUpdated);
this._globalActionsInitialized = true;
}
// when the user clicks on a folder, redirect to the corresponding // when the user clicks on a folder, redirect to the corresponding
// folder in the files app instead of opening it directly // folder in the files app instead of opening it directly
fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) { fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
@ -110,6 +133,23 @@ OCA.Sharing.App = {
return fileActions; return fileActions;
}, },
_onActionsUpdated: function(ev) {
_.each([this._inFileList, this._outFileList, this._linkFileList], function(list) {
if (!list) {
return;
}
if (ev.action) {
list.fileActions.registerAction(ev.action);
} else if (ev.defaultAction) {
list.fileActions.setDefault(
ev.defaultAction.mime,
ev.defaultAction.name
);
}
});
},
_extendFileList: function(fileList) { _extendFileList: function(fileList) {
// remove size column from summary // remove size column from summary
fileList.fileSummary.$el.find('.filesize').remove(); fileList.fileSummary.$el.find('.filesize').remove();

View file

@ -45,12 +45,7 @@ describe('OCA.Sharing.App tests', function() {
fileListOut = App.initSharingOut($('#app-content-sharingout')); fileListOut = App.initSharingOut($('#app-content-sharingout'));
}); });
afterEach(function() { afterEach(function() {
App._inFileList = null; App.destroy();
App._outFileList = null;
fileListIn.destroy();
fileListOut.destroy();
fileListIn = null;
fileListOut = null;
}); });
describe('initialization', function() { describe('initialization', function() {