package sk.yoz.data { import flash.display.Loader; import flash.display.LoaderInfo; import flash.events.Event; import flash.events.IOErrorEvent; import flash.events.SecurityErrorEvent; import flash.net.URLRequest; import flash.system.ApplicationDomain; import flash.system.LoaderContext; import flash.utils.getDefinitionByName; /** * XMLSkin class makes runtime settings/skinning easy * get latest version and examples on: * http://blog.yoz.sk/2009/10/xml-skin/ * updated: 2010-03-07 */ public class XMLSkin extends Object { protected var assets:Object; protected var assetsSource:String; protected var root:Object; protected var skin:XML; protected var autoApply:Boolean; protected var loader:Loader; public function XMLSkin(root:Object, skin:XML) { super(); this.root = root; this.skin = skin; } public function apply():void { XMLSkin.apply(root, skin, loader); } public static function apply(root:Object, skin:XML, assetsLoader:Loader = null):void { if(!skin) return; for each(var a:XML in skin.@*) doApply(root, a.name(), a.toString(), assetsLoader); var children:XMLList = skin.children(); if(!children.length()) return; var childName:String; for each(var child:XML in children) { childName = child.name(); if(!childName) continue; if(child.text().toString()) doApply(root, childName, child.text().toString(), assetsLoader); if(root.hasOwnProperty(childName)) XMLSkin.apply(root[childName], child, assetsLoader); else if(getDefinitionByName(childName)) XMLSkin.apply(getDefinitionByName(childName), child, assetsLoader); } } protected static function doApply(root:Object, attribute:String, value:String, assetsLoader:Loader = null):void { var name:String = attributeToName(attribute); if(isStyle(attribute)) root.setStyle(name, castStyle(root, value, attribute, assetsLoader)); else if(root.hasOwnProperty(name)) root[name] = castProperty(root, value, attribute, assetsLoader); } protected static function castProperty(object:Object, value:String, attribute:String, assetsLoader:Loader = null):* { var name:String = attributeToName(attribute); switch(typeof object[name]) { case "boolean": return Boolean(value.toLowerCase() == "true"); case "number": case "string": return value; default: return getClassFromLibrary(value, assetsLoader) || getClassFromAssets(value, assetsLoader) || value; } } protected static function castStyle(object:Object, value:String, attribute:String, assetsLoader:Loader = null):* { var name:String = attributeToName(attribute); if(!assetsLoader && isAsset(attribute)) return null; if(isAsset(attribute)) return getClassFromLibrary(value, assetsLoader) || getClassFromAssets(value, assetsLoader); return value; } protected static function getClassFromLibrary(value:String, assetsLoader:Loader):Class { var assetClass:Class; try { assetClass = getDefinitionByName(value) as Class; } catch(error:Error){} return assetClass; } protected static function getClassFromAssets(value:String, assetsLoader:Loader):Class { var assetClass:Class; try { var applicationDomain:ApplicationDomain = assetsLoader.contentLoaderInfo.applicationDomain; var assetsClass:Class = applicationDomain.getDefinition("Assets") as Class; assetClass = assetsClass[value]; } catch(error:Error){} return assetClass; } public function loadAssets(assetsSource:String):Loader { this.assetsSource = assetsSource; loader = new Loader(); var info:LoaderInfo = loader.contentLoaderInfo; info.addEventListener(Event.COMPLETE, assetsComplete, false, int.MAX_VALUE); info.addEventListener(IOErrorEvent.IO_ERROR, assetsIOError, false, int.MAX_VALUE); info.addEventListener(SecurityErrorEvent.SECURITY_ERROR, assetsSecurityError, false, int.MAX_VALUE); var request:URLRequest = new URLRequest(assetsSource); var context:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain); loader.load(request, context); return loader; } protected function assetsComplete(event:Event):void { apply(); } protected function assetsIOError(event:IOErrorEvent):void { } protected function assetsSecurityError(event:SecurityErrorEvent):void { } protected static function isStyle(attribute:String):Boolean { attribute = stripAsset(attribute); return attribute.toLowerCase().substr(0, 6) == "style."; } protected static function stripStyle(attribute:String):String { if(isStyle(attribute)) return attribute.substr(6); return attribute; } protected static function isAsset(attribute:String):Boolean { return attribute.toLowerCase().substr(0, 6) == "asset."; } protected static function stripAsset(attribute:String):String { if(isAsset(attribute)) return attribute.substr(6); return attribute; } public static function attributeToName(attribute:String):String { return stripStyle(stripAsset(attribute)); } } }