Add plugin options (#3922)

* Adds a plugin through options

* Fix requires

* Fix pr comments
This commit is contained in:
alschmiedt
2020-05-29 13:22:25 -07:00
committed by GitHub
parent afba82222e
commit 00df97a59d
5 changed files with 88 additions and 4 deletions

View File

@@ -110,6 +110,8 @@ Blockly.Options = function(options) {
var renderer = options['renderer'] || 'geras';
var plugins = options['plugins'] || {};
/** @type {boolean} */
this.RTL = rtl;
/** @type {boolean} */
@@ -174,6 +176,12 @@ Blockly.Options = function(options) {
* @type {Blockly.Workspace}
*/
this.parentWorkspace = options['parentWorkspace'];
/**
* Map of plugin type to name of registered plugin or plugin class.
* @type {!Object.<string, (function(new:?, ...?)|string)>}
*/
this.plugins = plugins;
};
/**

View File

@@ -13,6 +13,10 @@
goog.provide('Blockly.registry');
goog.requireType('Blockly.blockRendering.Renderer');
goog.requireType('Blockly.Field');
goog.requireType('Blockly.IToolbox');
/**
* A map of maps. With the keys being the type and name of the class we are
@@ -23,6 +27,12 @@ goog.provide('Blockly.registry');
*/
Blockly.registry.typeMap_ = {};
/**
* The string used to register the default class for a type of plugin.
* @type {string}
*/
Blockly.registry.DEFAULT = 'default';
/**
* A name with the type of the element stored in the generic.
* @param {string} name The name of the registry type.
@@ -49,6 +59,9 @@ Blockly.registry.Type.RENDERER = new Blockly.registry.Type('renderer');
/** @type {!Blockly.registry.Type<Blockly.Field>} */
Blockly.registry.Type.FIELD = new Blockly.registry.Type('field');
/** @type {!Blockly.registry.Type<Blockly.IToolbox>} */
Blockly.registry.Type.TOOLBOX = new Blockly.registry.Type('toolbox');
/**
* Registers a class based on a type and name.
* @param {string|Blockly.registry.Type<T>} type The type of the plugin.
@@ -152,3 +165,23 @@ Blockly.registry.getClass = function(type, name) {
}
return typeRegistry[name];
};
/**
* Gets the class name or the class from Blockly options for the given type.
* This is used for plugins that override a built in feature. (Ex: Toolbox)
* @param {Blockly.registry.Type<T>} type The type of the plugin.
* @param {!Blockly.Options} options The option object to check for the given
* plugin.
* @return {?function(new:T, ...?)} The class for the plugin.
* @template T
*/
Blockly.registry.getClassFromOptions = function(type, options) {
var typeName = type.toString();
var plugin = options.plugins[typeName] || Blockly.registry.DEFAULT;
// If the user passed in a plugin class instead of a registered plugin name.
if (typeof plugin == 'function') {
return plugin;
}
return Blockly.registry.getClass(type, plugin);
};

View File

@@ -16,6 +16,7 @@ goog.require('Blockly.Css');
goog.require('Blockly.Events');
goog.require('Blockly.Events.Ui');
goog.require('Blockly.navigation');
goog.require('Blockly.registry');
goog.require('Blockly.Touch');
goog.require('Blockly.tree.TreeControl');
goog.require('Blockly.tree.TreeNode');
@@ -917,3 +918,6 @@ Blockly.Css.register([
'}'
/* eslint-enable indent */
]);
Blockly.registry.register(Blockly.registry.Type.TOOLBOX,
Blockly.registry.DEFAULT, Blockly.Toolbox);

View File

@@ -24,6 +24,7 @@ goog.require('Blockly.MarkerManager');
goog.require('Blockly.Msg');
goog.require('Blockly.navigation');
goog.require('Blockly.Options');
goog.require('Blockly.registry');
goog.require('Blockly.ThemeManager');
goog.require('Blockly.Themes.Classic');
goog.require('Blockly.TouchGesture');
@@ -341,7 +342,7 @@ Blockly.WorkspaceSvg.prototype.flyout_ = null;
/**
* Category-based toolbox providing blocks which may be dragged into this
* workspace.
* @type {Blockly.Toolbox}
* @type {Blockly.IToolbox}
* @private
*/
Blockly.WorkspaceSvg.prototype.toolbox_ = null;
@@ -749,7 +750,9 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) {
if (!Blockly.Toolbox) {
throw Error('Missing require for Blockly.Toolbox');
}
this.toolbox_ = new Blockly.Toolbox(this);
var ToolboxClass = Blockly.registry.getClassFromOptions(
Blockly.registry.Type.TOOLBOX, this.options);
this.toolbox_ = new ToolboxClass(this);
}
if (this.grid_) {
this.grid_.update(this.scale);
@@ -948,7 +951,7 @@ Blockly.WorkspaceSvg.prototype.getFlyout = function(opt_own) {
/**
* Getter for the toolbox associated with this workspace, if one exists.
* @return {Blockly.Toolbox} The toolbox on this workspace.
* @return {Blockly.IToolbox} The toolbox on this workspace.
* @package
*/
Blockly.WorkspaceSvg.prototype.getToolbox = function() {
@@ -2232,7 +2235,7 @@ Blockly.WorkspaceSvg.prototype.scroll = function(x, y) {
/**
* Get the dimensions of the given workspace component, in pixels.
* @param {Blockly.Toolbox|Blockly.Flyout} elem The element to get the
* @param {Blockly.IToolbox|Blockly.Flyout} elem The element to get the
* dimensions of, or null. It should be a toolbox or flyout, and should
* implement getWidth() and getHeight().
* @return {!Blockly.utils.Size} An object containing width and height

View File

@@ -48,4 +48,40 @@ suite('Registry', function() {
}, 'Can not register a null value');
});
});
suite('getClassFromOptions', function() {
setup(function() {
this.defaultClass = function() {};
this.defaultClass.prototype.testMethod = function() {
return 'default';
};
this.options = {
'plugins': {
'test' : 'test_name'
}
};
Blockly.registry.typeMap_['test'] = {
'test_name': TestClass,
'default': this.defaultClass
};
});
test('Simple - Plugin name given', function() {
var testClass = Blockly.registry.getClassFromOptions('test', this.options);
chai.assert.instanceOf(new testClass(), TestClass);
});
test('Simple - Plugin class given', function() {
this.options.plugins['test'] = TestClass;
var testClass = Blockly.registry.getClassFromOptions('test', this.options);
chai.assert.instanceOf(new testClass(), TestClass);
});
test('No Plugin Name Given', function() {
delete this.options['plugins']['test'];
var testClass = Blockly.registry.getClassFromOptions('test', this.options);
chai.assert.instanceOf(new testClass(), this.defaultClass);
});
test('Incorrect Plugin Name', function() {
this.options['plugins']['test'] = 'random';
var testClass = Blockly.registry.getClassFromOptions('test', this.options);
chai.assert.isNull(testClass);
});
});
});