AS 3 Static Initializer

June 18th, 2008

I have been working on a new CSS parser for my SUMO Framework. The idea is to have something that can load a CSS file, parse each CSS class into objects then use them as templates to create TextFields. There is a lot of logic needed to work out the conversion so I started looking into using “Reference” classes to help validate the CSS. Here is some stuff I came up with.

My first idea was to simply create a stand alone class with just constants in it. I use these all over the place in the Framework1 so I started creating one for TextFeilds and the other for TextFormats. The goal is to have 1 CSS class that was smart enough to parse out each property, decide if it belongs to in a TextFeild or a TextFormat, and return a TextField styled by the created TextFormat. I want the system that did not rely on HTML markup to be styled. You should be able to say “give me a label with ‘this’ style” and here is the text “Hello World”.

Like all of my research, I asked the Google Gods to show me the way. Here is a great post I came across from Daniel Rinehart. I really like his idea of putting values in a constant object then using a function to return true of false if it exists. Here is sample code from his class:

package com.example {
    public class MIME {
        public static const GIF_MIME_TYPE:String = “image/gif”;
        public static const JPG_MIME_TYPE:String = “image/jpeg”;
        public static const PNG_MIME_TYPE:String = “image/png”;
        public static const SWF_MIME_TYPE:String = “application/x-shockwave-flash”;
       
        private static const IMAGE_TYPES:Object = new Object()
        // This block is run once when the class is first accessed
        {
            IMAGE_TYPES[GIF_MIME_TYPE] = true;
            IMAGE_TYPES[JPG_MIME_TYPE] = true;
            IMAGE_TYPES[PNG_MIME_TYPE] = true;
            IMAGE_TYPES[SWF_MIME_TYPE] = true;
        }
       
        public static function isImage(mimeType:String):Boolean {
            return (IMAGE_TYPES[mimeType] == true);
        }
    }
}

Its a really neat trick because all you have to do to validate that a constant exists is call “isImage” function (in his example) and it looks it up from the IMAGES_TYPES object. One of the commenters offered up this suggestion for looping through the constant by reflection:

public static function isImage(mimeType:String):Boolean {
        for each (var constant:XML in describeType(MIME).constant) {
                if (MIME[constant.@name] == mimeType) {
                        return true;
                }
        }
        return false;
}

I really liked Refection and I use it throughout the Framework. Because I don’t want to have multiple loops running all over the place when I am doing parsing, this Static Initializer class will cut down on a large part of the cpu overhead. The tradeoff is that I have to hard code a lot of the CSS rules. Luckily all of the properties I will be looking for are defined clearly in ActionScript so chances are I will not be adding new one very often. Here is what I came up with:

This is the TextFieldReference Class

package
{

        public class TextFieldReference
        {
                public static const ALWAYS_SHOW_SELECTION:String = “alwaysShowSelection”;
                public static const ANTI_ALIAS_TYPE:String = “antiAliasType”;
                public static const AUTO_SIZE:String = “autoSize”;
                public static const BACKGROUND:String = “background”;
                public static const BACKGROUND_COLOR:String = “backgroundColor”;
                public static const BORDER:String = “border”;
                public static const BORDER_COLOR:String = “borderColor”;
                public static const CONDENSE_WHITE:String = “condenseWhite”;
                public static const DISPLAY_AS_PASSWORD:String = “displayAsPassword”;
                public static const EMBED_FONTS:String = “embedFonts”;
                public static const GRID_FIT_TYPE:String = “gridFitType”;
                public static const MAX_CHARS:String = “maxChars”;
                public static const MOUSE_WHEEL_ENABLED:String = “mouseWheelEnabled”;
                public static const MULTILINE:String = “multiline”;
                public static const RESTRICT:String = “restrict”;
                public static const SELECTABLE:String = “selectable”;
                public static const SELECTION_BEGIN_INDEX:String = “selectionBeginIndex”;
                public static const SELECTIOEND_INDEX:String = “selectioendIndex”;
                public static const SHARPNESS:String = “sharpness”;
                public static const TEXT_COLOR:String = “textColor”;
                public static const TEXT_HEIGHT:String = “textHeight”;
                public static const TEXT_WIDTH:String = “textWidth”;
                public static const THICKNESS:String = “thickness”;
                public static const WORD_WRAP:String = “wordWrap”;
                public static const WIDTH:String = “width”;
                public static const HEIGHT:String = “height”;
                public static const ALPHA:String = “alpha”;
                public static const x:String = “x”;
                public static const y:String = “y”;
               
                private static const PROPERTY_TYPES:Object = new Object();{
                    PROPERTY_TYPES[ALWAYS_SHOW_SELECTION] = true;
                        PROPERTY_TYPES[ANTI_ALIAS_TYPE] = true;
                        PROPERTY_TYPES[AUTO_SIZE] = true;
                        PROPERTY_TYPES[BACKGROUND] = true;
                        PROPERTY_TYPES[BACKGROUND_COLOR] = true;
                        PROPERTY_TYPES[BORDER] = true;
                        PROPERTY_TYPES[BORDER_COLOR] = true;
                        PROPERTY_TYPES[CONDENSE_WHITE] = true;
                        PROPERTY_TYPES[DISPLAY_AS_PASSWORD] = true;
                        PROPERTY_TYPES[EMBED_FONTS] = true;
                        PROPERTY_TYPES[GRID_FIT_TYPE] = true;
                        PROPERTY_TYPES[MAX_CHARS] = true;
                        PROPERTY_TYPES[MOUSE_WHEEL_ENABLED] = true;
                        PROPERTY_TYPES[MULTILINE] = true;
                        PROPERTY_TYPES[RESTRICT] = true;
                        PROPERTY_TYPES[SELECTABLE] = true;
                        PROPERTY_TYPES[SELECTION_BEGIN_INDEX] = true;
                        PROPERTY_TYPES[SELECTIOEND_INDEX] = true;
                        PROPERTY_TYPES[SHARPNESS] = true;
                        PROPERTY_TYPES[TEXT_COLOR] = true;
                        PROPERTY_TYPES[TEXT_HEIGHT] = true;
                        PROPERTY_TYPES[TEXT_WIDTH] = true;
                        PROPERTY_TYPES[THICKNESS] = true;
                        PROPERTY_TYPES[WORD_WRAP] = true;
                        PROPERTY_TYPES[WIDTH] = true;
                        PROPERTY_TYPES[HEIGHT] = true;
                        PROPERTY_TYPES[ALPHA] = true;
                        PROPERTY_TYPES[x] = true;
                        PROPERTY_TYPES[y] = true;
                 }
               
                /**
                *
                */

                public static function isSupported(property:String):Boolean {
                     return (PROPERTY_TYPES[property] == true);
                 }
                
        }
}

And this is the TextFormatReference Class

package {
       
        public class TextFormatReference {
               
                public static const ALIGN:String = “align”;
                public static const BLOCK_INDENT:String = “blockIndent”;
                public static const BOLD:String = “bold”;
                public static const BULLET:String = “bullet”;
                public static const COLOR:String = “color”;
                public static const FONT:String = “font”;
                public static const INDENT:String = “indent”;
                public static const ITALIC:String = “italic”;
                public static const KERNING:String = “kerning”;
                public static const LEADING:String = “leading”;
                public static const LEFT_MARGIN:String = “leftMargin”;
                public static const LETTER_SPACING:String = “letterSpacing”;
                public static const RIGHT_MARGIN:String = “rightMargin”;
                public static const SIZE:String = “size”;
                public static const TAB_STOPS:String = “tabStops”;
                public static const TARGET:String = “target”;
                public static const UNDERLINE:String = “underline”;
               
                private static const PROPERTY_TYPES:Object = new Object();{
                PROPERTY_TYPES[ALIGN] = true;
                        PROPERTY_TYPES[BLOCK_INDENT] = true;
                        PROPERTY_TYPES[BOLD] = true;
                        PROPERTY_TYPES[BULLET] = true;
                        PROPERTY_TYPES[COLOR] = true;
                        PROPERTY_TYPES[FONT] = true;
                        PROPERTY_TYPES[INDENT] = true;
                        PROPERTY_TYPES[ITALIC] = true;
                        PROPERTY_TYPES[KERNING] = true;
                        PROPERTY_TYPES[LEADING] = true;
                        PROPERTY_TYPES[LEFT_MARGIN] = true;
                        PROPERTY_TYPES[LETTER_SPACING] = true;
                        PROPERTY_TYPES[RIGHT_MARGIN] = true;
                        PROPERTY_TYPES[SIZE] = true;
                        PROPERTY_TYPES[TAB_STOPS] = true;
                        PROPERTY_TYPES[TARGET] = true;
                        PROPERTY_TYPES[UNDERLINE] = true;
                        //PROPERTY_TYPES[URL] = true;
        }
       
        public static function isSupported(property:String):Boolean {
            return (PROPERTY_TYPES[property]);
        }

}

So for now this may be a lot to take in. You are probably wondering how the hell can you use this? Well here is a sample from my CSS parser:

/**
                 * Goes through css object and determines if the css prop can be used in a TextField, a TextFormat,
                 * or should be ignored.
                 */

                internal function parseCSS(cssObject:Object):void{
                       
                        var text_format:TextFormat = new TextFormat();
                        //
                        for (var prop:String in cssObject) {
                                if(TextFieldReference.isSupported(prop)){
                                        data[prop] = TextFieldReference.cleanupProp(prop,cssObject[prop]);
                                }else if (TextFormatReference.isSupported(prop)){
                                        text_format[prop] = TextFormatReference.cleanupProp(prop,cssObject[prop]);
                                }else{
                                        trace(“Alert: This prop ‘”+prop+“‘ is not supported.”);
                                }
                        }
                        data.defaultTextFormat = text_format;
                }

As you can see I am doing 1 loop through all the properties that come in from a css object (This is created from the css parser). For this example I have taken out the cleanupProp function from the two reference classes but will get into that specifically when I post about my super slick CSS parser. The thing I really wanted to show you was how clean these Static Initializer Class can make your code. I only have 1 loop, and the rest is all “static” so to speak.

  1. I call them Reference Classes []

One Response to “AS 3 Static Initializer”

  1. The Flash Art of War » Blog Archive » 1 Year Anniversary Says:

    [...] AS 3 Static Initializer Class [...]

Leave a Reply