ProtoElement.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * The dirty implementation in this class is quite naive. The reasoning for this is that the dirty state
  3. * will only be used in very specific circumstances, specifically, after the render process has begun but
  4. * the component is not yet rendered to the DOM. As such, we want it to perform as quickly as possible
  5. * so it's not as fully featured as you may expect.
  6. */
  7. /**
  8. * Manages certain element-like data prior to rendering. These values are passed
  9. * on to the render process. This is currently used to manage the "class" and "style" attributes
  10. * of a component's primary el as well as the bodyEl of panels. This allows things like
  11. * addBodyCls in Panel to share logic with addCls in AbstractComponent.
  12. * @private
  13. */
  14. Ext.define('Ext.util.ProtoElement', (function () {
  15. var splitWords = Ext.String.splitWords,
  16. toMap = Ext.Array.toMap;
  17. return {
  18. isProtoEl: true,
  19. /**
  20. * The property name for the className on the data object passed to {@link #writeTo}.
  21. */
  22. clsProp: 'cls',
  23. /**
  24. * The property name for the style on the data object passed to {@link #writeTo}.
  25. */
  26. styleProp: 'style',
  27. /**
  28. * The property name for the removed classes on the data object passed to {@link #writeTo}.
  29. */
  30. removedProp: 'removed',
  31. /**
  32. * True if the style must be converted to text during {@link #writeTo}. When used to
  33. * populate tpl data, this will be true. When used to populate {@link Ext.DomHelper}
  34. * specs, this will be false (the default).
  35. */
  36. styleIsText: false,
  37. constructor: function (config) {
  38. var me = this;
  39. Ext.apply(me, config);
  40. me.classList = splitWords(me.cls);
  41. me.classMap = toMap(me.classList);
  42. delete me.cls;
  43. if (Ext.isFunction(me.style)) {
  44. me.styleFn = me.style;
  45. delete me.style;
  46. } else if (typeof me.style == 'string') {
  47. me.style = Ext.Element.parseStyles(me.style);
  48. } else if (me.style) {
  49. me.style = Ext.apply({}, me.style); // don't edit the given object
  50. }
  51. },
  52. /**
  53. * Indicates that the current state of the object has been flushed to the DOM, so we need
  54. * to track any subsequent changes
  55. */
  56. flush: function(){
  57. this.flushClassList = [];
  58. this.removedClasses = {};
  59. // clear the style, it will be recreated if we add anything new
  60. delete this.style;
  61. },
  62. /**
  63. * Adds class to the element.
  64. * @param {String} cls One or more classnames separated with spaces.
  65. * @return {Ext.util.ProtoElement} this
  66. */
  67. addCls: function (cls) {
  68. var me = this,
  69. add = splitWords(cls),
  70. length = add.length,
  71. list = me.classList,
  72. map = me.classMap,
  73. flushList = me.flushClassList,
  74. i = 0,
  75. c;
  76. for (; i < length; ++i) {
  77. c = add[i];
  78. if (!map[c]) {
  79. map[c] = true;
  80. list.push(c);
  81. if (flushList) {
  82. flushList.push(c);
  83. delete me.removedClasses[c];
  84. }
  85. }
  86. }
  87. return me;
  88. },
  89. /**
  90. * True if the element has given class.
  91. * @param {String} cls
  92. * @return {Boolean}
  93. */
  94. hasCls: function (cls) {
  95. return cls in this.classMap;
  96. },
  97. /**
  98. * Removes class from the element.
  99. * @param {String} cls One or more classnames separated with spaces.
  100. * @return {Ext.util.ProtoElement} this
  101. */
  102. removeCls: function (cls) {
  103. var me = this,
  104. list = me.classList,
  105. newList = (me.classList = []),
  106. remove = toMap(splitWords(cls)),
  107. length = list.length,
  108. map = me.classMap,
  109. removedClasses = me.removedClasses,
  110. i, c;
  111. for (i = 0; i < length; ++i) {
  112. c = list[i];
  113. if (remove[c]) {
  114. if (removedClasses) {
  115. if (map[c]) {
  116. removedClasses[c] = true;
  117. Ext.Array.remove(me.flushClassList, c);
  118. }
  119. }
  120. delete map[c];
  121. } else {
  122. newList.push(c);
  123. }
  124. }
  125. return me;
  126. },
  127. /**
  128. * Adds styles to the element.
  129. * @param {String/Object} prop The style property to be set, or an object of multiple styles.
  130. * @param {String} [value] The value to apply to the given property.
  131. * @return {Ext.util.ProtoElement} this
  132. */
  133. setStyle: function (prop, value) {
  134. var me = this,
  135. style = me.style || (me.style = {});
  136. if (typeof prop == 'string') {
  137. if (arguments.length === 1) {
  138. me.setStyle(Ext.Element.parseStyles(prop));
  139. } else {
  140. style[prop] = value;
  141. }
  142. } else {
  143. Ext.apply(style, prop);
  144. }
  145. return me;
  146. },
  147. /**
  148. * Writes style and class properties to given object.
  149. * Styles will be written to {@link #styleProp} and class names to {@link #clsProp}.
  150. * @param {Object} to
  151. * @return {Object} to
  152. */
  153. writeTo: function (to) {
  154. var me = this,
  155. classList = me.flushClassList || me.classList,
  156. removedClasses = me.removedClasses,
  157. style;
  158. if (me.styleFn) {
  159. style = Ext.apply({}, me.styleFn());
  160. Ext.apply(style, me.style);
  161. } else {
  162. style = me.style;
  163. }
  164. to[me.clsProp] = classList.join(' ');
  165. if (style) {
  166. to[me.styleProp] = me.styleIsText ? Ext.DomHelper.generateStyles(style) : style;
  167. }
  168. if (removedClasses) {
  169. removedClasses = Ext.Object.getKeys(removedClasses);
  170. if (removedClasses.length) {
  171. to[me.removedProp] = removedClasses.join(' ');
  172. }
  173. }
  174. return to;
  175. }
  176. };
  177. }()));