Adding support for dynamic menus in extensions.

This commit is contained in:
picklesrus 2018-01-26 14:36:36 -08:00
parent 229cd7a50c
commit b6bb92d8f6
2 changed files with 42 additions and 15 deletions

View file

@ -551,22 +551,23 @@ class Runtime extends EventEmitter {
*/ */
_buildMenuForScratchBlocks (menuName, menuItems, categoryInfo) { _buildMenuForScratchBlocks (menuName, menuItems, categoryInfo) {
const menuId = this._makeExtensionMenuId(menuName, categoryInfo.id); const menuId = this._makeExtensionMenuId(menuName, categoryInfo.id);
var options = null;
/** @TODO: support dynamic menus when 'menuItems' is a method name string (see extension spec) */ if (typeof menuItems === 'function') {
if (typeof menuItems === 'string') { options = function () {
throw new Error(`Dynamic extension menus are not yet supported. Menu name: ${menuName}`); return menuItems();
}
const options = menuItems.map(item => {
switch (typeof item) {
case 'string':
return [item, item];
case 'object':
return [item.text, item.value];
default:
throw new Error(`Can't interpret menu item: ${item}`);
} }
}); } else {
options = menuItems.map(item => {
switch (typeof item) {
case 'string':
return [item, item];
case 'object':
return [item.text, item.value];
default:
throw new Error(`Can't interpret menu item: ${item}`);
}
});
}
return { return {
json: { json: {
message0: '%1', message0: '%1',

View file

@ -242,8 +242,34 @@ class ExtensionManager {
} }
return result; return result;
}, []); }, []);
extensionInfo.menus = extensionInfo.menus || [];
extensionInfo.menus = this._prepareMenuInfo(serviceName, extensionInfo.menus);
return extensionInfo; return extensionInfo;
} }
/**
* Prepare extension menus. e.g. setup binding for dynamic menu functions.
* @param {string} serviceName - the name of the service hosting this extension block
* @param {Array.<MenuInfo>} menuInfo - the menu defined by the extension.
* @returns {Array.<MenuInfo>} - a menuInfo object with all preprocessing done.
* @private
*/
_prepareMenuInfo (serviceName, menus) {
var menuNames = Object.getOwnPropertyNames(menus);
for (let i = 0; i < menuNames.length; i++) {
var item = menuNames[i];
// If the value is a string, it should be the name of a function in the
// extension object to call to populate the menu whenever it is opened.
// Set up the binding for the function object here so
// we can use it later when converting the menu for Scratch Blocks.
if (typeof menus[item] === 'string') {
const serviceObject = dispatch.services[serviceName];
const menuFunc = serviceObject[menus[item]].bind(serviceObject);
menus[item] = menuFunc;
}
}
return menus;
}
/** /**
* Apply defaults for optional block fields. * Apply defaults for optional block fields.