Simple Flex smilies (emoticons)

I recently developed a Flex chat application. A nice feature in every chat is the smilies support. I searched on the net looking for something that somebody else have done already but I found only some guys saying it is hard, it is not something you develop for fun, and so on. Also I found some guys that did it but haven’t released the source.

Anyway, I developed a nice smilies’ engine class, only to lose it by switching to another branch (in git) without committing. So, until I will recode the nice and efficient engine, here is another idea that I had regarding this matter.

The open source library flexlib has a nice container, named FlowBox. To quote it’s creators:

The FlowBox is an extension of Box that implements a FlowLayout algorithm for laying out children. FlowBox will lay out children in a horizontal fashion. When the width of the children exceeds the width of the container, the child is placed on a new row.

That’s great :) So it is like we now have free container wrapping. What if we broke down the string that contains the smilies and put each word in an container? It would be easier for us to insert smilies, each in it’s own container, that’s for sure.

Flex smilies demo (view source included): here.

If you right-click -> View Source doesn’t work, it means you have pop-ups blocked.

If you download the source and make it a Flex Project, don’t forget to download flexlib and link it in your compiler.

As I don’t like to clutter my code with comments, let me explain some parts of the code. The flow is as follows:

  1. the user inserts some text
  2. the user submits the text
  3. the input text is split into words and subsequently into simple text and smilies
  4. we rebuild the output text, creating from each text piece/smiley a display object and putting all in a FlowBox

First two points are obvious and I don’t think they require any explanation, the code below does this:

form

<mx:Form defaultButton=”{submitButton}>

    <mx:FormItem label=”Write something here:>
        <mx:TextInput id=”messageTI” width=”200/>
        <mx:Text text=”Supported smilies are :), :(, :P, :D, ;), :O/>
    </mx:FormItem>

    <mx:FormItem>
        <mx:Button id=”submitButton” label=”Do Magic!” click=”handleSubmit(event)/>
    </mx:FormItem>

    <mx:FormItem label=”Split input string:>
        <mx:TextInput id=”output” width=”200/>
    </mx:FormItem>

</mx:Form>

button click event handler function

private function handleSubmit(event:MouseEvent):void {
    createEmoticons(messageTI.text);
    messageTI.text = ;
}

Moving forward, we have the main function that actually does the work, creating the emoticons from text. It takes the string to process as an argument.

private function createEmoticons(text:String):void

First we define the smilies’ list, and their corresponding file termination (i.e. for grin, the file is called emoticon_grin.png).

var smilies:Array = new Array(‘:D’, ‘:)’, ‘:O’, ‘:P’, ‘:(’, ‘;)’);
var smiliesGfx:Array = new Array(‘grin’, ’smile’, ’surprised’, ‘tongue’, ‘unhappy’, ‘wink’);

Now the string splitting begins. First we split the string into words, storing all the output in initialArray. The splitting is done with a regular expression like /( )/ because I want to have in the output the spaces too.

var regExp:RegExp = new RegExp(“( )”, “i”);

initialArray = text.split(regExp);

Now we’ll search the smilies in the words (we can have hello:)wazza?, this will pass the first splitting).

for (i = 0; i < smilies.length; i++) {
    initialArray = splitArrayElements(smilies[i], initialArray);
}

I made up a function that takes a token and an array as arguments and does the following: goes through each array element and if it finds the token within it, it will split the string around that token and throw it into the return array (i.e. if we have bla:)bla with :) as the token, the result will be: [bla, :), bla]).

array of strings splitting function

function splitArrayElements(token:String, arr:Array):Array {

    if (arr.length == 0 || token == ) return arr;

    var returnArray:Array = new Array();
    var tempArray:Array = new Array();

    var escapedToken:String = token.replace(/\(|\)|\[|\]/, “\\$&”);

    var regExp:RegExp = new RegExp(“(”+escapedToken+“)”, “g”);

    for (var i:uint = 0; i < arr.length; i++) {
        tempArray = arr[i].split(regExp);

        returnArray = returnArray.concat(tempArray);
    }

    return returnArray;

}

Now back to the main function. Now we have an array that contains all the initial string split nicely into words, smilies and spaces. During the splitting, some empty elements appear. Also, I will get rid of all the spaces, as there will be enough separation between words in the final result.

for (i = 0; i < initialArray.length; i++)
    if (initialArray[i] !=  && initialArray[i] != ‘ ‘)
        outputArray.push(initialArray[i]);

The basic idea now is to create a FlowBox and, for each element of the outputArray, put a Text if we have a word or an Image if we have a smiley. There are also a lot of calls to validateNow() function. This function validates and updates the properties and layout of the caller object. Don’t ask me why, but we need this, else the FlowBox will appear empty. Also, the dummyFix is there because in the case that you will imput numbers only, the text will not appear. After composing the FlowBox, we add it to the mainContainer which is a VBox (chosen so to simulate a possible chat behaviour).

FlowBox composition

var flowBox:FlowBox = new FlowBox();

mainContainer.addChild(flowBox);
mainContainer.validateNow();

flowBox.setStyle(‘horizontalGap’, ‘0′);
flowBox.width = Math.floor(mainContainer.width * 0.95);

var dummyFix:Label = new Label();

flowBox.addChild(dummyFix);
flowBox.validateNow();

dummyFix.text = “Your message:”;
dummyFix.validateNow();

for (i = 0; i < outputArray.length; i++)
    if (smilies.indexOf(outputArray[i]) == -1) {
        var label:Text = new Text();
        label.text = outputArray[i];
        label.validateNow();
        flowBox.addChild(label);
        flowBox.validateNow();
    } else {
        var image:Image = new Image();
        image.load(‘assets/emoticon_’+ smiliesGfx[smilies.indexOf(outputArray[i])] + ‘.png’);
        flowBox.addChild(image);
        flowBox.validateNow();
    }

    mainContainer.validateNow();

}

And that’s it :) In case you missed the link above, try the demo here (view source included).

Now this isn’t the most optimised code you’ve seen, but I wrote it like this for clarity’s sake. Many improvements can be done (like spliting the string in one command with a regular expression, instead of doing all those useless for cycles; or checking if the text has any emoticons at all; yeah, some things would be nice:) ) but this is only a demo. Maybe if I have time I will create a component out of it, but certainly after I remake all the code for the other method.

The good part is that you have smilies support fast without much fuss. The bad part is that for every word you get an object on the screen. Depending on the size of your chat application and other goodies that you provide around it, this could make the client perform terribly. At least I suppose so, I am not fully certain, but a performance hit should happen.

Ah well, next time I’ll talk about smilies I will show you a much better method that in theory should be the best resource-wise.

Thanks for reading and share this with the world (for your convenience, you can use the bookmark button at the bottom of the post). I am sure many people are still searching for something like this :)

Tags: , , , , ,

15.Apr.08 Flex


You can follow any responses to this entry through the RSS 2.0 feed.
You can leave a response, or trackback from your own site.

23 Responses to “Simple Flex smilies (emoticons)”

  1. san |

    awesome component.. thank you so much for making it and sharing it.. you rule!

  2. san |

    Hi,
    There is another way to do this (as I have been searching for it) and this is via setting the htmlText of the TextArea like this: http://www.mail-archive.com/flexcoders@yahoogroups.com/msg64509.html (but it has some issues with the alignment of images with text).

    Your way is great too and probably what I’m going to be using for now, but just wanted to share. Thanks again.

  3. kiorull |

    Hi San,

    Thanks for comments. I too found that in the past, but if you try it, you will see that it is unusable. The img is treated as block, and it is thrown on the next row. You cannot have inline images only using htmlText of TextArea.

  4. Guido |

    I was faced with the same issue and went with the same solution! I think it works, great, i based mine on canvas and just
    * split on spaces
    * check if the word could be an emoticon (length)
    * if so, render matching graphic, else render word
    * append object, repeat
    * check if the latest object overflows the screen, if so move it down
    * do a cleanup if the wordcount is over x words, delete the first y number of objects and shift everything up

    should be online next month on iwon.com :)

  5. Xtian |

    Hi man,
    Well I found your code great, I have the same problem doing a chat in flex. The problem is the scrolling, do you think it can be fixed?

  6. kiorull |

    I didn’t check the scrolling of the FlowBox, but it should work like in any Box.

    I checked flexlib and none had any problems with scrolling of FlowBox…

  7. JChakir |

    So nice ,& thanks for your sharing , but there are some thing , this chat can’t supporte RTE text ,& Copy , so you must change the way . if u have an other idea? , because there is some costumer component ,supported this ex: FXCTextAria http://labs.flexcoders.nl/samples/EmoText/009/
    but not all people like you ,he don’t give the source

  8. Hobbis |

    I too have been having the same problem. Have got around it in a similar way but it is the input box that I am really stuck on: http://chat.coolbytes.co.uk. Any ideas how I can make it work so that emoticons will work in the input box as well?

  9. kiorull |

    I don’t think you can as input box is a predefined component. Maybe you can extend it and modify it to suit your needs, but I don’t think it is easy.

    But you really need to use input box?

  10. DonMoir |

    At this site, all images flow and wrap with the text cleanly and efficiently.

    Try entering some of these mixed with text:

    :brb :drink :video :) :cool

    For inline video try: Wow cool video :video

    After you have entered some images, try resizing the window. You will see the images wrap very well.

    Use any name to login.

    http://sms.pangolin.com/vflash/Venus.html

    Don

  11. kiorull |

    Probably it is flash, and it doesn’t have a source code. Anyway, this post is a tech demo/tutorial, it’s not supposed to be commercial chat application :)

  12. DonMoir |

    o venus is not commercial. It is my first flash app and I use it to fix flash problems among other things

    o the only difference between flash and flex is some syntax differences. It all amounts to the same result.

    Anyone trying to mix text and images is going to have problems with flash. In my case I needed to have the images wrap and flow with the text under a variety of circumstances (i.e. resizing).

    Additionally, it needed to be fast.

    It takes a great deal of effort to achieve the above so I am not inclined to give out the source code. It just shows you that it can be done.

    Don

  13. kiorull |

    Well, yes, the results are the same. But Flex SDK is diffrent than what you have in Flash.

    In any case, I cannot see your point. With FlowBox you benefit from the automatic layout of boxes in Flex, so resizing, scrolling, etc, so you don’t need to worry about that.

    I did this demo for images only, but you can feel free to add more emotes to the array and treat the special cases as you like (i.e. embed a movie, put more emote codes, etc).

    Again, this is a demo, it can be expanded in whatever you need. The basic engine is there, few small modifications, and it will do what you need.

    Also, in few hours I will upload a version that will support html text and scrolling in another post. With a lot of yummy source code!

    Whatever the effort it is always nice to share :)

  14. DonMoir |

    kiorull, first thanks for this blog :) This is an important issue for many.

    By looking at your demo, It appears to me that FlowBox is slow. I could be wrong. What would be good if you could demonstrate the same demo but allow it to resize horizontally so we can get a feel for how well it does flow. Also, it appears in the demo, that sometimes the images wrap and sometimes they don’t when you enter say 15 images or there abouts.

  15. kiorull |

    Don, thanks for the feedback.

    I didn’t really investigate the speed of FlowBox. It is done by flexlib people and I took it as is.

    I will try to make time to put up a demo that includes horizontal resize. I didn’t test this, I relied only on FlowBox.

    Also, as you pointed, lines do not wrap at all, as I see now. I will also see these to resolve these issues.

    In the new demo that I just put up right now (http://kiorull.com/blog/programming/flex/simple-flex-smilies-with-html-support) scrolling is enabled at the cost of fixed height.

    Automatic things in Flex usually come at the cost of fixed design.

  16. kiorull |

    Don, I looked into the image not wrapping, and it is my fault.

    image.width is 0 at the time when I add it to the FlowBox. I hardcoded the width of the image and they wrap nicely.

    I will make a preloader so that I can read the width of the image at the time of use. I will include this, along with the horizontal resizing in a future post, where I will be updating the HTML version.

  17. Jayesh Sharma |

    Hii kiorull,

    Very nice blog it solved a lot of problem realted to chat window. :)

    koirull, doesn’t flow box support copy all(ctrl+a) feature?

    I didn’t find it :(

    Also if one enter long string without any space then flow box shows scroll bars in that(it doesn’t wrap the string)

  18. kiorull |

    I am afraid that the ctrl+a is broken once I split the words in separate Text boxes. Also, even if it would have worked, the simlies as text are gone from the output window, they are replaced by images. I don’t think it is worth the time to try to do it with this implementation.

    The flowbox wraps text as a normal word processor. If you don’t have a line breaking character it will show scrolls and make the line as long as needed.

  19. Cobriya |

    very nice and effective code
    but when you try it on multiple line entery all the words gets messed up

    any SOLUTION FOR THAT

  20. kiorull |

    This is designed for one line entry, as the input is single line. If you want multiple line, please check the HTML version (which is better anyway): http://kiorull.com/blog/programming/flex/simple-flex-smilies-with-html-support/

  21. David |

    Great job and it’s really nice to see you’re opening the source up. The comments had me realize that my own meager attempt has serious shortcomings. My own smiley attempt doesn’t handle resizing. I’ll be opening the source on my own blog also. Hopefully all the feedback will amount to some nice solutions.

  22. AJ.H |

    how would you set the alignment (i.e. left, center, right and justify)?

    I noticed the setStyle method, might be used for this but cant find any examples or documentation.

    any help would be greatly appreciated.

    BTW props for the really good example. both the regular and the HTML version

  23. kiorull |

    Hi,

    You can do like this:

    .setStyle(”textAlign”, “left”);
    .setStyle(”textAlign”, “center”);
    .setStyle(”textAlign”, “right”);
    .setStyle(”textAlign”, “justify”);

    Maybe there are more aligns, but never used them.

    Thanks for the comment :)

Leave a Reply

© kiorull.com | RSS Feed | Design by David Herreman | Wordpressed by Ericulous