Introducing FlowMVC

FlowMVC

Introducing FlowMVC: A reference architecture & MVC extensions for developers using Sencha ExtJS or Sencha Touch with DeftJS.

Take what you already know and go with it… just code with the Flow.

FlowMVC builds on the work of DeftJS, Sencha ExtJS, and Sencha Touch APIs adding extensions that enable Flex and ActionScript developers to take their expertise and apply them to the HTML5/JavaScript world. It’s a framework that users of Flex MVC-based architectures, such as Swiz or Parsley, will be familiar with. FlowMVC can help anyone, but Flex developers will find it particularly familiar.

In addition, for enterprises looking to leverage intellectual capital across platforms with Sencha Touch and Sencha ExtJS, it provides an application structure with reusability and portability in mind encouraging the re-use of application and business logic.

For enterprises struggling with the myriad of available javascript frameworks, FlowMVC and the tools used in the Cafe Townsend Demo Project, provide a level of security for enterprise architects and managers that their goals, such as well defined project structure, documentation, testability, localization, and re-use of resources, both human and IC, are met.

FlowMVC works with ExtJS version 4.1 and up, Sencha Touch version 2.0 and up, and DeftJS version 0.8.0 and up.

Highlights

  • FlowMVC uses a Global Event Bus for loosely coupled object communication.
  • FlowMVC separates Mediators from Service Controllers — it strictly separates Mediators (View Controllers that own views) from Service Controllers (that own services).
  • FlowMVC has Service Objects separating server side logic into it’s own layer.
  • FlowMVC has Mock Service Objects with delays built-in for async service stubbing.
  • FlowMVC looks and feels like a robust OO client using traditional MVC architecture and IoC frameworks.
  • FlowMVC has an awesome logger!

Documentation Overview

Full documentation on the features and usage of FlowMVC is available on the Wiki. Show me code.

Examples

Pending Features

This effort is still ongoing with some in-progress work that will provide the following features:

  • Unit Tests with Jasmine - (In Progress @ 60%)

FlowMVC is currently considered an Alpha release, so help us make it better by adding to the Issues Page where necessary. Please free to reach out to us and lets us know what you like, love, hate, feature requests, defects, etc on the Issues Page.

Post to Twitter Tweet This Post

, , , ,

No Comments

Jasmine Unit Test for Sencha Custom Asynchronous Event

We’ve created some custom framework objects to extend the Sencha MVC framework and needed to test custom events we’re dispatching from those objects. Here’s a simple example testing a custom event being fired when a store’s selected record method has been called; the method should fire off an event with type “selectedRecord” and the actual selected record being set on the store using the fireEvent() method in the base Sencha Store:

describe("CafeTownsend.store.EmployeeStore", function() {

    // reusable scoped variable
    var store = null;

    // setup
    beforeEach(function() {
        store = Ext.create("CafeTownsend.store.EmployeeStore");
    });

    // teardown
    afterEach(function() {
        store = null;
    });

    describe("setSelectedRecord() method", function() {

        it("should be a function", function() {
            expect(typeof store.setSelectedRecord).toEqual("function");
        });

        it("should have a selected record", function() {

            var model = {
                id: 1,
                firstName: "Rob",
                lastName: "Dougan",
                phoneNumber: "508-566-6666"
            };

            spyOn(store, "fireEvent");
            store.setSelectedRecord(model);

            expect(store.fireEvent).toHaveBeenCalledWith("selectedRecord", store, model);
            expect(store.fireEvent).toHaveBeenCalledWith("selectedRecord", store, store.getSelectedRecord());
        });

    });
});

The key is using the Jasmine.spy object. The following thread shed some light on this topic for me.

Post to Twitter Tweet This Post

, , , ,

2 Comments

P90X Primer

DISCLAIMER: This is not a tech post. Since people seem to ask me about it all the time I have this email on the ready deck.

Best thing about P90X and what sold me on it 5+ years ago and why I still do it:

  • All workouts <= 60 mins. [NOTE: Except Yoga so I do the 45 min vr Tony offers.]
  • All workouts can be done in a 4×4 square ft area — I used to do it in my little living room in our little condo in Boston.
  • Most moves use your own body weight so less need for extra stuff (although you do need some once you really get into it, like a pull-bar and some bands and/or dumbbells).
  • Can do at home and on the road (via lap/ipad/iphone) — no more driving to gym and it’s cheaper. I have it all stored on my iPad and even use that at home rather than rely on a TV.
  • It’s dumb simple — old school strength and cardio moves that you can learn after 1 round if not already familiar with them. You remember pushups and pull-ups right?

Couple side notes I tell anyone getting into either P90X or Insanity:

If this is your first time doing p90x I highly recommend doing 1/2 of each workout the first wk and then starting to do the full thing the second wk, but counting your second wk as wk 1 in terms of p90x calendar.

Unless you’re in really good shape and have been doing these moves for awhile, the warmup vr of wk 1 that I recommended is more of a learning curve and gives your body a chance to slowly jump in without hurting yourself, tearing muscle, or getting frustrated b/c it’s moving too fast/hard. If you can plow through it without that break-in wk, then rock on…just my 2 cents.

One more tip — some of the moves are awkward and can lead to injury. Just listen yo your body and learn to know the diff between good pain and bad pain; good pain being you’re working hard and you can feel your muscles getting “that burn” vs bad pain where you tear things and injure yourself. Simply put, if you encounter bad pain then modify the move; eg, I have bad knees after years of volleyball so I modify on plyos where necessary but keep on pushing hard to keep the heart rate up.

If you want more details on P90X, then checkout my business partner’s blog as he tells you about his experience with it:

Good luck and hit me with any questions.

Post to Twitter Tweet This Post

, , ,

No Comments

TypeScript Quick Summary

After watching the 53 minute video “Anders Hejlsberg: Introducing TypeScript” last week, I threw together a summary in the form of a bulleted list so my partners that didn’t have time to watch could at least get the gist; if you do have time I highly suggest watching the video and then reading my partner Jesse Warden’s detailed post “TypeScript for ActionScript Developers“. If you want the 10,000 foot view from my POV, here ya go:

In a Nutshell

TypeScript (TS) provides the following constructs to JavaScript developers at author time: Strong, static typing including packages, classes, interfaces, and other common OO constructs; ie, your IDE will perform code completion and type checking as if JavaScript were a real, strongly typed language…to me, this is the single most important thing missing from native JS.

5,000 Foot View

  • Compiles down to normal JS and works with any other existing JS lib right in the same code base, even inline and mixed right in there with your existing JS; this is contrary to sayGWT or CoffeeScript which says you can only use Java and CoffeeScript respectively. With TS, it lives right inline with your JS and you can use as much/little as you want.
  • Common OO constructs with expected keywords and syntax:
    • class
    • interface
    • extends
    • implements
    • super
    • constructor
    • module
    • new
    • public
    • private
    • static
    • void
    • override — not used as TS compiler does for you
    • overload – not used as TS compiler does for you
    • ? — optional properties and method parameters
  • Looks like ActionScript typing:
    • var a:IFoo;
    • function bar(myString:string, myNum:number):bool
    • interface IFoo { var bar:string; doFoo(x:number):void; }
    • class Bar implements IFoo { var bar:string; doFoo(x:number):void; }
  • Private members in classes.
    • NOTE: This is not enforced at runtime. This is purely a author-time thing only as they’re really no private members in JS.
  • Getter/Setter methods in classes (like AS):
    • function get foo():string
    • function  set foo(s:string):void
  • Default and optional values in function methods.
    • interface IFoo { var bar?:string; doFoo(x:number=0, y?:number):void; }
  • Inheritance:
    • Can use the keyword extend for classes, ie classes with inheritance.
    • This is the only time TS injects extra code that you wouldn’t normally see in your JS.
  • Provides method overloading that us Java doods are accustomed to.
    • Nothing special to do here as the TS compiler picks up on multiple methods with the same name but different params and handles this behind the scenes
  • Better keyword this scoping within event handler methods using fat arrow =>. This eliminates the whole creating references to the outer class’s “this” with another var and then passing it into the event handler. Can also help clean up code by eliminating the need for inline, anonymous functions.
  • Support CommonJS and AMD modules
  • Pretty much follows the EcmaScript 6 definitions, which is very similar to AS3
  • Tooling:
  • Extendable:
    • You can create separate declaration/type/config files for existing libs — simply put, the TS compiler uses basic config files that suggest what the types are in the basic JS lang. You can create your own for JQuery, Angular, BackBone, whatever you want and add them to your TS setup — this will give you strong typing for any other JS framework you want.
  • Online, web editor TS Playground and server playground built into the stack
  • 100% Open Source
  • http://www.typescriptlang.org/

Post to Twitter Tweet This Post

,

No Comments

Adobe AIR Won’t Package Modules & Assets From Linked Resources

If you happen to leverage a linked resources directory as your output folder or bin-debug directory for modules and other loaded assets, then you’ll run into problems when trying to export your AIR application for release.

Flash Builder will not recognize linked resource directories in the packaging contents of your AIR application: http://forums.adobe.com/thread/492841

This means modules that you might build to a linked resource directory will not be discovered by AIR when packaging the installer. In order to get around this, you must either use absolute paths (and therefore remove your linked resources) or copy the files to a physical directory in the AIR project’s source path. A simple solution is to create a modules directory in your src/main/resources directory and copy and paste the built modules there.

NOTE: This is just a quick fix and developers should consider using Ant or Maven to do the copying and pasting during the build process.

Post to Twitter Tweet This Post

No Comments

Styling MX Alert in a Spark World

If you’ve ever tried to style the MX Alert in a Spark Application (Flex 4.x), then you know it’s painful…the solution?

Save yourself some time and just create a custom Alert view and skin and use the PopupManager to show/hide the sucker. Takes about 5 mins and ensures you can style it to your hearts content.

Post to Twitter Tweet This Post

2 Comments

One Java Service POJO for AMF/XML/JSON with Spring BlazeDS & Jersey JAX-RS

Introduction

I was reading Christophe Coenraets’ blog post on RESTful services with jQuery and Java using JAX-RS and Jersey and it got me thinking…in order to serve technology agnostic Java Service POJOs to HTML5/JavaScript clients as well as Flex/AIR/Flash clients without writing two service layers and a whole bunch of extra code, why not just put Jersey’s JAX-RS framework next to Spring BlazeDS framework?

Tutorial Goal: Create one Java Service POJO capable of handling RESTful services with XML/JSON over HTTP as well as AMF over HTTP (for RemoteObjects with the Flash Platform) and demonstrate this via a Sencha ExtJS (JavaScript) app and Apache Flex app.

NOTE: I could’ve used Spring’s owen REST framework, but I found Jersey easier than Spring’s 3.02 impl that I’m using and Christophe already banged this out in Jersey so I really just needed to add the Flex part with Spring BlazeDS — big thanks to @ccoenraets for kicking this post off for me! …the point is you can use either Spring or Jersey’s REST impl.

The following is a quick example of a simple Java CRUD Service for beers (because, well, I like beers — Untappd) that serves both HTML5/JavaScript clients via XML/JSON over HTTP as well as Flex clients via AMF over HTTP using Spring BlazeDS.

Download Sample Code

Assumptions

  • This post assumes you know what RESTful Services are and have read RESTful services with jQuery and Java using JAX-RS and Jersey so you’re familiar with Jersey.
  • This post assumes you’re familiar with Flex and using BlazeDS for RemoteObject calls with the Flash Platform.
  • This post assumes you’re familiar with JavaScript and/or Sencha ExtJS (a JavaScript framework similar to Flex with a robust UI library, services, and prescribed MVC architecture).
  • This example uses a Tomcat 7 server running on http://localhost:8080/SpringBlazeDSJerseyServer and will refer to that URL throughout the post.

How’s It Work At A High Level?
Both Spring BlazeDS and Jersey work off of the same simple principle of servlet filtering which is configured in web.xml and explained in detail further down in the article — in our example the following mappings take care of everything

Spring BlazeDS = http://localhost:8080/SpringBlazeDSJerseyServer/messagebroker/*

Jersey = http://localhost:8080/SpringBlazeDSJerseyServer/rest/*

Bottom line, these frameworks sit next to each other in the servlet container and do not interfere with each other or use each other in any way. These simply share the same Java Service so you’re not coding one for Flex and one for HTML/JavaScript.

One Java Service to Rule Them All

Let’s take a quick peak at the Java Service BeerService and see what’s so special about it. The key to exposing this service to both BlazeDS and Jersey is in the annotations; review the comments above the class to see what each does.

package com.webappsolution.springbdsjersey.service.impl;

/**
 * <b>Spring BlazeDS Annotations</b>
 * <p>
 * The annotation Service is used to tell Spring this object is a service bean.
 * The annotation RemotingDestination is used to expose it as a Flex Remoting destination.
 * The annotation RemotingInclude above individual methods is used to expose public methods of the service to Flex
 * as opposed to RemotingExclude which hides them from a Flex client.
 * </p>
 *
 * <b>Jersey JAX-RS Annotations</b>
 * <p>
 * The annotation Path is used to define the base URL pattern (after the app server's context) to map to this RESTful Jersey service.
 * The annotation GET above individual methods is used to define the HTTP action/verb associated with the service method.
 * The annotation Produces above individual methods is used to define the request and response types for the service method.
 * The annotation GET Path("{id}") above individual methods is used to add specific method parameters for the service method via REST path.
 * </p>
 */
@Service("beerService")
@RemotingDestination
@Path("/beer")
public class BeerService implements IBeerService
{
	private static Log logger = LogFactory.getLog(BeerService.class);

	BeerDAO dao = new BeerDAO();

	@Override
	@RemotingInclude // BDS
	@GET // JERSEY
	@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) // JERSEY
	public List<BeerDTO> findAll()
	{
		logger.debug("findAll");
		return dao.findAll();
	}

	@Override
	@RemotingInclude // BDS
	@GET @Path("{id}") // JERSEY
	@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) // JERSEY
	public BeerDTO findById(@PathParam("id") String id)
	{
		logger.debug("findById: " + id);
		return dao.findById(Integer.parseInt(id));
	}

	@Override
	public BeerDTO create()
	{
		logger.debug("create");
		return null;
	}

	@Override
	public BeerDTO update()
	{
		logger.debug("update");
		return null;
	}

	@Override
	public void delete()
	{
		logger.debug("delete");
	}

}

Next we’ll need to add an annotation to our simple BeerDTO so Jersey knows how to convert it to XML or JSON; take note of the annotation XMLRootElement:

@XmlRootElement
public class BeerDTO
{
	private int id;
	private String name;
	private String brewery;

	public BeerDTO()
	{
		// TODO Auto-generated constructor stub
	}

	public int getId()
	{
		return id;
	}

	public void setId(int id)
	{
		this.id = id;
	}

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public void setBrewery(String brewery)
	{
		this.brewery = brewery;
	}

	public String getBrewery()
	{
		return brewery;
	}
}

This has no effect on our DTO when being used by Spring BlazeDS.

After that the other big piece to getting this thing cranking is the required JARs (which I packaged up in the WAR so you can play easily) and checking out the web descriptor for the app (web.xml) as it maps incoming servlet requests for Jersey and BlazeDS appropriately.

web.xml - Spring BlazeDS config

<!-- ================================================= -->
<!-- SPRING BLAZEDS PROJECT SETUP -->
<!-- ================================================= -->
<!--	This will configure the BlazeDS message broker as a Spring-managed bean using the simple message-broker tag.
		This will bootstrap the BlazeDS message broker. When you use the message-broker tag without mapping child elements,
		all incoming DispatcherServlet requests are mapped to the MessageBroker.
		You can add mapping child elements if you need more control.
		Any requests hitting the URL http://SpringBlazeDSJerseyServer/messagebroker/* will get mapped to Spring BlazeDS.
                The component scanning for Spring BlazeDS services is done in app-context-flex.xml.
-->
<!-- ================================================= -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
		classpath:/spring/config/applicationContext.xml
	</param-value>
</context-param>

<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
	<listener-class>flex.messaging.HttpFlexSession</listener-class>
</listener>
<servlet>
	<servlet-name>flexspring</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value></param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>flexspring</servlet-name>
	<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>

web.xml - Jersey config

<!-- ================================================= -->
<!-- JERSEY -->
<!-- ================================================= -->
<!--	Configure Jersey JAX-RS to handle RESTful services
		Any requests hitting the URL http://SpringBlazeDSJerseyServer/rest/*
		will get mapped to Jersey. The param "com.sun.jersey.config.property.packages"
		with a value of "com.webappsolution.springbdsjersey.service" tells Jersey
		the package to scan for Jersey enabled services. You can add more than 1.
-->
<!-- ================================================= -->
<servlet>
	<servlet-name>Jersey</servlet-name>
	<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
	<init-param>
		<param-name>com.sun.jersey.config.property.packages</param-name>
		<param-value>com.webappsolution.springbdsjersey.service</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>Jersey</servlet-name>
	<url-pattern>/rest/*</url-pattern>
</servlet-mapping>

Quick HTTP REST Test
Start the Server and hit the following URL: http://localhost:8080/SpringBlazeDSJerseyServer/rest/beer and you should see an XML list of Beers. This is good and means you’re ready to test the Flex side.

As Christophe points out, you can also use the cURL command in terminal to see the results:

  • Get All Beers: curl -i -X GET http://localhost:8080/SpringBlazeDSJerseyServer/rest/beer
  • Get Beer By ID: curl -i -X GET http://localhost:8080/SpringBlazeDSJerseyServer/rest/beer/1
  • Get All Beers - XML: curl -i -X GET http://localhost:8080/SpringBlazeDSJerseyServer/rest/beer -H ‘Accept:application/xml’
  • Get All Beers - JSON: curl -i -X GET http://localhost:8080/SpringBlazeDSJerseyServer/rest/beer -H ‘Accept:application/json’

Flex RemoteObject Beer Service Example
Our simple Flex example has a button that invokes the RemoteObject BeerService.findAll() method and uses the ArrayCollection response to populate a DataGrid.

protected var beerService:RemoteObject;

protected function init(event:FlexEvent):void
{
	this.beerService = new RemoteObject("beerService");
	this.beerService.endpoint = "http://localhost:8080/SpringBlazeDSJerseyServer/messagebroker/amf";
	this.beerService.addEventListener(ResultEvent.RESULT, onBeerServiceResult);
	this.beerService.addEventListener(FaultEvent.FAULT, onBeerServiceRFault);
}

protected function onBeerServiceBtnClick(event:MouseEvent):void
{
	this.beerService.findAll();
}

protected function onBeerServiceResult(event:ResultEvent):void
{
	this.beerDG.dataProvider = event.result as ArrayCollection;
}

protected function onBeerServiceRFault(event:FaultEvent):void
{
	Alert.show("Beer Service Error = " + event.fault.faultDetail, "Error");
}

Assuming your server is still running, run the Flex app and click the “Get Beers!” button and watch the DataGrid populate with some solid brews. Your Flex app should look like:

Sencha ExtJS RESTful Beer Service Example
Similarly, our simple ExtJS example has a button that invokes the RESTful service method BeerService.findAll() via a Proxy within a store that requests JSON as the data format– the response is also mapped back to the Grid.

First, let’s define the matching Beer Model on the client — this matches our BeerDTO on the server and is similar to how we’d mapped Flex ActionScript objects to the same Java BeerDTO.

Ext.define('Beer', {
	extend: 'Ext.data.Model',
	fields:
		[ 'id', 'name', 'brewery' ],
});

Next we’ll create a Store that uses a REST proxy to interact with the Jersey Services and is responsible for mapping the Beer Model we just created to the JOSN request and responses from Jersey. There’s some additional CRUD code that isn’t actually being used in this post but will in the future.

var store = Ext.create('Ext.data.Store', {
    autoLoad: false,
    autoSync: true,
    model: 'Beer',
    proxy: {
    	headers: {
            'accept': 'application/json'
        },
        type: 'rest',
        url: 'http://localhost:8080/SpringBlazeDSJerseyServer/rest/beer',
        reader: {
            type: 'json',
            root: 'beerDTO'
        },
        writer: {
            type: 'json'
        }
    },
    listeners: {
        write: function(store, operation){
            var record = operation.getRecords()[0],
                name = Ext.String.capitalize(operation.action),
                verb;

            if (name == 'Destroy') {
                record = operation.records[0];
                verb = 'Destroyed';
            } else {
                verb = name + 'd';
            }
            Ext.example.msg(name, Ext.String.format("{0} user: {1}", verb, record.getId()));

        }
    }
});

Finally we’ll create our Grid and Button to invoke the service:

var grid = Ext.create('Ext.grid.Panel', {
    renderTo: document.body,
    plugins: [rowEditing],
    width: 500,
    height: 300,
    frame: true,
    title: 'Beers',
    store: store,
    iconCls: 'icon-beer',
    columns: [{
        text: 'ID',
        width: 40,
        sortable: true,
        dataIndex: 'id'
    }, {
        text: 'Name',
        flex: 1,
        sortable: true,
        dataIndex: 'name',
        field: {
            xtype: 'textfield'
        }
    }, {
        header: 'Brewery',
        flex: 1,
        sortable: true,
        dataIndex: 'brewery',
        field: {
            xtype: 'textfield'
        }
    }]
});

Ext.create('Ext.Button', {
    text: 'Get Beers!',
    renderTo: Ext.getBody(),
    handler: function() {
    	store.load();
    }
});

Assuming you’re server is still running, run the ExtJS app by hitting the URL http://localhost:8080/SpringBlazeDSJerseyServer/extjs/springblazedsjersey/restful.html and click the “Get Beers!” button and watch the DataGrid populate with some solid brews. Your ExtJS app should look like:

Any questions?

Post to Twitter Tweet This Post

3 Comments

How to Make a SWFLoader Scroll

By default, the SWFLoader doesn’t scroll so developers often wrap it in a scrolling mx container like a Canvas (since it does scroll and it’s scroll policies are set to auto). What I didn’t think about was that I’d have to know the actual size of the content I was loading in order for the scrollbars to appear. I tested this in both an MX Application and a Spark Application with Flex SDK 4.5 and achieved the same results.

To reiterate, my small test app below suggests that developers must know the size of the content they are loading in SWFLoader in order for the scrollbars to appear around that loaded content.

When I think about it, it makes sense…at the same time it caught me by surprise when I first implemented it in an app. Hoping this piece of info helps developers loading legacy or 3rd party SWFs they don’t have control over.

<?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"
	minWidth="0"
	minHeight="0"
	creationComplete="init(event)"
	backgroundColor="#FF0000"
	>

	<fx:Script>
		<![CDATA[
			import mx.containers.Canvas;
			import mx.controls.SWFLoader;
			import mx.events.FlexEvent;

			protected function init(event:FlexEvent):void
			{
				var swfLoaderContainer:Canvas = new Canvas();
				swfLoaderContainer.percentWidth = 100;
				swfLoaderContainer.percentHeight = 100;
				this.addElement(swfLoaderContainer);

				var swfLoader:SWFLoader = new SWFLoader();
				swfLoader.width = 1200; // does not add scroll bar
				swfLoader.height = 800; // does not add scroll bar
//				swfLoader.percentWidth = 100; // DOES NOT add scroll bar
//				swfLoader.percentHeight = 100; // DOES NOT add scroll bar
				swfLoader.scaleContent = false;
				swfLoaderContainer.addElement(swfLoader);

				var context:LoaderContext = new LoaderContext(false, new ApplicationDomain());
				swfLoader.loaderContext = context;
				swfLoader.load("SWFToLoad.swf");
			}

		]]>
	</fx:Script>

</s:Application>

Post to Twitter Tweet This Post

, , , ,

2 Comments

Getting Flex Spark & MX Components to Use Embedded Fonts :: Part 2

In my last post about this I found an ugly workaround in order to get embedded fonts to work in both MX and Spark Components. Since then I’ve learned the best way to do this is simply to select the checkbox in the Project Properties -> Flex Compiler -> “Use Flash Text Engine in MX Components” checkbox = true.

NOTE: Using Flash Builder Burrito and Flex Hero 4.5 — haven’t tested to see if this was the previous issue or not but I wanted to make note of it.

Use Flash Text Engine in MX ComponentsThis seems to make embedded fonts play nice in both MX and Spark components in almost every situation. The one I couldn’t seem to get around was mx:Legend.

When I embedded a font and used this compiler setting, I would randomly see only a couple of my legend labels show up. However, by using just a small piece of my old workaround I was soon back in business.

NOTE: There is one rather large drawback to this though…you have to embed your font twice — once for Spark and once for MX.

Your css should look something like this:

/********************************************************
/ Fonts
/*******************************************************/
@font-face
{
	src: url("/resources/font/MyriadPro-Regular.otf");
	font-family: SparkEmbeddedFont;
	font-weight: normal;
	embed-as-cff: true;
}

@font-face
{
	src: url("/resources/font/MyriadPro-Bold.otf");
	font-family: SparkEmbeddedFont;
	font-weight: bold;
	embed-as-cff: true;
}

/********************************************************
/ NOTE: Due to an issue with the legend and embedded
/ fonts we need to embed the font as non cff too.
/*******************************************************/
@font-face
{
	src: url("/resources/font/MyriadPro-Regular.otf");
	font-family: MXEmbeddedFont;
	font-weight: normal;
	embed-as-cff: false;
}

@font-face
{
	src: url("/resources/font/MyriadPro-Bold.otf");
	font-family: MXEmbeddedFont;
	font-weight: bold;
	embed-as-cff: false;
}

/************************************************************
/ Flex Class-Level Styles
/************************************************************/
s|Application
{
	font-family: SparkEmbeddedFont;
	color: #000000;
}

mx|LegendItem, mx|PieSeries
{
	font-family: MXEmbeddedFont;
	font-size: 12;
	textFieldClass: ClassReference("mx.core.UITextField");
}

Post to Twitter Tweet This Post

, , , , ,

1 Comment

Flex 4 ModuleManager & CSS Inheriting Styles

A client I’m working with has a Flex 3.5 app that’s being migrated to 4.5 and one of the immediate issues we ran into (after we got it compiling successfully) was that the modules didn’t inherit the styles from the main app…worked fine in 3.5, but not in 4.5, so what gives?

So I created a simple PoC with a ModuleLoader and it did indeed pick up on the main apps styles as expected. Next I changed my PoC to resemble the client’s architecture a bit more and used a ModuleManager to load the module — low and behold, the module didn’t inherit the main app’s styles.

After some reading on Adobe’s docs I found the following as the key fix:

Using the ModuleManager class to load modules

You can use the ModuleManager class to load the module. This technique is less abstract than using the tag, but it does provide you with greater control over how and when the module is loaded.

To use the ModuleManager to load a module in ActionScript:

  1. Get a reference to the module’s IModuleInfo interface by using the ModuleManager getModule() method.
  2. Call the interface’s load() method.
  3. The application that loads the module should pass in its moduleFactory property. This lets the module know who its parent style manager is. When using the load() method, you can specify the application’s moduleFactory with the fourth parameter, as the following example shows:

    info.load(null, null, null, moduleFactory);
  4. Use the factory property of the interface to call the create() method and cast the return value as the module’s class. If you are adding the module to a container, you can cast the return value as an IVisualElement (for Spark containers) or a DisplayObject (for MX containers) so that they can be added to the display list.

So the key is passing in a reference to the moduleFactory when calling the ModuleManager.load() method. The 4th parameter is the moduleManager. If you don’t have a reference the main app lying around, just use:

info.load(null, null, null, FlexGlobals.topLevelApplication.moduleFactory);

Link to Adobe’s Docs on this.

Post to Twitter Tweet This Post

, , , , , ,

6 Comments

Great Ant Build Series for Flex

Many people have asked if we use Maven or Ant for Flex builds…while we like Maven for Java, we don’t like Maven for Flex. It’s not that we don’t like Maven in general (obviously since we’re cool with it for Java), we just found it’s almost too much trouble with Flex. It never fails to make us want to pull our hair out and say “Why bother?” — Yes, we have used FlexMojos and we’re still not convinced. So we use Ant for Flex builds.

Instead of writing our own Ant build tutorial series for Flex, we’d like to push you to Jon Campos’s tutorials:

January 7th, 2010 - Using ANT to build an Application
January 14th, 2010 - Building a Library with ANT
January 19th, 2010 - Building the HTML Wrapper with ANT
January 20th, 2010 - Building a Custom HTML Wrapper with ANT
January 21st, 2010 - Including Assets Files with ANT
January 26th, 2010 - Building a Library and Application with ANT
January 28th, 2010 - Building ASDocs with ANT
February 2nd, 2010 - Run Flex Unit Tests from ANT
February 4th, 2010 - Run FlexMonkey Tests from ANT
February 9th, 2010 - The Master Flex ANT File

Thanks for an awesome series Jon.

As a side note, if someone can convince me that mvn + flex is better/easier than ant by all means ping me. brianr@webappsolution.com

Post to Twitter Tweet This Post

, ,

1 Comment

Getting Spark & MX Components to Use Embedded Fonts :: UPDATED**

You’d think embedding a font and declaring it as an Spark Application style would cascade down to all components — after all, CSS = Cascading Style Sheet, right? Well, it doesn’t. The font won’t show up in your MX components.

After bumping our heads against this about 8-9 months ago we decided to move on…I recently had to come back to it and found this helpful link that allowed me to do the following to get this working as expected.

UPDATE*: Added style for MX DataGrid.

@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";

@font-face
{
	src: url("/resources/fonts/Chalkboard.ttc");
	font-family: ChalkboardEmbedded;
	font-weight: normal;
	font-style: normal;
	embed-as-cff: true;
}

s|Application
{
	font-family: ChalkboardEmbedded;
	font-size: 12;
}

mx|global
{
	textFieldClass: ClassReference("mx.core.UIFTETextField");
}

mx|DataGrid
{
	defaultDataGridItemEditor: ClassReference("mx.controls.MXFTETextInput");
	defaultDataGridItemRenderer: ClassReference("mx.controls.dataGridClasses.FTEDataGridItemRenderer");
}

The class-level global style is what does the trick as it instructs all MX components using text fields to use the UIFTETextField class — it allows MX or Halo components to leverage CFF embedded fonts.

Run the app with those styles defined and you’ll notice that one component still doesn’t want to listen — the title of the Spark Panel (or at least that’s the only component I’ve run across so far that doesn’t work).

I tried defining the style for the Spark Panel specifically, but no dice. I also tried creating a new skin for the Spark Panel and set the fontFamily property of the titleDisplay to my embedded font of ChalkboardEmbedded and that also failed. Anyone else come up with a solution for this?

UPDATE*: This approach failed for the following MX classes:

  • ProgressBar
  • FormHeading

This approach failed for the following Spark classes:

  • Panel

UPDATE*:I spoke to several Adobeans on the Flex Doc team and this is unfortunately a known issue:

This approach works for most components, but not Panel and a couple others (he identified Panel and ProgressBar in his blog). I suspect he found a bug. This whole thing about using the same embedded font in MX and Spark components was meant to be a temporary solution until Spark had parity with MX controls. A year and a half later, and there’s still no parity, so there’s no surprise that users are running into this.

Brian, I would ask him to submit a bug.

He can take a look at the spec: http://opensource.adobe.com/wiki/display/flexsdk/Font+Embedding+Reprise

That spec seems to indicate that Panel and ProgressBar should work the way it is documented.

Post to Twitter Tweet This Post

, , , , ,

3 Comments

Swiz EventHandler Filtering With Pub/Sub Topics - Part 1

We tend to build many Flex applications with modules, so having the ability to broadcast and listen for messages based on the scope attribute for both Dispatchers and EventHandlers is essential in Swiz.

UPDATE: Part 2 has Swiz framework code changes and a more robust solution.

If you don’t know about Swiz Event Scoping, then read on; otherwise, skip to the section labeled Filtering With Topics below.

Background

You can read the actual documentation from Swiz in the last link, but the gist is that you can tell Swiz to either broadcast events on a “global” level (using the highest level Application object) or on a “local” level (using the Module itself) and then listen to those events in the same fashion. This allows you to tell modules to listen to events only from themselves and not other modules (that might have the same events) or to listen to all events from your main, shell application and/or all other modules. Let’s look at a quick example by assuming the dispatching code is in LoginViewMediator and the handling code is in LoginController in a Module.

Local Event Dispatching

Local Event Dispatching From LoginViewMediator

/**
 * Allows this class to dispatch local events. Only methods using an
 * EventHandler metatadata tag with the property of scope="local" can
 * handle this event.
 *
 * <p>
 * The event dispatcher is injected by Swiz due to the [Dispatcher] metadata
 * and the class member's type of IEventDispatcher.
 * </p>
 */
[Dispatcher(scope="local")]
public var localDispatcher:IEventDispatcher;
...
public function login(userName:String, password:String):void
{
	logger.debug("login");

	var appEvt:AppEvent;

	appEvt = new AppEvent(AppEvent.SERVICE_LOGIN);
	appEvt.username = userName;
	appEvt.password = password;
	this.localDispatcher.dispatchEvent(appEvt);
}

Local Event Handling in LoginController

[EventHandler(event="AppEvent.SERVICE_LOGIN", properties="username, password", scope="local")]
public function login(username:String, password:String):void
{
	logger.debug("login: username = " + username + ", password = " + password);
}

If we had other Modules with this same EventHandler statement in their LoginController they would not fire because we specified the scope as local. If we change the scope property to global and the AppEvent is in a common library that all Modules can use, then they would each hear this event and all fire, which in many cases is not what you want. Just so we have a full understanding of what’s going on, let’s show an example of broadcasting global events in a similar fashion:

Global Event Dispatching

Global Event Dispatching From ModuleA

/**
 * Allows this class to dispatch global events. Only methods using an
 * EventHandler metatadata tag with the property of scope="global" can
 * handle this event. This means other modules and even the shell application
 * can handle this event if we want.
 *
 * <p>
 * The event dispatcher is injected by Swiz due to the [Dispatcher] metadata
 * and the class member's type of IEventDispatcher.
 * </p>
 */
[Dispatcher(scope="global")]
public var globalDispatcher:IEventDispatcher;
...
public function sayHello():void
{
	logger.debug("sayHello");

	var appEvt:AppEvent;

	appEvt = new AppEvent(AppEvent.SAY_HELLO);
	appEvt.hello = "Hello World!";
	this.globalDispatcher.dispatchEvent(appEvt);
}

Global Event Handling in Module B

[EventHandler(event="AppEvent.SAY_HELLO", properties="hello", scope="global")]
public function hello(hello:String):void
{
	logger.debug("hello = " + hello);
}

Filtering With Topics

Again, this is awesome…but what if you want to broadcast a message that you only want some of the modules to hear? You could obviously put in some simple logic in the event handler that determines if your Module was supposed to listen to the event based on a parameter passed in the EventHandler MetaData, but this could potentially become a large and unwieldy task that you’ll need to apply to all new modules…so what if we introduce filtering of Swiz events via a topic attribute in the EventHandler metadata and a corresponding topic property in our dispatched event?

To do this, we’ll need to do some quick monkey patching to Swiz (by creating the same package structure and adding the same classes we want to change that exist in the Swiz SWC). First, let’s add the topic property to the org.swizframework.metadata.EventHandlerMetadataTag. Add the topic property:

protected var _topic:String;
public function get topic():String
{
	return _topic;
}

Then add the following to the method override public function copyFrom( metadataTag:IMetadataTag ):void

if( hasArg( "topic" ) )
    _topic = getArg( "topic" ).value;

Next we’ll edit the method public function handleEvent( event:Event ):void in org.swizframework.utils.event.EventHandler. Add the following right after the first if() statement:

// look for a topic -- if the one exists in the EventHandler MeataData and
// the event does not have one or the value does not equal the EventHandler's
// then we'll filter out this event and not allow it
if(metadataTag.topic != null)
{
	if(event["topic"] == null)
	{
		return;
	}
	else if(event["topic"] != metadataTag.topic)
	{
		return;
	}
}

That’s it. Let’s give it a whirl by using a global dispatcher again, but adding a topic property to the event and a topic attribute to the EventHandler metadata.

Global Event Dispatching From ModuleA

/**
 * Allows this class to dispatch global events. Only methods using an
 * EventHandler metatadata tag with the property of scope="global" can
 * handle this event. This means other modules and even the shell application
 * can handle this event if we want.
 *
 * <p>
 * The event dispatcher is injected by Swiz due to the [Dispatcher] metadata
 * and the class member's type of IEventDispatcher.
 * </p>
 */
[Dispatcher(scope="global")]
public var globalDispatcher:IEventDispatcher;
...
public function sayHello():void
{
	logger.debug("sayHello");

	var appEvt:AppEvent;

	appEvt = new AppEvent(AppEvent.SAY_HELLO);
	appEvt.hello = "Hello World!";
        appEvt.topic = "wasiTopic";
	this.globalDispatcher.dispatchEvent(appEvt);
}

Global Event Handling in Module B

[EventHandler(event="AppEvent.SAY_HELLO", properties="hello", scope="global", topic="wasiTopic")]
public function helloWithTopic(hello:String):void
{
	logger.debug("hello = " + hello); // WORKS
}

[EventHandler(event="AppEvent.SAY_HELLO", properties="hello", scope="global")]
public function helloWithOutTopic(hello:String):void
{
	logger.debug("hello = " + hello); // NOPE
}

[EventHandler(event="AppEvent.SAY_HELLO", properties="hello", scope="global", topic="fooTopic")]
public function helloWithOutTopic(hello:String):void
{
	logger.debug("hello = " + hello); // NOPE
}

UPDATE: Part 2 has Swiz framework code changes and a more robust solution.

Post to Twitter Tweet This Post

, , , , ,

1 Comment

Some Helpful Settings For Maven Builds

When running Maven builds, there are typically a few settings that are useful to have in your ~/.bash_profile (for Mac or similar, depending on your shell) to help get things off on the right foot.

Set memory usage to 1024M minimum.
export MAVEN_OPTS=-Xmx1024m

Set the path to the appropriate SDK for Flash Builder
FLASH4_SDK=’/Applications/Adobe Flash Builder 4 Plug-in/sdks/3.5.0′

Set the path for ADL if building AIR applications
ADL_PATH=${FLASH4_SDK}/bin

Set the path to the Flash Player for launching FlexUnit tests
FLASH_PLAYER_PATH=’/Applications/Adobe Flash Builder 4 Plug-in/Player/mac/Flash Player.app/Contents/MacOS’

Append these to the current path
export PATH=${PATH}:${ADL_PATH}
export PATH=${PATH}:${FLASH_PLAYER_PATH}

Post to Twitter Tweet This Post

, ,

No Comments