Posts Tagged ‘CS3’
Easy form validation for Flash
As a professional Flash and Flex developer, I wrote lots of handy utilities that I use on a daily basis when developing Flash websites or Flex applications. I developed my own library containing base classes and utilities that allow me to setup Flash website projects in no time. I call it the “viplib”.
I plan to releasing some of that code. And here’s a first code snippit:
In Flex, it’s easy to do form validation using the various validator components. But for Flash, one has to write his own code. Here’s a simple form-validation class that not only checks empty fields and invalid email entries, but also highlights those fields when their content is invalid. Using this class you can validate a form and highlight the fields that are invalid with only 1 line of code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | //copyright Ward De Langhe //Very Interactive People package be.viplib.util { import flash.display.Sprite; import flash.events.FocusEvent; import flash.text.TextField; public class FormValidator { private var _target:Sprite; private var _requiredFields:Array; private var _emailFields:Array; private var _normalColor:Number; private var _invalidColor:Number; private var _requiredMessage:String; private var _invalidEmailMessage:String; public function FormValidator(target:Sprite,requiredFields:Array, emailFields:Array,normalColor:Number=0x000000,invalidColor:Number=0xff0000,requiredFieldMessage:String="required field",invalidEmailMessage:String="invalid email") { _target=target; _requiredFields=requiredFields; _emailFields=emailFields; _normalColor=normalColor; _invalidColor=invalidColor; _requiredMessage=requiredFieldMessage; _invalidEmailMessage=invalidEmailMessage; } public function set invalidMailMessage(value:String):void{ _invalidEmailMessage=value; for(var i:Number=0;i<_emailFields.length;i++){ var field:TextField=_target.getChildByName(_emailFields[i]) as TextField; if(field.text==_invalidEmailMessage){ field.text=value; } } } public function set requiredMessage(value:String):void{ _requiredMessage=value; for(var i:Number=0;i<_requiredFields.length;i++){ var field:TextField=_target.getChildByName(_requiredFields[i]) as TextField; if(field.text==_requiredMessage){ field.text=value; } } } public function validate():Boolean{ var valid:Boolean=true; for(var i:Number=0;i<_requiredFields.length;i++){ var field:TextField=_target.getChildByName(_requiredFields[i]) as TextField; if(field.text=="" || field.text== _requiredMessage || field.text==_invalidEmailMessage || (field.text.length==1 && field.text.charCodeAt(0)==13)){ field.textColor=_invalidColor; field.text=_requiredMessage; field.addEventListener(FocusEvent.FOCUS_IN,fieldFocus_handler); valid=false; } } for(i=0;i<_emailFields.length;i++){ field=_target.getChildByName(_emailFields[i]) as TextField; if(field.textColor!=_invalidColor){ if(!MailValidator.validateEmail(field.text)){ field.textColor=_invalidColor; field.text=_invalidEmailMessage; field.addEventListener(FocusEvent.FOCUS_IN,fieldFocus_handler); valid=false; } } } return valid; } private function fieldFocus_handler(evt:FocusEvent):void{ for(var i:Number=0;i<_requiredFields.length;i++){ var field:TextField=_target.getChildByName(_requiredFields[i]) as TextField; if(field.textColor==_invalidColor){ field.textColor=_normalColor; field.text=""; field.removeEventListener(FocusEvent.FOCUS_IN,fieldFocus_handler); } } for(i=0;i<_emailFields.length;i++){ field=_target.getChildByName(_emailFields[i]) as TextField; if(field.textColor==_invalidColor){ field.textColor=_normalColor; field.text=""; field.removeEventListener(FocusEvent.FOCUS_IN,fieldFocus_handler); } } } } } |
This class uses my mailvalidator utility to validate the email adresses. It’s a simple utility which checks if a e-mailaddress is valid using a regular expression.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //copyright Ward De Langhe //Very Interactive People package be.viplib.util { public class MailValidator { public static function validateEmail(str:String):Boolean { var pattern:RegExp = /(\w|[_.\-])+@((\w|-)+\.)+\w{2,4}+/; var result:Object = pattern.exec(str); if(result == null) { return false; } return true; } } } |
You can download example source code here. It’s a simple form containing a couple of required fields, and an email field. Here’s how this sample looks when compiled:
Click the “validate” button to see the validation class do it’s job.
At my day job (http://www.epyc.be), we developed a framework for rendering exercises (drag and drop, select text, multiple choice, fill in,… you name it, we got it). One of the features of this framework is font libraries on exercise level. In this way we can use different fonts and only load them when needed. If in an application we have for example 100 multiple choice questions that need font A, and only one of those questions needs font B, font B will be loaded when that specific exercise is rendered. Once loaded they are cached in memory, in case another exercise needs the same font library.
When an exercise is loaded, the first thing the base class does is loading the necessary font library in order to render the exercise. In the exercise logic, whenever we need a font, we can create one like this:
1 2 3 4 | var font:Font=FontMananger.getInstance().getFont( fontName, fontLibrary ); |
In theory, this would also allow the use of foreign character sets…. Only in theory, because when we finally needed this feature, we ran into a “little” problem.
A font library in our system is an empty swf file with some embedded fonts. We normally create these libraries by clicking “new font” in the library:


This workflow worked fine until we had to create a Polish version of one of our projects. The problem is that it is impossible to define which characters you want to embed when embedding fonts in the library. Flash only embeds a basic char set. Strangly enough, when embedding a font for a specific text field, you CAN define the extra character set :

So, it looks like the folks at Adobe simply forgot about this. We tried everything, but no success using the Flash IDE.
Eventually we had to switch to Flexbuilder to create the font libraries. Here’s how we did this:
1 2 3 4 5 6 7 8 9 10 11 12 | package { import flash.display.Sprite; import flash.text.Font; public class FontLib extends Sprite { [Embed(systemFont = "Arial", fontName = "Arial", mimeType = "application/x-font", unicodeRange = "U+0-U+00FF,U+0100-U+01FF,U+0200-U+02FF" )] public var DefaultFont:Class; public function FontLib() { } } } |
As you can see, in Flex we can define the Unicode ranges that need to be embedded. In this way we can create font libraries containing Baltic or Cyrillic character sets, or even Chinese!
There’s also a little problem with this workflow: Since the DefaultFont class is defined inside the FontLib application class, the compiler internally changes the class name to “FontLib_DefaultFont”. After loading this font library, and we want to create an instance of a certain font class, we have to add “FontLib_” before the class name.
Conclusion: Adobe, please add functionality to the Flash IDE so we can define extra character sets to be embedded when embedding fonts in the library!
If anyone knows a way of doing this by using the Flash IDE, please let me know.
Some time ago, for my work at Epyc, I ran into a “little” problem: I had to use old Flash animations and load these into a Flex application. When you load an old Flash animation into Flash 9, it becomes an instance of the AVM1Movie class.
The problem with this is that AVM1Movie objects can use methods and properties inherited from the DisplayObject class, but no interoperability (such as calling methods or using parameters) between the AVM1Movie object and AVM2 objects is allowed. I needed to be able to control these animations trough actionscript, and that simply wasn’t possible.
Fortunately, there was no actionscript in the old animation files, so opening the original .fla, and changing the publish profile to Flash 9, solved this problem. But… then I discovered that there were 2500 fla’s that needed to be updated this way. Horror! No way I was going to open all these flash files manually, update the settings and save them.
Flash comes with a javascript API, which allows you to script commands. So you are able to write your own “plugins”. I’ve never used JSFL before, so I did some research first. I found these blogposts on the web, that both covered a part of my problem:
- http://www.stevensacks.net/2008/03/26/using-jsfl-to-change-publish-profile-settings-v2/
- http://miian.com/en/node/399
Throwing them together, and adding some of my own magic… I ended up with this script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | var tempDoc=undefined; if(fl.documents.length==0){ tempDoc=fl.createDocument(); } xui = fl.getDocumentDOM().xmlPanel(fl.configURI + "Commands/AutoConvertToFlash9.xml"); if(tempDoc){ fl.closeDocument(tempDoc); } var exportlog=""; if(xui.dismiss=="accept"){ var searchSubDir=xui.searchSubDir; var folder=xui.path; if(folder.substr(0,8)!="file:///"){ folder="file:///"+folder.split(":").join("|").split("\\").join("/"); } if(folder.substr(folder.length-1,1)!="/"){ folder=folder+"/"; } } exportlist=new Array(); checkFolder(folder,exportlist,searchSubDir); var totaltime=0; if(exportlist.length==0){ alert("No file need to publish."); }else{ if(confirm(exportlist.length+" files will be updated and published")){ for(var i=0;i<exportlist.length;i++){ setPublishProfileSettings(exportlist[i]); //FLfile.write("file:///c:/exportlog.txt", exportlog);//uncomment if you want to log all files } } } function checkFolder(folder,list,checkSub,pre){ if(pre==undefined){ pre=""; } var flas=FLfile.listFolder(folder+"*.fla","files"); for(var i=0;i<flas.length;i++){ list.push(folder+flas[i]); } if(checkSub=="true"){ var flds=FLfile.listFolder(folder,"directories"); for(var i=0;i<flds.length;i++){ checkFolder(folder+flds[i]+"/",list,checkSub,pre+" "); } } } function setPublishProfileSettings(fileURI) { if (fl.fileExists(fileURI)) { var xml, from, to, delta; var doc=fl.openDocument(fileURI); var fileName = fileURI.split("/").pop(); var folderPath = fileURI.split(fileName)[0]; fileName = fileName.split(".")[0]; var pPath = folderPath + "/_Profile_.xml"; fl.getDocumentDOM().exportPublishProfile(pPath); xml = FLfile.read(pPath); var swfpath=fileName+".swf"; from = xml.indexOf("<flashFileName>"); to = xml.indexOf("</flashFileName>"); delta = xml.substring(from, to); xml = xml.split(delta).join("<flashFileName>"+swfpath); from = xml.indexOf("<Version>"); to = xml.indexOf("</Version>"); delta = xml.substring(from, to); xml = xml.split(delta).join("<Version>9"); from = xml.indexOf("<ActionScriptVersion>"); to = xml.indexOf("</ActionScriptVersion>"); delta = xml.substring(from, to); xml = xml.split(delta).join("<ActionScriptVersion>3"); from = xml.indexOf("<AS3PackagePaths>"); to = xml.indexOf("</AS3PackagePaths>"); delta = xml.substring(from, to); var classPath = "./"; if (fileName.indexOf("/") > -1) { classPath = ""; var splitPath = fileName.split("/"); splitPath.length--; var i = splitPath.length; while (i--) { classPath += "../"; } } xml = xml.split(delta).join("<AS3PackagePaths>" + classPath + "classes"); FLfile.write(pPath, xml); fl.getDocumentDOM().importPublishProfile(pPath); fl.saveDocument( doc); fl.getDocumentDOM().publish(); FLfile.remove(pPath); fl.closeDocument(doc); exportlog+="updated and exported " + fileURI+"\r\n"; } } |
One small problem though. Flash warns you when you try to save an old .fla as a newer version. So, when I ran the script the first time, Flash gave a warning for each of the .fla files. This ment I had to press “ok” 2500 times! Luckily, this is just a setting. This can be turned off under “preferences -> Alerts”.
So, how do you use this?:
- Download the files here
- Extract the script, and place the script and the GUI under “Documents and Settings/[Your login id]/Local Settings/Application Data/Macromedia/[Your flash version]/[language]/Configuration/Commands/”
- Run flash, you will see a new command named “AutoConvertToFlash9″ in the command menu.
- Run the script, everything else should be obvious
I only tested this in CS3, but I think it will work fine under CS4 too. If you are a CS4 user, and this doesn’t work, please let me know and I’ll look into it.

