|
Jonathan
Cooper |
Exporting from HyperCard
Originally published in MACinations (Club Mac, Sydney, Australia)
While having text broken up into cards and fields in HyperCard makes information easier to find and manipulate, there are times when you want to get pieces of text, or all the text from one or more cards, into one file for editing and/or printing with a word processor. Even if you have enough memory to run HyperCard plus your favourite word processor together, having to select, copy, switch applications, click, paste and switch back over and over again can get very tedious. HyperTalk has four commands that allow a stack to exchange data with a text file automatically (1), but having to write a custom handler every time you want to export text just isn't practical.
Robert Murray of the Massachussets Institute of Technology Media Lab has created a HyperCard 2.x stack called Import/Export Tools which enables you to transfer data from text file to stack, from stack to text file and even stack to stack. To allow for any stack structure (including multiple backgrounds) and for user preferences as to which fields are to be exported and in what order, the stack is by necessity fairly complex. If the amount and/or complexity of information is high however, then this is the way to go. If, on the other hand, you need to export data 'on the fly', without structuring beforehand, another solution might be more suitable.
The first thing that we need to do is set up a link between HyperCard and a text file (either freshly created or already existing) so that we can export all our text to the one place. Two message handlers will do the trick:
on createFile global textFile -- global variables keep their contents -- as long as HyperCard is running, which -- is why we declare file's path-name as -- a global variable ask file "Save as:" with short name of this stack && "Text" if it is empty then exit createFile -- (If "Cancel" is clicked 'it' is empty: -- allows user to back out) put it into textFile open file textFile -- (This is where the file is created) close file textFile -- (For safety; other handlers will open -- it again when necessary) end createFile on openFile global textFile answer file "Select a text file to export to:" of type "TEXT" if it is empty then exit openFile put it into textFile end openFile
Secondly we need to create handlers to actually do the exporting. However, it is important to keep adding the text we export to the declared file. Normally when you tell HyperCard to open a file and then write text to it, the text replaces whatever is already there. The solution is to read from the file until the end and then write to it. The data gets read into the special global variable 'it' but we don't actually need to do anything with it; it is simply to move a pointer from the beginning to the end of the file. This pointer is like a bookmark; it is the computer's way of keeping track of where it is up to, where to write (or read) the next bit of text. The default is always the beginning of the file. (2)
The following five lines are the basis of what is required. (In an actual script, we would substitute an actual expression for the place-holder <data> .)
...
global textFile
open file textFile
read from file textFile until empty
write <data> to file textFile
close file textFile
...
Thirdly, we must create handlers to collect text ready for
exporting. The most basic (exporting whatever text is selected) is also the
easiest...
get the selection -- i.e. put the selection into
the variable 'it'
-- later we will write 'it' to file textFile
Next, all the text from the current card...
put empty into soFar
-- (soFar is a local variable for
-- storing text, ready for exporting)
repeat with i=1 to the number of card fields
put card field i & return & return after soFar
-- (Put blank line after each field)
end repeat
repeat with i=1 to the number of bkgnd fields
put bkgnd field i & return & return after soFar
end repeat
-- we will later write soFar to file textFile
Then, the same as above but from a range of cards (using an repeat loop with the repeat loop listed above nested inside it).
Also, to help make the resultant text file easier to read, we should provide ways to separate the slabs of text we export. A blank line (or extra return), and possibly a series of 'bullets' should do the trick.
OK, we have enough to create the required handlers. The trouble is, must we remember their names so that we can type them into the message box when required? Some people have no problem with this, but it is not really in keeping with the philosophy of Macintosh, let alone HyperCard. (Also, typing return or enter-to 'enter' the command-will deselect any text.) Why not create a menu, since HyperCard 2.x makes it so easy? (No messy XCMDs!)
The recommended (but not the only) way to do it is to create a menu-creating handler (say "ExportMenu") which calls two functions createExportMenuItems and createExportMenuMsgs:
on ExportMenu
if there is a menu "Export"
then exit ExportMenu
-- (Don't want to duplicate)
create menu "Export"
put createExportMenuItems() into menu "Export" with menuMsg
createExportMenuMsgs()
end ExportMenu
function createExportMenuItems
global textFile
-- (The name of the export file,
-- stored as a global variable)
return "New File..." & return & ![]()
...
-- other menu item names listed
-- here, separated by returns
end createExportMenuItems
function createExportMenuMsgs
return "createFile" & return & ![]()
...
-- other menu messages listed
-- here, separated by returns
end createExportMenuMsgs
The reason for doing it in three handlers rather than one is to make it easier to read, and edit if necessary. Each menu item now has its own command (or "menuMessage") that can be trapped by a message handler that we create. E.g. Selecting the first menu item ("New File...") sends the message "createFile" which we can trap with an "on createFile" handler.
Two more things are needed to make our technique functional: a way of indicating whether or not field names are to be included when each card's text is exported and a way to open the text file when all the exporting is complete.
The former could be handled by a checkable menu item "Include Field Names"with the menuMessage "toggleFieldNames":
on toggleFieldNames
set checkMark of menuItem "Include Field Names" of menu
"Export"![]()
to not checkMark of menuItem "Include Field Names" of
menu "Export"
end toggleFieldNames
(Any export handlers would need to check the checkmark of menuItem "Include Field Names" before collecting any text.)
The latter is as simple as:
open textFile with "Microsoft Word" -- or whatever
See these techniques in action
To see the techniques described above in a working stack, download my stack Export Menu.
_____
2. Starting with HyperCard 2.2, you
can write:
write to file textFile at end
to avoid having to read the entire file first.