28.2 Making the Components
After formulating the general overview of the
application's pieces, the next step is to create
each of the components. All the components in the subsequent sections
should be placed within a single Flash document. To start, create a
new Flash document named scheduler.fla.
28.2.1 Designing the TimeSelector Component
The TimeSelector
component consists of a scroll pane in which 24 TimeSelectorItem
instances appear. Additionally, the TimeSelector component should
have the following functionality:
You should be able to make the component selectable or nonselectable.
When the user is adding notes or to-do items to a daily schedule, the
entire time selector should become nonselectable to signify this. You should be able to highlight or remove a highlight from any of the
time selector items by index. You should be able to set a callback function that is automatically
invoked whenever a time selector item is selected.
To create the TimeSelector component, complete the following steps:
The TimeSelector component requires you to include the ScrollPane
component in your movie. Create a copy of the ScrollPane component in
your movie's Library by dragging an instance from
the Components panel to the Stage. You can then delete the instance
on stage; a copy of the symbol remains in the Library. Create a new movie clip symbol named
TimeSelector. Open the linkage properties for the symbol. Select the Export for ActionScript and Export in First Frame
checkboxes. Give the symbol a linkage identifier of
TimeSelectorSymbol. Click OK to close the Linkage Properties dialog box. Edit the TimeSelector symbol. Add the following code to the first frame of the default layer: #initclip 0
// The constructor creates a scroll pane instance and populates it with 24
// instances of the TimeSelectorItem component.
function TimeSelector( ) {
// Create the scroll pane instance.
this.attachMovie("FScrollPaneSymbol", "sp", this.getNewDepth( ));
this.sp.setSize(150, 380);
// Create a scroll content movie clip.
this.createEmptyMovieClip("sc", this.getNewDepth( ));
// The times property is an array that the component uses to keep track of all
// the TimeSelectorItem instances.
this.times = new Array( );
var time;
// Perform the same actions 24 times, once for each hour of the day.
for (var i = 0; i < 24; i++) {
// Create an instance of the TimeSelectorItem component and set its y
// coordinate so that it appears directly below the previous
// TimeSelectorItem.
time = this.sc.attachMovie("TimeSelectorItemSymbol", "time" + i,
this.sp.getNewDepth( ), {_y: i * 20});
// The TimeSelectorItem.setTime( ) method sets the time displayed by the
// component based on an integer from 0 (12 A.M.) to 23 (11 P.M.).
time.setTime(i);
// The TimeSelectorItem.setOnSelect( ) method sets the callback function that
// should be invoked when the item is selected by the user.
time.setOnSelect("onSelectTime", this);
// Add the TimeSelectorItem component to the times array.
this.times.push(time);
}
// Set the scroll pane's scroll content.
this.sp.setScrollContent(this.sc);
}
// TimeSelector extends MovieClip.
TimeSelector.prototype = new MovieClip( );
// The setSelectable( ) method sets whether
// items in the time selector are selectable.
TimeSelector.prototype.setSelectable = function (isSelectable) {
// If isSelectable is true, enable all TimeSelectorItems and call
// TimeSelectorItem.grayOut( ) with a value of false so that the items appear
// normally. Otherwise, dim and disable the TimeSelectorItems.
for (var i = 0; i < this.times.length; i++) {
this.times[i].enabled = isSelectable;
this.times[i].grayOut(!isSelectable);
}
};
// The TimeSelector.setHasValue( ) method calls the
// TimeSelectorItem.setHasValue( ) method of the item that corresponds to the
// specified index. See TimeSelectorItem.setHasValue( ) for more information.
TimeSelector.prototype.setHasValue = function (index, hasValue) {
this.times[index].setHasValue(hasValue);
};
// The onSelectTime( ) method is the callback function for each of the
// TimeSelectorItem instances (as assigned in the class constructor). The cmpt
// parameter is a reference to the TimeSelectorItem that has been selected.
TimeSelector.prototype.onSelectTime = function (cmpt) {
// Call TimeSelectorItems.deselect( ) for every item except the selected one.
for (var i = 0; i < this.times.length; i++) {
if (this.times[i] != cmpt) {
this.times[i].deselect( );
}
}
// Invoke the onSelect callback function.
this.onSelectPath[this.onSelectCB](cmpt);
};
// The setOnSelect( ) method allows you to define a callback function for the
// TimeSelector component. The functionName parameter is the name of the
// function, and the path parameter is a reference to a timeline in which the
// callback function exists.
TimeSelector.prototype.setOnSelect = function (functionName, path) {
if (path == undefined) {
path = this._parent;
}
this.onSelectPath = path;
this.onSelectCB = functionName;
};
Object.registerClass("TimeSelectorSymbol", TimeSelector);
#endinitclip
The TimeSelector component is not very complex. The component loads
24 TimeSelectorItems into a scroll pane and acts as an interface by
which some commands can be sent to the items. The constructor simply
creates these instances and places them in a scroll pane.
function TimeSelector( ) {
this.attachMovie("FScrollPaneSymbol", "sp", this.getNewDepth( ));
this.sp.setSize(150, 380);
this.createEmptyMovieClip("sc", this.getNewDepth( ));
this.times = new Array( );
var time;
for (var i = 0; i < 24; i++) {
time = this.sc.attachMovie("TimeSelectorItemSymbol", "time" + i,
this.sp.getNewDepth( ), {_y: i * 20});
time.setTime(i);
time.setOnSelect("onSelectTime", this);
this.times.push(time);
}
this.sp.setScrollContent(this.sc);
}
The setSelectable(
) method enables or disables all the
associated TimeSelectorItems, graying them out if appropriate. This
method is used when the user selects another entry type (such as
notes or the to-do list), and it serves to visually indicate whether
the user is making hourly entries.
TimeSelector.prototype.setSelectable = function (isSelectable) {
for (var i = 0; i < this.times.length; i++) {
this.times[i].enabled = isSelectable;
this.times[i].grayOut(!isSelectable);
}
};
When the user selects a TimeSelectorItem, the
TimeSelector.onSelectTime( )
method is invoked automatically (see the constructor in which you set
the onSelect callback function for each item).
When an item is selected, call the deselect( )
method for all the other TimeSelectorItems, and call the
onSelect callback function for the TimeSelector.
TimeSelector.prototype.onSelectTime = function (cmpt) {
for (var i = 0; i < this.times.length; i++) {
if (this.times[i] != cmpt) {
this.times[i].deselect( );
}
}
this.onSelectPath[this.onSelectCB](cmpt);
};
28.2.2 Designing the TimeSelectorItem Component
The TimeSelectorItem
component constitutes the content of the TimeSelector component. Each
TimeSelectorItem represents one hour of the day, and it should
include the following functionality:
The component should draw a filled rectangle. You should be able to set a time label based on an integer from 0 to
23. When the item is selected, the rectangle's outline
should be bolded, and when deselected, the outline should not be
bolded. You should be able to change the rectangle's fill
color to highlight the component. (This is used to indicate that an
hour has a scheduled event.) You should be able to gray out the component to indicate it is
disabled. You should be able to specify a callback function that is invoked
when the item is selected.
To create the TimeSelectorItem component, complete the following
steps.
Create a new movie clip symbol named
TimeSelectorItem. Open the linkage properties for the symbol. Select the Export for ActionScript and Export in First Frame
checkboxes. Give the symbol a linkage identifier of
TimeSelectorItemSymbol. Click OK to close the Linkage Properties dialog box. Edit the TimeSelectorItem symbol. Add the following code to the first frame of the default layer: #initclip 0
// In the constructor, create the rectangle with a fill and outline and create a
// text field to use as the label.
function TimeSelectorItem( ) {
// Create a movie clip and two nested movie clips within it, one for the fill
// and one for the outline.
this.createEmptyMovieClip("indicator", this.getNewDepth( ));
this.indicator.createEmptyMovieClip("fill", this.indicator.getNewDepth( ));
this.indicator.createEmptyMovieClip("outline", this.indicator.getNewDepth( ));
// Draw the fill as a white rectangle using the drawRectangle( ) method.
with (this.indicator.fill) {
lineStyle(0, 0x000000, 0);
beginFill(0xFFFFFF, 100);
drawRectangle(150, 20);
endFill( );
_x += 75;
_y += 10;
}
// Call the drawOutline( ) method to draw the outline.
this.drawOutline( );
// Create color objects to control the color for both the outline and the fill.
this.indicator.fill.col = new Color(this.indicator.fill);
this.indicator.outline.col = new Color(this.indicator.outline);
// Create a text field in which the time label should appear.
this.createTextField("time", this.getNewDepth( ), 0, 0, 150, 20);
}
// TimeSelectorItem extends MovieClip.
TimeSelectorItem.prototype = new MovieClip( );
// The drawOutline( ) method draws/redraws the rectangle's outline. If selected
// is true, draw the line with a thickness of 2. Otherwise, use no outline.
TimeSelectorItem.prototype.drawOutline = function (selected) {
with (this.indicator.outline) {
clear( );
if (selected) {
lineStyle(2, 0x000000, 100);
} else {
lineStyle(0, 0x000000, 100);
}
drawRectangle(150, 20);
_x = 75;
_y = 10;
}
};
// The static getDisplayTime( ) method takes an integer from 0 to 23 and returns
// a string in the format HH AM/PM (i.e., 12 AM, 3 PM, etc.).
TimeSelectorItem.getDisplayTime = function (timeVal) {
var time;
if (timeVal == 0) {
time = "12 AM";
} else if (timeVal < 11) {
time = timeVal + " AM";
} else if (timeVal == 12) {
time = "12 PM";
} else {
time = (timeVal - 12) + " PM";
}
return time;
};
// The setTime( ) method takes an integer from 0 to 23 and it displays the
// corresponding time label in the text field.
TimeSelectorItem.prototype.setTime = function (timeVal) {
this.timeVal = timeVal;
this.time.text = TimeSelectorItem.getDisplayTime(timeVal);
};
// The grayOut( ) method changes the colors of the outline and fill movie clips.
TimeSelectorItem.prototype.grayOut = function (grayOut) {
if (grayOut) {
this.indicator.outline.col.setRGB(0xBCBCBC);
if (this.hasValue) {
this.indicator.fill.col.setRGB(0xE4E4E4);
}
} else {
this.indicator.outline.col.setRGB(0);
if (this.hasValue) {
this.indicator.fill.col.setRGB(0xCCEFFD);
}
}
};
// The setHasValue( ) method highlights or removes a highlight from the
// TimeSelectorItem by setting the color of the fill.
TimeSelectorItem.prototype.setHasValue = function (hasValue) {
if (hasValue) {
this.indicator.fill.col.setRGB(0xCCEFFD);
this.hasValue = true;
} else {
this.indicator.fill.col.setRGB(0xFFFFFF);
this.hasValue = false;
}
};
// When an item is selected, call drawOutline(true) to bold the outline.
TimeSelectorItem.prototype.select = function ( ) {
this.drawOutline(true);
};
// When an item is deselected, call drawOutline( ) to unbold the outline.
TimeSelectorItem.prototype.deselect = function ( ) {
this.drawOutline( );
};
// Get the time (an integer from 0 to 23) that
// corresponds to the TimeSelectorItem.
TimeSelectorItem.prototype.getTime = function ( ) {
return this.timeVal;
};
// When the item is rolled over, set the color of the fill to a light gray.
TimeSelectorItem.prototype.onRollOver = function ( ) {
this.indicator.fill.col.setRGB(0xDFDFDF);
};
// When the item is rolled out, set the color of the fill to either white (if the
// user has not scheduled anything for the hour) or light blue (if the user has
// scheduled something for the hour).
TimeSelectorItem.prototype.onRollOut = function ( ) {
if (this.hasValue) {
this.indicator.fill.col.setRGB(0xCCEFFD)
} else {
this.indicator.fill.col.setRGB(0xFFFFFF);
}
};
// When the item is clicked on, call the select( ) method and
// the onSelect callback function.
TimeSelectorItem.prototype.onPress = function ( ) {
this.select( );
this.onSelectPath[this.onSelectCB](this);
};
// Set the onSelect callback function.
TimeSelectorItem.prototype.setOnSelect = function (functionName, path) {
if (path == undefined) {
path = this._parent;
}
this.onSelectPath = path;
this.onSelectCB = functionName;
};
Object.registerClass("TimeSelectorItemSymbol", TimeSelectorItem);
#endinitclip
Although the TimeSelectorItem class has a lot of
code, there is nothing within the code that is unusual or
complicated. The majority of the code involves either drawing shapes
or changing colors.
28.2.3 Designing the Schedule Component
The Schedule
component acts as a container for each of the ScheduleItem
components. While ScheduleItem components correspond to specific
calendar dates, the Schedule component is the framework within which
each of these items is stored. The Schedule component should have the
following functionality:
It should allow you to add new schedule items for calendar dates. It should keep track of all notifications that a user has set, and it
should alert the user at the appropriate interval automatically. It should save the data to a local shared object and retrieve that
data whenever the application is reopened.
To create the Schedule component, complete the following steps:
Create a new movie clip symbol named Schedule. Open the linkage properties for the symbol. Select the Export for ActionScript and Export in First Frame
checkboxes. Give the symbol a linkage identifier of
ScheduleSymbol. Click OK to close the Linkage Properties dialog box. Edit the Schedule symbol. Add the following code to the first frame of the default layer: #initclip
function Schedule( ) {
// Create associative arrays to keep track of schedule items and notifiers.
this.items = new Object( );
this.notifiers = new Object( );
// Create a local shared object or open an existing LSO.
this.so = SharedObject.getLocal("mySchedule");
// If LSO is not new, populate the schedule
// application with the retrieved data.
if (this.so.data.schedules != undefined) {
for (var i in this.so.data.schedules) {
var dt = this.so.data.schedules[i].siDate;
this.addItem(dt);
this.items[dt].setValues(this.so.data.schedules[i]);
}
this.notifiers = this.so.data.notifiers;
}
// Run the notifier routine now and call it once per hour.
this.runNotify( );
this.interval = setInterval(this, "runNotify", 3600000);
}
Schedule.prototype = new MovieClip( );
// The save( ) method is called when the module is closed;
// it writes the schedule data to the local shared object.
Schedule.prototype.save = function ( ) {
// Create a schedules associative array and fill it
// with the values from every schedule item.
this.so.data.schedules = new Object( );
for (var i in this.items) {
this.so.data.schedules[i] = this.items[i].getValues( );
}
// Create a notifiers associative array that has the
// value of the notifiers property of the schedule component.
this.so.data.notifiers = this.notifiers;
// Invoke the flush( ) method to write the data to disk.
this.so.flush( );
};
// The onCloseNotification( ) method is the callback function
// for when the user closes a notifier window. It removes
// the Notifier component instance from the movie.
Schedule.prototype.onCloseNotification = function (cmpt) {
this.noteDisp.removeMovieClip( );
};
// Get a schedule item by index (which is a date string).
Schedule.prototype.getItem = function (index) {
return this.items[index];
};
// Add a new schedule item by index (which is a date string).
Schedule.prototype.addItem = function (index) {
var uniqueVal = this.getNewDepth( );
// Create a new instance of the ScheduleItem component and assign a reference
// to the new component to an element of the items associative array.
this.items[index] = this.attachMovie("ScheduleItemSymbol", "item" + uniqueVal,
uniqueVal);
this.items[index].setDate(index);
};
// The runNotify( ) method is called at hourly
// intervals to display any new updates.
Schedule.prototype.runNotify = function ( ) {
// Create a date for tomorrow and get that value as a formatted date string.
var d = new Date( );
d.setDate(d.getDate( ) + 1);
index = d.format("MM-dd-yyyy");
// Check to see if a notifier exists for that date.
if (this.notifiers[index] != undefined) {
var notification = "";
// Loop through all the elements for that date's notifiers and add them to
// the notification string.
for (var i = 0; i < this.notifiers[index].length; i++) {
if (this.notifiers[index][i]) {
notification += index + " " +
TimeSelectorItem.getDisplayTime(i) + newline +
this.items[index].getSchedule(i) + "\n\n";
}
}
// Delete the notifier information so that
// the user will not be notified again.
delete this.notifiers[index];
// Call the displayNotifications( ) method
// to display information to the user.
this.displayNotifications(notification);
}
};
// Create a new NotifierDisplayer component instance and display the notification
// information to the user.
Schedule.prototype.displayNotifications = function (displayValue) {
this.attachMovie("NotifierDisplayerSymbol", "noteDisp", this.getNewDepth( ));
this.noteDisp._x = Stage.width/2 - this.noteDisp._width/2;
this.noteDisp._y = Stage.height/2 - this.noteDisp._height/2;
this.noteDisp.display(displayValue);
};
// The setNotify( ) method adds a new notifier to the schedule, or, if doNotify
// is not true, it removes any existing notifiers for the date and time.
Schedule.prototype.setNotify = function (dt, hour, doNotify) {
if (doNotify) {
if (this.notifiers[dt] == undefined) {
this.notifiers[dt] = new Array( );
}
this.notifiers[dt][hour] = true;
} else {
delete this.notifiers[dt][hour];
}
};
// Call the open( ) method for a schedule item, which makes it visible, by index.
Schedule.prototype.openItem = function (index) {
this.items[index].open( );
};
// The onClose( ) method is invoked automatically when a schedule item is closed.
// This method invokes the schedule's onClose callback function.
Schedule.prototype.onClose = function ( ) {
this.onClosePath[this.onCloseCB]( );
};
// Set the onClose callback function.
Schedule.prototype.setOnClose = function (functionName, path) {
if (path == undefined) {
path = this._parent;
}
this.onClosePath = path;
this.onCloseCB = functionName;
};
Object.registerClass("ScheduleSymbol", Schedule);
#endinitclip
Let's examine the Schedule component code more
closely to shed light on parts of the code that might be unclear.
When you initialize the Schedule component, it must create properties
to keep track of the schedule items and the notifiers. It uses an
associative array for each of these properties so that the keys are
in the form of formatted date strings (instead of simply integer
indexes). Additionally, it creates (or opens) the shared object in
which the schedule information is stored. If the shared object
already exists, the retrieved data is used to populate the schedule.
Finally, it sets up an interval for notifications, which runs once an
hour. Although this example auto-saves the data when the user clicks
the close box, you could implement a manual save feature using a
button instead.
function Schedule( ) {
this.items = new Object( );
this.notifiers = new Object( );
this.so = SharedObject.getLocal("mySchedule");
if (this.so.data.schedules != undefined) {
for (var i in this.so.data.schedules) {
var dt = this.so.data.schedules[i].siDate;
this.addItem(dt);
this.items[dt].setValues(this.so.data.schedules[i]);
}
this.notifiers = this.so.data.notifiers;
}
this.runNotify( );
this.interval = setInterval(this, "runNotify", 3600000);
}
The addItem( ) method adds a new schedule item. The
index is a formatted date string, and the new
schedule item is added to the items associative
array using that date string as the key. This makes it easy to
retrieve a reference to the schedule item later on.
Schedule.prototype.addItem = function (index) {
var uniqueVal = this.getNewDepth( );
this.items[index] = this.attachMovie("ScheduleItemSymbol", "item" + uniqueVal,
uniqueVal);
this.items[index].setDate(index);
};
The runNotify( ) method is invoked every 60 minutes; it
checks for any notifications for the next day. To calculate the date
that represents the next day, add one to the current date. From this
date, you can create a formatted date string (the format used by the
keys of the notifiers associative array) using the
Date.format( ) method. Each element of the
notifiers associative array is an array of
notifications for that day. Therefore, if there is an entry in the
notifiers associative array for the next day, loop
through all the elements of that array and create a string of those
values. Then, run the displayNotifications(
) method to actually open the notifier
displayer.
Schedule.prototype.runNotify = function ( ) {
var d = new Date( );
d.setDate(d.getDate( ) + 1);
index = d.format("MM-dd-yyyy");
if (this.notifiers[index] != undefined) {
var notification = "";
for (var i = 0; i < this.notifiers[index].length; i++) {
if (this.notifiers[index][i]) {
notification += index + " " +
TimeSelectorItem.getDisplayTime(i) + newline +
this.items[index].getSchedule(i) + "\n\n";
}
}
delete this.notifiers[index];
this.displayNotifications(notification);
}
};
28.2.4 Designing the ScheduleItem Component
The ScheduleItem
component represents a single calendar date. Each schedule item
consists of a time selector, an input text field, and a list box from
which the user can select the type of entry he wants to make (hourly
schedule, notes, or to-do list). The schedule item should have the
following functionality:
A user should be able to select from different types of schedule
entries, and he should be able to make an entry for that type by
typing into a text field. A user should be able to select from available hours in the time
selector and add an entry for that hour. Time selector items
corresponding to hours with entries should be colorized to indicate
this. A user should be able to specify whether the scheduler should notify
him of hourly entries on the day before they are scheduled to occur. A user should be able to close a schedule item window.
To create the ScheduleItem component, complete the following steps:
The ScheduleItem component requires you to include the ScrollBar and
CheckBox components in your movie. Create a copy of these components
in your movie's Library by dragging an instance of
each component from the Components panel onto the Stage and then
deleting them. A copy of the symbols remains in the Library. Create a new movie clip symbol named
ScheduleItem. Open the linkage properties for the symbol. Select the Export for ActionScript and Export in First Frame
checkboxes. Give the symbol a linkage identifier of
ScheduleItemSymbol. Click OK to close the Linkage Properties dialog box. Edit the ScheduleItem symbol. Add the following code to the first frame of the default layer: #initclip 2
function ScheduleItem ( ) {
// Draw the component.
this.draw( );
// Create arrays to hold information about the hourly schedule entries and any
// entries for which the user has chosen to be notified.
this.hourlySchedule = new Array( );
this.notifiers = new Array( );
// Initialize the component, such that 12 A.M. is the selected hour.
this.selectedHour = 0;
// Initialize the component so that it is not visible.
this._visible = false;
}
// ScheduleItem extends MovieClip.
ScheduleItem.prototype = new MovieClip( );
// Retrieve the schedule item's values.
ScheduleItem.prototype.getValues = function ( ) {
var valuesObj = new Object( );
// siDate is the formatted date string that indicates the date to which the
// schedule item corresponds.
valuesObj.siDate = this.siDate;
// These properties are the entries (and notifiers) for the schedule item.
valuesObj.hourlySchedule = this.hourlySchedule;
valuesObj.notifiers = this.notifiers;
valuesObj.toDo = this.toDo;
valuesObj.notes = this.notes;
return valuesObj;
};
// The setValues( ) method is used to populate a schedule item when the values
// have been saved to disk and have been retrieved again when the schedule
// application is reopened. The valuesObj is in the same form as the valuesObj
// that getValues( ) returns. Therefore, setValues( ) does essentially the reverse
// of what getValues( ) does.
ScheduleItem.prototype.setValues = function (valuesObj) {
this.hourlySchedule = valuesObj.hourlySchedule;
this.notifiers = valuesObj.notifiers;
this.toDo = valuesObj.toDo;
this.notes = valuesObj.notes;
// In addition to setting the properties of the schedule item, call the
// setHasValue( ) method for the time selector for any times that have entries.
for (var i = 0; i < this.hourlySchedule.length; i++) {
if (this.hourlySchedule[i] != undefined) {
this.times.setHasValue(i, true);
}
}
};
// The draw( ) method creates the component on the Stage.
ScheduleItem.prototype.draw = function ( ) {
// Create a text field for the schedule item title.
this.createTextField("title", this.getNewDepth( ), 0, 0, 550, 20);
this.title.selectable = false;
this.title.border = true;
this.title.background = true;
this.title.backgroundColor = 0xDFDFDF;
// Create a TimeSelector instance and set its onSelect callback function.
this.attachMovie("TimeSelectorSymbol", "times", this.getNewDepth( ));
this.times.setOnSelect("onSelectTime", this);
// Create an input text field so that the user can make entries.
this.createInputTextField("scheduleInfo", this.getNewDepth( ), 0, 0, 234, 350);
this.scheduleInfo.multiline = true;
// When the user removes focus from the text field (usually by clicking
// elsewhere in the movie), call the saveInfo( ) method to save the entry.
this.scheduleInfo.onKillFocus = function ( ) {
this._parent.saveInfo( );
};
// Create a scrollbar for the input text field.
this.attachMovie("FScrollBarSymbol", "sb", this.getNewDepth( ));
this.sb.setScrollTarget(this.scheduleInfo);
this.sb.setSize(this.scheduleInfo._height);
// Create a movie clip for the notification checkbox.
this.createEmptyMovieClip("notifyBox", this.getNewDepth( ));
// Draw a filled rectangle as a background.
this.notifyBox.createEmptyMovieClip("background",
this.notifyBox.getNewDepth( ));
with (this.notifyBox.background) {
lineStyle(0, 0x000000, 100);
beginFill(0xFFFFFF, 100);
drawRectangle(this.scheduleInfo._width + this.sb._width, 30);
endFill( );
_x = _width / 2;
_y = _height / 2;
}
// Attach a CheckBox component instance and set the callback function for it.
this.notifyBox.attachMovie("FCheckBoxSymbol", "notifyCheckBox",
this.notifyBox.getNewDepth( ), {_x: 10, _y: 10});
this.notifyBox.notifyCheckBox.setLabel("notify me");
this.notifyBox.notifyCheckBox.setChangeHandler("notifyChange", this);
// Use a table to position all the elements that you have created thus far.
midTr0 = new TableRow(0, new TableColumn(0, this.scheduleInfo),
new TableColumn(0, this.sb));
midTr1 = new TableRow(0, new TableColumn(0, this.notifyBox));
midTable = new Table(0, 0, 0, midTr0, midTr1);
// Add a list box so the user can select an entry type.
this.attachMovie("FListBoxSymbol", "entryTypeMenu", this.getNewDepth( ));
this.entryTypeMenu.setSize(150, 380);
this.entryTypeMenu._height = 380;
// Set the values for the list box.
this.entryTypeMenu.setDataProvider(["hourly", "to do list", "notes"]);
this.entryTypeMenu.setChangeHandler("onSelectEntryType", this);
this.entryTypeMenu.setSelectedIndex(0);
// Create a table to position all the elements, including ones from midTable.
tr0 = new TableRow(0, new TableColumn(0, this.title));
tr1 = new TableRow(0,
new TableColumn(0, this.times),
new TableColumn(0, midTable),
new TableColumn(0, this.entryTypeMenu));
t = new Table(0, 0, 0, tr0, tr1);
// Create a button movie clip to let the user close the schedule item window.
this.createEmptyMovieClip("closeBtn", this.getNewDepth( ));
with (this.closeBtn) {
lineStyle(0, 0x000000, 100);
beginFill(0xFFFFFF, 100);
drawRectangle(10, 10);
endFill( );
_x = 540;
_y = 10;
}
this.closeBtn.onRelease = function ( ) {
this._parent.close( );
// Invoke the save( ) method of the schedule to
// save the data when the item window is closed.
this._parent._parent.save( )
};
};
// Return the entry for an hour.
ScheduleItem.prototype.getSchedule = function (hour) {
return this.hourlySchedule[hour];
};
// The notifyChange( ) method is the callback function for the notification
// checkbox. This method calls the setNotify( ) method of the parent schedule and
// adds to the notifiers array property.
ScheduleItem.prototype.notifyChange = function (cmpt) {
this._parent.setNotify(this.siDate, this.selectedHour, cmpt.getValue( ));
this.notifiers[this.selectedHour] = cmpt.getValue( );
};
// The onSelectEntryType( ) method is the callback function that is invoked when
// a user selects an item from the list box.
ScheduleItem.prototype.onSelectEntryType = function (cmpt) {
var index = cmpt.getSelectedIndex( );
switch (index) {
case 0:
// If the first item (hourly) is selected, make sure the time selector is
// set to selectable and also enable the checkbox.
this.times.setSelectable(true);
this.entryType = "hourly";
this.selectTime( );
this.notifyBox.notifyCheckBox.setEnabled(true);
break;
case 1:
// If the second item (to-do list) is selected, make sure the time selector
// is not selectable and disable the checkbox.
this.times.setSelectable(false);
this.scheduleInfo.text = "";
this.entryType = "toDo";
this.scheduleInfo.text = this.toDo;
this.notifyBox.notifyCheckBox.setEnabled(false);
this.notifyBox.notifyCheckBox.setValue(false);
break;
case 2:
// If the third item (notes) is selected, make sure the time selector is
// not selectable and disable the checkbox.
this.times.setSelectable(false);
this.scheduleInfo.text = "";
this.entryType = "notes";
this.scheduleInfo.text = this.notes;
this.notifyBox.notifyCheckBox.setEnabled(false);
this.notifyBox.notifyCheckBox.setValue(false);
}
};
// The setDate( ) method takes a formatted date string as a parameter and sets
// the title text and the siDate property for the schedule item.
ScheduleItem.prototype.setDate = function (val) {
this.title.text = val;
var tf = new TextFormat( );
tf.bold = true;
tf.align = "center";
tf.size = 15;
this.title.setTextFormat(tf);
this.siDate = val;
};
ScheduleItem.prototype.open = function ( ) {
this._visible = true;
};
ScheduleItem.prototype.close = function ( ) {
this._visible = false;
this._parent.onClose( );
};
// The saveInfo( ) method is invoked whenever the text field loses focus.
ScheduleItem.prototype.saveInfo = function ( ) {
switch (this.entryType) {
case "hourly":
// If the user has made an hourly schedule entry, save that entry in the
// hourlySchedule array and colorize the corresponding time selector item;
// otherwise, remove any colorization on a time selector item.
if (this.scheduleInfo.text != "") {
this.hourlySchedule[this.selectedHour] = this.scheduleInfo.text;
this.times.setHasValue(this.selectedHour, true);
} else {
this.times.setHasValue(this.selectedHour, false);
}
break;
case "toDo":
// Save the to-do information.
this.toDo = this.scheduleInfo.text;
break;
case "notes":
// Save the notes information.
this.notes = this.scheduleInfo.text;
}
};
// The onSelectTime( ) method is the callback function
// when a time selector item is chosen.
ScheduleItem.prototype.onSelectTime = function (cmpt) {
this.selectedHour = cmpt.getTime( );
this.selectTime( );
};
// The selectTime( ) method displays any saved entries for a selected time in the
// input text field. Also, if the user has chosen to be notified for the event,
// the checkbox is checked.
ScheduleItem.prototype.selectTime = function ( ) {
if (this.hourlySchedule[this.selectedHour] != undefined) {
this.scheduleInfo.text = this.hourlySchedule[this.selectedHour];
} else {
this.scheduleInfo.text = "";
}
if (this.notifiers[this.selectedHour] != undefined) {
this.notifyBox.notifyCheckBox.setValue(this.notifiers[this.selectedHour]);
} else {
this.notifyBox.notifyCheckBox.setValue(false);
}
};
Object.registerClass("ScheduleItemSymbol", ScheduleItem);
#endinitclip
Although the ScheduleItem component code is not particularly
daunting, it is still worth taking a closer look at some of what is
going on here.
The getValues( ) and setValues(
) methods do the reverse of one another.
The getValues( ) method is used in conjunction
with the Schedule component's save(
) method. It returns an object that contains the user
data, which is, in turn, saved to the shared object. Then, when the
data is retrieved from the shared object, the same data object is
passed back to the setValues( ) method to
repopulate the schedule item.
ScheduleItem.prototype.getValues = function ( ) {
var valuesObj = new Object( );
valuesObj.siDate = this.siDate;
valuesObj.hourlySchedule = this.hourlySchedule;
valuesObj.notifiers = this.notifiers;
valuesObj.toDo = this.toDo;
valuesObj.notes = this.notes;
return valuesObj;
};
ScheduleItem.prototype.setValues = function (valuesObj) {
this.hourlySchedule = valuesObj.hourlySchedule;
this.notifiers = valuesObj.notifiers;
this.toDo = valuesObj.toDo;
this.notes = valuesObj.notes;
for (var i = 0; i < this.hourlySchedule.length; i++) {
if (this.hourlySchedule[i] != undefined) {
this.times.setHasValue(i, true);
}
}
};
The onSelectEntryType(
) method is the change handler function
for the entry types list box. Although there are many lines of code
in the method, it is really nothing complex. The entire method is a
single switch statement that sets the time
selector's selectable status, the
entryType property, and other minor modifications
depending on the type of entry the user has selected (hourly, to-do
list, or notes):
ScheduleItem.prototype.onSelectEntryType = function (cmpt) {
var index = cmpt.getSelectedIndex( );
switch (index) {
case 0:
this.times.setSelectable(true);
this.entryType = "hourly";
this.selectTime( );
this.notifyBox.notifyCheckBox.setEnabled(true);
break;
case 1:
this.times.setSelectable(false);
this.scheduleInfo.text = "";
this.entryType = "toDo";
this.scheduleInfo.text = this.toDo;
this.notifyBox.notifyCheckBox.setEnabled(false);
this.notifyBox.notifyCheckBox.setValue(false);
break;
case 2:
this.times.setSelectable(false);
this.scheduleInfo.text = "";
this.entryType = "notes";
this.scheduleInfo.text = this.notes;
this.notifyBox.notifyCheckBox.setEnabled(false);
this.notifyBox.notifyCheckBox.setValue(false);
}
};
The saveInfo( ) method is invoked automatically when the
user removes the focus from the input text field. This technique
ensures that the schedule item's data is updated to
reflect the new entry (or entry changes). This method
doesn't do anything particularly tricky. It just
sets the appropriate schedule item property values depending on the
type of entry.
ScheduleItem.prototype.saveInfo = function ( ) {
switch(this.entryType) {
case "hourly":
if (this.scheduleInfo.text != "") {
this.hourlySchedule[this.selectedHour] = this.scheduleInfo.text;
this.times.setHasValue(this.selectedHour, true);
} else {
this.times.setHasValue(this.selectedHour, false);
}
break;
case "toDo":
this.toDo = this.scheduleInfo.text;
break;
case "notes":
this.notes = this.scheduleInfo.text;
}
};
The selectTime( ) method is invoked whenever a user
selects a time selector item. In this method, you should make sure
that if the schedule item already has an entry for the selected hour,
the text field should be populated with that data. Otherwise, remove
any text from the text field. Also, if the user has chosen to be
notified for an event stored for that hour, you should mark the
checkbox as selected. Otherwise, deselect the checkbox.
ScheduleItem.prototype.selectTime = function ( ) {
if (this.hourlySchedule[this.selectedHour] != undefined) {
this.scheduleInfo.text = this.hourlySchedule[this.selectedHour];
} else {
this.scheduleInfo.text = "";
}
if (this.notifiers[this.selectedHour] != undefined) {
this.notifyBox.notifyCheckBox.setValue(this.notifiers[this.selectedHour]);
} else {
this.notifyBox.notifyCheckBox.setValue(false);
}
};
28.2.5 Designing the NotifierDisplayer Component
The NotifierDisplayer
component is nothing more than a scrollable text field with a
rectangle background and a Close button. This simple component should
do the following:
Draw a rectangle for the background Add a text field and a scrollbar that scrolls the text field Add a button that enables the user to close the displayer
To create the NotifierDisplayer component, complete the following
steps.
The NotifierDisplayer component requires you to include the ScrollBar
and PushButton components in your movie. You should already have
included the ScrollBar component earlier, so you only need to include
the PushButton component by dragging an instance from the Components
panel to the Stage and then deleting the instance. A copy of the
symbol remains in the Library. Create a new movie clip symbol named
NotifierDisplayer. Open the linkage properties for the symbol. Select the Export for ActionScript and Export in First Frame
checkboxes. Give the symbol a linkage identifier of
NotifierDisplayerSymbol. Click OK to close the Linkage Properties dialog box. Edit the NotifierDisplayer symbol. Add the following code to the first frame of the default layer: #initclip 0
function NotifierDisplayer ( ) {
// Create a movie clip and draw a filled square in it. This serves as the
// background for the component.
this.createEmptyMovieClip("background", this.getNewDepth( ));
with (this.background) {
lineStyle(0, 0x000000, 100);
beginFill(0xFFFFFF, 100);
drawRectangle(300, 300);
endFill( );
_x = 150;
_y = 150;
}
// Create a text field in which the notifications can be displayed.
this.createTextField("notificationText", this.getNewDepth( ), 0, 0, 240, 240);
this.notificationText.border = true;
this.notificationText.background = true;
// Create a scrollbar and set its size.
this.attachMovie("FScrollBarSymbol", "sb", this.getNewDepth( ));
this.sb.setSize(this.notificationText._height);
// Create a push button that closes the notifier displayer.
this.attachMovie("FPushButtonSymbol", "closeBtn", this.getNewDepth( ));
this.closeBtn.setLabel("close");
this.closeBtn.setClickHandler("onCloseNotification", this._parent);
// Use a table to position the elements.
tr0 = new TableRow(0, new TableColumn(0, this.notificationText),
new TableColumn(0, this.sb));
tr1 = new TableRow(0, new TableColumn(0, this.closeBtn));
t = new Table(5, 30, 30, tr0, tr1);
}
// NotifierDisplayer extends MovieClip.
NotifierDisplayer.prototype = new MovieClip( );
// The display( ) method sets the notification text.
NotifierDisplayer.prototype.display = function (value) {
this.notificationText.text = value;
this.sb.setScrollTarget(this.notificationText);
};
Object.registerClass("NotifierDisplayerSymbol", NotifierDisplayer);
#endinitclip
|