aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Appelman <robin@icewind.nl>2014-12-12 11:43:31 +0100
committerRobin Appelman <robin@icewind.nl>2014-12-12 11:43:31 +0100
commit3bf0922b1337115c7cfc8a03547bc2d7d0d9fa69 (patch)
tree5c594dff36a1210b12dbb05558f50310819a5325
parentc451d99daae86290281806d0e8cdcfcfcf451412 (diff)
parentbf887eca8bac04cbbd2f1bd5197017c0e0583edd (diff)
downloadnextcloud-server-3bf0922b1337115c7cfc8a03547bc2d7d0d9fa69.tar.gz
nextcloud-server-3bf0922b1337115c7cfc8a03547bc2d7d0d9fa69.zip
Merge pull request #12527 from owncloud/js-pluginsystem
Simple Plugin system for Javascript
-rw-r--r--apps/files/js/filelist.js6
-rw-r--r--apps/files_external/tests/js/mountsfilelistSpec.js6
-rw-r--r--apps/files_sharing/js/app.js3
-rw-r--r--apps/files_sharing/js/public.js4
-rw-r--r--apps/files_sharing/js/share.js74
-rw-r--r--apps/files_sharing/js/sharedfilelist.js1
-rw-r--r--apps/files_sharing/tests/js/shareSpec.js8
-rw-r--r--apps/files_sharing/tests/js/sharedfilelistSpec.js20
-rw-r--r--apps/files_trashbin/js/filelist.js1
-rw-r--r--core/js/js.js81
-rw-r--r--core/js/tests/specHelper.js3
-rw-r--r--core/js/tests/specs/coreSpec.js31
12 files changed, 172 insertions, 66 deletions
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index 6ffc10cdcbd..7abbf2c80b2 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -166,6 +166,9 @@
}
this.$el = $el;
+ if (options.id) {
+ this.id = options.id;
+ }
this.$container = options.scrollContainer || $(window);
this.$table = $el.find('table:first');
this.$fileList = $el.find('#fileList');
@@ -215,6 +218,8 @@
self.scrollTo(options.scrollTo);
});
}
+
+ OC.Plugins.attach('OCA.Files.FileList', this);
},
/**
@@ -224,6 +229,7 @@
// TODO: also unregister other event handlers
this.fileActions.off('registerAction', this._onFileActionsUpdated);
this.fileActions.off('setDefault', this._onFileActionsUpdated);
+ OC.Plugins.detach('OCA.Files.FileList', this);
},
/**
diff --git a/apps/files_external/tests/js/mountsfilelistSpec.js b/apps/files_external/tests/js/mountsfilelistSpec.js
index b599df77aac..50603081b6a 100644
--- a/apps/files_external/tests/js/mountsfilelistSpec.js
+++ b/apps/files_external/tests/js/mountsfilelistSpec.js
@@ -9,8 +9,7 @@
*/
describe('OCA.External.FileList tests', function() {
- var testFiles, alertStub, notificationStub, fileList, fileActions;
- var oldFileListPrototype;
+ var testFiles, alertStub, notificationStub, fileList;
beforeEach(function() {
alertStub = sinon.stub(OC.dialogs, 'alert');
@@ -49,14 +48,11 @@ describe('OCA.External.FileList tests', function() {
'<div id="emptycontent">Empty content message</div>' +
'</div>'
);
- fileActions = new OCA.Files.FileActions();
});
afterEach(function() {
- OCA.Files.FileList.prototype = oldFileListPrototype;
testFiles = undefined;
fileList.destroy();
fileList = undefined;
- fileActions = undefined;
notificationStub.restore();
alertStub.restore();
diff --git a/apps/files_sharing/js/app.js b/apps/files_sharing/js/app.js
index 1314304c567..ff6997ab12f 100644
--- a/apps/files_sharing/js/app.js
+++ b/apps/files_sharing/js/app.js
@@ -30,6 +30,7 @@ OCA.Sharing.App = {
this._inFileList = new OCA.Sharing.FileList(
$el,
{
+ id: 'shares.self',
scrollContainer: $('#app-content'),
sharedWithUser: true,
fileActions: this._createFileActions()
@@ -49,6 +50,7 @@ OCA.Sharing.App = {
this._outFileList = new OCA.Sharing.FileList(
$el,
{
+ id: 'shares.others',
scrollContainer: $('#app-content'),
sharedWithUser: false,
fileActions: this._createFileActions()
@@ -68,6 +70,7 @@ OCA.Sharing.App = {
this._linkFileList = new OCA.Sharing.FileList(
$el,
{
+ id: 'shares.link',
scrollContainer: $('#app-content'),
linksOnly: true,
fileActions: this._createFileActions()
diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js
index 0627ed6ab54..2ddcd84d4c1 100644
--- a/apps/files_sharing/js/public.js
+++ b/apps/files_sharing/js/public.js
@@ -53,6 +53,7 @@ OCA.Sharing.PublicApp = {
this.fileList = new OCA.Files.FileList(
$el,
{
+ id: 'files.public',
scrollContainer: $(window),
dragOptions: dragOptions,
folderDropOptions: folderDropOptions,
@@ -61,6 +62,9 @@ OCA.Sharing.PublicApp = {
);
this.files = OCA.Files.Files;
this.files.initialize();
+ // TODO: move to PublicFileList.initialize() once
+ // the code was split into a separate class
+ OC.Plugins.attach('OCA.Sharing.PublicFileList', this.fileList);
}
var mimetype = $('#mimetype').val();
diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js
index 8474c66d4b8..bbd107e070e 100644
--- a/apps/files_sharing/js/share.js
+++ b/apps/files_sharing/js/share.js
@@ -17,46 +17,47 @@
*/
OCA.Sharing.Util = {
/**
- * Initialize the sharing app overrides of the default
- * file list.
+ * Initialize the sharing plugin.
*
* Registers the "Share" file action and adds additional
* DOM attributes for the sharing file info.
*
- * @param {OCA.Files.FileActions} fileActions file actions to extend
+ * @param {OCA.Files.FileList} fileList file list to be extended
*/
- initialize: function(fileActions) {
- if (OCA.Files.FileList) {
- var oldCreateRow = OCA.Files.FileList.prototype._createRow;
- OCA.Files.FileList.prototype._createRow = function(fileData) {
- var tr = oldCreateRow.apply(this, arguments);
- var sharePermissions = fileData.permissions;
- if (fileData.mountType && fileData.mountType === "external-root"){
- // for external storages we cant use the permissions of the mountpoint
- // instead we show all permissions and only use the share permissions from the mountpoint to handle resharing
- sharePermissions = sharePermissions | (OC.PERMISSION_ALL & ~OC.PERMISSION_SHARE);
- }
- if (fileData.type === 'file') {
- // files can't be shared with delete permissions
- sharePermissions = sharePermissions & ~OC.PERMISSION_DELETE;
- }
- tr.attr('data-share-permissions', sharePermissions);
- if (fileData.shareOwner) {
- tr.attr('data-share-owner', fileData.shareOwner);
- // user should always be able to rename a mount point
- if (fileData.isShareMountPoint) {
- tr.attr('data-permissions', fileData.permissions | OC.PERMISSION_UPDATE);
- }
- }
- if (fileData.recipientsDisplayName) {
- tr.attr('data-share-recipients', fileData.recipientsDisplayName);
- }
- return tr;
- };
+ attach: function(fileList) {
+ if (fileList.id === 'trashbin') {
+ return;
}
+ var fileActions = fileList.fileActions;
+ var oldCreateRow = fileList._createRow;
+ fileList._createRow = function(fileData) {
+ var tr = oldCreateRow.apply(this, arguments);
+ var sharePermissions = fileData.permissions;
+ if (fileData.mountType && fileData.mountType === "external-root"){
+ // for external storages we cant use the permissions of the mountpoint
+ // instead we show all permissions and only use the share permissions from the mountpoint to handle resharing
+ sharePermissions = sharePermissions | (OC.PERMISSION_ALL & ~OC.PERMISSION_SHARE);
+ }
+ if (fileData.type === 'file') {
+ // files can't be shared with delete permissions
+ sharePermissions = sharePermissions & ~OC.PERMISSION_DELETE;
+ }
+ tr.attr('data-share-permissions', sharePermissions);
+ if (fileData.shareOwner) {
+ tr.attr('data-share-owner', fileData.shareOwner);
+ // user should always be able to rename a mount point
+ if (fileData.isShareMountPoint) {
+ tr.attr('data-permissions', fileData.permissions | OC.PERMISSION_UPDATE);
+ }
+ }
+ if (fileData.recipientsDisplayName) {
+ tr.attr('data-share-recipients', fileData.recipientsDisplayName);
+ }
+ return tr;
+ };
// use delegate to catch the case with multiple file lists
- $('#content').delegate('#fileList', 'fileActionsReady', function(ev){
+ fileList.$el.on('fileActionsReady', function(ev){
var fileList = ev.fileList;
var $files = ev.$files;
@@ -198,12 +199,5 @@
};
})();
-$(document).ready(function() {
- // FIXME: HACK: do not init when running unit tests, need a better way
- if (!window.TESTING) {
- if (!_.isUndefined(OC.Share) && !_.isUndefined(OCA.Files)) {
- OCA.Sharing.Util.initialize(OCA.Files.fileActions);
- }
- }
-});
+OC.Plugins.register('OCA.Files.FileList', OCA.Sharing.Util);
diff --git a/apps/files_sharing/js/sharedfilelist.js b/apps/files_sharing/js/sharedfilelist.js
index 7a7c24993c0..bd26b13b78a 100644
--- a/apps/files_sharing/js/sharedfilelist.js
+++ b/apps/files_sharing/js/sharedfilelist.js
@@ -55,6 +55,7 @@
if (options && options.linksOnly) {
this._linksOnly = true;
}
+ OC.Plugins.attach('OCA.Sharing.FileList', this);
},
_renderRow: function() {
diff --git a/apps/files_sharing/tests/js/shareSpec.js b/apps/files_sharing/tests/js/shareSpec.js
index 2cf5dc47b63..33c9c83b970 100644
--- a/apps/files_sharing/tests/js/shareSpec.js
+++ b/apps/files_sharing/tests/js/shareSpec.js
@@ -9,7 +9,6 @@
*/
describe('OCA.Sharing.Util tests', function() {
- var oldFileListPrototype;
var fileList;
var testFiles;
@@ -24,10 +23,6 @@ describe('OCA.Sharing.Util tests', function() {
}
beforeEach(function() {
- // back up prototype, as it will be extended by
- // the sharing code
- oldFileListPrototype = _.extend({}, OCA.Files.FileList.prototype);
-
var $content = $('<div id="content"></div>');
$('#testArea').append($content);
// dummy file list
@@ -41,12 +36,12 @@ describe('OCA.Sharing.Util tests', function() {
$('#content').append($div);
var fileActions = new OCA.Files.FileActions();
- OCA.Sharing.Util.initialize(fileActions);
fileList = new OCA.Files.FileList(
$div, {
fileActions : fileActions
}
);
+ OCA.Sharing.Util.attach(fileList);
testFiles = [{
id: 1,
@@ -67,7 +62,6 @@ describe('OCA.Sharing.Util tests', function() {
};
});
afterEach(function() {
- OCA.Files.FileList.prototype = oldFileListPrototype;
delete OCA.Sharing.sharesLoaded;
delete OC.Share.droppedDown;
fileList.destroy();
diff --git a/apps/files_sharing/tests/js/sharedfilelistSpec.js b/apps/files_sharing/tests/js/sharedfilelistSpec.js
index dc6931af6e8..7fdc6345e38 100644
--- a/apps/files_sharing/tests/js/sharedfilelistSpec.js
+++ b/apps/files_sharing/tests/js/sharedfilelistSpec.js
@@ -9,8 +9,7 @@
*/
describe('OCA.Sharing.FileList tests', function() {
- var testFiles, alertStub, notificationStub, fileList, fileActions;
- var oldFileListPrototype;
+ var testFiles, alertStub, notificationStub, fileList;
beforeEach(function() {
alertStub = sinon.stub(OC.dialogs, 'alert');
@@ -46,18 +45,11 @@ describe('OCA.Sharing.FileList tests', function() {
'<div id="emptycontent">Empty content message</div>' +
'</div>'
);
- // back up prototype, as it will be extended by
- // the sharing code
- oldFileListPrototype = _.extend({}, OCA.Files.FileList.prototype);
- fileActions = new OCA.Files.FileActions();
- OCA.Sharing.Util.initialize(fileActions);
});
afterEach(function() {
- OCA.Files.FileList.prototype = oldFileListPrototype;
testFiles = undefined;
fileList.destroy();
fileList = undefined;
- fileActions = undefined;
notificationStub.restore();
alertStub.restore();
@@ -72,6 +64,7 @@ describe('OCA.Sharing.FileList tests', function() {
sharedWithUser: true
}
);
+ OCA.Sharing.Util.attach(fileList);
fileList.reload();
@@ -193,6 +186,7 @@ describe('OCA.Sharing.FileList tests', function() {
sharedWithUser: false
}
);
+ OCA.Sharing.Util.attach(fileList);
fileList.reload();
@@ -433,6 +427,7 @@ describe('OCA.Sharing.FileList tests', function() {
linksOnly: true
}
);
+ OCA.Sharing.Util.attach(fileList);
fileList.reload();
@@ -575,11 +570,8 @@ describe('OCA.Sharing.FileList tests', function() {
'</div>');
$('#content').append($div);
- fileList = new OCA.Files.FileList(
- $div, {
- fileActions: fileActions
- }
- );
+ fileList = new OCA.Files.FileList($div);
+ OCA.Sharing.Util.attach(fileList);
});
it('external storage root folder', function () {
diff --git a/apps/files_trashbin/js/filelist.js b/apps/files_trashbin/js/filelist.js
index 12f3f1982f6..71b63721897 100644
--- a/apps/files_trashbin/js/filelist.js
+++ b/apps/files_trashbin/js/filelist.js
@@ -64,6 +64,7 @@
return parts;
};
+ OC.Plugins.attach('OCA.Trashbin.FileList', this);
return result;
},
diff --git a/core/js/js.js b/core/js/js.js
index eb2f10b51f0..cc3a548de28 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -499,6 +499,87 @@ var OC={
};
/**
+ * @namespace OC.Plugins
+ */
+OC.Plugins = {
+ /**
+ * @type Array.<OC.Plugin>
+ */
+ _plugins: {},
+
+ /**
+ * Register plugin
+ *
+ * @param {String} targetName app name / class name to hook into
+ * @param {OC.Plugin} plugin
+ */
+ register: function(targetName, plugin) {
+ var plugins = this._plugins[targetName];
+ if (!plugins) {
+ plugins = this._plugins[targetName] = [];
+ }
+ plugins.push(plugin);
+ },
+
+ /**
+ * Returns all plugin registered to the given target
+ * name / app name / class name.
+ *
+ * @param {String} targetName app name / class name to hook into
+ * @return {Array.<OC.Plugin>} array of plugins
+ */
+ getPlugins: function(targetName) {
+ return this._plugins[targetName] || [];
+ },
+
+ /**
+ * Call attach() on all plugins registered to the given target name.
+ *
+ * @param {String} targetName app name / class name
+ * @param {Object} object to be extended
+ * @param {Object} [options] options
+ */
+ attach: function(targetName, targetObject, options) {
+ var plugins = this.getPlugins(targetName);
+ for (var i = 0; i < plugins.length; i++) {
+ if (plugins[i].attach) {
+ plugins[i].attach(targetObject, options);
+ }
+ }
+ },
+
+ /**
+ * Call detach() on all plugins registered to the given target name.
+ *
+ * @param {String} targetName app name / class name
+ * @param {Object} object to be extended
+ * @param {Object} [options] options
+ */
+ detach: function(targetName, targetObject, options) {
+ var plugins = this.getPlugins(targetName);
+ for (var i = 0; i < plugins.length; i++) {
+ if (plugins[i].detach) {
+ plugins[i].detach(targetObject, options);
+ }
+ }
+ },
+
+ /**
+ * Plugin
+ *
+ * @todo make this a real class in the future
+ * @typedef {Object} OC.Plugin
+ *
+ * @property {String} name plugin name
+ * @property {Function} attach function that will be called when the
+ * plugin is attached
+ * @property {Function} [detach] function that will be called when the
+ * plugin is detached
+ */
+
+};
+
+/**
* @namespace OC.search
*/
OC.search.customResults={};
diff --git a/core/js/tests/specHelper.js b/core/js/tests/specHelper.js
index 4111b6763d9..59c2a99645f 100644
--- a/core/js/tests/specHelper.js
+++ b/core/js/tests/specHelper.js
@@ -120,6 +120,9 @@ window.isPhantom = /phantom/i.test(navigator.userAgent);
if (!OC.TestUtil) {
OC.TestUtil = TestUtil;
}
+
+ // reset plugins
+ OC.Plugins._plugins = [];
});
afterEach(function() {
diff --git a/core/js/tests/specs/coreSpec.js b/core/js/tests/specs/coreSpec.js
index 2c5c22905b0..08395f4d4c2 100644
--- a/core/js/tests/specs/coreSpec.js
+++ b/core/js/tests/specs/coreSpec.js
@@ -655,5 +655,36 @@ describe('Core base tests', function() {
]);
});
});
+ describe('Plugins', function() {
+ var plugin;
+
+ beforeEach(function() {
+ plugin = {
+ name: 'Some name',
+ attach: function(obj) {
+ obj.attached = true;
+ },
+
+ detach: function(obj) {
+ obj.attached = false;
+ }
+ };
+ OC.Plugins.register('OC.Test.SomeName', plugin);
+ });
+ it('attach plugin to object', function() {
+ var obj = {something: true};
+ OC.Plugins.attach('OC.Test.SomeName', obj);
+ expect(obj.attached).toEqual(true);
+ OC.Plugins.detach('OC.Test.SomeName', obj);
+ expect(obj.attached).toEqual(false);
+ });
+ it('only call handler for target name', function() {
+ var obj = {something: true};
+ OC.Plugins.attach('OC.Test.SomeOtherName', obj);
+ expect(obj.attached).not.toBeDefined();
+ OC.Plugins.detach('OC.Test.SomeOtherName', obj);
+ expect(obj.attached).not.toBeDefined();
+ });
+ });
});