componentfactory.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /**
  2. * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /**
  6. * @module ui/componentfactory
  7. */
  8. import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
  9. /**
  10. * A helper class implementing the UI component ({@link module:ui/view~View view}) factory.
  11. *
  12. * It allows functions producing specific UI components to be registered under their unique names
  13. * in the factory. A registered component can be then instantiated by providing its name.
  14. * Note that names are case insensitive.
  15. *
  16. * // The editor provides localization tools for the factory.
  17. * const factory = new ComponentFactory( editor );
  18. *
  19. * factory.add( 'foo', locale => new FooView( locale ) );
  20. * factory.add( 'bar', locale => new BarView( locale ) );
  21. *
  22. * // An instance of FooView.
  23. * const fooInstance = factory.create( 'foo' );
  24. *
  25. * // Names are case insensitive so this is also allowed:
  26. * const barInstance = factory.create( 'Bar' );
  27. *
  28. * The {@link module:core/editor/editor~Editor#locale editor locale} is passed to the factory
  29. * function when {@link module:ui/componentfactory~ComponentFactory#create} is called.
  30. */
  31. export default class ComponentFactory {
  32. /**
  33. * Creates an instance of the factory.
  34. *
  35. * @constructor
  36. * @param {module:core/editor/editor~Editor} editor The editor instance.
  37. */
  38. constructor( editor ) {
  39. /**
  40. * The editor instance that the factory belongs to.
  41. *
  42. * @readonly
  43. * @member {module:core/editor/editor~Editor}
  44. */
  45. this.editor = editor;
  46. /**
  47. * Registered component factories.
  48. *
  49. * @private
  50. * @member {Map}
  51. */
  52. this._components = new Map();
  53. }
  54. /**
  55. * Returns an iterator of registered component names. Names are returned in lower case.
  56. *
  57. * @returns {Iterable.<String>}
  58. */
  59. * names() {
  60. for ( const value of this._components.values() ) {
  61. yield value.originalName;
  62. }
  63. }
  64. /**
  65. * Registers a component factory function that will be used by the
  66. * {@link #create create} method and called with the
  67. * {@link module:core/editor/editor~Editor#locale editor locale} as an argument,
  68. * allowing localization of the {@link module:ui/view~View view}.
  69. *
  70. * @param {String} name The name of the component.
  71. * @param {Function} callback The callback that returns the component.
  72. */
  73. add( name, callback ) {
  74. if ( this.has( name ) ) {
  75. /**
  76. * The item already exists in the component factory.
  77. *
  78. * @error componentfactory-item-exists
  79. * @param {String} name The name of the component.
  80. */
  81. throw new CKEditorError(
  82. 'componentfactory-item-exists: The item already exists in the component factory.', { name }
  83. );
  84. }
  85. this._components.set( getNormalized( name ), { callback, originalName: name } );
  86. }
  87. /**
  88. * Creates an instance of a component registered in the factory under a specific name.
  89. *
  90. * When called, the {@link module:core/editor/editor~Editor#locale editor locale} is passed to
  91. * the previously {@link #add added} factory function, allowing localization of the
  92. * {@link module:ui/view~View view}.
  93. *
  94. * @param {String} name The name of the component.
  95. * @returns {module:ui/view~View} The instantiated component view.
  96. */
  97. create( name ) {
  98. if ( !this.has( name ) ) {
  99. /**
  100. * The required component is not registered in the component factory. Please make sure
  101. * the provided name is correct and the component has been correctly
  102. * {@link #add added} to the factory.
  103. *
  104. * @error componentfactory-item-missing
  105. * @param {String} name The name of the missing component.
  106. */
  107. throw new CKEditorError(
  108. 'componentfactory-item-missing: The required component is not registered in the factory.', { name }
  109. );
  110. }
  111. return this._components.get( getNormalized( name ) ).callback( this.editor.locale );
  112. }
  113. /**
  114. * Checks if a component of a given name is registered in the factory.
  115. *
  116. * @param {String} name The name of the component.
  117. * @returns {Boolean}
  118. */
  119. has( name ) {
  120. return this._components.has( getNormalized( name ) );
  121. }
  122. }
  123. //
  124. // Ensures that the component name used as the key in the internal map is in lower case.
  125. //
  126. // @private
  127. // @param {String} name
  128. // @returns {String}
  129. function getNormalized( name ) {
  130. return String( name ).toLowerCase();
  131. }