Shared Know How


Howto: fix, find, use, make & do it guide

Fixed AS3 Flash TextArea – CSS incompatibility

author Posted by: wytze on date Jul 8th, 2008 | filed Filed under: flash

When working with flash components we often run into disadvantages. As with the TextArea class (fl.controls.TextArea) we encountered that it is not possible to use a CSS on its 'textField' property. Once again we thought to have the fast way to an end with components, but nothing of the sort.:'(

Since the 'styleSheet' property returns a standard TextField instance it struck us as weird that setting its 'styleSheet' property didn't work. The TextArea class was trying to set textFormat which fails after setting the stylesheet of the textfield.

Error message:

Error: Error #2009: This method cannot be used on a text field with a style sheet.
at flash.text::TextField/setTextFormat()
at fl.controls::TextArea/drawTextFormat()
at fl.controls::TextArea/draw()
at fl.core::UIComponent/callLaterDispatcher()

This pointed us to the 'drawTextFormat()' function in the TextArea class. After taking a look we figured out what to do.

The problem turned out to be that every time you add text to your textarea the class tries to add a designated, or default flash-textFormat to the textfield. Adding Flash TextFormat objects to textfields conflicts with stylesheets. Our solutions was relatively simple: a small class extends of the textArea class.

Click continue for the fixing source

  1. import fl.controls.TextArea;
  2.  
  3. /**
  4.   * @makes it possible to do textArea.textField.styleSheet
  5.   * @author Tim de Jong - Dooping VOF 2008 - tim -AT- dooping.nl
  6.   * @version 001
  7.   */
  8.  
  9. public class doopingTextArea extends TextArea
  10. {
  11. public function doopingTextArea()
  12. {
  13. super();
  14. }
  15.  
  16. override protected function drawTextFormat():void {
  17. if(!this.textField.styleSheet) super.drawTextFormat();
  18. else {
  19. setEmbedFont();
  20. if(_html) textField.htmlText = _savedHTML;
  21. }
  22. }
  23.  
  24. }

Then load the stylesheet by passing it to the textField object inside the textArea.

  1. var myTextArea = new doopingTextArea();
  2. myTextArea.textField.styleSheet = styleSheetObject;

As you can see we simply check if a styleSheet exists and than decide whether or not to do the original text formatting or not. Now we're able to use CSS on TextArea's and keep styling and code neatly separated.

Did this help you? Wanna help too?

tag31 Responses to “Fixed AS3 Flash TextArea – CSS incompatibility”

  1. Willem van den Goorbergh Said,

    Thanks so much Wytze and Tim. Works like a charm!!
    Would this also work with existing TextAreas? iow: Can I cast a TextArea to a doopingTextArea?
    groet,
    Willem van den Goorbergh

  2. wytze Said,

    Hi,

    What do you mean by “existing TextArea”?
    If you mean instanciated Textarea’s, than no. But I don’t think that’s what you mean, is it? 😉

    greetz Wytze

  3. bunny007 Said,

    Hi,

    I am fairly new to actionscript, so please bear with me.

    I created a custom class that creates a textArea and loads my css, but I don’t know how to apply your fix so that I can apply the stylesheet to my textArea.

    I think I need to call your doopingTextArea class from within my CSSFormatTextArea class. Is that correct, and, if so, would you mind showing me how?

    Thanks in advance… and extra thanks for the fix!!

    b.

  4. bunny007 Said,

    i figured out how to do it.

    i imported the doopintTextArea class into my CSSFormatTextArea class and created the doopingTextArea instead of a regular textArea.

    thanks again for the fix! it works perfectly!

    bunny007 =)

  5. wytze Said,

    Glad it works bunny007,

    Although I’m not sure why you created the CSSFormatTextArea class. The doopingTextArea class has all you need for css styling properties.
    My suggestion (for the sake of neat coding) would be to simply import the doopingTextArea into your code, load your css-file, add that to a newly created doopingTextArea like the sample above and fill the text area with your specific text. Something like this:


    import flash.gui.text.Stylesheet;

    var cssReq:URLRequest = new URLRequest("http://www.whateveryourdomainmybe.net");
    var cssLoader:URLLoader = new URLLoader(cssReq);
    cssLoader.addEventListener(Event.COMPLETE, cssComplete);

    private function cssComplete(e:Event):void{
    var CSS:Stylesheet = Stylesheet.parse(e.target.data);
    var myTxtArea:doopingTextArea = new doopingTextArea();
    myTxtArea.textField.styleSheet = CSS;

    /* now the onlything to do is filling it with text and adding it to the stage */
    }

  6. João Aliano Said,

    I’d love to see a working example for this. I’m new to AS3 and classes and find it extremey difficult to follow.

  7. Willem van den Goorbergh Said,

    Hi,
    on july 24th Wytse wrote:

    > What do you mean by “existing TextArea”?
    > If you mean instanciated Textarea’s, than no. But I don’t think > that’s what you mean, is it? 😉

    what I meant was using a TextArea created on the stage at authoring time instead of creating a doopingTextArea through Actionscript and cast that somehow to a doopingTextArea.
    Possible?
    Thanks
    Willem van den Goorbergh

  8. wytze Said,

    Hi Willem,

    I think it’s possible. You might want to try to change the baseclass of the component that you selected from your library to the doopingTextArea. Than you can drag it to your stage and do what ever you want with it. Dont forget to add your CSS 😉

    Wytze

  9. dezza Said,

    thanks!

  10. FlashSpec Said,

    5 – the correct syntax:

    function cssComplete(e:Event):void{
    var CSS:StyleSheet = new StyleSheet;
    CSS.parseCSS(e.target.data);
    var myTxtArea:doopingTextArea = new doopingTextArea();
    myTxtArea.textField.styleSheet = CSS;
    addChild(myTxtArea);

  11. FlashSpec Said,

    and “import flash.text.StyleSheet”

  12. FlashSpec Said,

    worked! CS4.

    fyi:
    field.textField.htmlText = exampleText;
    addChild(field.textField);
    and
    in case you get 2 errors saying:
    1. can’t find TextArea when trying to extend
    2. can’t override the function
    then you need to put in the correct path to the fl. folder by going to Edit > Preferences > ActionScript, ActionScript 3.0 settings…

    Then add the following path:
    $(AppConfig)/Component Source/ActionScript 3.0/User Interface

    And watch out for correctly formatting CSS and source text.

    Thanks to wytze for the script!
    Wishing nice coding to everyone!

  13. Jakob E Said,

    A bit out of topic but… When loading external stylesheets I’ve created this little loader class. It is in no way perfect – but I find it quite usefull.

    package {
    import flash.text.StyleSheet;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.events.Event;
    import flash.events.IOErrorEvent;

    public class StyleSheetLoader extends StyleSheet {
    public var loader:URLLoader;
    public function StyleSheetLoader(css:String=””):void {
    super();
    loader=new URLLoader();
    if (css!=””)load(css);
    }
    public function load(css:String):void {
    loader.load(new URLRequest(css));
    loader.addEventListener(Event.COMPLETE,completeHandler,false,0,true);
    loader.addEventListener(IOErrorEvent.IO_ERROR,ioErrorHandler,false,0,true);
    }
    private function completeHandler(e:Event):void {
    parseCSS(e.target.data);
    dispatchEvent(e);
    destroy();
    }
    private function ioErrorHandler(e:Event):void {
    dispatchEvent(e);
    destroy();
    }
    private function destroy():void {
    loader.removeEventListener(Event.COMPLETE,completeHandler);
    loader.removeEventListener(IOErrorEvent.IO_ERROR,ioErrorHandler);
    }
    }
    }

    Usage Example 1:
    var DTA:doopingTextArea = new doopingTextArea();
    DTA.textField.styleSheet=new StyleSheetLoader(“css.css”)
    DTA.htmlText=”HEADER”

    Usage Example 2:
    var css:StyleSheetLoader=new StyleSheetLoader(“css.css”)

    var DTA1:doopingTextArea = new doopingTextArea();
    DTA1.textField.styleSheet=scc
    DTA1.htmlText=”HEADER”

    var DTA2:doopingTextArea = new doopingTextArea();
    DTA2.textField.styleSheet=scc
    DTA2.htmlText=”FOOTER”

  14. Jakob E Said,

    Hmm… Seems like the span tags got removed (around HEADER and FOOTER) and scc should be css 😉

  15. wytze Said,

    Hi Jacob,

    Thanks for posting your handy StyleSheet class extend. Seems to save a few lines of code, each time you load a StyleSheet.
    One remark though. Don’t forget to listen to the onComplete event before you fill your textarea with HTML. Although you do dispath the event in your class. This way the HTML/Text won’t render becase it’s still missing the stylesheet (it’s still loading and parsing it), so it doesn’t have any style apply (yet).
    Your adjusted example:

    //Usage Example 1:
    var DTA:doopingTextArea = new doopingTextArea();
    DTA.textField.styleSheet=new StyleSheetLoader(”css.css”);
    DTA.textField.styleSheet.addEventListener(Event.COMPLETE,completeHandler);
    //the function called when the StyleSheet is loaded
    function completeHandler(e:Event):void{
       DTA.htmlText=”HEADER”;
    }
    
    //Usage Example 2:
    var css:StyleSheetLoader=new StyleSheetLoader(”css.css”);
    
    var DTA1:doopingTextArea = new doopingTextArea();
    DTA1.textField.styleSheet=css;
    css.addEventListener(Event.COMPLETE,completeHandler1);
    
    //the function called when the StyleSheet is loaded
    function completeHandler1(e:Event):void{
       DTA.htmlText=”HEADER”;
    }
    
    var DTA2:doopingTextArea = new doopingTextArea();
    DTA2.textField.styleSheet=css;
    css.addEventListener(Event.COMPLETE,completeHandler2);
    
    //the function called when the StyleSheet is loaded
    function completeHandler2(e:Event):void{
       DTA.htmlText=”FOOTER”;
    }
    
  16. Jakob E Said,

    Hi Wytze,

    The good part is that you don’t need to listen for the complete event – the css is automatically applied when done loading (the parseCSS part).

    Try this example:

    // StyleSheetLoader
    // Create a loader and delay the load method with two seconds.

    var css:StyleSheetLoader=new StyleSheetLoader();
    setTimeout(loadStyles,2000);
    function loadStyles():void {
    css.load(“css.css”);
    }

    // Dooping TextArea
    // Create the DTA and apply the StyleSheetLoader
    // … again just imagine the span tags
    var DTA:doopingTextArea=new doopingTextArea();
    DTA.textField.styleSheet=css;
    DTA.htmlText=”Loerm ipsum dolor sit amet “;
    addChild(DTA);

    What ought to happen is the DTA displaying the text
    unstyled for two seconds and then turn styled. Give it a try and please let me know if this does not work (it does for me)

  17. wytze Said,

    Hi Jakob,

    It turns out I was wrong! I ran your test and it seems to render the HTML after the after all. I think it’s leftover as2 habits 😉

    Thanks for your addition

  18. Jakob E Said,

    You are welcome :)

  19. Nehal Said,

    somehow after applying stylesheet, textArea doesnt allow me to edit text, any clue how to make it editable?

  20. wytze Said,

    Hi Nehal,

    Did you try to set the textfield type to input?

    textArea.textField.type = TextFieldType.INPUT;

    Don’t Forget to import the TextFieldType class.

    Greetz Wytze

  21. Thomas Said,

    Thanks a lot for this great trick!
    I have 1 problem: I can’t change the fontFamily (doopingTextArea just ignores what I’ve put in the stylesheet => can’t get it to Arial).

    Any hints would be highly appreciated as I’m struggling with this for hours now.

    Thanks!
    Thomas

  22. Kevin Said,

    I’m having the same fontFamily problem. Any solution? Is there a way to use an embedded font?

  23. wytze Said,

    Hi Thomas,

    Sorry for the late response, but the mail function of this WordPress-distribution seems to have stopped working (will be working on that).
    I’m not sure what the problem could be. The fontFamily-cssproperty is supported by AS3…
    Are you embedding fonts? And is your DoopingTextArea’s embedFonts-property set to true?
    If so, try setting it to false. If not, then make sure you’ve embedded the font. And make sure you initialize it at least once before using the DoopingTextArea.
    So In your case it means just adding:

     
    var just4Init = new ArialFont(); //or what name you gave the embedded font in the library
    

    hope to have helped you…

    Greetz Wytze

  24. wytze Said,

    Hi Kevin,

    See my response to Thomas, the same goes for you.

    Cheers Wytze

  25. diamondTearz Said,

    Thanks for this component. It saved me hours of work!

  26. Joel Said,

    Many many thanks for sharing this invaluable class. Perhaps someday I’ll be able to similarly pick apart source code and return the favor.

  27. Matt Said,

    Guess I got here to late to download the full source?

    If not, I when I copy/paste the text above I get the following error:
    1114: The public attribute can only be used inside a package.

  28. Matt Said,

    I guess it’s just implied to wrap it in a package…

  29. Visco Said,

    works fine! thanks for the post….

  30. Ayman Said,

    Thank you so much worked very well..

  31. Embussy Said,

    Could some one please post a working example as I can’t get my head around it

     Add A Comment

trackback Trackback URI | rsscomment Comments RSS