config.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. 'use strict';
  6. /**
  7. * Handles a configuration dictionary.
  8. *
  9. * @class Config
  10. * @extends Model
  11. */
  12. CKEDITOR.define( [ 'model', 'utils' ], ( Model, utils ) => {
  13. class Config extends Model {
  14. /**
  15. * Creates an instance of the {@link Config} class.
  16. *
  17. * @param {Object} [configurations] The initial configurations to be set.
  18. * @constructor
  19. */
  20. constructor( configurations ) {
  21. super();
  22. if ( configurations ) {
  23. this.set( configurations );
  24. }
  25. }
  26. /**
  27. * Set configuration values.
  28. *
  29. * It accepts both a name/value pair or an object, which properties and values will be used to set
  30. * configurations.
  31. *
  32. * It also accepts setting a "deep configuration" by using dots in the name. For example, `'resize.width'` sets
  33. * the value for the `width` configuration in the `resize` subset.
  34. *
  35. * config.set( 'width', 500 );
  36. * config.set( 'toolbar.collapsed', true );
  37. *
  38. * // Equivalent to:
  39. * config.set( {
  40. * width: 500
  41. * toolbar: {
  42. * collapsed: true
  43. * }
  44. * } );
  45. *
  46. * Passing an object as the value will amend the configuration, not replace it.
  47. *
  48. * config.set( 'toolbar', {
  49. * collapsed: true,
  50. * } );
  51. *
  52. * config.set( 'toolbar', {
  53. * color: 'red',
  54. * } );
  55. *
  56. * config.toolbar.collapsed; // true
  57. * config.toolbar.color; // 'red'
  58. *
  59. * @param {String|Object} nameOrConfigurations The configuration name or an object from which take properties as
  60. * configuration entries. Configuration names are case-insensitive.
  61. * @param {*} [value=null] The configuration value. Used if a name is passed to nameOrConfigurations.
  62. */
  63. set( name, value ) {
  64. // Just pass the call to the original set() in case of an object. It'll deal with recursing through the
  65. // object and calling set( name, value ) again for each property.
  66. if ( utils.isObject( name ) ) {
  67. super.set.apply( this, arguments );
  68. return;
  69. }
  70. // The target for this configuration is, for now, this object.
  71. //jscs:disable safeContextKeyword
  72. let target = this;
  73. //jscs:enable
  74. // The configuration name should be split into parts if it has dots. E.g: `resize.width`.
  75. const parts = name.toLowerCase().split( '.' );
  76. // Take the name of the configuration out of the parts. E.g. `resize.width` -> `width`
  77. name = parts.pop();
  78. // Retrieves the final target for this configuration recursively.
  79. for ( let i = 0; i < parts.length; i++ ) {
  80. // The target will always be an instance of Config.
  81. if ( !( target[ parts[ i ] ] instanceof Config ) ) {
  82. target.set( parts[ i ], new Config() );
  83. }
  84. target = target[ parts[ i ] ];
  85. }
  86. // Values set as pure objects will be treated as Config subsets.
  87. if ( utils.isPlainObject( value ) ) {
  88. // If the target is an instance of Config (a deep config subset).
  89. if ( target[ name ] instanceof Config ) {
  90. // Amend the target with the value, instead of replacing it.
  91. target[ name ].set( value );
  92. return;
  93. }
  94. value = new Config( value );
  95. }
  96. // Values will never be undefined.
  97. if ( typeof value == 'undefined' ) {
  98. value = null;
  99. }
  100. // Call the original set() on the target.
  101. super.set.call( target, name, value );
  102. }
  103. /**
  104. * Gets the value for a configuration entry.
  105. *
  106. * config.get( 'name' );
  107. *
  108. * Deep configurations can be retrieved by separating each part with a dot.
  109. *
  110. * config.get( 'toolbar.collapsed' );
  111. *
  112. * @param {String} name The configuration name. Configuration names are case-insensitive.
  113. * @returns {*} The configuration value or `undefined` if the configuration entry was not found.
  114. */
  115. get( name ) {
  116. // The target for this configuration is, for now, this object.
  117. //jscs:disable safeContextKeyword
  118. let source = this;
  119. //jscs:enable
  120. // The configuration name should be split into parts if it has dots. E.g. `resize.width` -> [`resize`, `width`]
  121. const parts = name.toLowerCase().split( '.' );
  122. // Take the name of the configuration from the parts. E.g. `resize.width` -> `width`
  123. name = parts.pop();
  124. // Retrieves the source for this configuration recursively.
  125. for ( let i = 0; i < parts.length; i++ ) {
  126. // The target will always be an instance of Config.
  127. if ( !( source[ parts[ i ] ] instanceof Config ) ) {
  128. source = null;
  129. break;
  130. }
  131. source = source[ parts[ i ] ];
  132. }
  133. // Try to retrieve it from the source object.
  134. if ( source && ( typeof source[ name ] != 'undefined' ) ) {
  135. return source[ name ];
  136. }
  137. // If not found, take it from the definition.
  138. if ( this.definition ) {
  139. return this.definition[ name ];
  140. }
  141. }
  142. /**
  143. * Defines the name and default value for configurations. It accepts the same parameters as the
  144. * {@link Config#set set()} method.
  145. *
  146. * On first call, the {@link Config#definition definition} property is created to hold all defined
  147. * configurations.
  148. *
  149. * This method is supposed to be called by plugin developers to setup plugin's configurations. It would be
  150. * rarely used for other needs.
  151. *
  152. * @param {String|Object} nameOrConfigurations The configuration name or an object from which take properties as
  153. * configuration entries.
  154. * @param {*} [value] The configuration value. Used if a name is passed to nameOrConfigurations. If undefined,
  155. * the configuration is set to `null`.
  156. */
  157. define( name, value ) {
  158. if ( !this.definition ) {
  159. /**
  160. * TODO
  161. *
  162. * @property
  163. * @type {Config}
  164. */
  165. this.definition = new Config();
  166. }
  167. this.definition.set( name, value );
  168. }
  169. }
  170. return Config;
  171. } );