By jberman on November 12, 2009 at 2:00 pm.
Filed under: Actionscript, IE
With a recent update either in IE8 or within the Flash Player, I noticed a lot of our AS2 Flash sites that load external assets were failing; either the asset wouldn’t load or it wouldn’t properly report its EVENT_LOADED event. It was happening sporadically, and usually when a lot of external assets were being loaded at the same time.
When I looked into this further I found this line of code within the “run” function that executes on an interval:
if (mc_clip.getBytesTotal( ) < 0)
{
// failed to load
bool_isLoaded = false;
clearInterval( int_interval );
dispatchEvent( new Event( this, EVENT_FAILED ) );
}
To fix it, I simply added a counter. It now checks to see if getBytesTotal( ) returns negative 10 times before finally reporting EVENT_FAILED.
However, in IE, mc_clip.getBytesTotal( ) is returning a negative number - even though the clip exists and is still loading!
Updating this code to include a wait counter to make sure this the number is still negative after 10 tries seems to have fixed it.
if (mc_clip.getBytesTotal( ) < 0)
{
if (int_wait > 10)
{
// failed to load
bool_isLoaded = false;
clearInterval( int_interval );
dispatchEvent( new Event( this, EVENT_FAILED ) );
}
int_wait++;
}
By rgriffith on July 17, 2009 at 4:08 pm.
Filed under: Actionscript, Flex, Frameworks, Languages
In a flex app I’m building, I have two dates a user needs to put in for an event. I needed a way to make sure the end date was not before the start date. Now, I know this is pretty common sense for a user to be able to do this but you never can tell. At any rate, I needed a custom validator for this to take two dates and compare them to make sure that the end date was not before the start date when the validations occurred.
After doing some research on the Google to find ways to get me started, I came up with the following as the fruit of my labor. Please note that the comments give reference to the articles that I utilized in building this validtor.
////////////////////////////////////////////////////////////////////////////////
// Based loosley on examples found in the following places:
//
// How to Validate a Date Range in Flex:
// (Basic idea for comparing a given date to a pre-defined range. This object did not meet my needs exactly so I used this as a starting point.)
// http://www.davidortinau.com/blog/how_to_validate_a_date_range_in_flex/
//
//
// How to Compare Two Dates in ActionScript 3:
// (Shows comparing dates as Numbers)
// http://userflex.wordpress.com/2008/09/11/as3-date-compare/
//
// Flex: How do you validate 2 password fields to make sure they match?
// (Shows how to get two fields to validate, makes use of the getValueFromSource() method.)
// http://stackoverflow.com/questions/508696/flex-how-do-you-validate-2-password-fields-to-make-sure-they-match
//
// Actionscript 3 - Fastest way to parse yyyy-mm-dd hh:mm:ss to a Date object?
// (Ran into trouble on getting my dates to parse correctly given the yyyy-mm-dd format, this article pointed to a solution)
// http://stackoverflow.com/questions/3163/actionscript-3-fastest-way-to-parse-yyyy-mm-dd-hhmmss-to-a-date-object
////////////////////////////////////////////////////////////////////////////////
package com.wg.utility
{
import mx.validators.DateValidator;
import mx.validators.ValidationResult;
public class StartEndDateValidation extends DateValidator
{
private var _startDateSource:Object;
private var _startDateProperty:String;
public function StartEndDateValidation()
{
super();
}
public function set StartDateSource(value:Object): void
{
_startDateSource = value;
}
public function set StartDateProperty(value:String):void
{
_startDateProperty = value;
}
override protected function doValidation(value:Object):Array {
// Create an array to return validator results
var validatorResults:Array = new Array();
// Call base doValidation() this assures EndDate (source) is correctly validated as a date.
validatorResults = super.doValidation(value.enddate);
// Return if validation has errors.
if (validatorResults.length > 0) {
return validatorResults;
}
if (String(value).length == 0) {
return validatorResults;
}
// Use castDate to properly cast the date's text property into a Date object.
var startDate:Date = castDate(value.startdate);
var endDate:Date = castDate(value.enddate);
var startDateTimeStamp:Number = startDate.getTime();
var endDateTimeStamp:Number = endDate.getTime();
if (endDateTimeStamp < startDateTimeStamp) {
validatorResults.push(new ValidationResult(true, null, "Invalid Date Range", "End Date is before Start Date"));
return validatorResults;
}
return validatorResults;
}
override protected function getValueFromSource():Object
{
var value:Object = {};
value.enddate = super.getValueFromSource();
if (_startDateSource && _startDateProperty) {
value.startdate = _startDateSource[_startDateProperty];
}
return value;
}
private function castDate(dateString:String):Date {
if ( dateString == null )
return null;
if ( dateString.length != 10 && dateString.length != 19)
return null;
dateString = dateString.replace("-", "/");
return new Date(Date.parse( dateString ));
}
}
}
To implement this in my MXML, I needed to put in the following code. In my component declaration, I needed the following namespace so I could reference to it as a validator.
...
The fields I wanted to validate are illustrated in the following snippet below:
...
...
Make note in the above code that the format string for each field is "YYYY-MM-DD." I did this for ease of entry into my database. However, this tripped me up when trying to get an actual date object parsed in so I could use it for comparison. That is the reason for the function castDate() in the validator.
The validator array grouping I used for the component listed below shows how the validator references both the start date and the end date. The way this validator works is the validation is bound to the endDate field and the startDate is referenced by the attributes "StartDateSource" and "StartDateProperty." In addition, the endDate is also validated as a valid date by the standard DateValidator method. For validating the startDate field, I used a standard DateValidator reference.
Finally, the validation is executed (normally via a button click) with the following code:
var results:Array = Validator.validateAll(validators);
// if any of the fields were not valid
if (results.length > 0) {
return;
}
By jberman on June 25, 2009 at 12:09 pm.
Filed under: Actionscript
I’m building a Flash application for a client which displays a question, waits for the user to absorb it, then disappears, finally showing the various answer choices.
Its been difficult coming to a happy medium when deciding how long it should display the question and make sure the user has enough time to read and absorb its information.
I’ve come to the conclusion that it takes a person one tenth a second for each character to properly read and absorb the sentence before it disappears.
Therefore, you should have taken no longer than 57.5 seconds to read this blog post!
By jberman on June 3, 2009 at 9:30 am.
Filed under: Actionscript
I searched forever on trying to find a good way to preload an external SWF in AS3 while passing through external FlashVars. I finally saw this post and it worked perfectly!
http://www.zedia.net/2008/external-preloader-more-complex-cases/
The trick is writing an Interface – in this case it’s a way of having the preloader call the init function of the main document class without requiring all of the internal linked assets of the SWF. The main document class then implements the interface (shown below).
So I just wrote an Interface that has an init() method with each of my FlashVars as arguments:
MyFlashApp_Interface.as
package {
public interface MyFlashApp_Interface{
function init(externalArg1:String, externalArg2:String):void;
}
}
Then in my preloader I can import it and use it for casting. This can be done in a frame script.
MyFlashApp_loader.fla (Frame 1 Script)
import MyFlashApp_Interface;
var l:Loader = new Loader();
l.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, loop);
l.contentLoaderInfo.addEventListener(Event.COMPLETE, done);
l.load(new URLRequest("MyFlashApp.swf"));
function loop(e:ProgressEvent):void
{
var perc:Number = e.bytesLoaded / e.bytesTotal;
loadBar.gotoAndStop(Math.ceil(perc*100));
}
function done(e:Event):void
{
// cast the loader content as MyFlashApp_Interface interface
var mainContent:MyFlashApp_Interface = MyFlashApp_Interface(l.content);
addChild(Sprite(mainContent) );
mainContent.init( String(root.loaderInfo.parameters.externalArg1),
String(root.loaderInfo.parameters.externalArg2) )
}
stop();
Then in my main class, I implement the interface and have some extra stuff in the constructor so it will initialize correctly when placed on the stage using addChild. Also I put in a check to prevent the init() function from being called more than once:
MyFlashApp.as
public class MyFlashApp extends Sprite implements MyFlashApp_Interface {
public var externalArg1:String="default_value";
public var externalArg2:String="default_value";
private var inited:Boolean=false;
public function MyFlashApp():void {
if(stage!=null) {
// stage will be null when this movie is loaded externally
// otherwise call the _init function
_init();
}
}
public function init(_externalArg1:String, _externalArg2:String):void{
// this function is called by the MyFlashApp_Interface interface
// when this SWF is loaded externally
if(_externalArg1!="undefined")
externalArg1=_externalArg1;
if(_externalArg2!="undefined")
externalArg2=_externalArg2;
_init();
}
// internal init function
private function _init(evt:Event=null) {
if(!inited) {
inited=true;
// initialize code goes here
}
}
}