1 /** 2 * com.sekati.utils.ClassUtils 3 * @version 2.2.0 4 * @author jason m horwitz | sekati.com 5 * Copyright (C) 2007 jason m horwitz, Sekat LLC. All Rights Reserved. 6 * Released under the MIT License: http://www.opensource.org/licenses/mit-license.php 7 */ 8 9 import com.sekati.core.KeyFactory; 10 11 /** 12 * Static class for wrapping various Class utilities. For example linking 'extend MovieClip' type 13 * classes to MovieClips thru attachMovie, createEmptyMovieClip or MovieClip Instances on stage.<br/><br/> 14 * 15 * An initObject param is available in methods: {@link #createEmptyMovieClip}, {@link #attachMovie} 16 * and {@link #attachClass}. _depth is a custom initObject param which will set the clip to this depth 17 * regardless of method but *will not* store _depth as a MovieClip property; use getDepth if needed. 18 * 19 * {@code Example Class: 20 * class com.sekati.Test extends MovieClip { 21 * public function Test(){ 22 * trace("Test Class instantiated on: "+this._name); 23 * } 24 * } 25 * } 26 * 27 * @TODO Add an AS2 Class index getter for debugging purposes. 28 */ 29 class com.sekati.utils.ClassUtils { 30 31 /** 32 * create a movieclip with linked class (various init options) 33 * @param classRef (Function) reference to class to attach 34 * @param target (MovieClip) target scope to create MovieClip 35 * @param instanceName (String) created MovieClip instance name 36 * @param initObject (Object) object of properties to create MovieClip with. Depth will automatically be created if none is specified 37 * @return MovieClip 38 * {@code Usage: 39 * var mc0:MovieClip = ClassUtils.createEmptyMovieClip (com.sekati.Test, this, "mc0"); 40 * var mc0:MovieClip = ClassUtils.createEmptyMovieClip (com.sekati.Test, _root, "mc0", {_depth: 100, _x:25, _y:25}); 41 * var mc0:MovieClip = ClassUtils.createEmptyMovieClip (com.sekati.Test, this, "mc0", {_x:25, _y:25}); 42 * } 43 */ 44 public static function createEmptyMovieClip(classRef:Function, target:MovieClip, instanceName:String, initObject:Object):MovieClip { 45 var depth:Number = (!initObject._depth) ? target.getNextHighestDepth( ) : initObject._depth; 46 var mc:MovieClip = target.createEmptyMovieClip( instanceName, depth ); 47 mc.__proto__ = classRef.prototype; 48 if (initObject) { 49 for (var i in initObject) { 50 if (i != "_depth") { 51 mc[i] = initObject[i]; 52 } 53 } 54 } 55 classRef.apply( mc ); 56 KeyFactory.inject( mc ); 57 return mc; 58 } 59 60 /** 61 * attach a MovieClip from library and extend with class (various init options) 62 * @param classRef (Function) reference to class to attach 63 * @param target (MovieClip) target scope to create MovieClip 64 * @param idName (String) linkage id for exported MovieClip in library 65 * @param instanceName (String) created MovieClip instance name 66 * @param initObject (Object) object of properties to create MovieClip with. Depth will automatically be created if none is specified 67 * @return MovieClip 68 * {@code Usage: 69 * var mc1:MovieClip = ClassUtils.attachMovie (com.sekati.Test, _root, "linkedMc", "mc1"); 70 * var mc1:MovieClip = ClassUtils.attachMovie (com.sekati.Test, _root, "linkedMc", "mc1", {_x:50, _y:50}); 71 * var mc1:MovieClip = ClassUtils.attachMovie (com.sekati.Test, _root, "linkedMc", "mc1", {_depth:200, _x:50, _y:50}); 72 * } 73 */ 74 public static function attachMovie(classRef:Function, target:MovieClip, idName:String, instanceName:String, initObject:Object):MovieClip { 75 var depth:Number = (!initObject._depth) ? target.getNextHighestDepth( ) : initObject._depth; 76 var mc:MovieClip = target.attachMovie( idName, instanceName, depth, initObject ); 77 mc.__proto__ = classRef.prototype; 78 if (mc._depth) { 79 delete mc._depth; 80 } 81 classRef.apply( mc ); 82 KeyFactory.inject( mc ); 83 return mc; 84 } 85 86 /** 87 * Attach a movie from a DLL swf's library (loads dll then attaches requested movie). 88 * NOTE: you should insert a delay between your callback and methods calls in the shared library as it initializes. 89 * @param dll (Function) url of the dll.swf which contains exported assets in its library 90 * @param target (MovieClip) target scope to attachMovie within 91 * @param idName (String) linkage id for exported MovieClip in library 92 * @param instanceName (String) created MovieClip instance name 93 * @param initObject (Object) object of properties to create MovieClip with. Depth will automatically be created if none is specified 94 * @param cb (Function) callback function to fire when dll has been loaded and clip attached 95 * @return MovieClip 96 * {@code Usage: 97 * var mc0:MovieClip = ClassUtils.attachDllMovie("dll.swf", _root, "myDllExportedItem", "mc0", {_x:50, _y:50, _depth:20}, myCallBackFn); 98 * } 99 */ 100 public static function attachDllMovie(dll:String, target:MovieClip, idName:String, instanceName:String, initObject:Object, cb:Function):MovieClip { 101 var depth:Number = (!initObject._depth) ? target.getNextHighestDepth( ) : initObject._depth; 102 var mc:MovieClip = target.createEmptyMovieClip( instanceName, depth ); 103 var mcLoader:MovieClipLoader = new MovieClipLoader( ); 104 var onDLLLoaded:Function = function():Void { 105 mcLoader.removeListener( listener ); 106 if(cb) _global["setTimeout"]( this, "cb", 50 ); 107 }; 108 var listener:Object = new Object( ); 109 listener.onLoadInit = function(mc:MovieClip):Void { 110 mc.attachMovie( idName, instanceName, mc.getNextHighestDepth( ) ); 111 target[instanceName] = target[instanceName][instanceName]; 112 if (initObject) { 113 for (var i in initObject) { 114 if (i != "_depth") mc[i] = initObject[i]; 115 } 116 } 117 onDLLLoaded( ); 118 }; 119 mcLoader.addListener( listener ); 120 mcLoader.loadClip( dll, mc ); 121 return mc; 122 } 123 124 /** 125 * extend a MovieClip instance (on stage) with class (various init options) 126 * @param classRef (Function) reference to class to attach 127 * @param target (MovieClip) target scope to create MovieClip 128 * @param initObject (Object) object of properties to create MovieClip with. Depth will automatically be created if none is specified 129 * @return MovieClip 130 * {@code Usage: 131 * var mc2:MovieClip = ClassUtils.attachClass (com.sekati.Test, mc2); 132 * var mc2:MovieClip = ClassUtils.attachClass (com.sekati.Test, _root.mc2, {_x:75, _y:75}); 133 * var mc2:MovieClip = ClassUtils.attachClass (com.sekati.Test, mc2, {_depth:300, _x:75, _y:75}); 134 * } 135 */ 136 public static function attachClass(classRef:Function, target:MovieClip, initObject:Object):MovieClip { 137 var mc:MovieClip = target; 138 mc.__proto__ = classRef.prototype; 139 if (initObject) { 140 for (var i in initObject) { 141 if (i != "_depth") { 142 mc[i] = initObject[i]; 143 } else { 144 target.swapDepths( initObject[i] ); 145 } 146 } 147 } 148 classRef.apply( mc ); 149 KeyFactory.inject( mc ); 150 return target; 151 } 152 153 /** 154 * Create and return a new instance of a defined class 155 * @param classRef (Function) reference to full class namespace 156 * @param args (Array) array of constructor arguments 157 * @return Object - instantiated class object 158 * {@code Usage: 159 * var o:Point = ClassUtils.createInstance (com.sekati.geom.Point, [15,50]); 160 * } 161 */ 162 public static function createInstance(classRef:Function, args:Array):Object { 163 var o:Object = {__constructor__:classRef, __proto__:classRef.prototype}; 164 classRef.apply( o, args ); 165 KeyFactory.inject( o ); 166 return o; 167 } 168 169 /** 170 * Create and return a new instance of a defined class without 171 * invoking its constructor 172 * @param classRef (Function) reference to full class namespace 173 * @return Object - class object 174 * {@code Usage: 175 * var scr:Scroll = ClassUtils.createCleanInstance(com.sekati.ui.Scroll); 176 * } 177 */ 178 public static function createCleanInstance(classRef:Function):Object { 179 var o:Object = new Object; 180 o.__proto__ = classRef.prototype; 181 o.__constructor__ = classRef; 182 KeyFactory.inject( o ); 183 return o; 184 } 185 186 /** 187 * Check if a subclass is extended by a superclass 188 * @param subclassRef (Function) reference to the full subclass namespace 189 * @param superclassRef (Function) reference to the full superclass namespace 190 * @return Boolean 191 * {@code Usage: 192 * trace(ClassUtils.isSubclassOf(com.sekati.display.AbstractClip, com.sekati.display.CoreClip)); // returns: true 193 * } 194 */ 195 public static function isSubclassOf(subclassRef:Function, superclassRef:Function):Boolean { 196 var o:Object = subclassRef.prototype; 197 while(o !== undefined) { 198 o = o.__proto__; 199 if(o === superclassRef.prototype) { 200 return true; 201 } 202 } 203 return false; 204 } 205 206 /** 207 * Check if a class implements an interface 208 * @param classRef (Function) reference to the full class namespace 209 * @param interfaceRef (Function) reference to the full interface namespace 210 * @return Boolean 211 * {@code Usage: 212 * trace(ClassUtils.isImplementationOf(com.sekati.display.CoreClip, com.sekati.display.ICoreClip)); // returns: true 213 * } 214 */ 215 public static function isImplementationOf(classRef:Function, interfaceRef:Function):Boolean { 216 // interface will not be in prototype chain 217 if(isSubclassOf( classRef, interfaceRef )) { 218 return false; 219 } 220 // if an instance it is not extended, the class has to be an instance of it 221 return (createCleanInstance( classRef ) instanceof interfaceRef); 222 } 223 224 private function ClassUtils() { 225 } 226 }