281 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
 | |
| /*
 | |
| * Licensed to the Apache Software Foundation (ASF) under one
 | |
| * or more contributor license agreements.  See the NOTICE file
 | |
| * distributed with this work for additional information
 | |
| * regarding copyright ownership.  The ASF licenses this file
 | |
| * to you under the Apache License, Version 2.0 (the
 | |
| * "License"); you may not use this file except in compliance
 | |
| * with the License.  You may obtain a copy of the License at
 | |
| *
 | |
| *   http://www.apache.org/licenses/LICENSE-2.0
 | |
| *
 | |
| * Unless required by applicable law or agreed to in writing,
 | |
| * software distributed under the License is distributed on an
 | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | |
| * KIND, either express or implied.  See the License for the
 | |
| * specific language governing permissions and limitations
 | |
| * under the License.
 | |
| */
 | |
| 
 | |
| var _config = require("../config");
 | |
| 
 | |
| var __DEV__ = _config.__DEV__;
 | |
| 
 | |
| var zrUtil = require("zrender/lib/core/util");
 | |
| 
 | |
| /*
 | |
| * Licensed to the Apache Software Foundation (ASF) under one
 | |
| * or more contributor license agreements.  See the NOTICE file
 | |
| * distributed with this work for additional information
 | |
| * regarding copyright ownership.  The ASF licenses this file
 | |
| * to you under the Apache License, Version 2.0 (the
 | |
| * "License"); you may not use this file except in compliance
 | |
| * with the License.  You may obtain a copy of the License at
 | |
| *
 | |
| *   http://www.apache.org/licenses/LICENSE-2.0
 | |
| *
 | |
| * Unless required by applicable law or agreed to in writing,
 | |
| * software distributed under the License is distributed on an
 | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | |
| * KIND, either express or implied.  See the License for the
 | |
| * specific language governing permissions and limitations
 | |
| * under the License.
 | |
| */
 | |
| var TYPE_DELIMITER = '.';
 | |
| var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';
 | |
| /**
 | |
|  * Notice, parseClassType('') should returns {main: '', sub: ''}
 | |
|  * @public
 | |
|  */
 | |
| 
 | |
| function parseClassType(componentType) {
 | |
|   var ret = {
 | |
|     main: '',
 | |
|     sub: ''
 | |
|   };
 | |
| 
 | |
|   if (componentType) {
 | |
|     componentType = componentType.split(TYPE_DELIMITER);
 | |
|     ret.main = componentType[0] || '';
 | |
|     ret.sub = componentType[1] || '';
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| /**
 | |
|  * @public
 | |
|  */
 | |
| 
 | |
| 
 | |
| function checkClassType(componentType) {
 | |
|   zrUtil.assert(/^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType), 'componentType "' + componentType + '" illegal');
 | |
| }
 | |
| /**
 | |
|  * @public
 | |
|  */
 | |
| 
 | |
| 
 | |
| function enableClassExtend(RootClass, mandatoryMethods) {
 | |
|   RootClass.$constructor = RootClass;
 | |
| 
 | |
|   RootClass.extend = function (proto) {
 | |
|     var superClass = this;
 | |
| 
 | |
|     var ExtendedClass = function () {
 | |
|       if (!proto.$constructor) {
 | |
|         superClass.apply(this, arguments);
 | |
|       } else {
 | |
|         proto.$constructor.apply(this, arguments);
 | |
|       }
 | |
|     };
 | |
| 
 | |
|     zrUtil.extend(ExtendedClass.prototype, proto);
 | |
|     ExtendedClass.extend = this.extend;
 | |
|     ExtendedClass.superCall = superCall;
 | |
|     ExtendedClass.superApply = superApply;
 | |
|     zrUtil.inherits(ExtendedClass, this);
 | |
|     ExtendedClass.superClass = superClass;
 | |
|     return ExtendedClass;
 | |
|   };
 | |
| }
 | |
| 
 | |
| var classBase = 0;
 | |
| /**
 | |
|  * Can not use instanceof, consider different scope by
 | |
|  * cross domain or es module import in ec extensions.
 | |
|  * Mount a method "isInstance()" to Clz.
 | |
|  */
 | |
| 
 | |
| function enableClassCheck(Clz) {
 | |
|   var classAttr = ['__\0is_clz', classBase++, Math.random().toFixed(3)].join('_');
 | |
|   Clz.prototype[classAttr] = true;
 | |
| 
 | |
|   Clz.isInstance = function (obj) {
 | |
|     return !!(obj && obj[classAttr]);
 | |
|   };
 | |
| } // superCall should have class info, which can not be fetch from 'this'.
 | |
| // Consider this case:
 | |
| // class A has method f,
 | |
| // class B inherits class A, overrides method f, f call superApply('f'),
 | |
| // class C inherits class B, do not overrides method f,
 | |
| // then when method of class C is called, dead loop occured.
 | |
| 
 | |
| 
 | |
| function superCall(context, methodName) {
 | |
|   var args = zrUtil.slice(arguments, 2);
 | |
|   return this.superClass.prototype[methodName].apply(context, args);
 | |
| }
 | |
| 
 | |
| function superApply(context, methodName, args) {
 | |
|   return this.superClass.prototype[methodName].apply(context, args);
 | |
| }
 | |
| /**
 | |
|  * @param {Object} entity
 | |
|  * @param {Object} options
 | |
|  * @param {boolean} [options.registerWhenExtend]
 | |
|  * @public
 | |
|  */
 | |
| 
 | |
| 
 | |
| function enableClassManagement(entity, options) {
 | |
|   options = options || {};
 | |
|   /**
 | |
|    * Component model classes
 | |
|    * key: componentType,
 | |
|    * value:
 | |
|    *     componentClass, when componentType is 'xxx'
 | |
|    *     or Object.<subKey, componentClass>, when componentType is 'xxx.yy'
 | |
|    * @type {Object}
 | |
|    */
 | |
| 
 | |
|   var storage = {};
 | |
| 
 | |
|   entity.registerClass = function (Clazz, componentType) {
 | |
|     if (componentType) {
 | |
|       checkClassType(componentType);
 | |
|       componentType = parseClassType(componentType);
 | |
| 
 | |
|       if (!componentType.sub) {
 | |
|         storage[componentType.main] = Clazz;
 | |
|       } else if (componentType.sub !== IS_CONTAINER) {
 | |
|         var container = makeContainer(componentType);
 | |
|         container[componentType.sub] = Clazz;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return Clazz;
 | |
|   };
 | |
| 
 | |
|   entity.getClass = function (componentMainType, subType, throwWhenNotFound) {
 | |
|     var Clazz = storage[componentMainType];
 | |
| 
 | |
|     if (Clazz && Clazz[IS_CONTAINER]) {
 | |
|       Clazz = subType ? Clazz[subType] : null;
 | |
|     }
 | |
| 
 | |
|     if (throwWhenNotFound && !Clazz) {
 | |
|       throw new Error(!subType ? componentMainType + '.' + 'type should be specified.' : 'Component ' + componentMainType + '.' + (subType || '') + ' not exists. Load it first.');
 | |
|     }
 | |
| 
 | |
|     return Clazz;
 | |
|   };
 | |
| 
 | |
|   entity.getClassesByMainType = function (componentType) {
 | |
|     componentType = parseClassType(componentType);
 | |
|     var result = [];
 | |
|     var obj = storage[componentType.main];
 | |
| 
 | |
|     if (obj && obj[IS_CONTAINER]) {
 | |
|       zrUtil.each(obj, function (o, type) {
 | |
|         type !== IS_CONTAINER && result.push(o);
 | |
|       });
 | |
|     } else {
 | |
|       result.push(obj);
 | |
|     }
 | |
| 
 | |
|     return result;
 | |
|   };
 | |
| 
 | |
|   entity.hasClass = function (componentType) {
 | |
|     // Just consider componentType.main.
 | |
|     componentType = parseClassType(componentType);
 | |
|     return !!storage[componentType.main];
 | |
|   };
 | |
|   /**
 | |
|    * @return {Array.<string>} Like ['aa', 'bb'], but can not be ['aa.xx']
 | |
|    */
 | |
| 
 | |
| 
 | |
|   entity.getAllClassMainTypes = function () {
 | |
|     var types = [];
 | |
|     zrUtil.each(storage, function (obj, type) {
 | |
|       types.push(type);
 | |
|     });
 | |
|     return types;
 | |
|   };
 | |
|   /**
 | |
|    * If a main type is container and has sub types
 | |
|    * @param  {string}  mainType
 | |
|    * @return {boolean}
 | |
|    */
 | |
| 
 | |
| 
 | |
|   entity.hasSubTypes = function (componentType) {
 | |
|     componentType = parseClassType(componentType);
 | |
|     var obj = storage[componentType.main];
 | |
|     return obj && obj[IS_CONTAINER];
 | |
|   };
 | |
| 
 | |
|   entity.parseClassType = parseClassType;
 | |
| 
 | |
|   function makeContainer(componentType) {
 | |
|     var container = storage[componentType.main];
 | |
| 
 | |
|     if (!container || !container[IS_CONTAINER]) {
 | |
|       container = storage[componentType.main] = {};
 | |
|       container[IS_CONTAINER] = true;
 | |
|     }
 | |
| 
 | |
|     return container;
 | |
|   }
 | |
| 
 | |
|   if (options.registerWhenExtend) {
 | |
|     var originalExtend = entity.extend;
 | |
| 
 | |
|     if (originalExtend) {
 | |
|       entity.extend = function (proto) {
 | |
|         var ExtendedClass = originalExtend.call(this, proto);
 | |
|         return entity.registerClass(ExtendedClass, proto.type);
 | |
|       };
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return entity;
 | |
| }
 | |
| /**
 | |
|  * @param {string|Array.<string>} properties
 | |
|  */
 | |
| 
 | |
| 
 | |
| function setReadOnly(obj, properties) {// FIXME It seems broken in IE8 simulation of IE11
 | |
|   // if (!zrUtil.isArray(properties)) {
 | |
|   //     properties = properties != null ? [properties] : [];
 | |
|   // }
 | |
|   // zrUtil.each(properties, function (prop) {
 | |
|   //     var value = obj[prop];
 | |
|   //     Object.defineProperty
 | |
|   //         && Object.defineProperty(obj, prop, {
 | |
|   //             value: value, writable: false
 | |
|   //         });
 | |
|   //     zrUtil.isArray(obj[prop])
 | |
|   //         && Object.freeze
 | |
|   //         && Object.freeze(obj[prop]);
 | |
|   // });
 | |
| }
 | |
| 
 | |
| exports.parseClassType = parseClassType;
 | |
| exports.enableClassExtend = enableClassExtend;
 | |
| exports.enableClassCheck = enableClassCheck;
 | |
| exports.enableClassManagement = enableClassManagement;
 | |
| exports.setReadOnly = setReadOnly; | 
