I'm going to be working on a new voting control using flex to provide real time/cached display of images. Will post a link soon. For now, checkout the current system they have for voting on designs. Static page loads FOR THE LOSS!
http://www.collarfree.com
Monday, May 5, 2008
Friday, October 26, 2007
Flex and FileReference.Upload using Firefox and SSL
Either the SSL handshake doesn't complete because firefox creates a new session when using file protection sandboxing, or something more horrible is going on with the flash player - for whatever reason, file uploads in firefox over SSL don't work.
This post is a workaround until Adobe gets its act together and fixes this problem.
We will be using javascript and normal html forms to accomplish our upload.
First things first: Trap the case that the user is using firefox, and call a javascript function.
Ok, now on the html file that hosts the swf, we need to make this javascript function available, and have it do the work.
Just after this script should be this part of the file that flex autogenerated:
<!-- BEGIN DeepLinking required section -->
<link rel="stylesheet" type="text/css" ...
Ok. So whats goign to happen here?
You perform an action within the flex app (clicking a button or something) which calls addFiles. In firefox, flex then calls the javascript function showUploadComponent. This method then creates a popup window, writes html to it to upload the image. Some of my code here will need to be changed for you - I'm using php and have some variable use in there to point it at the php file that accepts the upload. You will need to write this code yourself (it can be the same place fileReference.upload is posting to). The important thing is that this page after accepting the upload, then writes some html on success.
The way I do it in php is like so:
Basically, you'll want to print out that script that closes the window, and then calls the callback in window.opener. Lets revisit what that function does.
It calls getFlexApp and then calls a method updateImages inside the flex app. In my case, the user was uploading an image. I then wanted them to see their image inside the flex app after the upload completed. However, to accomplish javascript calling a flex method, you need to do something back in your flex app:
First you write the updateImages function (mine updates an image with id thumbImage):
Then you need to register it as callable in your creationComplete function for the <Application creationComplete="onCreationComplete();">
Now you're good to go. This solution isn't out of the box ready, but should walk you through all the steps you need to write a javascript/html forms workaround for file upload in firefox under SSL.
This post is a workaround until Adobe gets its act together and fixes this problem.
We will be using javascript and normal html forms to accomplish our upload.
First things first: Trap the case that the user is using firefox, and call a javascript function.
private function addFiles(s:String):void {
//if not IE:
if(flash.system.Capabilities.playerType != "ActiveX")
{
var imagename:String = "yourimagename";
flash.external.ExternalInterface.call("showUploadComponent",imagename);
}
else
{ //do normal image upload within flex
_refAddFiles = new FileReferenceList();
_typeUploadFile = s;
_refAddFiles.addEventListener(Event.SELECT, onSelectFile);
var imageTypes:FileFilter = new FileFilter("Images (*.jpg, *.jpeg, *.gif, *.png)", "*.jpg; *.jpeg; *.gif; *.png");
_refAddFiles.browse([imageTypes]);
}
}
Ok, now on the html file that hosts the swf, we need to make this javascript function available, and have it do the work.
<script language="JavaScript" type="text/javascript">
function showUploadComponent(imageName)
{
var w = window.open("","ARESUploadWindow","height=400, width=600,scrollbars=no,status=no,titlebar=no,toolbar=no");
var s = "<html><body><form method='POST' action='<?=$flexapi?>' ENCTYPE='multipart/form-data'><input type='hidden' name='request' value='imageUpload'/>Upload Image:<input type='file' name='"+imageName+"'/><br/><input type='submit' value='Upload'/></form></body></html>";
w.document.open();
w.document.write(s);
w.document.close();
}
function imageUploaded()
{
getFlexApp("<?=$swfname?>").updateImages();
}
function getFlexApp(appName) {
if (navigator.appName.indexOf ("Microsoft") !=-1) return window[appName];
else return document[appName];
}
</script>
Just after this script should be this part of the file that flex autogenerated:
<!-- BEGIN DeepLinking required section -->
<link rel="stylesheet" type="text/css" ...
Ok. So whats goign to happen here?
You perform an action within the flex app (clicking a button or something) which calls addFiles. In firefox, flex then calls the javascript function showUploadComponent. This method then creates a popup window, writes html to it to upload the image. Some of my code here will need to be changed for you - I'm using php and have some variable use in there to point it at the php file that accepts the upload. You will need to write this code yourself (it can be the same place fileReference.upload is posting to). The important thing is that this page after accepting the upload, then writes some html on success.
The way I do it in php is like so:
if($params['request']=="imageUpload")
{
if(UploadImages())
{
echo "<ok><script language='JavaScript' type='text/javascript'>window.close(); window.opener.imageUploaded();</script></ok>";
}
else
{
echo "<error type='imageUpload' description='Call to UploadImages() failed.'>";
print_r($results);
echo "</error>";
}
}
Basically, you'll want to print out that script that closes the window, and then calls the callback in window.opener. Lets revisit what that function does.
It calls getFlexApp and then calls a method updateImages inside the flex app. In my case, the user was uploading an image. I then wanted them to see their image inside the flex app after the upload completed. However, to accomplish javascript calling a flex method, you need to do something back in your flex app:
First you write the updateImages function (mine updates an image with id thumbImage):
public function updateDealImages():void {
this.thumbImage.source = "put where you saved the file to on the server here";
}
Then you need to register it as callable in your creationComplete function for the <Application creationComplete="onCreationComplete();">
public function onCreationComplete():void {
if (flash.external.ExternalInterface.available)
flash.external.ExternalInterface.addCallback("updateImages", updateImages);
}
Now you're good to go. This solution isn't out of the box ready, but should walk you through all the steps you need to write a javascript/html forms workaround for file upload in firefox under SSL.
Thursday, July 26, 2007
I'm back on the flex bandwagon!
Now I'm working for a company in San Diego, and I've made a very beautiful reporting engine for them. As I'm going through my code wanting to make it even easier to work with and make future reports, I came across the DataGridColumn itemRenderer - which imo was implemented incorrectly by adobe.
The problem: You want to pass the field to render in and reuse the same renderer many times, but theres no way to do that!
So, I found a few solutions online, but modified them slightly to require no actionscript coding within the UI component itself (a practice of mine I'm trying my damnedest to stick to, as it forces me to write simple reusable classes, though not always clean and easy to understand the internals of).
The result I aimed for was being able to do this:
<itemRenderers:MoneyRenderer field="roomRevenue" datagridcolumn="{this.roomRevenueDataGridColumn}"/>
roomRevenueDataGridColumn is the id of a datagridcolumn in some datagrid in the report, and "roomRevenue" is the XML field we want to be given a dollar sign and comma separators with two decimal spaces.
And here is MoneyRenderer.as file that enables this:
The problem: You want to pass the field to render in and reuse the same renderer many times, but theres no way to do that!
So, I found a few solutions online, but modified them slightly to require no actionscript coding within the UI component itself (a practice of mine I'm trying my damnedest to stick to, as it forces me to write simple reusable classes, though not always clean and easy to understand the internals of).
The result I aimed for was being able to do this:
<itemRenderers:MoneyRenderer field="roomRevenue" datagridcolumn="{this.roomRevenueDataGridColumn}"/>
roomRevenueDataGridColumn is the id of a datagridcolumn in some datagrid in the report, and "roomRevenue" is the XML field we want to be given a dollar sign and comma separators with two decimal spaces.
And here is MoneyRenderer.as file that enables this:
package com.somecompany.reports.itemRenderers
{
import mx.core.IFactory;
import mx.controls.dataGridClasses.DataGridColumn;
/*
Class used for converting a number to a dollar preceded, comma delimited, 2 decimal formatted string.
Sample Usage:
<itemrenderers:moneyrenderer id="theMoneyRenderer" field="roomRevenue" datagridcolumn="{this.roomRevenueDataGridColumn}"/>
*/
public class MoneyRenderer implements mx.core.IFactory
{
public var field:String;
public function set dataGridColumn(dgc:DataGridColumn):void {
dgc.itemRenderer=this;
}
public function newInstance():* {
return new MoneyClass(field);
}
}
}
import mx.controls.Text;
import mx.formatters.CurrencyFormatter;
class MoneyClass extends mx.controls.Text
{
public var field:String;
public function MoneyClass(f:String):void {
field=f;
}
override public function set data(value:Object):void {
super.data = value;
var cf:CurrencyFormatter = new CurrencyFormatter;
cf.currencySymbol = "$";
cf.precision = 2;
if (value != null) {
this.text = cf.format(value[field]);
}
super.invalidateDisplayList();
}
}
Tuesday, January 16, 2007
nullpointerexception in flex style compiling
So far my experience with flex builder's compiler and debugger has been amazing.
However I ran into my first encounter with bad error reporting today.
I would get java.exception.NullPointerException on thetag <mx:Style source="somestyle.css"/>. Hrm. Had to go through commenting out the stylesheet until it compiled to figure out that the swf I generated from an .fla where I didn't have fonts wouldn't coerce the system fonts into the expected names, so trying to access them in that swf generated the exception.
Annoying that the part of the css that caused the error wasn't pointed to - the compiler I guess calls some other java css compiler and can't bubble the details into its context.
Oh well, still a pretty easy thing to fix, but I felt like I was back in javascript or php land, commenting out partial pieces of code to find the culprit breaking the build =)
However I ran into my first encounter with bad error reporting today.
I would get java.exception.NullPointerException on the
Annoying that the part of the css that caused the error wasn't pointed to - the compiler I guess calls some other java css compiler and can't bubble the details into its context.
Oh well, still a pretty easy thing to fix, but I felt like I was back in javascript or php land, commenting out partial pieces of code to find the culprit breaking the build =)
Monday, January 8, 2007
Progress Event in Flex's URLStream
The low down is that the progress event does not work like I wanted it to. In case anyone else is attempting to use it and running into problems, I feel for you.
I have a .net aspx page which stores the Response stream in the application state and just idles, so that other page activations can write to it when needed. I keep track of client ID's and all is good: I can send the right stuff to the right clients.
However, I needed to set up polling on URLStream.bytesAvailable because ProgressEvent wouldn't fire if only a few bytes had been received. I also have to send at least 300 bytes to get Response.Flush() to actually flush! Kind of annoying. I try to avoid setInterval like the plague. Another odd thing, before any bytesAvailable is shown, I have to send about 2000 bytes. Then I can detect changes within 3-400 bytes as they come in, even if separated by 10 seconds or 10 minutes.
Now I have a framework accomplishing server push where clients can interact very quickly and be aware of eachother's actions immediately.
Say a user posts a reply in a forum you're currently looking at. Well, his page activation to save his reply will trigger a server-side event listener you established on that forum, causing you to get the updated data BEFORE it's even written to the database. Your view updates the forum live as if it were some kind of chat application. No need to refresh constantly while at work and tabbing back into that forum you're interested in, just leave it up and see the replies already there when you tab back in.
This is a HUGE step forward imo. All this talk about web 2.0 and I'm excited to be part of it.. and to be doing it right; not with some polling ajax hack.
Flex rocks.
I haven't been posting a lot of my work lately because I got a talk from the boss about keeping it under wraps. So I likely won't be posting code here anymore.
I have a .net aspx page which stores the Response stream in the application state and just idles, so that other page activations can write to it when needed. I keep track of client ID's and all is good: I can send the right stuff to the right clients.
However, I needed to set up polling on URLStream.bytesAvailable because ProgressEvent wouldn't fire if only a few bytes had been received. I also have to send at least 300 bytes to get Response.Flush() to actually flush! Kind of annoying. I try to avoid setInterval like the plague. Another odd thing, before any bytesAvailable is shown, I have to send about 2000 bytes. Then I can detect changes within 3-400 bytes as they come in, even if separated by 10 seconds or 10 minutes.
Now I have a framework accomplishing server push where clients can interact very quickly and be aware of eachother's actions immediately.
Say a user posts a reply in a forum you're currently looking at. Well, his page activation to save his reply will trigger a server-side event listener you established on that forum, causing you to get the updated data BEFORE it's even written to the database. Your view updates the forum live as if it were some kind of chat application. No need to refresh constantly while at work and tabbing back into that forum you're interested in, just leave it up and see the replies already there when you tab back in.
This is a HUGE step forward imo. All this talk about web 2.0 and I'm excited to be part of it.. and to be doing it right; not with some polling ajax hack.
Flex rocks.
I haven't been posting a lot of my work lately because I got a talk from the boss about keeping it under wraps. So I likely won't be posting code here anymore.
Friday, December 15, 2006
Flex Builder 2.01 and mx.modules
Ok, so pong exploration project delayed slightly.
I'm working with flex builder 2.01 and they have put quite a bit of work into mx.modules.
There weren't any examples anywhere, so I was left to explore the API documentation.
Most of my day was spent wrestling in IIS PHP MYSQL hell getting a wiki setup, but after I got that done, I devoted fulltime to replacing my old classloader flex hacks with mx.modules.
I just got them working. They were very foreign at first and I was cursing at not having better examples to work with, but now that I know how they're used, I can drive home victorious.
Some code for others who may be struggling with these puppies:
First I created a ModuleEventHandler to hold an instance of my global framework that I want to pass into the module with an init method later. (You're supposed to be able to do this by passing it to the create method, but I couldn't get that working yet).
public class ModuleEventHandler {
public var gui:SomeFrameworkInterface;
public function ModuleEventHandler(gui:SomeFrameworkInterface) { this.gui=gui; }
public function onModuleReady(e:ModuleEvent):void {
var i:IModuleInfo = ModuleManager.getModule(e.target.url);
Object(i.factory.create()).init(gui);
}
}
Then I created a generic loadModule function that will do the dirty work. All my modules will be suffixed with Wrapper.swf.
public function loadModule(name:String):void {
var m:ModuleLoader = new ModuleLoader();
m.url = name+"Wrapper.swf";
m.loadModule();
m.addEventListener(mx.events.ModuleEvent.READY ,(new ModuleEventHandler(gui)).onModuleReady);
}
the SomeWrapper class looks like this
public class SomeWrapper extends mx.modules.ModuleBase implements IFlexModuleFactory
{
public var gui:SomeFrameworkInterface;
public function init(gui:SomeFrameworkInterface) { this.gui=gui;
//other code here to modify the gui how you want to using the module stuff
// most likely dispatch some event on it that it reacts to.
}
public function create(... parameters):Object { return new SomeWrapper(); }
public function info():Object { return {}; }
}
In my interface I have an accordian that the module adds itself to, and its working so I'm stoked =)
I'm working with flex builder 2.01 and they have put quite a bit of work into mx.modules.
There weren't any examples anywhere, so I was left to explore the API documentation.
Most of my day was spent wrestling in IIS PHP MYSQL hell getting a wiki setup, but after I got that done, I devoted fulltime to replacing my old classloader flex hacks with mx.modules.
I just got them working. They were very foreign at first and I was cursing at not having better examples to work with, but now that I know how they're used, I can drive home victorious.
Some code for others who may be struggling with these puppies:
First I created a ModuleEventHandler to hold an instance of my global framework that I want to pass into the module with an init method later. (You're supposed to be able to do this by passing it to the create method, but I couldn't get that working yet).
public class ModuleEventHandler {
public var gui:SomeFrameworkInterface;
public function ModuleEventHandler(gui:SomeFrameworkInterface) { this.gui=gui; }
public function onModuleReady(e:ModuleEvent):void {
var i:IModuleInfo = ModuleManager.getModule(e.target.url);
Object(i.factory.create()).init(gui);
}
}
Then I created a generic loadModule function that will do the dirty work. All my modules will be suffixed with Wrapper.swf.
public function loadModule(name:String):void {
var m:ModuleLoader = new ModuleLoader();
m.url = name+"Wrapper.swf";
m.loadModule();
m.addEventListener(mx.events.ModuleEvent.READY ,(new ModuleEventHandler(gui)).onModuleReady);
}
the SomeWrapper class looks like this
public class SomeWrapper extends mx.modules.ModuleBase implements IFlexModuleFactory
{
public var gui:SomeFrameworkInterface;
public function init(gui:SomeFrameworkInterface) { this.gui=gui;
//other code here to modify the gui how you want to using the module stuff
// most likely dispatch some event on it that it reacts to.
}
public function create(... parameters):Object { return new SomeWrapper(); }
public function info():Object { return {}; }
}
In my interface I have an accordian that the module adds itself to, and its working so I'm stoked =)
Thursday, December 14, 2006
VO Objects and a Command Pattern in Flex
I'm doing a bunch of experimenting with a sort of AJAX style Flex Client-Server implementation.
Basically, I'm setting up a one-way socket connection from the server to the client, sending an int of the size of an AMF3 object, followed by that object. (in c#.net using flourine), and if I don't need to send another object, the connection is keep-alive, so I just don't send it. A use case of this is any real-time network based application such as chat, or a networked game such as pong. Its less expensive to keep a connection rather than make a new one over and over. This is an excellent way of accomplishing Server-Push for applications where the client isn't sending data to the server that often, but is receiving it very often. (so no polling protocol is required)
The flex client reads an int SIZE, then waits for that many bytes to be available, then reads an AMF3 object, casts it to a type MessageVO, and then calls interpret on it.
[code]
package vo {
[RemoteClass(alias="vo.MessageVO")]
public class MessageVO { public var type:Number; public function interpret():void { } }}
[/code]
We can then have many different types of messages, each who's client implementation has a fleshed out interpret method, but who's server implementation has only the members defined.
For example:
import model.ModelLocator;
package .vo {
[RemoteClass(alias="vo.ChatMessageVO")]
public class ChatMessageVO extends MessageVO {
public var message:String;
public var fromUserID:Number;
public function interpret() { ModelLocator.getInstance().chatMessages.push(this); }
}
}
When flex reads the amf object, and calls interpret on it, flex knows the object type is a ChatMessage underneath the covers, so the implemented interpret method in the ChatMessage class is called, and the singleton ModelLocator gets a new chat message in the chatMessages array. (Which other classes are binding to).
I'm also debating making a new event type of MessageReceivedEvent which contains the message that was received, so anyone can listen for events that they broadcast.
I'm working on a very modular architecture at the moment, modules need to be able to implement a pattern and expect other modules to adhere to this pattern for interoperability, so I'm testing out a bunch of different patterns to see what will work best across the categories of development time, runtime execution, 3rd party implementation time.
Tomorrow I'll have a networked version of that pong app using this pattern available, additionally you will be able to chat with your opponent.
Basically, I'm setting up a one-way socket connection from the server to the client, sending an int of the size of an AMF3 object, followed by that object. (in c#.net using flourine), and if I don't need to send another object, the connection is keep-alive, so I just don't send it. A use case of this is any real-time network based application such as chat, or a networked game such as pong. Its less expensive to keep a connection rather than make a new one over and over. This is an excellent way of accomplishing Server-Push for applications where the client isn't sending data to the server that often, but is receiving it very often. (so no polling protocol is required)
The flex client reads an int SIZE, then waits for that many bytes to be available, then reads an AMF3 object, casts it to a type MessageVO, and then calls interpret on it.
[code]
package vo {
[RemoteClass(alias="vo.MessageVO")]
public class MessageVO { public var type:Number; public function interpret():void { } }}
[/code]
We can then have many different types of messages, each who's client implementation has a fleshed out interpret method, but who's server implementation has only the members defined.
For example:
import model.ModelLocator;
package .vo {
[RemoteClass(alias="vo.ChatMessageVO")]
public class ChatMessageVO extends MessageVO {
public var message:String;
public var fromUserID:Number;
public function interpret() { ModelLocator.getInstance().chatMessages.push(this); }
}
}
When flex reads the amf object, and calls interpret on it, flex knows the object type is a ChatMessage underneath the covers, so the implemented interpret method in the ChatMessage class is called, and the singleton ModelLocator gets a new chat message in the chatMessages array. (Which other classes are binding to).
I'm also debating making a new event type of MessageReceivedEvent which contains the message that was received, so anyone can listen for events that they broadcast.
I'm working on a very modular architecture at the moment, modules need to be able to implement a pattern and expect other modules to adhere to this pattern for interoperability, so I'm testing out a bunch of different patterns to see what will work best across the categories of development time, runtime execution, 3rd party implementation time.
Tomorrow I'll have a networked version of that pong app using this pattern available, additionally you will be able to chat with your opponent.
Subscribe to:
Posts (Atom)