diff --git a/apps/files/js/app.js b/apps/files/js/app.js index 6d8a9788d9..6ccf513500 100644 --- a/apps/files/js/app.js +++ b/apps/files/js/app.js @@ -24,20 +24,27 @@ initialize: function() { this.navigation = new OCA.Files.Navigation($('#app-navigation')); - // TODO: ideally these should be in a separate class / app (the embedded "all files" app) - this.fileActions = OCA.Files.FileActions.clone(); + var fileActions = new OCA.Files.FileActions(); + // default actions + fileActions.registerDefaultActions(); + // legacy actions + fileActions.merge(window.FileActions); + // regular actions + fileActions.merge(OCA.Files.fileActions); + this.files = OCA.Files.Files; + // TODO: ideally these should be in a separate class / app (the embedded "all files" app) this.fileList = new OCA.Files.FileList( $('#app-content-files'), { scrollContainer: $('#app-content'), dragOptions: dragOptions, - folderDropOptions: folderDropOptions + folderDropOptions: folderDropOptions, + fileActions: fileActions, + allowLegacyActions: true } ); this.files.initialize(); - this.fileActions.registerDefaultActions(); - this.fileList.setFileActions(this.fileActions); // for backward compatibility, the global FileList will // refer to the one of the "files" view @@ -146,7 +153,7 @@ })(); $(document).ready(function() { - // wait for other apps/extensions to register their event handlers + // wait for other apps/extensions to register their event handlers and file actions // in the "ready" clause _.defer(function() { OCA.Files.App.initialize(); diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js index a12b1f0342..8cee037e29 100644 --- a/apps/files/js/fileactions.js +++ b/apps/files/js/fileactions.js @@ -11,11 +11,40 @@ /* global trashBinApp */ (function() { - var FileActions = { + /** + * Construct a new FileActions instance + */ + var FileActions = function() { + this.initialize(); + } + FileActions.prototype = { actions: {}, defaults: {}, icons: {}, currentFile: null, + initialize: function() { + this.clear(); + }, + /** + * Merges the actions from the given fileActions into + * this instance. + * + * @param fileActions instance of OCA.Files.FileActions + */ + merge: function(fileActions) { + var self = this; + // merge first level to avoid unintended overwriting + _.each(fileActions.actions, function(sourceMimeData, mime) { + var targetMimeData = self.actions[mime]; + if (!targetMimeData) { + targetMimeData = {}; + } + self.actions[mime] = _.extend(targetMimeData, sourceMimeData); + }); + + this.defaults = _.extend(this.defaults, fileActions.defaults); + this.icons = _.extend(this.icons, fileActions.icons); + }, register: function (mime, name, permissions, icon, action, displayName) { if (!this.actions[mime]) { this.actions[mime] = {}; @@ -31,18 +60,6 @@ this.actions[mime][name]['displayName'] = displayName; this.icons[name] = icon; }, - /** - * Clones the current file actions handler including the already - * registered actions. - */ - clone: function() { - var fileActions = _.extend({}, this); - // need to deep copy the actions as well - fileActions.actions = _.extend({}, this.actions); - fileActions.defaults = _.extend({}, this.defaults); - //fileActions.icons = _.extend({}, this.icons); - return fileActions; - }, clear: function() { this.actions = {}; this.defaults = {}; @@ -137,6 +154,9 @@ event.preventDefault(); self.currentFile = event.data.elem; + // also set on global object for legacy apps + window.FileActions.currentFile = self.currentFile; + var file = self.getCurrentFile(); var $tr = $(this).closest('tr'); @@ -276,8 +296,25 @@ }; OCA.Files.FileActions = FileActions; + + // global file actions to be used by all lists + OCA.Files.fileActions = new OCA.Files.FileActions(); + OCA.Files.legacyFileActions = new OCA.Files.FileActions(); + + // for backward compatibility + // + // legacy apps are expecting a stateful global FileActions object to register + // their actions on. Since legacy apps are very likely to break with other + // FileList views than the main one ("All files"), actions registered + // through window.FileActions will be limited to the main file list. + window.FileActions = OCA.Files.legacyFileActions; + window.FileActions.register = function (mime, name, permissions, icon, action, displayName) { + console.warn('FileActions.register() is deprecated, please use OCA.Files.fileActions.register() instead'); + OCA.Files.FileActions.prototype.register.call(window.FileActions, mime, name, permissions, icon, action, displayName); + }; + window.FileActions.setDefault = function (mime, name) { + console.warn('FileActions.setDefault() is deprecated, please use OCA.Files.fileActions.setDefault() instead'); + OCA.Files.FileActions.prototype.setDefault.call(window.FileActions, mime, name); + }; })(); -// for backward compatibility -window.FileActions = OCA.Files.FileActions; - diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index e1cbfc3856..52d4c8ba3f 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -125,7 +125,7 @@ this.$container = options.scrollContainer || $(window); this.$table = $el.find('table:first'); this.$fileList = $el.find('#fileList'); - this.fileActions = OCA.Files.FileActions; + this._initFileActions(options.fileActions); this.files = []; this._selectedFiles = {}; this._selectionSummary = new OCA.Files.FileSummary(); @@ -168,6 +168,14 @@ this.$container.on('scroll', _.bind(this._onScroll, this)); }, + _initFileActions: function(fileActions) { + this.fileActions = fileActions; + if (!this.fileActions) { + this.fileActions = new OCA.Files.FileActions(); + this.fileActions.registerDefaultActions(); + } + }, + /** * Event handler for when the URL changed */ @@ -248,6 +256,8 @@ var action = this.fileActions.getDefault(mime,type, permissions); if (action) { event.preventDefault(); + // also set on global object for legacy apps + window.FileActions.currentFile = this.fileActions.currentFile; action(filename, { $file: $tr, fileList: this, @@ -791,15 +801,6 @@ return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); }, - /** - * Sets the file actions handler. - * - * @param fileActions FileActions handler - */ - setFileActions: function(fileActions) { - this.fileActions = fileActions; - }, - /** * Sets the current directory name and updates the breadcrumb. * @param targetDir directory to display diff --git a/apps/files/tests/js/appSpec.js b/apps/files/tests/js/appSpec.js index 0e9abad698..a9bbab03ec 100644 --- a/apps/files/tests/js/appSpec.js +++ b/apps/files/tests/js/appSpec.js @@ -41,6 +41,10 @@ describe('OCA.Files.App tests', function() { '' ); + window.FileActions = new OCA.Files.FileActions(); + OCA.Files.legacyFileActions = window.FileActions; + OCA.Files.fileActions = new OCA.Files.FileActions(); + pushStateStub = sinon.stub(OC.Util.History, 'pushState'); parseUrlQueryStub = sinon.stub(OC.Util.History, 'parseUrlQuery'); parseUrlQueryStub.returns({}); @@ -51,8 +55,6 @@ describe('OCA.Files.App tests', function() { App.navigation = null; App.fileList = null; App.files = null; - App.fileActions.clear(); - App.fileActions = null; pushStateStub.restore(); parseUrlQueryStub.restore(); @@ -64,6 +66,53 @@ describe('OCA.Files.App tests', function() { expect(App.fileList.fileActions.actions.all).toBeDefined(); expect(App.fileList.$el.is('#app-content-files')).toEqual(true); }); + it('merges the legacy file actions with the default ones', function() { + var legacyActionStub = sinon.stub(); + var actionStub = sinon.stub(); + // legacy action + window.FileActions.register( + 'all', + 'LegacyTest', + OC.PERMISSION_READ, + OC.imagePath('core', 'actions/test'), + legacyActionStub + ); + // legacy action to be overwritten + window.FileActions.register( + 'all', + 'OverwriteThis', + OC.PERMISSION_READ, + OC.imagePath('core', 'actions/test'), + legacyActionStub + ); + + // regular file actions + OCA.Files.fileActions.register( + 'all', + 'RegularTest', + OC.PERMISSION_READ, + OC.imagePath('core', 'actions/test'), + actionStub + ); + + // overwrite + OCA.Files.fileActions.register( + 'all', + 'OverwriteThis', + OC.PERMISSION_READ, + OC.imagePath('core', 'actions/test'), + actionStub + ); + + App.initialize(); + + var actions = App.fileList.fileActions.actions; + expect(actions.all.OverwriteThis.action).toBe(actionStub); + expect(actions.all.LegacyTest.action).toBe(legacyActionStub); + expect(actions.all.RegularTest.action).toBe(actionStub); + // default one still there + expect(actions.dir.Open.action).toBeDefined(); + }); }); describe('URL handling', function() { diff --git a/apps/files/tests/js/fileactionsSpec.js b/apps/files/tests/js/fileactionsSpec.js index edd7e34388..fa634da08a 100644 --- a/apps/files/tests/js/fileactionsSpec.js +++ b/apps/files/tests/js/fileactionsSpec.js @@ -21,7 +21,7 @@ describe('OCA.Files.FileActions tests', function() { var $filesTable, fileList; - var FileActions = OCA.Files.FileActions; + var FileActions; beforeEach(function() { // init horrible parameters @@ -31,10 +31,11 @@ describe('OCA.Files.FileActions tests', function() { // dummy files table $filesTable = $body.append('
'); fileList = new OCA.Files.FileList($('#testArea')); - FileActions.registerDefaultActions(fileList); + FileActions = new OCA.Files.FileActions(); + FileActions.registerDefaultActions(); }); afterEach(function() { - FileActions.clear(); + FileActions = null; fileList = undefined; $('#dir, #permissions, #filestable').remove(); }); diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js index 739ae599c6..a197fd5722 100644 --- a/apps/files/tests/js/filelistSpec.js +++ b/apps/files/tests/js/filelistSpec.js @@ -21,7 +21,6 @@ describe('OCA.Files.FileList tests', function() { var testFiles, alertStub, notificationStub, fileList; - var FileActions = OCA.Files.FileActions; /** * Generate test file data @@ -117,15 +116,11 @@ describe('OCA.Files.FileList tests', function() { }]; fileList = new OCA.Files.FileList($('#app-content-files')); - FileActions.clear(); - FileActions.registerDefaultActions(fileList); - fileList.setFileActions(FileActions); }); afterEach(function() { testFiles = undefined; fileList = undefined; - FileActions.clear(); notificationStub.restore(); alertStub.restore(); }); diff --git a/apps/files_sharing/js/app.js b/apps/files_sharing/js/app.js index 57551237a3..7a71684f1a 100644 --- a/apps/files_sharing/js/app.js +++ b/apps/files_sharing/js/app.js @@ -23,11 +23,11 @@ OCA.Sharing.App = { $el, { scrollContainer: $('#app-content'), - sharedWithUser: true + sharedWithUser: true, + fileActions: this._createFileActions() } ); - this._initFileActions(this._inFileList); this._extendFileList(this._inFileList); this._inFileList.appName = t('files_sharing', 'Shared with you'); this._inFileList.$el.find('#emptycontent').text(t('files_sharing', 'No files have been shared with you yet.')); @@ -41,25 +41,31 @@ OCA.Sharing.App = { $el, { scrollContainer: $('#app-content'), - sharedWithUser: false + sharedWithUser: false, + fileActions: this._createFileActions() } ); - this._initFileActions(this._outFileList); this._extendFileList(this._outFileList); this._outFileList.appName = t('files_sharing', 'Shared with others'); this._outFileList.$el.find('#emptycontent').text(t('files_sharing', 'You haven\'t shared any files yet.')); }, - _initFileActions: function(fileList) { - var fileActions = OCA.Files.FileActions.clone(); + _createFileActions: function() { + // inherit file actions from the files app + var fileActions = new OCA.Files.FileActions(); + // note: not merging the legacy actions because legacy apps are not + // compatible with the sharing overview and need to be adapted first + fileActions.merge(OCA.Files.fileActions); + // when the user clicks on a folder, redirect to the corresponding - // folder in the files app + // folder in the files app instead of opening it directly fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) { OCA.Files.App.setActiveView('files', {silent: true}); OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true); }); - fileList.setFileActions(fileActions); + fileActions.setDefault('dir', 'Open'); + return fileActions; }, _extendFileList: function(fileList) { diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js index d825ee9de1..446f3f2442 100644 --- a/apps/files_sharing/js/public.js +++ b/apps/files_sharing/js/public.js @@ -19,9 +19,18 @@ OCA.Sharing.PublicApp = { initialize: function($el) { var self = this; + var fileActions; if (this._initialized) { return; } + fileActions = new OCA.Files.FileActions(); + // default actions + fileActions.registerDefaultActions(); + // legacy actions + fileActions.merge(window.FileActions); + // regular actions + fileActions.merge(OCA.Files.fileActions); + this._initialized = true; this.initialDir = $('#dir').val(); @@ -32,7 +41,8 @@ OCA.Sharing.PublicApp = { { scrollContainer: $(window), dragOptions: dragOptions, - folderDropOptions: folderDropOptions + folderDropOptions: folderDropOptions, + fileActions: fileActions } ); this.files = OCA.Files.Files; @@ -121,10 +131,8 @@ OCA.Sharing.PublicApp = { }; }); - this.fileActions = _.extend({}, OCA.Files.FileActions); - this.fileActions.registerDefaultActions(this.fileList); - delete this.fileActions.actions.all.Share; - this.fileList.setFileActions(this.fileActions); + // do not allow sharing from the public page + delete this.fileList.fileActions.actions.all.Share; this.fileList.changeDirectory(this.initialDir || '/', false, true); diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js index 28586a179a..1fcb1f088b 100644 --- a/apps/files_sharing/js/share.js +++ b/apps/files_sharing/js/share.js @@ -9,10 +9,7 @@ */ $(document).ready(function() { - - var sharesLoaded = false; - - if (typeof OC.Share !== 'undefined' && typeof FileActions !== 'undefined') { + if (!_.isUndefined(OC.Share) && !_.isUndefined(OCA.Files)) { // TODO: make a separate class for this or a hook or jQuery event ? if (OCA.Files.FileList) { var oldCreateRow = OCA.Files.FileList.prototype._createRow; @@ -64,18 +61,18 @@ $(document).ready(function() { } }) - if (!sharesLoaded){ + if (!OCA.Sharing.sharesLoaded){ OC.Share.loadIcons('file', $fileList); // assume that we got all shares, so switching directories // will not invalidate that list - sharesLoaded = true; + OCA.Sharing.sharesLoaded = true; } else{ OC.Share.updateIcons('file', $fileList); } }); - OCA.Files.FileActions.register( + OCA.Files.fileActions.register( 'all', 'Share', OC.PERMISSION_SHARE, diff --git a/apps/files_trashbin/js/app.js b/apps/files_trashbin/js/app.js index cf3fb1d0d1..c59a132b8c 100644 --- a/apps/files_trashbin/js/app.js +++ b/apps/files_trashbin/js/app.js @@ -19,22 +19,20 @@ OCA.Trashbin.App = { this._initialized = true; this.fileList = new OCA.Trashbin.FileList( $('#app-content-trashbin'), { - scrollContainer: $('#app-content') + scrollContainer: $('#app-content'), + fileActions: this._createFileActions() } ); - this.registerFileActions(this.fileList); }, - registerFileActions: function(fileList) { - var self = this; - var fileActions = _.extend({}, OCA.Files.FileActions); - fileActions.clear(); - fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename) { - var dir = fileList.getCurrentDirectory(); + _createFileActions: function() { + var fileActions = new OCA.Files.FileActions(); + fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) { + var dir = context.fileList.getCurrentDirectory(); if (dir !== '/') { dir = dir + '/'; } - fileList.changeDirectory(dir + filename); + context.fileList.changeDirectory(dir + filename); }); fileActions.setDefault('dir', 'Open'); @@ -69,7 +67,7 @@ OCA.Trashbin.App = { _.bind(fileList._removeCallback, fileList) ); }); - fileList.setFileActions(fileActions); + return fileActions; } }; diff --git a/apps/files_trashbin/js/filelist.js b/apps/files_trashbin/js/filelist.js index 205f879f33..826c1bd64d 100644 --- a/apps/files_trashbin/js/filelist.js +++ b/apps/files_trashbin/js/filelist.js @@ -26,8 +26,8 @@ return name; } - var FileList = function($el) { - this.initialize($el); + var FileList = function($el, options) { + this.initialize($el, options); }; FileList.prototype = _.extend({}, OCA.Files.FileList.prototype, { id: 'trashbin', diff --git a/apps/files_trashbin/tests/js/filelistSpec.js b/apps/files_trashbin/tests/js/filelistSpec.js index d41c24c3cc..11eeff68df 100644 --- a/apps/files_trashbin/tests/js/filelistSpec.js +++ b/apps/files_trashbin/tests/js/filelistSpec.js @@ -21,7 +21,6 @@ describe('OCA.Trashbin.FileList tests', function() { var testFiles, alertStub, notificationStub, fileList; - var FileActions = OCA.Files.FileActions; beforeEach(function() { alertStub = sinon.stub(OC.dialogs, 'alert'); @@ -87,14 +86,18 @@ describe('OCA.Trashbin.FileList tests', function() { etag: '456' }]; - fileList = new OCA.Trashbin.FileList($('#app-content-trashbin')); - OCA.Trashbin.App.registerFileActions(fileList); + // register file actions like the trashbin App does + var fileActions = OCA.Trashbin.App._createFileActions(fileList); + fileList = new OCA.Trashbin.FileList( + $('#app-content-trashbin'), { + fileActions: fileActions + } + ); }); afterEach(function() { testFiles = undefined; fileList = undefined; - FileActions.clear(); $('#dir').remove(); notificationStub.restore(); alertStub.restore(); diff --git a/apps/files_versions/js/versions.js b/apps/files_versions/js/versions.js index a23935495d..942a1a929f 100644 --- a/apps/files_versions/js/versions.js +++ b/apps/files_versions/js/versions.js @@ -8,7 +8,7 @@ * */ -/* global FileActions, scanFiles, escapeHTML, formatDate */ +/* global scanFiles, escapeHTML, formatDate */ $(document).ready(function(){ if ($('#isPublic').val()){ @@ -18,9 +18,9 @@ $(document).ready(function(){ return; } - if (typeof FileActions !== 'undefined') { + if (OCA.Files) { // Add versions button to 'files/index.php' - FileActions.register( + OCA.Files.fileActions.register( 'file', 'Versions', OC.PERMISSION_UPDATE,