8
0

config.js 5.8 KB

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