clazz.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. var _config = require("../config");
  20. var __DEV__ = _config.__DEV__;
  21. var zrUtil = require("zrender/lib/core/util");
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. var TYPE_DELIMITER = '.';
  41. var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';
  42. /**
  43. * Notice, parseClassType('') should returns {main: '', sub: ''}
  44. * @public
  45. */
  46. function parseClassType(componentType) {
  47. var ret = {
  48. main: '',
  49. sub: ''
  50. };
  51. if (componentType) {
  52. componentType = componentType.split(TYPE_DELIMITER);
  53. ret.main = componentType[0] || '';
  54. ret.sub = componentType[1] || '';
  55. }
  56. return ret;
  57. }
  58. /**
  59. * @public
  60. */
  61. function checkClassType(componentType) {
  62. zrUtil.assert(/^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType), 'componentType "' + componentType + '" illegal');
  63. }
  64. /**
  65. * @public
  66. */
  67. function enableClassExtend(RootClass, mandatoryMethods) {
  68. RootClass.$constructor = RootClass;
  69. RootClass.extend = function (proto) {
  70. var superClass = this;
  71. var ExtendedClass = function () {
  72. if (!proto.$constructor) {
  73. superClass.apply(this, arguments);
  74. } else {
  75. proto.$constructor.apply(this, arguments);
  76. }
  77. };
  78. zrUtil.extend(ExtendedClass.prototype, proto);
  79. ExtendedClass.extend = this.extend;
  80. ExtendedClass.superCall = superCall;
  81. ExtendedClass.superApply = superApply;
  82. zrUtil.inherits(ExtendedClass, this);
  83. ExtendedClass.superClass = superClass;
  84. return ExtendedClass;
  85. };
  86. }
  87. var classBase = 0;
  88. /**
  89. * Can not use instanceof, consider different scope by
  90. * cross domain or es module import in ec extensions.
  91. * Mount a method "isInstance()" to Clz.
  92. */
  93. function enableClassCheck(Clz) {
  94. var classAttr = ['__\0is_clz', classBase++, Math.random().toFixed(3)].join('_');
  95. Clz.prototype[classAttr] = true;
  96. Clz.isInstance = function (obj) {
  97. return !!(obj && obj[classAttr]);
  98. };
  99. } // superCall should have class info, which can not be fetch from 'this'.
  100. // Consider this case:
  101. // class A has method f,
  102. // class B inherits class A, overrides method f, f call superApply('f'),
  103. // class C inherits class B, do not overrides method f,
  104. // then when method of class C is called, dead loop occured.
  105. function superCall(context, methodName) {
  106. var args = zrUtil.slice(arguments, 2);
  107. return this.superClass.prototype[methodName].apply(context, args);
  108. }
  109. function superApply(context, methodName, args) {
  110. return this.superClass.prototype[methodName].apply(context, args);
  111. }
  112. /**
  113. * @param {Object} entity
  114. * @param {Object} options
  115. * @param {boolean} [options.registerWhenExtend]
  116. * @public
  117. */
  118. function enableClassManagement(entity, options) {
  119. options = options || {};
  120. /**
  121. * Component model classes
  122. * key: componentType,
  123. * value:
  124. * componentClass, when componentType is 'xxx'
  125. * or Object.<subKey, componentClass>, when componentType is 'xxx.yy'
  126. * @type {Object}
  127. */
  128. var storage = {};
  129. entity.registerClass = function (Clazz, componentType) {
  130. if (componentType) {
  131. checkClassType(componentType);
  132. componentType = parseClassType(componentType);
  133. if (!componentType.sub) {
  134. storage[componentType.main] = Clazz;
  135. } else if (componentType.sub !== IS_CONTAINER) {
  136. var container = makeContainer(componentType);
  137. container[componentType.sub] = Clazz;
  138. }
  139. }
  140. return Clazz;
  141. };
  142. entity.getClass = function (componentMainType, subType, throwWhenNotFound) {
  143. var Clazz = storage[componentMainType];
  144. if (Clazz && Clazz[IS_CONTAINER]) {
  145. Clazz = subType ? Clazz[subType] : null;
  146. }
  147. if (throwWhenNotFound && !Clazz) {
  148. throw new Error(!subType ? componentMainType + '.' + 'type should be specified.' : 'Component ' + componentMainType + '.' + (subType || '') + ' not exists. Load it first.');
  149. }
  150. return Clazz;
  151. };
  152. entity.getClassesByMainType = function (componentType) {
  153. componentType = parseClassType(componentType);
  154. var result = [];
  155. var obj = storage[componentType.main];
  156. if (obj && obj[IS_CONTAINER]) {
  157. zrUtil.each(obj, function (o, type) {
  158. type !== IS_CONTAINER && result.push(o);
  159. });
  160. } else {
  161. result.push(obj);
  162. }
  163. return result;
  164. };
  165. entity.hasClass = function (componentType) {
  166. // Just consider componentType.main.
  167. componentType = parseClassType(componentType);
  168. return !!storage[componentType.main];
  169. };
  170. /**
  171. * @return {Array.<string>} Like ['aa', 'bb'], but can not be ['aa.xx']
  172. */
  173. entity.getAllClassMainTypes = function () {
  174. var types = [];
  175. zrUtil.each(storage, function (obj, type) {
  176. types.push(type);
  177. });
  178. return types;
  179. };
  180. /**
  181. * If a main type is container and has sub types
  182. * @param {string} mainType
  183. * @return {boolean}
  184. */
  185. entity.hasSubTypes = function (componentType) {
  186. componentType = parseClassType(componentType);
  187. var obj = storage[componentType.main];
  188. return obj && obj[IS_CONTAINER];
  189. };
  190. entity.parseClassType = parseClassType;
  191. function makeContainer(componentType) {
  192. var container = storage[componentType.main];
  193. if (!container || !container[IS_CONTAINER]) {
  194. container = storage[componentType.main] = {};
  195. container[IS_CONTAINER] = true;
  196. }
  197. return container;
  198. }
  199. if (options.registerWhenExtend) {
  200. var originalExtend = entity.extend;
  201. if (originalExtend) {
  202. entity.extend = function (proto) {
  203. var ExtendedClass = originalExtend.call(this, proto);
  204. return entity.registerClass(ExtendedClass, proto.type);
  205. };
  206. }
  207. }
  208. return entity;
  209. }
  210. /**
  211. * @param {string|Array.<string>} properties
  212. */
  213. function setReadOnly(obj, properties) {// FIXME It seems broken in IE8 simulation of IE11
  214. // if (!zrUtil.isArray(properties)) {
  215. // properties = properties != null ? [properties] : [];
  216. // }
  217. // zrUtil.each(properties, function (prop) {
  218. // var value = obj[prop];
  219. // Object.defineProperty
  220. // && Object.defineProperty(obj, prop, {
  221. // value: value, writable: false
  222. // });
  223. // zrUtil.isArray(obj[prop])
  224. // && Object.freeze
  225. // && Object.freeze(obj[prop]);
  226. // });
  227. }
  228. exports.parseClassType = parseClassType;
  229. exports.enableClassExtend = enableClassExtend;
  230. exports.enableClassCheck = enableClassCheck;
  231. exports.enableClassManagement = enableClassManagement;
  232. exports.setReadOnly = setReadOnly;