Showing posts with label flex. Show all posts
Showing posts with label flex. Show all posts

Friday, April 22, 2011

Flex Compiler Constants

There is plenty of information on the web talking about how to specify constants for the Flex compiler so I've compiled a cheat sheet of the essentials:
  • Constant values can be defined in main-config.xml for the flex/mxml compiler so that they don't have to be edited in eclipse preferences.
  • Values for String constants should have quotation marks around them
    • Whether you are defining strings in your maven's pom.xml file to manage maven builds:
      <property>
           <name>MY_CONSTANTS::someStringConstant</name>
           <value>"Hello World"</value>
      </property>
    • Or you are using *-config.xml file to manage Eclipse builds:
      <define>
           <name>MY_CONSTANTS::someStringConstant</name>
           <value>"Hello World"</value>
      </define>
  • Values for Boolean constants DO NOT need any quotations.
    • pom.xml
      <property>
           <name>MY_CONSTANTS::someBooleanConstant</name>
           <value>true</value>
      </property>
    • *-config.xml
      <define>
           <name>MY_CONSTANTS::someBooleanConstant</name>
           <value>true</value>
      </define>
  • More to come...

Wednesday, February 16, 2011

Making the most of Spring-Flex 1.5.x

First of all the maven dependency can be appropriated like so:
<dependency>
<groupid>org.springframework.flex</groupId>
<artifactid>spring-flex-core</artifactId>
<version>1.5.0.M2</version>
</dependency>

One of the never-before-seen features that has just been released as part of M2 is to allow a custom LoginCommand to be plugged in via the tag. Here's the forum thread that served as the matchstick for this great feature to be added. Why else would someone want to do this? Well to take away simple flaws like this one until the open-source project gets around to it.

If you run into issues with the latest spring-flex-1.5.xsd not being published look here. And its always a good idea to visit the forums as well.

Any users who utilized the services-config.xml to setup a custom logger, may notice that it doesn't kick-in anymore. That is because the good folks at spring-flex had the foresight to add a DefaultExceptionLogger. But as great as that is, I must admit that it is a bit of mystery as to how one can make the default go away.

Regardless, having the javadocs and the reference by your side is always helpful.

Something that troubles a few folks is not knowing that using <flex:secured/> tag (even before M2) will blow away any security configuration that was done in services-config.xml, so it is important to have a look at flex-servlet.xml and make sure you know whether or not the <flex:secured/> tag is being used.

It is also worth knowing that the M2 release is not without its flaws. Whatever is wrong with it will be fixed in 1.5.0RC1 so if you want whatever has already been fixed before RC1 becomes available then get a SNAPSHOT build.

Friday, October 1, 2010

ResourceManager is only as good as the components you use it with

The flex framework provides many conveniences out-of-the-box, one of them being the ResourceManager. It works wells and until recently I thought one could do no wrong by it.

Yet, as I recently found out, even the most fool-proof components are only as good as the developer using them. Being someone who started working directly with Flex 4, I have had it way too easy. And sometimes I miss out on the bigger picture as I lack the fundamentals that someone who predates the flex 4 framework, would naturally have.

Recently I was faced with a surprising scenario where the ResourceManager had all the translations in various languages for a given key, yet it would always only load one set of translations. After loading the initial translation for a given language, it would simply refuse to update the label, even as I flipped through and tried to change the locales one by one.

The resources for the resource manager were being downloaded from the server side and loaded on the fly into the ResourceManager instance. Adobe has a very nice example of this on their live docs website. But the first translation for the first language to have appeared would stick around and not change!

Another colleague, who was not so naive as to simply take things at face value, pointed out to me that I was trying to use the ResourceManager too soon so perhaps the translation in my label was from a point in time when the rest of the translations had not made it over. But looking at IResourceManager we realized what a well-behaved component it is! As it makes an effort to fire-off change events in order to alert its users that perhaps now there are more exact/locale-specific translations for them to lookup. So what could possibly be wrong?

The AHA moment: my pre-flex-4 colleague noticed that the over-arching component containing the ResourceManager bindings was actually and since it did not implement, extend or mixin the event dispatcher functionality, it would NOT receive property change events! And as soon as I started using something like the problem disappeared.

It just goes to show you that frameworks cannot replace a competent and well-versed developer who excels in his/her area.

Wednesday, September 1, 2010

How to view source for an embedded SWF hosted on a different domain

This is second in a series of blogs that attempt to capture all the aspects of making a good blog even better. The first one covered how to Add SWFs to your blogger posts.

Today we will cover how to allow the SWFs in your blog to provide the users with the option to with the source. You can start by following the instructions provided here, in order to make sure that when users right-click on a SWF file, they would see the "View Source" option.

But this brings up a new challenge if your SWF file itself is embedded in the blog but is actually hosted elsewhere because right-clicking and selecting "view source" results in a URL which is broken because it is generated relative to the blog (http://www.blog.com/article/srcview/index.html) ... instead of the hosting webspace url (https://some.website.com/hosting/srcview/index.html).
  1. You might notice that when you use Flash Builder to publish the code, it adds the viewSourceURL property to your main application file. What you need to do in addition to that is:
    1. Leave the original property in place because setting it later for the first time in an event handler, such as the one for applicationComplete, does not add it to the context-menu so one must still have the original attribute/propety in the application tag.
    2. Set the viewSourceURL again in a handler for the applicationComplete event so that the value is updated correctly.
    3. Build the host URL as shown here in the handler when updating the viewSourceURL value.
    <s:Application
                   ...
                   viewSourceURL="srcview/index.html"
                   applicationComplete="applicationCompleteHandler(event)"
                   >
        <fx:Script>
            <![CDATA[
                protected function applicationCompleteHandler(event:FlexEvent):void
                {
                    var swfURL:String = FlexGlobals.topLevelApplication.loaderInfo.url;
                    swfURL = swfURL.substr(0, swfURL.lastIndexOf("/") + 1)
                    var tempDom:Array = swfURL.split("/");
                    var domURL:String = tempDom.slice(0,3).join("/") + "/";
                    viewSourceURL = domURL+ "srcview/index.html";
                }
            ]]>
        </fx:Script>
        ...
    </s:Application>
  2. A workaround is to use the <iframe/> tag instead of <embed/> tag because that way the url generated to "view source" will be relative to the hosting website and not the embedding website.
  3. Also there is some speculation that if one uses swfobject instead of the embed tag. This blog seems to have a non-standard URL specified for the source versus the SWF but it is relative and not absolute, so again it may or may not work for absolute URLs. Following this example, it could probably be accomplished like so:
    var flashvars = {};
    flashvars.srcUrl = "https://some.website.com/hosting/srcview/index.html";
    ...
    swfobject.embedSWF(arg1,arg2,arg3,arg4,arg5,arg6,flashvars,arg8,arg9);

As a side-note here's an article that makes a very convincing argument for using SWF Object 2.

Flex4: How to build a Stop Watch Timer

Here's a working sample:

The following blog offered a series of very convincing arguments that led me to use flash.utils.getTimer() to build the Stopwatch demonstrated above.

The component constantly resets the time based on when it is made visible/invisible (click here twice to see it get reset +/-). If your components show a custom busy / loading skin rather than just a simple busy cursor, then you can leverage this component to also track how long your activities usually take visually.

Here's the source code:
  1. main.mxml
  2. StopWatch.as
  3. StopWatchSkin.mxml



Monday, August 2, 2010

Versioning Flex Applications: Displaying Hudson, Maven, SVN build or revision numbers

Hudson sets the values for the following environment variables:
  1. BUILD_NUMBER
  2. SVN_REVISION
In order to show the build and revision numbers in the UI, these variables could be written out to a properties file via a maven project's pom.xml file using a plugin. And then if one did this early enough in the maven lifecycle, your flex application could be compiled to read the version information as key-value pairs from the properties file and show the info on screen when it runs.

Alas there is no decent maven plugin out there to write environment variables out to a file. I found the following plugins out there but none of them (+/-) did the trick.
  1. org.codehaus.mojo:properties-maven-plugin can be found in the following repo You can find proper documentation here. It never printed anything but the Java system level variables so it was useless when it came to tracking the environment variables set by Hudson.
  2. org.sonatype.plugins:maven-properties-plugin can be found in the following repo but this isn't the one you want to use. It has only one goal called filter-file and I cannot find any page documenting its usage no matter how hard I try.
  3. Even placing the info generated by the mvn help:system command-line invocation seemed like a decent idea. But after configuring the same command to be invoked inside a pom file(+/-) I realized that it spit out some header lines that weren't commented out in a manner suited for a properties file.
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-help-plugin</artifactId>
            <version>2.1.1</version>
            <executions>
              <execution>
                <phase>generate-resources</phase>
                <goals>
                  <goal>system</goal>
                </goals>
                <configuration>
                  <output>${basedir}/src/locale/app.properties</output>
                </configuration>
              </execution>
            </executions>
          </plugin>

You can resort to usind the ant plugin inside Maven to do a macro-style replace technique. You can read more about it here.

Or the best way is to have a template file (+-) and leverage Maven model like this (+-)
<?xml version="1.0" encoding="UTF-8"?>
<root>
<buildNumber>${buildNumber}</buildNumber>
<svnRevisionNumber>${svnRevision}</svnRevisionNumber>
</root>
<project >
  ...
  <!-- Map the values provided by the Hudson build to local variables -->
  <properties>
    <buildNumber>${BUILD_NUMBER}</buildNumber>
    <svnRevision>${SVN_REVISION}</svnRevision>
  </properties>
  ...
  <build>
    ...
    <!-- Update version.xml file with the versioning data -->
    <resources>
      <resource>
        <targetPath>${project.build.directory}/${project.artifactId}-${project.version}</targetPath>
        <filtering>true</filtering>
        <directory>${basedir}/src/main/resources</directory>
        <includes><include>version.xml</include></includes>
      </resource>
    </resources>
    ...
  <build>
  ...
<project >

Also as a sidenote: The Hudson variables can be placed inside the manifest file if your artifact being built happens to be a war or jar file. Read more on that here.

Links:
Home / Using Flex 4 / Developer tools / Flex compilers / Using mxmlc, the application compiler / Passing Strings
How to configure flexmojos to pass in compile time variables:
gmail thread
official docs


Friday, July 9, 2010

Flex Deep Linking and Server Side Redirects

With Flex its easy to:
a) use deep-linking (IBrowserManager & BrowserManager) to create application URLs that allow the use of the browser's backward & forward navigation buttons,
b) bookmarking a deep-linked URL and reloading it also works just fine

B U T ... what doesn't work is when you need to authenticate users before letting them access their bookmarked content. The reason behind this is simple ... the out-of-the-box javascript (history.js file) provided by the flex framework uses the # (pound/sharp) symbol to manage the deep link fragments. For ex:

1) http://www.hostname.com/application.swf#view=account
2) http://www.hostname.com/application.swf#view=profile
3) http://www.hostname.com/application.swf#edit=account
4) http://www.hostname.com/application.swf#edit=profile

Now according to the HTTP spec, the part after the # symbol is not sent over to the server in the HTTP request. This means that your server has no clue where to redirect the users after they successfully authenticate!

What can you do?

Workaround # 1:
1) Provide a bookmark button in the application itself and replace the # symbol with the ? symbol when storing the link.
2) Edit your client side to treat the ? symbol in the same way it treats the # symbol, therefore picking up the deep link fragments properly.

Workaround # 2:
1) Have your users manually edit their bookmarked links to replace the # symbol with the ? symbol.
2) Now that the deep link fragment is making it over to your server side as a URL parameter, edit your server side to replace the ? symbol with the # symbol when redirecting the user back to their bookmarked link. If you are using the spring-security framework then you can refer to the following blog as a reference on how to configure your application context's xml files properly.

Saturday, May 22, 2010

Moving from compile time to run time locales

So you just woke up and realized that users are complaining about slow load times and you need to make you SWF file leaner ... where do you start?

Baby Step # 1: If you have localized your application then begin by removing all the properties files for the various locales and only loading what any given user needs at a given time.

The best place to start such an endeavor is at Adobe's live help: Using Flex 4 > Enhancing usability > Localization

The link above is helpful and critical in many ways but it doesn't talk about developers who use Maven and what they need to start doing differently in their build process before they start worrying about how to load the localized SWF files.

If you are using flexmojos then a part of your pom.xml probably looks something like:
        <configuration>
          ...
          <compiledLocales>
              <locale>en_US</locale>
              <locale>de_DE</locale>
          </compiledLocales>
          <mergeResourceBundle>true</mergeResourceBundle>
          <resourceBundlePath>${basedir}/src/main/flex/locale/{locale}</resourceBundlePath>
        </configuration>

Initially this may have seemed great as it did the job fast but now you need to change this to something like:
        <configuration>
          ...
          <runtimeLocales>
              <locale>en_US</locale>
              <locale>de_DE</locale>
          </runtimeLocales>
          <mergeResourceBundle>false</mergeResourceBundle>
          <resourceBundlePath>${basedir}/src/main/flex/locale/{locale}</resourceBundlePath>
        </configuration>
A few helpful flexmojos references can be found here and here.

Also in the project where you put together your war file, you need to get the runtime locales' SWF files over in addition to the application. So follow the instructions here, with a few more details listed here.

Now if you head over to the adobe site I mentioned earlier and follow their instructions, you may end up with:
Error: Unable to load resource module from ...
This happened when using:
var resourceModuleURL:String = "locales/myApp-version-locale.swf";
var resourceManager:IResourceManager = ResourceManager.getInstance();
var eventDispatcher:IEventDispatcher = resourceManager.loadResourceModule(resourceModuleURL);
Even though it may seem logical to try and reference the resource SWF as if it was a relative file and hope that Flex will fill in the blanks, that is not the case ... so a quick & dirty solution can be to use localhost like so:
var resourceModuleURL:String = "http://localhost:8080/myApp/locales/myApp-version-locale.swf";
var resourceManager:IResourceManager = ResourceManager.getInstance();
var eventDispatcher:IEventDispatcher = resourceManager.loadResourceModule(resourceModuleURL);
And you'll have a working solution ... mind you that I've left out some critical code that Adobe cover in their article which come after the few lines I've outlined here.

If it is unappealing to use localhost, you can look into configuring crossdomail.xml or refer to these great articles for an alternative approach:
1) Flex: Loading Remote Modules Throws the following: Error: Unable to load resource module from…
2) Loading a Remote Module into a Local App

Monday, May 17, 2010

Fluid Layout

Assumptions:
1) The browser represents the container.
2) The resizing of the container's width and height are primarily at the user's mercy and the components inside it must behave like water, which has no choice but to overflow if the beaker that it is being poured into is too small.

I've provided a sample that demonstrates what it would be like to have fluidity on the horizontal plane.

Click here to see the sample in action.

1) Try to resize your browser window and click on the collapsible and expandable right/left side buttons to see how the horizontal scroller behaves as the browser is resized.
2) If both the left and right side buttons stay expanded, then you will see the horizontal scrollbar appear after shrinking the browser window to be smaller than 500 pixels wide.
2) If both the left and right side buttons stay collapsed, then you will see the horizontal scrollbar appear after shrinking the browser window to be smaller than 300 pixels wide.

Here's the sample source.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx">

    <fx:Script>
        <![CDATA[
            protected function expandCollapseHandler(event:Event):void
            {
                if (event.target.width>100) {
                    event.target.width=100;
                } else {
                    event.target.width=200;
                }
            }
        ]]>
    </fx:Script>

    <s:Scroller left="0" right="0" top="0" bottom="0">
        <s:Group width="100%" height="100%">
            <s:Group width="100%" height="100%">
                <s:Button id="buttonLeft"
                          minWidth="100"
                          width="200"
                          height="100%"
                          label="buttonLeft Height:{buttonLeft.height}, Width:{buttonLeft.width}"
                          click="expandCollapseHandler(event)"/>
                <s:Button id="buttonCenter"
                          left="{buttonLeft.width}"
                          right="{buttonRight.width}"
                          minWidth="100"
                          height="100%"
                          label="buttonCenter Height:{buttonCenter.height}, Width:{buttonCenter.width}" />
                <s:Button id="buttonRight"
                          right="0"
                          minWidth="100"
                          width="200"
                          height="100%"
                          label="buttonRight Height:{buttonRight.height}, Width:{buttonRight.width}"
                          click="expandCollapseHandler(event)"/>
            </s:Group>
        </s:Group>
    </s:Scroller>
</s:Application>
That's all folks.


Thursday, May 13, 2010

Adding SWFs to your blogger posts

1) Find a location to host your swf files.
For example, you can log into Google Sites and host your content by uploading the swf files as attachments:
http://sites.google.com/site/yourUsernameGoesHere/system/app/pages/admin/attachments

2) Make sure to upload the following swf files in addition to your main swf file.
2.1) spark_4.0.0.14159.swf
2.2) textLayout_1.0.0.595.swf
2.3) rpc_4.0.0.14159.swf
2.4) sparkskins_4.0.0.14159.swf
2.5) framework_4.0.0.14159.swf
2.6) playerProductInstall.swf
2.7) osmf_flex.4.0.0.13495.swf
These are dependencies without which you will face various errors when trying to run your main swf file.

a) Error: Error #2030: End of file was encountered.
at flash.net::URLStream/readBytes()
at flash.net::URLLoader/onComplete()

b) Error #2048: Security sandbox violation: http://...-s-sites.googlegroups.com/site/usernam/blah.swf?attachauth=...&attredirects=0 cannot load data from http://sites.google.com/site/username/some_missing_dependency.swf

3) Afterwards, get the link to your swf and to embed it in your blog as outlined here.

4) After embedding the SWFs in your blog, you may feel that your posts load significantly slower that they did before. You can remedy this situation and speed-up the load times if you place a div tag around your embedded tags and have the default mode set to be collapsed. This will give your readers the option of expanding the content and causing the flash player to load the swf files on demand.

Here's an example of all the code that I had to put into this post.
<style type="text/css">
  .commenthidden {display:none}
  .commentshown {display:inline}
</style>
<script type="text/Javascript">
  function togglecomments (postid)
  {
    var whichpost = document.getElementById(postid);
    if (whichpost.className=="commentshown")
    {
      whichpost.className="commenthidden";
    }
    else
    {
      whichpost.className="commentshown";
    }
  }
</script>

<a href="javascript:togglecomments('1')">Expand/Collapse Example</a>
<div class="commenthidden" id="1">

<embed src="http://sites.google.com/site/pulkitsinghal/Bounds1.swf" quality="high" bgcolor="#869ca7" width="650" height="100" name="Main" align="middle" play="true" loop="false" quality="high" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.adobe.com/go/getflashplayer">
</embed>

</div>

To get the following to work as I described above: Expand/Collapse Example