|
For the next six months you should find plenty of randomness in this
space, as I have the great opportunity to take a 6-month sabbatical
from my gig at Maricopa. I will focus
some concentrated time on development projects (my Lingo rust is
showing) plus get a chance to meet colleagues on the opposite side of
the globe as I visit Kiwis and Aussies (travel to New Zealand and
Australia). You can check my progress at http://dommy.com/az2nzau/
If anyone is worried about Director Web,
just relax, as we have set it on auto pilot, and it will continue to
self-update as always. (Maybe I am not really so essential.)
For July and August of my sabbatical, my travel is just two hours north
up the highway to Flagstaff, Arizona, where I will work on some
Director projects with Mike Kelly and his CREATE project (Center
for Research and Evaluation of Advanced Technologies in Education) at
Northern Arizona University. This portion was cleverly planned to
avoid the summer
heat of Phoenix. Next month I will share a bit more about the
highly interactive educational applications they "create" here and
what I come up with in dabbling with the Shockwave Multiuser Server.
This column will review my approach to using Director's ability to
send data from a Shockwave application or a Projector to a web server
CGI via PostNetText.
But first a small diversion related to last month's menu randomness.
Menus part deux
My last column dealt with customizing the droplist behavior to create
menus that looked like other menus on Macs or Windows. It took 4
sprites to make it happen (plus a behavior, plus an ancestor script).
In that column, I wished that Director had the ability to package
all of that into a single package I could insert as a single sprite,
like having encapsulated mini-movies.
Recently, James Newton (author of the original behavior I hacked away
at) e-mailed and let me know that this certainly was possible via a
Linked Director Movie, or as the gurus refer to them, an LDM.
James's example had all of the sprites and code for the menus in a
Director movie that could then be linked into our main or host movie,
thus shielding the developer from the intricacies of 4 sprites
and code.
There is some significant Lingo going back and forth, but it is a
brilliant solution. For more, see James's example files at:
http://perso.planetb.fr/newton/realmenu/
Thanks to James for sharing this code (and not spitting on me for
mucking up your original behavior).
Post it? Get it?
There
are two protocols for how data is sent from something like a web page
form (or, in what we will do, a desktop projector or a Shockwave
doo-dad) to a web server
program (CGI) that does something with the information. The
data is always sent in a paired format of variable name and variable
value.
When the data is transmitted using the GET method, the variable names
are simply appended to the URL for the server script. So if the data
we are sending is something like (variable / value):
name / alan
eyes / brown
iq / 212
and it goes to a script at
http://www.blah.com/cgi-bin/record_user.pl, the data string that is
sent looks like:
http://www.blah.com/cgi-bin/record_user.pl?name=alan&eyes=brown&iq=212
You would see this exact URL in the address field of your web browser
after it was sent from a web form where this information was entered.
The POST method still sends information as
variable/value pairs, but they are encoded with extra information that
describes the length of each variable/value pair. When sent from a
web form, you do not see the encoded data appended to the URL, so if
you sent the same data from a web form with the information above,
after clicking submit you would just see in the address field:
http://www.blah.com/cgi-bin/record_user.pl
Why then would anyone ever use the GET method? Someone with more HTTP
protocol knowledge than I can tell you, but I would bet it might be
faster and/or more efficient to process. However, the GET method limits
how much data can be sent, so typically the POST method is used where
large amounts of data or text (sentences to
paragraphs) are to be transmitted.
What does this have to do with Director?
When Shockwave first came out (Director 4-6 era), we were granted the
ability to send data from Shockwave to a web server CGI, but only with
the GET method. This meant that there was a length limit to how much
text (the variable name/value pairs) could be strapped on the back of
a URL (1-4k depending on the browser flavor). So if you needed to
send large chunks of text, you were forced to send it in multiple
calls and re-assemble on the server side. Not only that, but you had to convert normal looking text to hexadecimal equivalents (spaces, question marks, etc., translated to special codes). It was not pretty.
Fortunately, Director 7 brought the ability to send large data chunks
via the POST method with the PostNetText command. In addition, you could assemble the data as a Lingo property list, and Director
would convert it to the arcane string the CGI expects. So, in Lingo,
we could send information like:
-- assemble cgi param names and values as prop list cgiData = [#name:"Alan Levine", #eyes:"brown", #iq:212, #comments:"If my iq were that high, I would write better articles"]
-- web address for server cgiURL = "http://www.blah.com/cgi-bin/record_user.pl"
-- send it! postNetText (cgiURL, cgiData)
Not only does Director 7+ provide the POST method, it allows you to
send all of the data as a familiar-looking property list, and
Director does the necessary grunt work to turn it into something the
CGI script can understand.
The context
The first time I devised this strategy was for a CD project that was
pretty much wrapped up. We decided to tack on a user survey when a
user exited the program. Yes, it was a fine case of a feature that
crept in, but it would be valuable as we sent it out for testing and
eventual use.
Fortunately, the program already funneled all exits to a specific
movie credits.dir (the one that makes lawyers happy by displaying
the Macromedia copyright badge). So it was a snap to rename this
movie finalcredits.dir and write a new one named credits.dir that
would be our survey, and would then exit through the
finalcredits.dir movie. This way, all exits pass through the survey.
The survey needed to have some flexibility so it would not be
received like a dinner time phone solicitor. Basically, the survey
started with three options:
- No Thanks!
User exits without doing the survey ("roll the final credits and
say goodbye")
- Okay, but I do not want to go online.
User completes the survey, but saves data as text file that could
be printed or e-mailed later (export data with FileIO and roll the
credits)
- Okay, do it online.
User completes the survey and data is sent to web server CGI
directly from Lingo
(and yes, roll the credits)
As a footnote, when I built the survey, I used the Radio buttons
behavior "as is" from the Director 7 Library. If you read my last
column, I lobbied for pages abut the
virtues of modifying these behaviors and putting them on a Jenny
Craig weight-loss program. But in this case, the pre-built behavior
did exactly what I needed (multiple sets of 5 buttons on a screen).
PostNetText in action
I created a mini-demo that can demonstrate a strategy for
doing this kind of net operation. You can try it first as Shockwave
from my site:
http://dommy.com/random/postnettext.html
and then download the Director 8 source files in PC and Mac formats. This page
also contains a web form that allows you to view results that were
submitted and stored on the server:
In the original CD application, the survey was optional, so before it
even started, there was an option to bypass the survey completely.
The first stage is to construct a series of questions that allows your
users to submit their responses. For the demo, I have data that comes
from:
- radio buttons (using off-the-shelf D8 Library behavior)
- drop-down menus (using the example I wrote about in my last column)
- editable fields (hopefully that it not much of a mystery!)
- Lingo-calculated variables (in this case date/time and theuser's computer platform)
All you are doing is providing a series of screens with this input, and then saving the responses to a property list after leaving the screen. In my first version I just stashed the information in a global variable, but
in this demo I am using a behavior stashed in a sprite (channel 2 in
the demo) that spans the entire question sequence.
-- script "data bin" -- This sits in a sprite that spans the entire question -- sequence. Returning to the first frame of it resets -- the prop list that captures the responses
property pData, pPlatform
on beginSprite me if the platform contains "Windows" then pPlatform = "Windows" else pPlatform = "Macintosh" end if
-- initialize survey data with 2 generated values -- a date time stamp, and the computer platform pData = [#taken: the long date && the time, #plat: pPlatform] end
on putData me, dname, dvalue -- dname is property name (string) -- dvalue is associated value (string or number)
-- called by other handlers to add/update data to our list pData[symbol(dname)] = dvalue end
on getData me -- called by other handlers to return the property list return pData end
By the end of the survey, you have a property list of name/value
pairs to be sent to the CGI. The property names are
exact matches for the variables expected by the CGI. Be sure that the
case of the variable names matches, as UNIX servers will ignore
values for a Lingo property named #myBigValue if the CGI variable is
named $mybigvalue.
When you are ready to send, you provide the user the option to send the
info via the web, or to skip it. On a Projector version, you could also
offer the opportunity for the user to save the data as a text file that
could later be e-mailed or printed and sent, even through snail mail (done
via FileIO, left as an exercise for the reader). This
option allows the user to avoid going online.
The processing through the web runs as follows:
(1) Initiate a net process through PostNetText, storing the network
ID for later reference. The call is pretty simple: you pass it a
variable that contains the URL for the CGI and the property list of
data.
global gNetID myFormData = sendAllSprites(#getData)
-- Assign a global to the net call so you can track the progress elsewhere gNetId = postNetText( myCGI, myFormData)
-- start a Lingo timer so you can track how long since the net call was initiated startTimer
-- go to a looping frame so you can check progress go to frame "saveToNet"
(2) In the looping frame, you are checking the network processes.
First, you test netDone(gNetID) to see if the process is complete. If
it is done, you next see if netError reports a problem code. If it does,
you jump to a problem report screen and provide a link to the options
screen (where the user can resubmit or cancel).
If there are no network errors, you check netTextResult(gNetID), the
string that was returned from the CGI script. I write mine to return
"ok" if things went fine on the server side (tricky, eh?). If this
all happened successfully, you can proceed to a confirmation screen.
If the network process is not complete (netDone(gNetID) = false), you
first check to see if the timer has passed a certain delay time. If it has,
consider it as timed out and pop an alert letting the user know she
can either continue to wait or bail.
The looping frame also contains a "cancel" button so the user can stop
the process at any time. The script cleans out the network processes:
global gNetId netAbort(gNetId) gNetId = void
and jumps back to the options frame.
That is pretty much what you need on the Lingo side.
On the server end, you need a script to take this data and do
something with it. In this case, my simple perl script (included in the source download)
simply takes the values of the variables it
receives and writes them in tab-delimited format to a log file.
The important thing is to make sure the CGI script is set to return
any response (an "ok" status) as plain text, not as HTML as most
scripts do.
And that's about it -- the POST method makes it easy to shuttle a
pile of content to a web server (provided you have something on the
web server side to process it). The CGI in this example was pretty
simple; you could call it a WebFileIO, as it just did an mWrite in
Append mode (for all those fileIO geeks out there).
Look here in a few weeks as I share what I am able to wrangle out of
the Shockwave Multiuser Server.
|