clazz.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. var _config = require("../config");
  2. var __DEV__ = _config.__DEV__;
  3. var zrUtil = require("zrender/lib/core/util");
  4. var TYPE_DELIMITER = '.';
  5. var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';
  6. var MEMBER_PRIFIX = '\0ec_\0';
  7. /**
  8. * Hide private class member.
  9. * The same behavior as `host[name] = value;` (can be right-value)
  10. * @public
  11. */
  12. function set(host, name, value) {
  13. return host[MEMBER_PRIFIX + name] = value;
  14. }
  15. /**
  16. * Hide private class member.
  17. * The same behavior as `host[name];`
  18. * @public
  19. */
  20. function get(host, name) {
  21. return host[MEMBER_PRIFIX + name];
  22. }
  23. /**
  24. * For hidden private class member.
  25. * The same behavior as `host.hasOwnProperty(name);`
  26. * @public
  27. */
  28. function hasOwn(host, name) {
  29. return host.hasOwnProperty(MEMBER_PRIFIX + name);
  30. }
  31. /**
  32. * Notice, parseClassType('') should returns {main: '', sub: ''}
  33. * @public
  34. */
  35. function parseClassType(componentType) {
  36. var ret = {
  37. main: '',
  38. sub: ''
  39. };
  40. if (componentType) {
  41. componentType = componentType.split(TYPE_DELIMITER);
  42. ret.main = componentType[0] || '';
  43. ret.sub = componentType[1] || '';
  44. }
  45. return ret;
  46. }
  47. /**
  48. * @public
  49. */
  50. function checkClassType(componentType) {
  51. zrUtil.assert(/^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType), 'componentType "' + componentType + '" illegal');
  52. }
  53. /**
  54. * @public
  55. */
  56. function enableClassExtend(RootClass, mandatoryMethods) {
  57. RootClass.$constructor = RootClass;
  58. RootClass.extend = function (proto) {
  59. var superClass = this;
  60. var ExtendedClass = function () {
  61. if (!proto.$constructor) {
  62. superClass.apply(this, arguments);
  63. } else {
  64. proto.$constructor.apply(this, arguments);
  65. }
  66. };
  67. zrUtil.extend(ExtendedClass.prototype, proto);
  68. ExtendedClass.extend = this.extend;
  69. ExtendedClass.superCall = superCall;
  70. ExtendedClass.superApply = superApply;
  71. zrUtil.inherits(ExtendedClass, this);
  72. ExtendedClass.superClass = superClass;
  73. return ExtendedClass;
  74. };
  75. } // superCall should have class info, which can not be fetch from 'this'.
  76. // Consider this case:
  77. // class A has method f,
  78. // class B inherits class A, overrides method f, f call superApply('f'),
  79. // class C inherits class B, do not overrides method f,
  80. // then when method of class C is called, dead loop occured.
  81. function superCall(context, methodName) {
  82. var args = zrUtil.slice(arguments, 2);
  83. return this.superClass.prototype[methodName].apply(context, args);
  84. }
  85. function superApply(context, methodName, args) {
  86. return this.superClass.prototype[methodName].apply(context, args);
  87. }
  88. /**
  89. * @param {Object} entity
  90. * @param {Object} options
  91. * @param {boolean} [options.registerWhenExtend]
  92. * @public
  93. */
  94. function enableClassManagement(entity, options) {
  95. options = options || {};
  96. /**
  97. * Component model classes
  98. * key: componentType,
  99. * value:
  100. * componentClass, when componentType is 'xxx'
  101. * or Object.<subKey, componentClass>, when componentType is 'xxx.yy'
  102. * @type {Object}
  103. */
  104. var storage = {};
  105. entity.registerClass = function (Clazz, componentType) {
  106. if (componentType) {
  107. checkClassType(componentType);
  108. componentType = parseClassType(componentType);
  109. if (!componentType.sub) {
  110. storage[componentType.main] = Clazz;
  111. } else if (componentType.sub !== IS_CONTAINER) {
  112. var container = makeContainer(componentType);
  113. container[componentType.sub] = Clazz;
  114. }
  115. }
  116. return Clazz;
  117. };
  118. entity.getClass = function (componentMainType, subType, throwWhenNotFound) {
  119. var Clazz = storage[componentMainType];
  120. if (Clazz && Clazz[IS_CONTAINER]) {
  121. Clazz = subType ? Clazz[subType] : null;
  122. }
  123. if (throwWhenNotFound && !Clazz) {
  124. throw new Error(!subType ? componentMainType + '.' + 'type should be specified.' : 'Component ' + componentMainType + '.' + (subType || '') + ' not exists. Load it first.');
  125. }
  126. return Clazz;
  127. };
  128. entity.getClassesByMainType = function (componentType) {
  129. componentType = parseClassType(componentType);
  130. var result = [];
  131. var obj = storage[componentType.main];
  132. if (obj && obj[IS_CONTAINER]) {
  133. zrUtil.each(obj, function (o, type) {
  134. type !== IS_CONTAINER && result.push(o);
  135. });
  136. } else {
  137. result.push(obj);
  138. }
  139. return result;
  140. };
  141. entity.hasClass = function (componentType) {
  142. // Just consider componentType.main.
  143. componentType = parseClassType(componentType);
  144. return !!storage[componentType.main];
  145. };
  146. /**
  147. * @return {Array.<string>} Like ['aa', 'bb'], but can not be ['aa.xx']
  148. */
  149. entity.getAllClassMainTypes = function () {
  150. var types = [];
  151. zrUtil.each(storage, function (obj, type) {
  152. types.push(type);
  153. });
  154. return types;
  155. };
  156. /**
  157. * If a main type is container and has sub types
  158. * @param {string} mainType
  159. * @return {boolean}
  160. */
  161. entity.hasSubTypes = function (componentType) {
  162. componentType = parseClassType(componentType);
  163. var obj = storage[componentType.main];
  164. return obj && obj[IS_CONTAINER];
  165. };
  166. entity.parseClassType = parseClassType;
  167. function makeContainer(componentType) {
  168. var container = storage[componentType.main];
  169. if (!container || !container[IS_CONTAINER]) {
  170. container = storage[componentType.main] = {};
  171. container[IS_CONTAINER] = true;
  172. }
  173. return container;
  174. }
  175. if (options.registerWhenExtend) {
  176. var originalExtend = entity.extend;
  177. if (originalExtend) {
  178. entity.extend = function (proto) {
  179. var ExtendedClass = originalExtend.call(this, proto);
  180. return entity.registerClass(ExtendedClass, proto.type);
  181. };
  182. }
  183. }
  184. return entity;
  185. }
  186. /**
  187. * @param {string|Array.<string>} properties
  188. */
  189. function setReadOnly(obj, properties) {// FIXME It seems broken in IE8 simulation of IE11
  190. // if (!zrUtil.isArray(properties)) {
  191. // properties = properties != null ? [properties] : [];
  192. // }
  193. // zrUtil.each(properties, function (prop) {
  194. // var value = obj[prop];
  195. // Object.defineProperty
  196. // && Object.defineProperty(obj, prop, {
  197. // value: value, writable: false
  198. // });
  199. // zrUtil.isArray(obj[prop])
  200. // && Object.freeze
  201. // && Object.freeze(obj[prop]);
  202. // });
  203. }
  204. exports.set = set;
  205. exports.get = get;
  206. exports.hasOwn = hasOwn;
  207. exports.parseClassType = parseClassType;
  208. exports.enableClassExtend = enableClassExtend;
  209. exports.enableClassManagement = enableClassManagement;
  210. exports.setReadOnly = setReadOnly;