Simple Plugin system for Javascript

This commit is contained in:
Vincent Petry 2014-12-01 16:17:28 +01:00
parent 8db4dd7585
commit c02ef69521
11 changed files with 169 additions and 42 deletions

View File

@ -166,6 +166,9 @@
} }
this.$el = $el; this.$el = $el;
if (options.id) {
this.id = options.id;
}
this.$container = options.scrollContainer || $(window); this.$container = options.scrollContainer || $(window);
this.$table = $el.find('table:first'); this.$table = $el.find('table:first');
this.$fileList = $el.find('#fileList'); this.$fileList = $el.find('#fileList');
@ -215,6 +218,8 @@
self.scrollTo(options.scrollTo); self.scrollTo(options.scrollTo);
}); });
} }
OC.Plugins.attach('OCA.Files.FileList', this);
}, },
/** /**
@ -224,6 +229,7 @@
// TODO: also unregister other event handlers // TODO: also unregister other event handlers
this.fileActions.off('registerAction', this._onFileActionsUpdated); this.fileActions.off('registerAction', this._onFileActionsUpdated);
this.fileActions.off('setDefault', this._onFileActionsUpdated); this.fileActions.off('setDefault', this._onFileActionsUpdated);
OC.Plugins.detach('OCA.Files.FileList', this);
}, },
/** /**

View File

@ -30,6 +30,7 @@ OCA.Sharing.App = {
this._inFileList = new OCA.Sharing.FileList( this._inFileList = new OCA.Sharing.FileList(
$el, $el,
{ {
id: 'shares.self',
scrollContainer: $('#app-content'), scrollContainer: $('#app-content'),
sharedWithUser: true, sharedWithUser: true,
fileActions: this._createFileActions() fileActions: this._createFileActions()
@ -49,6 +50,7 @@ OCA.Sharing.App = {
this._outFileList = new OCA.Sharing.FileList( this._outFileList = new OCA.Sharing.FileList(
$el, $el,
{ {
id: 'shares.others',
scrollContainer: $('#app-content'), scrollContainer: $('#app-content'),
sharedWithUser: false, sharedWithUser: false,
fileActions: this._createFileActions() fileActions: this._createFileActions()
@ -68,6 +70,7 @@ OCA.Sharing.App = {
this._linkFileList = new OCA.Sharing.FileList( this._linkFileList = new OCA.Sharing.FileList(
$el, $el,
{ {
id: 'shares.link',
scrollContainer: $('#app-content'), scrollContainer: $('#app-content'),
linksOnly: true, linksOnly: true,
fileActions: this._createFileActions() fileActions: this._createFileActions()

View File

@ -53,6 +53,7 @@ OCA.Sharing.PublicApp = {
this.fileList = new OCA.Files.FileList( this.fileList = new OCA.Files.FileList(
$el, $el,
{ {
id: 'files.public',
scrollContainer: $(window), scrollContainer: $(window),
dragOptions: dragOptions, dragOptions: dragOptions,
folderDropOptions: folderDropOptions, folderDropOptions: folderDropOptions,
@ -61,6 +62,9 @@ OCA.Sharing.PublicApp = {
); );
this.files = OCA.Files.Files; this.files = OCA.Files.Files;
this.files.initialize(); 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(); var mimetype = $('#mimetype').val();

View File

@ -17,18 +17,20 @@
*/ */
OCA.Sharing.Util = { OCA.Sharing.Util = {
/** /**
* Initialize the sharing app overrides of the default * Initialize the sharing plugin.
* file list.
* *
* Registers the "Share" file action and adds additional * Registers the "Share" file action and adds additional
* DOM attributes for the sharing file info. * 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) { attach: function(fileList) {
if (OCA.Files.FileList) { if (fileList.id === 'trashbin') {
var oldCreateRow = OCA.Files.FileList.prototype._createRow; return;
OCA.Files.FileList.prototype._createRow = function(fileData) { }
var fileActions = fileList.fileActions;
var oldCreateRow = fileList._createRow;
fileList._createRow = function(fileData) {
var tr = oldCreateRow.apply(this, arguments); var tr = oldCreateRow.apply(this, arguments);
var sharePermissions = fileData.permissions; var sharePermissions = fileData.permissions;
if (fileData.mountType && fileData.mountType === "external-root"){ if (fileData.mountType && fileData.mountType === "external-root"){
@ -53,10 +55,9 @@
} }
return tr; return tr;
}; };
}
// use delegate to catch the case with multiple file lists // 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 fileList = ev.fileList;
var $files = ev.$files; var $files = ev.$files;
@ -198,12 +199,5 @@
}; };
})(); })();
$(document).ready(function() { OC.Plugins.register('OCA.Files.FileList', OCA.Sharing.Util);
// 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);
}
}
});

View File

@ -55,6 +55,7 @@
if (options && options.linksOnly) { if (options && options.linksOnly) {
this._linksOnly = true; this._linksOnly = true;
} }
OC.Plugins.attach('OCA.Sharing.FileList', this);
}, },
_renderRow: function() { _renderRow: function() {

View File

@ -41,12 +41,12 @@ describe('OCA.Sharing.Util tests', function() {
$('#content').append($div); $('#content').append($div);
var fileActions = new OCA.Files.FileActions(); var fileActions = new OCA.Files.FileActions();
OCA.Sharing.Util.initialize(fileActions);
fileList = new OCA.Files.FileList( fileList = new OCA.Files.FileList(
$div, { $div, {
fileActions : fileActions fileActions : fileActions
} }
); );
OCA.Sharing.Util.attach(fileList);
testFiles = [{ testFiles = [{
id: 1, id: 1,

View File

@ -50,7 +50,6 @@ describe('OCA.Sharing.FileList tests', function() {
// the sharing code // the sharing code
oldFileListPrototype = _.extend({}, OCA.Files.FileList.prototype); oldFileListPrototype = _.extend({}, OCA.Files.FileList.prototype);
fileActions = new OCA.Files.FileActions(); fileActions = new OCA.Files.FileActions();
OCA.Sharing.Util.initialize(fileActions);
}); });
afterEach(function() { afterEach(function() {
OCA.Files.FileList.prototype = oldFileListPrototype; OCA.Files.FileList.prototype = oldFileListPrototype;
@ -72,6 +71,7 @@ describe('OCA.Sharing.FileList tests', function() {
sharedWithUser: true sharedWithUser: true
} }
); );
OCA.Sharing.Util.attach(fileList);
fileList.reload(); fileList.reload();
@ -193,6 +193,7 @@ describe('OCA.Sharing.FileList tests', function() {
sharedWithUser: false sharedWithUser: false
} }
); );
OCA.Sharing.Util.attach(fileList);
fileList.reload(); fileList.reload();
@ -433,6 +434,7 @@ describe('OCA.Sharing.FileList tests', function() {
linksOnly: true linksOnly: true
} }
); );
OCA.Sharing.Util.attach(fileList);
fileList.reload(); fileList.reload();
@ -580,6 +582,7 @@ describe('OCA.Sharing.FileList tests', function() {
fileActions: fileActions fileActions: fileActions
} }
); );
OCA.Sharing.Util.attach(fileList);
}); });
it('external storage root folder', function () { it('external storage root folder', function () {

View File

@ -64,6 +64,7 @@
return parts; return parts;
}; };
OC.Plugins.attach('OCA.Trashbin.FileList', this);
return result; return result;
}, },

View File

@ -498,6 +498,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 * @namespace OC.search
*/ */

View File

@ -120,6 +120,9 @@ window.isPhantom = /phantom/i.test(navigator.userAgent);
if (!OC.TestUtil) { if (!OC.TestUtil) {
OC.TestUtil = TestUtil; OC.TestUtil = TestUtil;
} }
// reset plugins
OC.Plugins._plugins = [];
}); });
afterEach(function() { afterEach(function() {

View File

@ -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();
});
});
}); });