Remember Y2K? About five years ago, we all learned that handling dates in computer applications really is a big deal. Although most of that scare was because someone thought it a good idea to represent years with just two digits to save memory, and somehow that "good" idea caught on. You really have to wonder, don't you? Today, with memory as cheap as it is, you can safely use those two extra digits to represent years in their full, four-digit glory.
All joking aside, before we get to the database part of things you need to first get the calendar part of the application working. To create a dynamic calendar there are a few things you'll have to know. For starters you already know how many days there are in each month of the year, except for February. If the month being displayed is February you'll need to check if the year is a leap year to know if it has 28 or 29 days that year. For any month being displayed, you will also need to determine which day of the week the first falls on, so you can fill in the rest of the calendar properly.
When the training log is first run, it should display the current month and year in the calendar. From that point, the month being displayed will depend on the Previous and Next month buttons being pressed by the user.
Open the myTRainer Director file from the project_two folder on your hard drive. If you don't have the file, you can open mytrainer_start from the Lesson07 folder on the CD-ROM.
To make things simple we'll store the current month and year in a couple of global variables when the application is first run. The best place to do this is within the startMovie handler, because a startMovie event is issued when a movie is first played.
Within the scripts cast, double-click the first cast member, Main Script, to open a script window.
Main Script is currently empty except for the getURL() handler you used for testing in the previous lesson.
Before you add the startMovie() handler to the script, let's talk a bit about how you'll be getting the month and year in order to store them. There are two ways you can work with dates in Director: date strings and date objects.
Look at the following output from the Message window:
trace(_movie.date()) -- "7/8/2004" trace(_movie.systemDate()) -- date( 2004, 7, 8 )
Although it might seem like either of these methods would work, the string version provided by _movie.date() is dependent on the user's operating system settings. In some locations the string will display with the year first. For this reason it's not a reliable method of determining the date.
The date object, on the other hand, provided by _movie.systemDate() is perfect. Why? Because the object contains year, month, and day properties that you can access individually, as this Message window output shows:
trace(_movie.systemDate().year) -- 2004 trace(_movie.systemDate().month) -- 7
With this in mind, you can code the startMovie() handler.
Within the Main Script, add the following startMovie() handler.
on startMovie _global.theYear = _movie.systemDate().year _global.theMonth = _movie.systemDate().month _global.theDay = 0 _global.dataSprites = 10 _global.daySprites = 53 _global.exerciseSprites = 96 end
First, two global variables are created that store the current month and year. Next, a global variable, theDay, is set to zero. This variable will hold the day of the month that is clicked on when you want to edit data for that day.
The next three globals define the sprite channel numbers where each range of calendar text sprites begins. These three ranges are the data sprites that will display the information from the database, the day sprites that will display the days of the month, and the exercise indicator sprites that will display a B, R or W depending on the type of exercise (biking, running, or walking) entered for that day. The following image shows how the first week of the calendar is laid out and how the three ranges work.
If you look through the Score you will see that the data sprites take channels 10 through 51, the day sprites 53 to 94, and the exercise indicator sprites channels 96 to 137. A blank channel is left between each range to make the ranges easier to see when scrolling in the Score.
Displaying a Month
With the startMovie() handler in place, you can begin to write the method that will populate all of the day sprites in order to display the days of the current month. The displayMonth() method will display the month according to the values stored in the globals created by the startMovie() handler. Later, once the previous and next month buttons are working, you'll use them to alter the values in the month and year globals, and then simply call the displayMonth() to show the calendar view for that month.
After the startMovie() handler, add the displayMonth() method as shown.
on displayMonth thisMonth = _global.theMonth thisYear = _global.theYear --number of days in each month daysList = [31,28,31,30,31,30,31,31,30,31,30,31] --determine number of days in this month and check for leap year days = daysList[thisMonth] if thisMonth = 2 then leapCheck = date(thisYear, 2, 29) if leapCheck.month = 2 then days = 29 end if end if --Now get the day of week the first starts on flashDate = newObject("date") flashDate.setFullYear(thisYear, thisMonth - 1, 1) _global.firstDayOfWeek = integer(flashDate.getDay()) --returns 0-6 dayChannel = _global.daySprites + _global.firstDayOfWeek repeat with thisDay = 1 to days sprite(dayChannel).member.text = string(thisDay) dayChannel = dayChannel + 1 end repeat end
I know, it looks a bit long, but without the extra spaces and comments, it's really only 20 lines. Let's walk through the code now to see what each line does.
First, two local variables are set to the month and year values stored in the global variables. This is done simply because the month and year values are used more than one time in the code. Storing them first in local variables makes the code more efficient. Next, the variable daysList is set to a list representing the number of days in each month of the year. There are 12 items in the list, one for each month.
Lists are a very handy data type in Director, as you can store just about anything in them including strings, objects, numbers, or even other lists. To retrieve data from the list you use an index into the list, like so:
daysList = [31, 28, 31] trace(daysList) -- 28
As you can see, the second item in the list is the number 28. Can you see how you can use the list to get the number of days in the month? Let's look at the next line in the script:
days = daysList[thisMonth]
You know that the thisMonth variable contains a number from 1 to 12 representing the number of the month. Therefore if the current month is July, then thisMonth will be 7. So the line could be written as:
days = daysList
If you count to the seventh item in the list, you'll find that it's 31. The days variable therefore becomes 31. Regardless of the month, you'll know the number of days in itexcept of course for February.
A note about leap years: our calendar year is 365 days long, but it actually takes the earth 365.24219 days to orbit the sun, so an extra day is added to the calendar every four years to account for the quarter day we lose per year. This is done to keep the seasons in line with the calendar so that they always occur during the same months each year.
So when the month is February, you need to check the year to see if it's a leap year. If it is, you must set days to 29 instead of the standard 28 as defined in the list. The next few lines of code accomplish this by taking advantage of Director's date object. What you do is create a date object and tell it that it is February 29th, of whatever year you want to check. If the year in question is not a leap year the date object will automatically set the date to March 1stnifty! All you need to do then is check the month property of the object; if it's still February then the year is a leap year, and the days variable gets set to 29.
if thisMonth = 2 then leapCheck = date(thisYear, 2, 29) if leapCheck.month = 2 then days = 29 end if end if
Note that you can also use a standard formula when checking for leap years when you don't have the ease of Director's date object handy. The formula is easiest to represent with the following image.
Use Lingo's mod operator to see if a number is evenly divisible by another number. The mod operator returns the remainder of integer division. For example, 25 mod 5 = 0 because 5 can be evenly divided into 25 five times with no remainder 5 x 5 = 25. 25 mod 4 = 1 however because 4 x 6 = 24. Now that you know the number of days in the month being displayed, you need to determine what day of the week the first falls on so that you can fill in the rest of the days. The next three lines of code do that, using a Flash date object. While it is possible to figure out what day the first of any month falls on using Lingo, it's actually much easier to do using Flash because the functions you need are already present.
This also shows another cool feature of being able to create Flash objects directly from Lingo, giving you access to Flash's math routines, date handling abilities and more. Once the Flash date object has been instantiated into the flashDate variable, you're free to use any of methods you would if you were in Flash. To determine which weekday the first of the month falls on, two methods are employed. The first, is the setFullYear() method, which allows you to set the date object to a specific date, using a year, month, day format.
flashDate.setFullYear(thisYear, thisMonth - 1, 1)
Note that you have to use thisMonth 1, because the Flash date object accepts months in the 011 range, instead of 112.
When using code object like this it can help to keep Flash open so you can reference the ActionScript dictionary. Once the date is set to first, the geTDay() method is called, which returns the day of the week for the given date. Here again, Flash returns a number ranging from 06 where 0 is Sunday, and 6 is Saturday. Note that the call is wrapped within the integer() function because Flash returns a floating-point number, and there is no need for the decimal place. Lingo's integer() function turns any floating-point, or real, number into an integer with no decimal.
One other point to take note of here is that you're storing the first day of the week in a global variable: _global.firstDayOfWeek. This is so it can be used by other functions, such as filling in the data retrieved by the database, without having to be recalculated.
So now you know how many days are in the month and you know what day the first falls on. You're just about ready to actually fill in the text fields on Stage with the days of the month, which is exactly what the last few lines of the script do. Recall that in the startMovie handler you set the global variable daySprites to 53 since that represents the channel where the text fields for the days begin. The next line of code uses the firstDayOfWeek offset you just calculated to determine the starting channel number within the range of day sprites:
dayChannel = _global.daySprites + _global.firstDayOfWeek
Let's assume the first is on a Thursday. This would make the firstDayOfWeek variable equal to 4, because of the way the Flash getday() method returns 0 through 6. If the global daySprites is 53 then dayChannel equals 53 + 4, or 57. If you were to select the sprite in channel 57, you'd find it to be the day field for Thursday, as shown here.
Once the starting channel number is known, the repeat loop at the end of the script does all the real work of populating the text sprites.
A repeat loop is just a way of repeatedly applying the statements within the loop as many times as necessary. If you have any programming experience, you may have seen similar structures in other languages. ActionScript, for instance, uses the more common for loop as well as a while loop, although functionally they work much like the repeat loop.
When the loop executes the counter variable used in the loop (thisDay in this case), it will start at the initial value (1) and be incremented by 1 until the final value is reached (days), at which point the loop will terminate. Look at the following simple example:
repeat with myCounter = 1 to 5 trace(myCounter) end repeat
If this code were run, you'd see the numbers 1 through 5 appear in the Message window, because the counter variable is being traced.
One thing to keep in mind when using repeat loops is that only one line of code can execute at a time in Lingo. This means that while a repeat loop is running, nothing else will be able to. In some cases this is perfectly acceptable, but if you're not aware of it you may run into problems. Now, let's get back to the actual loop that you're using:
repeat with thisDay = 1 to days sprite(dayChannel).member.text = string(thisDay) dayChannel = dayChannel + 1 end repeat
Here, the counter variable (thisDay) starts at 1 and increments by 1 until it reaches the value in days, which of course contains the number of days in the month. While the loop executes, the two lines of code do the job of setting the text of each sprite to the correct date. Note that you need to set the text property of a cast member to a string. Because the thisDay loop counter variable is a number, it must first be turned into a string, using the string() function, before it can be used in this manner. In the next line, dayChannel is incremented by 1, so that as the loop variable increments, the sprite channel being used increments right along with it.
As an example, let's assume the month being displayed is July 2004. There are 31 days, and the first is on a Thursday. Therefore, when the script is executed it could be broken down as follows:
--initial variables thisMonth = 7 thisYear = 2004 days = 31 firstDayOfWeek = 4 dayChannel = daySprites + dayOfWeek = 53 + 4 = 57 --begin repeat loop thisDay dayChannel 1 57 sprite(57).member.text = string(1) 2 58 sprite(58).member.text = string(2) ... ... ... 31 87 sprite(87).member.text = string(31) --end repeat loop
In this manner, the days of the month for any given month can be displayed quite easily. To see how this is working so far, you just need to call the displayMonth() method at the start of the main section. You can do this by adding a behavior to frame 30.
Select the scripts cast, then double-click in the behavior channel at frame 30 to open a script window. Add the call to displayMonth() within a prepareFrame handler as shown. Be sure to delete the default exitFrame handler as well.
on prepareFrame me displayMonth() end
When the movie is run, the startMovie handler will run and set the global month and year variables to the current month and year. When the prepareFrame handler at the start of the main section is then encountered, the displayMonth method is called and the calendar displays the current month stored in the global variables.
Note that you are using prepareFrame here instead of exitFrame because prepareFrame runs before the frame is drawn. This ensures that the correct date is displayed when the user first sees the calendar view. If you were to use exitFrame to call displayMonth() instead, the frame would be drawn before displayMonth() is called, and any prior month and year would flash briefly in the upper left corner before the new month and year was displayed.
Name this script member begin main and close the script window. Rewind and play the movie.
After the intro screen fades out and the calendar fades in, the day fields are populated according to the current month. One immediate problem with this though, is that the current month is probably not July 2004, as is indicated at upper left. To remedy that you just need to modify the displayMonth() handler a bit. Do you know what you need to do? Basically, you need to do exactly the same thing as what's done to find the number of days in the month: make a list containing the 12 month names and use the number of the month as an index into the list.
Stop the movie and open the Main Script so that you can edit the displayMonth method. Add the following four lines of Lingo to the method, immediately after the line that declares the daysList.
monthList = ["January", "February", "March", "April", "May", "June", ¬ "July", "August", "September", "October", "November", "December"] --show month and year dateString = monthList[thisMonth] && string(thisYear) member("date shadow").text = dateString member("date display").text = dateString
Assuming once again that it is July 2004, the variable thisMonth will equal 7, and thisYear will equal 2004, after the startMovie handler runs when the program is first played. In the same manner as getting the number of days in the month, you retrieve the string name of the month from the monthList, by using an index into the list.
dateString = monthList[thisMonth] && string(thisYear)
This would become:
dateString = monthList && string(2004)
Which would then become:
dateString = "July" && "2004"
Which finally becomes:
dateString = "July 2004"
In Lingo, the & and && operators are known as concatenators because they concatenate, or combine, multiple strings into one. Here is the difference between the two operators: The single ampersand simply concatenates the strings into one single string. The double ampersand concatenates the strings, but also inserts a space between them. So, instead of the && concatenator, you could have used & and done something like this:
dateString = monthList[thisMonth] & " " & string(thisYear)
While this produces the exact same result, using the double ampersand is more appropriate, and also easier to read.
Note that you're using two text members here so that a drop shadow is created. And while field members do actually have a drop shadow property, the shadow used by field members can't be modified, and fields can't contain anti-aliased text.
Rewind and play the movie to observe the results of the new code.
Now when the movie plays, the correct date is displayed within the two text sprites in the upper left corner.
The calendar is beginning to take shape. There are just a couple of things left to do before getting to the database implementation. First of all, the Previous and Next month buttons need to have code attached that will make them work. Currently, they just contain a simple rollover behavior and do nothing when clicked.
After that, the set of data sprites in channels 10 through 51 will need a script attached so that when they're clicked, the input dialog will open and allow data to be entered for that day.
Stop the movie if it's playing. In the Score, right-click the frame bar and turn on the Sprite toolbar if it's not showing. Make sure the scripts cast is active and then select the Previous month button. Finally, choose New behavior in the sprite toolbar's behavior drop-down as shown, then enter the decrement month script.
on mouseUp me curMonth = _global.theMonth curMonth = curMonth - 1 if curMonth < 1 then curMonth = 12 _global.theYear = _global.theYear - 1 end if _global.theMonth = curMonth displayMonth() end
The script to decrement the month is really pretty simple. First, a local variable curMonth is set to the month value stored in the global. Next, the value is decremented by 1, and then checked to see if it has become less than 1. If it has, then the month was January already and it needs to become December while the year is decremented by 1 as well. Finally, the month value is placed back into the global variable and the displayMonth method is called so the new month is displayed.
Be sure and give the new script member a name; decrement month is appropriate, and what I used for the sample movies on the CD.
Close the script window, then select the Next month button. Choose New Behavior in the sprite toolbar's behavior drop-down menu so that you can enter the increment month behavior as shown here:
on mouseUp me curMonth = _global.theMonth curMonth = curMonth + 1 if curMonth > 12 then curMonth = 1 _global.theYear = _global.theYear + 1 end if _global.theMonth = curMonth displayMonth() end
As you can see, the increment month is nearly identical to the decrement month behavior. The only real difference is that the month is checked to see if it has gone past 12. When it has, it is set to 1 (January) and the year is incremented by 1. Name the script increment month before moving on.
Close the script window, then rewind and play the movie. Use the Previous and Next month buttons to scroll through the months and see how the calendar is displaying. Stop the movie when you're ready. Although the calendar display code is working properly, it needs to first clear out the day numbers being displayed before drawing in new ones. There are a couple of ways you could do this, including using a repeat loop to iterate through the range of day sprites and set the text property of each sprite's member to "".
You probably noticed a problem with the old days not being erased when a new month is displayed as is shown here.
However, you can use Lingo's sendAllSprites(#handlerName) method instead. This method will run the handler named #handlerName within every sprite that contains a handler with that name. Currently, all of the text sprites used by the calendar display have script cast member 4 attachedclear text field on beginSprite.
From the scripts cast, open script member 4 for editing and add the doClear() method after the beginSprite handler.
The beginSprite handler currently in place is a one line script that sets the text property of the sprite's member to "" as is shown here. This, of course, erases any text in the field when the playhead first encounters the sprite span.
on beginSprite me sprite(me.spriteNum).member.text = "" end
However, you want to be able to do the exact same thing whenever a new month is displayed. Add the doClear() method after the beginSprite handler as shown:
on doClear me sprite(me.spriteNum).member.text = "" end
All you need to do now is call doClear(), on every text sprite, from the displayMonth() handler in the main script.
Double-click the Main Script cast member in the scripts cast to open the script window, then add the sendAllSprites() line as the first line of the script, right before you retrieve the month and year from the globals.
It doesn't matter where you add the line, so long as you do it before displaying the numbers, or you'll erase them all. Now, whenever you make a call to the displayMonth method the sendAllSprites(#doClear) line will execute and call the doClear() method within all of the text sprites used to display the calendar.
Rewind and play the movie and scroll through the months using the previous and next month buttons. Stop the movie when you're finished.
The old days are now being properly erased before a new month is drawn, and the calendar is working quite well. Next, you'll need a way for the sprites that will display the data for each day to know what day they are attached to, so that when you click them they will be able to open the input dialog with the correct information.
Using the Input Dialog
When the training log is fully up and running, clicking on any given day of the month should open the input dialog and allow you to enter or edit data for that day. For this to work, you'll need a way for each of the data sprites to know what day of the month they are displaying data forand of course this value could change anytime a new month is displayed.
Because the displayMonth method within the main script updates the calendar view anytime a new month is selected, it's the perfect spot to place the code to update the data sprites as well.
Let's begin by placing a simple behavior on each of the data sprites, in channels 10 through 51, that will be called from the displayMonth method.
Select the first data sprite, in channel 10, and from the behavior drop-down menu in the sprite toolbar, select New Behavior. In the script window, enter the following code. Name the new behavior set date.
property myDate on clearDate me myDate = 0 end on setDate me, theDate myDate = theDate end on mouseUp me trace(myDate) end
First, the clearDate method will be called to zero out the date of each field. Like the day sprites, you want to zero out the values before displaying a new month to prevent any data from the prior month interfering with the month being displayed. And as before, you'll use Lingo's sendAllSprites to easily call the clearDate method.
The setDate method will be used a bit differently. It will be called from within the repeat loop of the displayMonth method. Because the loop already iterates through the days of the month and sets the text of the appropriate day sprite to the date, it's the ideal location to also call the setDate method.
The mouseUp handler is there just for testing so you can see the value of myDate in the Message window when one of the sprites is clicked.
Close the script window and then select the remainder of the data sprites in channels 11 through 51, by single-clicking on the sprite in channel 11, then holding down Shift while clicking the sprite in channel 51. From the behavior drop-down in the sprite toolbar of the Score, select the set date behavior.
This will add the behavior to all of the selected sprites at once. Next, you'll need to add a few lines of code to the displayMonth method in order to make use of the new behavior.
Double-click the Main Script so that you can edit the displayMonth method. Add the following line of Lingo immediately after the existing sendAllSprites .
First sendAllSprites(#doClear) clears out any text in the calendar, then sendAllSprites(#clearDate) sets the myDate property of every data sprite to zero. Remember, you need to do this in order to prevent any overlap of data from a previously displayed month. As an example let's assume that August 2004 is being displayed in the calendar. August 1 falls on a Sunday. Now the Next month button is pressed and September is displayed. September 1 is a Wednesday. If you fail to zero out the sprites, Sunday, Monday, and Tuesday would still contain 1, 2, and 3 respectively, from August being previously displayed.
Add the following line of code immediately before the start of the repeat loop.
dataChannel = _global.dataSprites + _global.firstDayOfWeek
In the same manner that you use the firstDayOfWeek value to determine the start of the day sprites for the current month, you determine the start of the data sprites.
Next, you'll add two lines of code within the repeat loop in order to send the date value to the data sprites.
Add the following three lines of Lingo within the repeat loop.
sendSprite(dataChannel, #setDate, thisDay) --SQL SELECT goes here dataChannel = dataChannel + 1
Somewhat like the sendAllSprites method, the sendSprite method allows you to call a handler within a sprite's behavior. The difference is that sendAllSprites affects any and all sprites with the attached handler while sendSprite calls a handler within a specific sprite.
Here, as you use the repeat loop to iterate through the days of the month you send the value in thisDay to the setDate handler of the sprite specified by the dataChannel variable. (The comment line --SQL SELECT goes here will be replaced later, when the database is working.)
So that you have a reference, the displayMonth method should currently appear like the following:
on displayMonth sendAllSprites(#doClear) sendAllSprites(#clearDate) thisMonth = _global.theMonth thisYear = _global.theYear --number of days in each month daysList = [31,28,31,30,31,30,31,31,30,31,30,31] monthList = ["January", "February", "March", "April", "May", "June", ¬ "July", "August", "September", "October", "November", "December"] --show month and year dateString = monthList[thisMonth] && string(thisYear) member("date shadow").text = dateString member("date display").text = dateString --determine number of days in this month and check for leap year days = daysList[thisMonth] if thisMonth = 2 then leapCheck = date(thisYear, 2, 29) if leapCheck.month = 2 then days = 29 end if end if --Now get the day of week the first starts on flashDate = newObject("date") flashDate.setFullYear(thisYear, thisMonth - 1, 1) _global.firstDayOfWeek = integer(flashDate.getDay()) --returns 0-6 dayChannel = _global.daySprites + _global.firstDayOfWeek dataChannel = _global.dataSprites + _global.firstDayOfWeek repeat with thisDay = 1 to days sprite(dayChannel).member.text = string(thisDay) sendSprite(dataChannel, #setDate, thisDay) --SQL SELECT goes here dataChannel = dataChannel + 1 dayChannel = dayChannel + 1 end repeat end
Close the script window, open the Message window, then rewind and play the movie. Click the blank data sprites to verify that they trace the correct day of the month to the Message window.
As you click the empty data sprites, the day of the month appears in the Message window, as shown here.
All that's left to do now is to update the title within the input dialog according to the date that's been clicked on, and then move the dialog onto the Stage so that the data can be edited.
Stop the movie and open the Set Date script from the scripts cast. Edit the mouseUp handler within the script so that it appears like the following:
on mouseUp me if myDate <> 0 then _global.theDay = myDate sendSprite("dialog", #endSprite) _movie.updateStage() dateString = string(_global.theMonth) & "/" & string(myDate) & "/" ¬ & string(_global.theYear) sprite("dialog").title.text = "Edit data for" && dateString --SQL SELECT goes here end if end
First a check is done to see if the myDate property of the sprite is not currently zero, as you only want the input dialog to appear if a valid day of the month has been clicked. If a valid day has been clicked, then myDate will be something other than zero and the remainder of the code will be executed.
The first thing that's done is to set the global variable theDay to the value of myDate. This variable will be used later when saving the actual data into the database.
Next, you may notice that the endSprite handler of the input dialog sprite is being called. This may seem a little strange, but you can use sendSprite to issue any event you like including any events generated by Director such as mouseUp, exitFrame, beginSprite, etc.
Because the endSprite handler attached to the dialog sprite already moves the sprite onto the stage if the movie is stopped or the playhead leaves the span, you might as well also use the handler to move the sprite on Stage when you need it.
The next line of code is something you haven't seen yet: _movie.updateStage(). It does exactly what it says; it forces a redraw of the Stage whenever it's encountered. Normally the Stage is updated only between frames, but can be updated manually by using this method. The reason you need to do it here is that you can only update properties within a Flash sprite if that sprite is showing on the Stage. If you try to set the title with the sprite still off Stage you will get an error, and your movie will stop. Because of this you need to move the input dialog on Stage, and be sure it's showing, before trying to modify any of its properties.
Once the input dialog is available on the Stage, a date string is created by concatenating the month, date, and year together with slashes. Note that the sprite's myDate property is being used here instead of the global theDay. This just happens to be the way I wrote it; it wouldn't matter at all if you used the global instead. Finally, the text property of the title instance within the Flash sprite is updated.
The final comment line will be replaced in the database section on updating data.
Rewind and play the movie, and then click on various days of the month.
As you click on any valid days of the month, the title will be updated within the Flash sprite, informing you what day of the month is being edited. If you click a blank day in the calendar, where the myDate property of the data sprite is zero, the input dialog will either not open or won't be updated if it is already open. However, once the dialog has been opened you can't close it without stopping the movie and then playing it.
Recall, that in Lesson 6 you added the getURL handler to the Main Script to intercept the save and close being sent from the Flash sprite.
Stop the movie and double-click the Main Script, in the scripts cast, to open it for editing. Modify the existing getURL handler so that it appears like the following.
on getURL me, data if data = "close" then sendSprite("dialog", #beginSprite) end
Here again, you are using sendSprite to send an event, beginSprite, normally generated by Director. Doing so is a perfectly valid option and an easy way to hide the input dialog when the Close button is pressed. Recall that the move off Stage behavior, attached to the input dialog, sets the locV property of the sprite to -2000 on beginSprite. This moves the sprite far off Stage, and does the same thing when you call it from the getURL handler.
Stop and Save the movie as mytrainer within your project_two folder.
The calendar is now working and the input dialog appears, allowing you to enter data for any valid day of the month. The question now is, what do you do with the data once it's been entered? Enter the database. Finally.