fireworks

FWXHR

Since Fireworks is used so heavily for web graphics production, it's quite likely that there'll be times when you developers out there would like your JSF commands to interact with a web service. Unlike a browser's JS environment, unfortunately, Fireworks doesn't offer any XmlHttpRequest functionality. Flash panels can make HTTP calls, but there hasn't been easy way to integrate Flash with JSF commands. Until now.

Installation

After installing the extension, you should have a FWXHR directory in your commands folder, which will look like:

/Adobe Fireworks CS4
    /Configuration
        /Commands
            /FWXHR
                Example - Insert Stock Price.jsf
                Example - Translate Text.jsf
                /lib
                    lib.js
                    /dojo
                        ...
                    /fwlib
                        FWXHR.swf
                        io.js

The lib sub-folder contains all the files necessary to make XHR-style calls from your JavaScript commands. The io.js file implements an API for making requests, and the FWXHR.swf Flash file provides the XHR functionality.

To use the library in your .jsf commands, copy the entire lib sub-folder to the folder that contains your .jsf. Your folder hierarchy should look something like:

/Adobe Fireworks CS4
    /Configuration
        /Commands
            /My XHR Commands
                XHR Command 1.jsf
                XHR Command 2.jsf
                /lib
                    ...

Loading the fwlib.io library

From within XHR Command 1.jsf in the example above, you can load the API by including this code:

try { dojo.require; } catch (e)
    { fw.runScript(fw.currentScriptDir + "/lib/lib.js"); }

dojo.require("fwlib.io");

This first loads the dojo API, if it's not already loaded, and then loads the fwlib.io library, which is what you'll use to make the XHR calls.

A simple GET

To make a simple HTTP GET request, call fwlib.io.request() with a URL. The following example looks up the current price of Adobe stock using Yahoo!'s Finance API:

var response = fwlib.io.request(
    "http://download.finance.yahoo.com/d/quotes.csv?f=snl1c1p2d1t5&s=ADBE"
);

The call to request() is always synchronous, so by the time the next line in your script executes, the request has either succeeded or failed and will have returned the response as an object.

When your script calls request(), a Flash dialog is opened. It's a pretty simple dialog, consisting of a Cancel button, a progress bar and a few text fields showing the current request method and the URL. The dialog will remain open until the HTTP request succeeds, fails, times out, or is canceled by the user. If you're making a GET request, the loaded and total bytes will be shown next to the progress bar. For a POST request, an indeterminate progress bar is shown, as Flex doesn't provide any information about the progress of the request. Either way, if the request works, the dialog usually opens and closes too fast to interact with.

The response object

When the HTTP transaction is complete, the response is returned from request() as an object with the following fields:

status
The HTTP status code as a number, such as 200 for a successful transaction.
statusText
The HTTP status code as a string, such as OK for a successful transaction.
responseText
The data returned from the web service endpoint as a string. If the HTTP request failed for some reason, this will contain the resulting error message. If the response is in some structured format like XML or JSON, it's up to you to convert it from text to that format.

If the user cancels the dialog before the transaction can complete, then request() returns null, so your code should check for that.

The response from the previous example can be handled like this:

var response = fwlib.io.request(
    "http://download.finance.yahoo.com/d/quotes.csv?f=snl1c1p2d1t5&s=ADBE"
);

if (!response) {
    alert("The request was canceled.");
} else if (response.status != 200) {
    alert("The request failed: " + response.responseText);
} else {
    var dom = fw.getDocumentDOM();

        // the stock data fields are comma-separated
    var data = response.responseText.split(",");
    var currentStock = data[0] + " is at $" + data[2];

        // insert the stock price as a text element centered in the document
    dom.addNewText({ left: 0, top: 0, right: 150, bottom: 10 }, true);
    dom.align("center vertical", true);
    dom.align("center horizontal", true);
    dom.setTextRuns({ initialAttrs: { alignment: "center" },
        textRuns: [{ changedAttrs: {}, characters: currentStock }] });
}

This script extracts the comma-separated stock price data from the response and then uses that data to create a text element.

The request configuration object

Similar to the io() method of YUI3, the second parameter to request() can be an object that defines the parameters of the transaction. This parameter and all of its fields are optional:

method
Specifies the HTTP method of the transaction, either GET (the default) or POST.
headers
An object containing key-value pairs of headers to supply with the transaction, e.g., { "Content-Type": "application/xml; charset=utf-8" }. Due to a limitation in Flex, custom headers work only with POST requests. They will be ignored by GET requests.
data

Data to be sent with the transaction, defined as either a string of key-value pairs (e.g., "foo=bar&baz=42") or an object (e.g., { foo: "bar", baz: 42 }), which will be serialized into a URI-encoded string.

If the method is GET, then data will be appended to the URL after a ? (the question mark is added automatically if the URL doesn't end with one). If the method is POST, then the data will be sent as the body of the request.

fileData
An object containing key-value pairs of form field names and local file paths. If specified, the local files are loaded into memory and then posted as a multi-part form submission. The files are combined with the key-value pairs in the data parameter, if any, and the method is set to POST. See below for more information on posting local files.

The data parameter can make it more convenient to build up a complicated set of query parameters. Here's another way to look up stock price data in the previous example:

var symbol = prompt("Enter the stock symbol to look up.");

var response = fwlib.io.request(
    "http://download.finance.yahoo.com/d/quotes.csv",
    {
        data: {
            f: "snl1c1p2d1t5",
            s: symbol
        }
    }
);

Posting local files

Normally, a web page can't upload arbitrary files from the local computer without the user's interaction. But since Fireworks and its commands already have access to the local filesystem, it's possible to upload files directly from a JSF command.

A typical scenario might be to POST the current document to a file server. How exactly this request should be constructed will depend on the web service you are posting to, but an example might look something like this:

var tempPath = Files.getTempFilePath(null) + ".png";
var dom = fw.getDocumentDOM();
dom.exportTo(tempPath, null);

var response = fwlib.io.request(
    "http://your.domain.com/upload.php",
    {
        method: "POST",
        data: {
            username: "myuser",
            password: "mypass",
            pageName: dom.pageName
        },
        fileData: {
            pageImage: tempPath
        }
    }
);

In this example, the current document is exported to a temp file, and the path to that temp file is passed to request() in the fileData parameter of the request configuration object. This causes the file to be loaded into memory and then combined with the data parameter to form the body of the POST. To the server page receiving this post, it will look like a regular form submission.

The Content-Type of each file is determined by its extension. An image type of PNG, for instance, is given a content type of image/png. All other file types default to application/octet-stream.

Example scripts

There are two example .jsf scripts in the installation folder, one that demonstrates using a GET request to access Yahoo's stock price API, and another that uses a POST request to access Google's translation API. (The latter is a simplified version of the Translate Text extension.) The scripts are well-commented and should help you get started making your own HTTP requests from Fireworks.

Future directions

The FWXHR extension is still pretty basic, so let me know if you run into any problems and how you'd like to see it extended.

Credits

The FWXHR extension uses a slightly modified version of the URLRequestBuilder AS3 library (Copyright (c) Mike Stead 2009) to create the multi-part form requests when posting file data.

Release history

0.1.2
Added an example that uses Google's translation API.
0.1.1
Added progress bar for GET requests, and an indeterminate bar for POST requests. Enlarged area showing requested URL. Added support for multiple dojo installations.
0.1.0
Initial release.

Package contents

  • Example - Insert Stock Price
  • Example - Translate Text
  • FWXHR
comments powered by Disqus