componentfactory.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  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.',
  83. this,
  84. { name }
  85. );
  86. }
  87. this._components.set( getNormalized( name ), { callback, originalName: name } );
  88. }
  89. /**
  90. * Creates an instance of a component registered in the factory under a specific name.
  91. *
  92. * When called, the {@link module:core/editor/editor~Editor#locale editor locale} is passed to
  93. * the previously {@link #add added} factory function, allowing localization of the
  94. * {@link module:ui/view~View view}.
  95. *
  96. * @param {String} name The name of the component.
  97. * @returns {module:ui/view~View} The instantiated component view.
  98. */
  99. create( name ) {
  100. if ( !this.has( name ) ) {
  101. /**
  102. * The required component is not registered in the component factory. Please make sure
  103. * the provided name is correct and the component has been correctly
  104. * {@link #add added} to the factory.
  105. *
  106. * @error componentfactory-item-missing
  107. * @param {String} name The name of the missing component.
  108. */
  109. throw new CKEditorError(
  110. 'componentfactory-item-missing: The required component is not registered in the factory.',
  111. this,
  112. { name }
  113. );
  114. }
  115. return this._components.get( getNormalized( name ) ).callback( this.editor.locale );
  116. }
  117. /**
  118. * Checks if a component of a given name is registered in the factory.
  119. *
  120. * @param {String} name The name of the component.
  121. * @returns {Boolean}
  122. */
  123. has( name ) {
  124. return this._components.has( getNormalized( name ) );
  125. }
  126. }
  127. //
  128. // Ensures that the component name used as the key in the internal map is in lower case.
  129. //
  130. // @private
  131. // @param {String} name
  132. // @returns {String}
  133. function getNormalized( name ) {
  134. return String( name ).toLowerCase();
  135. }