Runtime Revolution's Transcript scripting language has a simple yet powerful message inheritance scheme which is inherently extensible to minimize code redundancy and maximize reuse. This article describes how to use libraries, backScripts and frontScripts effectively to achieve those goals.
Revolution's Native Message Path
Runtime Revolution's object model is easy to learn and work with, while flexible enough to build nearly any user interface an application needs. Similar to how Visual Basic places controls on forms, in Revolution you place controls on cards. Where Revolution goes beyond most implementations of Basic is that it natively accommodates multiple screens, or cards, within a given window, allowing rapid development of wizards and multimedia apps easily.
Revolution goes even further to provide an object that acts as a container of control lists (cards), called a stack, which has its own script.
One of the most useful aspects of this object model is that the event messages that drive it are inherited by each object in the hierarchy. For example, when the user clicks on a button control a mouseUp message is generated which can be handled in the script of the button control. If there is no mouseUp handler in the control script the message is passed to the card, and if not handled there it's passed to the stack, and then to the Revolution engine where any default behavior may be invoked.
It's worth noting that a collection of controls can be placed inside of a group object, which by default only receive system messages in response to user events in objects contained within it. Groups can be nested, and scripts within a given group can be called by other groups within it.
A group can be made to receive card messages by setting the group's backgroundBehavior property. When this property is active such objects are often distinguished from other groups by referring to them as backgrounds. When receiving such messages, a background occupies a place between the card and the stack for compatibility with similar languages.
If any object in the message path has a handler for a given message, by default the message is not sent further down the path. You can override this default behavior by using the pass command to allow the message to continue through the native message path:
on mouseUp put "Hello World!" into field 1 pass mouseUp end mouseUp
Figure 1 illustrates the simplest form of the Transcript message path.
Figure 1: Native Transcript message path
Extending the Message Path
While the native message path is quite powerful, it has some limitations. For example, what if you wanted to use a library of handlers across multiple projects, or handle messages before even controls get them? Fortunately Transcript provides three different mechanisms for extending the message path: libraries, backScripts, and frontScripts.
HyperCard first introduced libraries with the addition of the start using syntax:
start using "MyLibraryStack"
The start using command inserts the script of the specific stack object into the back of the message path. A script brought into use in this way can be removed with the stop using command:
Later this concept was expanded on by Oracle Media Objects with the addition of a libraryStack message, sent to the stack object immediately after it is brought into use, useful if the library needs to perform any initialization:
on libraryStack global gInited put true into gInited end libraryStack
A releaseStack message is provided as a corollary to libraryStack, sent when a stack script is removed from the message path with stop using, useful for any housekeeping that may need to be done before the library is removed:
on releaseStack global gInited put empty into gInited end libraryStack
Revolution supports all four of these constructs for libraries.
SuperCard introduced two alternatives for extending the message path, which are both fully supported and improved upon in Revolution: frontScripts and backScripts.
The advantage of backScripts over libraries is that you are not limited to using only stack scripts; the script of any object can be inserted into the message path with the insert script command:
insert script of button "ScriptUtilities: into back
Scripts inserted into the message path this way can be removed with the remove script command:
remove script of button "ScriptUtilities" from back
Note that unlike libraries, backScripts receive no notifying message when they are inserted or removed.
Where Revolution has improved on SuperCard's original implementation of backScripts is that a script can be edited in Revolution without first removing it from the message path, whereas in SuperCard the script must be removed and re-inserted to reflect any changes made while it was in the backScripts.
Also, in SuperCard the order of insertion is strictly enforced, such that a script inserted after another does not have direct access to the first script's handlers and must call them explicitly using the send command (see "Changing the Firing Order of Messages" below).
In Revolution all libraries and backscripts can freely call each others' handlers by name, with the order of insertion only coming into play in the event that two scripts contain handlers of the same name; in such cases libraries take precedence over backscripts, and scripts inserted first take precedence over scripts inserted later.
FrontScripts are inserted into the front of the message path, before any other object gets a message. This can be useful for implementing logging features where you can write a record of user activity to a file, or for implementing plugin utilities where you might want the plugin to have access to messages like selectedObjectChanged in order to update itself.
Like backScripts, frontScripts are inserted and removed with the same commands:
insert script of button "MessageTraps: into front remove script of button "MessageTraps" from front
Figure 2 shows the Transcript message path with all extensible scripting options.
Figure 2: Transcript message path showing
Changing the Firing Order of Messages
While messages ordinarily travel only through the message path as shown in the figures above, you can invoke handlers in scripts of objects outside of the current message path with the send and call commands:
send "mouseUp" to button "Cancel"call "CalculateTotals" of button "Total"
The difference between the send and call commands is that the send command changes the context so that object references are treated as relative to the object you send the message to, while the call command does not change the context and continues to treat object references relative to the original object.
One thing to keep in mind when using libraries, backScripts, and frontScripts is the difference in the number of each of these allowed when running outside of the Revolution development environment, such as in a standalone or with a player. These limits are noted in the scriptLimits function, which (as of this writing) at runtime returns 10, 10, 50, 10 when running as a standalone, which corresponds to (in order):
• the number of executable statements permitted when changing a script (10)
These limits only apply when running outside of the Revolution development environment. When working in the Revolution development environment no such limits exist.
Revolution gives you the option of determining whether a stack will remain cached in memory or be purged when it is closed. This is determined by the destroyStack property, which is set to false by default. The name of this property refers only to the copy of the stack in memory; when true, a stack is purged from memory when closed.
You have to be careful if the stack containing scripts that extend the message path, either with the start using or insert script commands, has its destroyStack property set to true. As of this writing, as soon as you close the stack all of its scripts will be removed from memory with it, so they will no longer be present in the message path.