8
0

config.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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( [ 'ckeditor', 'mvc/model', 'utils' ], function( CKEDITOR, 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.
  62. * @param {*} [value] The configuration value. Used if a name is passed to nameOrConfigurations. If undefined,
  63. * the configuration is set to `null`.
  64. */
  65. set: function( name, value ) {
  66. // Just pass the call to the original set() in case of an object. It'll deal with recursing through the
  67. // object and calling set( name, value ) again for each property.
  68. if ( utils.isObject( name ) ) {
  69. Model.prototype.set.apply( this, arguments );
  70. return;
  71. }
  72. // The target for this configuration is, for now, this object.
  73. //jscs:disable safeContextKeyword
  74. var target = this;
  75. //jscs:enable
  76. // The configuration name should be split into parts if it has dots. E.g: `resize.width`.
  77. var parts = name.toLowerCase().split( '.' );
  78. // Take the name of the configuration out of the parts. E.g. `resize.width` -> `width`
  79. name = parts.pop();
  80. // Retrieves the final target for this configuration recursively.
  81. for ( var i = 0; i < parts.length; i++ ) {
  82. // The target will always be an instance of Config.
  83. if ( !( target[ parts[ i ] ] instanceof Config ) ) {
  84. target.set( parts[ i ], new Config() );
  85. }
  86. target = target[ parts[ i ] ];
  87. }
  88. // Values set as pure objects will be treated as Config subsets.
  89. if ( utils.isPlainObject( value ) ) {
  90. // If the target is an instance of Config (a deep config subset).
  91. if ( target[ name ] instanceof Config ) {
  92. // Amend the target with the value, instead of replacing it.
  93. target[ name ].set( value );
  94. return;
  95. }
  96. value = new Config( value );
  97. }
  98. // Values will never be undefined.
  99. if ( typeof value == 'undefined' ) {
  100. value = null;
  101. }
  102. // Call the original set() on the target.
  103. Model.prototype.set.call( target, name, value );
  104. },
  105. /**
  106. * Gets the value for a configuration entry.
  107. *
  108. * config.get( 'name' );
  109. *
  110. * Deep configurations can be retrieved by separating each part with a dot.
  111. *
  112. * config.get( 'toolbar.collapsed' );
  113. *
  114. * @param {String} name The configuration name.
  115. * @returns {*} The configuration value or `undefined` if the configuration entry was not found.
  116. */
  117. get: function( name ) {
  118. // The target for this configuration is, for now, this object.
  119. //jscs:disable safeContextKeyword
  120. var source = this;
  121. //jscs:enable
  122. // The configuration name should be split into parts if it has dots. E.g. `resize.width` -> [`resize`, `width`]
  123. var parts = name.toLowerCase().split( '.' );
  124. // Take the name of the configuration from the parts. E.g. `resize.width` -> `width`
  125. name = parts.pop();
  126. // Retrieves the source for this configuration recursively.
  127. for ( var i = 0; i < parts.length; i++ ) {
  128. // The target will always be an instance of Config.
  129. if ( !( source[ parts[ i ] ] instanceof Config ) ) {
  130. source = null;
  131. break;
  132. }
  133. source = source[ parts[ i ] ];
  134. }
  135. // Try to retrieve it from the source object.
  136. if ( source && ( typeof source[ name ] != 'undefined' ) ) {
  137. return source[ name ];
  138. }
  139. // If not found, take it from the definition.
  140. if ( this.definition ) {
  141. return this.definition[ name ];
  142. }
  143. return undefined;
  144. },
  145. /**
  146. * Defines the name and default value for configurations. It accepts the same parameters as the
  147. * {@link Config#set set()} method.
  148. *
  149. * On first call, the {@link Config#definition definition} property is created to hold all defined
  150. * configurations.
  151. *
  152. * This method is supposed to be called by plugin developers to setup plugin's configurations. It would be
  153. * rarely used for other needs.
  154. *
  155. * @param {String|Object} nameOrConfigurations The configuration name or an object from which take properties as
  156. * configuration entries.
  157. * @param {*} [value] The configuration value. Used if a name is passed to nameOrConfigurations. If undefined,
  158. * the configuration is set to `null`.
  159. */
  160. define: function( name, value ) {
  161. if ( !this.definition ) {
  162. /**
  163. *
  164. *
  165. * @property
  166. * @type {Config}
  167. */
  168. this.definition = new Config();
  169. }
  170. this.definition.set( name, value );
  171. }
  172. } );
  173. return Config;
  174. } );