/yarn-blocks/blockly/core/registry.js

https://gitlab.com/then-try-this/penelopean-robotics · JavaScript · 265 lines · 113 code · 29 blank · 123 comment · 24 complexity · a012395183fbac127aaa0b50520d9359 MD5 · raw file

  1. /**
  2. * @license
  3. * Copyright 2020 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /**
  7. * @fileoverview This file is a universal registry that provides generic methods
  8. * for registering and unregistering different types of classes.
  9. * @author aschmiedt@google.com (Abby Schmiedt)
  10. */
  11. 'use strict';
  12. goog.provide('Blockly.registry');
  13. goog.requireType('Blockly.blockRendering.Renderer');
  14. goog.requireType('Blockly.Events.Abstract');
  15. goog.requireType('Blockly.Field');
  16. goog.requireType('Blockly.IConnectionChecker');
  17. goog.requireType('Blockly.IFlyout');
  18. goog.requireType('Blockly.IToolbox');
  19. goog.requireType('Blockly.Theme');
  20. /**
  21. * A map of maps. With the keys being the type and name of the class we are
  22. * registering and the value being the constructor function.
  23. * e.g. {'field': {'field_angle': Blockly.FieldAngle}}
  24. *
  25. * @type {Object<string, Object<string, function(new:?)>>}
  26. */
  27. Blockly.registry.typeMap_ = {};
  28. /**
  29. * The string used to register the default class for a type of plugin.
  30. * @type {string}
  31. */
  32. Blockly.registry.DEFAULT = 'default';
  33. /**
  34. * A name with the type of the element stored in the generic.
  35. * @param {string} name The name of the registry type.
  36. * @constructor
  37. * @template T
  38. */
  39. Blockly.registry.Type = function(name) {
  40. /**
  41. * @type {string}
  42. * @private
  43. */
  44. this.name_ = name;
  45. };
  46. /**
  47. * Returns the name of the type.
  48. * @return {string} The name.
  49. * @override
  50. */
  51. Blockly.registry.Type.prototype.toString = function() {
  52. return this.name_;
  53. };
  54. /** @type {!Blockly.registry.Type<Blockly.IConnectionChecker>} */
  55. Blockly.registry.Type.CONNECTION_CHECKER =
  56. new Blockly.registry.Type('connectionChecker');
  57. /** @type {!Blockly.registry.Type<Blockly.Events.Abstract>} */
  58. Blockly.registry.Type.EVENT = new Blockly.registry.Type('event');
  59. /** @type {!Blockly.registry.Type<Blockly.Field>} */
  60. Blockly.registry.Type.FIELD = new Blockly.registry.Type('field');
  61. /** @type {!Blockly.registry.Type<Blockly.blockRendering.Renderer>} */
  62. Blockly.registry.Type.RENDERER = new Blockly.registry.Type('renderer');
  63. /** @type {!Blockly.registry.Type<Blockly.IToolbox>} */
  64. Blockly.registry.Type.TOOLBOX = new Blockly.registry.Type('toolbox');
  65. /** @type {!Blockly.registry.Type<Blockly.Theme>} */
  66. Blockly.registry.Type.THEME = new Blockly.registry.Type('theme');
  67. /** @type {!Blockly.registry.Type<Blockly.ToolboxItem>} */
  68. Blockly.registry.Type.TOOLBOX_ITEM = new Blockly.registry.Type('toolboxItem');
  69. /** @type {!Blockly.registry.Type<Blockly.IFlyout>} */
  70. Blockly.registry.Type.FLYOUTS_VERTICAL_TOOLBOX =
  71. new Blockly.registry.Type('flyoutsVerticalToolbox');
  72. /** @type {!Blockly.registry.Type<Blockly.IFlyout>} */
  73. Blockly.registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX =
  74. new Blockly.registry.Type('flyoutsHorizontalToolbox');
  75. /**
  76. * Registers a class based on a type and name.
  77. * @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
  78. * (e.g. Field, Renderer)
  79. * @param {string} name The plugin's name. (Ex. field_angle, geras)
  80. * @param {?function(new:T, ...?)|Object} registryItem The class or object to
  81. * register.
  82. * @param {boolean=} opt_quiet True to prevent an error when overriding an
  83. * already registered item.
  84. * @throws {Error} if the type or name is empty, a name with the given type has
  85. * already been registered, or if the given class or object is not valid for it's type.
  86. * @template T
  87. */
  88. Blockly.registry.register = function(type, name, registryItem, opt_quiet) {
  89. if ((!(type instanceof Blockly.registry.Type) && typeof type != 'string') || String(type).trim() == '') {
  90. throw Error('Invalid type "' + type + '". The type must be a' +
  91. ' non-empty string or a Blockly.registry.Type.');
  92. }
  93. type = String(type).toLowerCase();
  94. if ((typeof name != 'string') || (name.trim() == '')) {
  95. throw Error('Invalid name "' + name + '". The name must be a' +
  96. ' non-empty string.');
  97. }
  98. name = name.toLowerCase();
  99. if (!registryItem) {
  100. throw Error('Can not register a null value');
  101. }
  102. var typeRegistry = Blockly.registry.typeMap_[type];
  103. // If the type registry has not been created, create it.
  104. if (!typeRegistry) {
  105. typeRegistry = Blockly.registry.typeMap_[type] = {};
  106. }
  107. // Validate that the given class has all the required properties.
  108. Blockly.registry.validate_(type, registryItem);
  109. // Don't throw an error if opt_quiet is true.
  110. if (!opt_quiet && typeRegistry[name]) {
  111. throw Error('Name "' + name + '" with type "' + type + '" already registered.');
  112. }
  113. typeRegistry[name] = registryItem;
  114. };
  115. /**
  116. * Checks the given registry item for properties that are required based on the
  117. * type.
  118. * @param {string} type The type of the plugin. (e.g. Field, Renderer)
  119. * @param {Function|Object} registryItem A class or object that we are checking
  120. * for the required properties.
  121. * @private
  122. */
  123. Blockly.registry.validate_ = function(type, registryItem) {
  124. switch (type) {
  125. case String(Blockly.registry.Type.FIELD):
  126. if (typeof registryItem.fromJson != 'function') {
  127. throw Error('Type "' + type + '" must have a fromJson function');
  128. }
  129. break;
  130. }
  131. };
  132. /**
  133. * Unregisters the registry item with the given type and name.
  134. * @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
  135. * (e.g. Field, Renderer)
  136. * @param {string} name The plugin's name. (Ex. field_angle, geras)
  137. * @template T
  138. */
  139. Blockly.registry.unregister = function(type, name) {
  140. type = String(type).toLowerCase();
  141. name = name.toLowerCase();
  142. var typeRegistry = Blockly.registry.typeMap_[type];
  143. if (!typeRegistry) {
  144. console.warn('No type "' + type + '" found');
  145. return;
  146. }
  147. if (!typeRegistry[name]) {
  148. console.warn('No name "' + name + '" with type "' + type + '" found');
  149. return;
  150. }
  151. delete Blockly.registry.typeMap_[type][name];
  152. };
  153. /**
  154. * Gets the registry item for the given name and type. This can be either a
  155. * class or an object.
  156. * @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
  157. * (e.g. Field, Renderer)
  158. * @param {string} name The plugin's name. (Ex. field_angle, geras)
  159. * @return {?function(new:T, ...?)|Object} The class or object with the given
  160. * name and type or null if none exists.
  161. * @template T
  162. */
  163. Blockly.registry.getItem_ = function(type, name) {
  164. type = String(type).toLowerCase();
  165. name = name.toLowerCase();
  166. var typeRegistry = Blockly.registry.typeMap_[type];
  167. if (!typeRegistry) {
  168. console.warn('No type "' + type + '" found');
  169. return null;
  170. }
  171. if (!typeRegistry[name]) {
  172. console.warn('No name "' + name + '" with type "' + type + '" found');
  173. return null;
  174. }
  175. return typeRegistry[name];
  176. };
  177. /**
  178. * Returns whether or not the registry contains an item with the given type and
  179. * name.
  180. * @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
  181. * (e.g. Field, Renderer)
  182. * @param {string} name The plugin's name. (Ex. field_angle, geras)
  183. * @return {boolean} True if the registry has an item with the given type and
  184. * name, false otherwise.
  185. * @template T
  186. */
  187. Blockly.registry.hasItem = function(type, name) {
  188. type = String(type).toLowerCase();
  189. name = name.toLowerCase();
  190. var typeRegistry = Blockly.registry.typeMap_[type];
  191. if (!typeRegistry) {
  192. return false;
  193. }
  194. return !!(typeRegistry[name]);
  195. };
  196. /**
  197. * Gets the class for the given name and type.
  198. * @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
  199. * (e.g. Field, Renderer)
  200. * @param {string} name The plugin's name. (Ex. field_angle, geras)
  201. * @return {?function(new:T, ...?)} The class with the given name and type or
  202. * null if none exists.
  203. * @template T
  204. */
  205. Blockly.registry.getClass = function(type, name) {
  206. return /** @type {?function(new:T, ...?)} */ (Blockly.registry.getItem_(type, name));
  207. };
  208. /**
  209. * Gets the object for the given name and type.
  210. * @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
  211. * (e.g. Category)
  212. * @param {string} name The plugin's name. (Ex. logic_category)
  213. * @returns {T} The object with the given name and type or null if none exists.
  214. * @template T
  215. */
  216. Blockly.registry.getObject = function(type, name) {
  217. return /** @type {T} */ (Blockly.registry.getItem_(type, name));
  218. };
  219. /**
  220. * Gets the class from Blockly options for the given type.
  221. * This is used for plugins that override a built in feature. (e.g. Toolbox)
  222. * @param {!Blockly.registry.Type<T>} type The type of the plugin.
  223. * @param {!Blockly.Options} options The option object to check for the given
  224. * plugin.
  225. * @return {?function(new:T, ...?)} The class for the plugin.
  226. * @template T
  227. */
  228. Blockly.registry.getClassFromOptions = function(type, options) {
  229. var typeName = type.toString();
  230. var plugin = options.plugins[typeName] || Blockly.registry.DEFAULT;
  231. // If the user passed in a plugin class instead of a registered plugin name.
  232. if (typeof plugin == 'function') {
  233. return plugin;
  234. }
  235. return Blockly.registry.getClass(type, plugin);
  236. };