Adding CSS Support to the CS3 Components

The CS3 component architecture makes use of TextFormats for all the text-styling needs. This decision was (likely) made to simplify the API, but still allow full control over the formatting of the text.

Natively, there is zero support for CSS styling, in fact, setting a styleSheet on the textField of a component (all components expose their textField instances) results in a run-time error, since TextFormats can not be set on textFields with a styleSheet.

But fear not! Not only are the components easy to extend, but it is not at all difficult to add CSS support to any component. In this example, I have added a styleSheet component style to a TextArea, which plays nicely with the built-in TextFormat. Rather than just posting the source code, I have broken down how the implementation works to provide some insight on how the components work, and how this sort of approach can be applied to any component, for almost any task.

UPDATE: As Freddy pointed out in the comments, once the TextArea has a CSS styleSheet applied to it, it will no longer be editable. Unfortunately this is a limitation of flash, as TextFields with styleSheets are not editable.

Extend the Component

The easiest way to do this is to duplicate the component, and put a new class on it. This will copy the component definition and live preview, and maintain all the component parameters on the instances. You can delete the original component too, since all the skins, and code (compiled in the ComponentShim component in the library) will not be removed.

  1. Duplicate the TextArea Component
  2. Export the new Clip for ActionScript, and set the class to “CSSTextArea”

Set up the class

Create the class which extends TextArea. For this example, I am using CSSTextArea.as, and not putting it in a package for simplicity sake. Make sure the class name and package matches the one you put on the TextArea, and that it’s in your project’s classpath.

package {
import fl.controls.TextArea;
public class CSSTextArea extends TextArea {
public function CSSTextArea() {
super();
}
}
}

Add the styleSheet component style

Styles in the CS3 components are ridiculously simple, and in my opinion a pleasure to implement and use (except when they aren’t). The basic idea is that each component class has a “definition” of styles that it is interested in. It exposes this by means of the getStyleDefinition() static method. If you don’t specify this method, the StyleManager will walk the inheritance chain until it finds one. Also, if you want to add to an existing definition, there is a nifty method you can use called “mergeStyles”, which you can merge component definitions. We can use this functionality to define a new “styleSheet” style, and merge it with TextArea’s existing styles. Note that we even though we are defining it with a default value of null, it still tells the StyleManager to listen for “styleSheet” style changes on an instance, component, or global level.

private static var defaultStyles:Object = {
styleSheet: null
}
public static function getDefaultStyles():Object {
return UIComponent.mergeStyles(defaultStyles, TextArea.getStyleDefinition());
}

Don’t forget to import fl.core.UIComponent

The code that makes it work

Even though we have defined the styleSheet style, this component is functionally identical to the TextArea. In order to apply it, we have to override the method of TextArea that does the TextFormat work. Luckily, all the classes are included in the installation directory (Adobe Flash CS3/Configuration/Component Source/ActionScript 3.0/User Interface/). Also, most of the textFormatting happens in an isolated method, drawTextFormat. This might not be true for all components, but it shouldn’t be too different.

For this example, we want to maintain TextFormat styling, but also add in CSS styling. This means that we will use TextFormat unless the styleSheet style has been defined. Also, we want to maintain the font embedding, and any HTML formatting. If the CSS style isn’t defined, we can just default to the TextArea’s method.

override protected function drawTextFormat():void {
var styleSheet:StyleSheet = getStyleValue("styleSheet") as StyleSheet;
textField.styleSheet = styleSheet;
if (styleSheet == null) {
super.drawTextFormat();
} else {
setEmbedFont();
if (_html) { textField.htmlText = _savedHTML; }
}
}

Don’t forget to import the flash.text.StyleSheet class

Applying a StyleSheet

All we do now is create a StyleSheet, and apply it to our CSSTextArea. As I mentioned earlier, this can be done on an instance, component, or global basis.

var style:StyleSheet = new StyleSheet();
style.setStyle(".heading", {fontWeight:"bold", color:"#FF0000", fontSize:22});
style.setStyle("body", {fontStyle:"italic"});
t.htmlText = "<body><span class='heading'>Hello</span> World...</body>";
import fl.managers.StyleManager;
t.setStyle("styleSheet", style); // instance
StyleManager.setComponentStyle(CSSTextArea, "styleSheet", style); // All CSSTextArea components
StyleManager.setStyle("styleSheet", style); // All components (who support the style)

Download the CSSTextArea source

Lanny McNie

As the dev mgr, Lanny oversees the technical day-to-day details of production and makes sure things get out the door.

@astrostyle

17 Comments

  1. I have been working with CSS yesterday and it works like a charm. For example, i used an style for links in my htmltext. One error occured here and I was wondering if anybody encountered this. When you have a mask for your textField,(as3 btw), the textfiles is unable to detect the mouse click! The mask is a shape, so it should block the mouse…

    Maybe sombody knows a solution?

    Cheers,

    Joris

  2. Why is it that when you post something you always find the solution 10 minutes later?

    masking works perfectly.(made a mistake in the hyrachie with other movies)

    textBox = new TextBox(width,”auto”);

    textBoxMask = new Sprite();

    textBoxMask.mouseEnabled = false;

    textBoxMask.buttonMode = false

    textBoxMask.mouseChildren=false;

    addChild(textBoxMask);

    addChild(textBox);

    textBox.mask=textBoxMask;

    textBoxMask.graphics.beginFill(0xFF0000,1);

    textBoxMask.graphics.drawRect(0, 0, width, height);

    textBoxMask.graphics.endFill();

  3. hummm… the textarea is not editable!!??

  4. @Freddy

    TextFields with stylesheets are not editable. Good point, I will add it above 🙂

  5. You wrote, “TextFormats can not be set on textFields with a styleSheet.” Check this out: http://livedocs.adobe.com/flash/mx2004/main_7_2/wwhelp/wwhimpl/common/html/wwhelp.htm?context=Flash_MX_2004&file=00002846.html

  6. @ozgur

    The document you linked to covers the styleSheet property of the AS2 TextArea component. If you try and set a textFormat on a textField with a styleSheet on it, you will see the error I was referring to. You *can* set both properties, but they are mutually exclusive.

  7. I get the following error.

    1172: Definition fl.managers:StyleManager could not be found.

    can’t seem to find any documentation on why anywhere.

  8. @caleb

    The source for the components (including StyleManager) are not available in your classpaths by default. You can add them simply by dropping any UI Component (like TextArea or Button) into your application – since the components have a “componentShim” symbol, which contains all the compiled classes.

  9. Ah, makes sense. Thanks Lanny. So if I wanted to use the style manager without having a component, I would need to add the class path.

  10. This is extremely useful information!

    But it is a pain to rewrite existing css stylesheets into the actionscript. Is there a way you can use URLLoader to import an external .css document?

    I can do it with text fields like this…

    var tf:TextArea = new TextArea();

    tf.width = stage.stageWidth;

    tf.height = stage.stageHeight;

    addChild(tf);

    var wordList:Array = new Array();

    var textLoader:URLLoader = new URLLoader();

    textLoader.addEventListener(Event.COMPLETE, textLoaded);

    var cssLoader:URLLoader = new URLLoader();

    var css:StyleSheet = new StyleSheet();

    function cssLoaded(e:Event):void {

    css.parseCSS(e.target.data);

    blog.styleSheet = css;

    for (var i:int = 0; i ” + wordList[i] + “”;

    }

    }

    function textLoaded(e:Event):void {

    wordList = e.target.data.split(“\n”);

    cssLoader.load(new URLRequest(“http://technobreakfast.com/xml_css/blog.css”));

    cssLoader.addEventListener(Event.COMPLETE, cssLoaded);

    }

    textLoader.load(new URLRequest(“http://technobreakfast.com/xml/xml_blog.php”));

    But the text field component will not add a scroll bar, and that is too limiting for blog text…

  11. css textboxt ınput (textfield) style – examples – –

    http://www.css-lessons.ucoz.com/textbox-css-examples.htm

  12. this works for the style sheets, but i was also trying to extend the component to skins scrollbars for different textareas and found a few issues.

    1. public static function getDefaultStyles():Object should be getStyleDefinition();

    2. the implementation of that method should be

    return UIComponent.mergeStyles(SCROLL_BAR_STYLES, TextArea.getStyleDefinition());

    here is my class

    public class CSSTextArea extends TextArea {

    private var __styleSheet:StyleSheet;

    protected static const SCROLL_BAR_STYLES:Object = {

    downArrowDisabledSkin:”ScrollArrowDown_disabledSkinTextArea”,

    downArrowDownSkin:”ScrollArrowDown_downSkinTextArea”,

    downArrowOverSkin:”ScrollArrowDown_overSkinTextArea”,

    downArrowUpSkin:”ScrollArrowDown_upSkinTextArea”,

    thumbDisabledSkin:”ScrollThumb_upSkinTextArea”,

    thumbDownSkin:”ScrollThumb_downSkinTextArea”,

    thumbOverSkin:”ScrollThumb_overSkinTextArea”,

    thumbUpSkin:”ScrollThumb_upSkinTextArea”,

    trackDisabledSkin:”ScrollTrack_skinTextArea”,

    trackDownSkin:”ScrollTrack_skinTextArea”,

    trackOverSkin:”ScrollTrack_skinTextArea”,

    trackUpSkin:”ScrollTrack_skinTextArea”,

    upArrowDisabledSkin:”ScrollArrowUp_disabledSkinTextArea”,

    upArrowDownSkin:”ScrollArrowUp_downSkinTextArea”,

    upArrowOverSkin:”ScrollArrowUp_overSkinTextArea”,

    upArrowUpSkin:”ScrollArrowUp_upSkinTextArea”,

    thumbIcon:”ScrollBar_thumbIconTextArea”,

    repeatDelay:”repeatDelay”,

    repeatInterval:”repeatInterval”,

    scrollBarWidth:8,

    scrollArrowHeight:0

    };

    public static function getStyleDefinition():Object {

    return UIComponent.mergeStyles(SCROLL_BAR_STYLES, TextArea.getStyleDefinition());

    }

    public function CSSTextArea() {

    super();

    }

    override protected function drawTextFormat():void {

    if(!this.textField.styleSheet) super.drawTextFormat();

    else {

    setEmbedFont();

    if(_html) textField.htmlText = _savedHTML;

    }

    }

    override protected function configUI():void {

    super.configUI();

    }

    }

  13. Hi Grant,

    Just wondering if you have any idea how I could add CSS styles to a Flash multiple choice quiz. I need to be able to make some of the text in a text field italics.

    any ideas?

  14. Thanks for the code!

    My textArea was coming up blank because I’d also set a textFormat, so I replaced the drawTextFormat function as follows:

    override protected function drawTextFormat():void {

    var styleSheet:StyleSheet = getStyleValue(“styleSheet”) as StyleSheet;

    textField.styleSheet = null;

    super.drawTextFormat();

    textField.styleSheet = styleSheet;

    }

Leave a Reply

Your email address will not be published. Required fields are marked *