blob: 6d45041c2890a94bc5a7eafcda6251b7b10830ff [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package mx.controls
{
import flash.display.DisplayObject;
import flash.events.Event;
import flash.events.FocusEvent;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.events.TextEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.ui.Keyboard;
import mx.controls.dataGridClasses.DataGridListData;
import mx.controls.listClasses.BaseListData;
import mx.controls.listClasses.IDropInListItemRenderer;
import mx.controls.listClasses.IListItemRenderer;
import mx.controls.listClasses.ListData;
import mx.core.ClassFactory;
import mx.core.IDataRenderer;
import mx.core.IFactory;
import mx.core.LayoutDirection;
import mx.core.mx_internal;
import mx.core.UIComponentGlobals;
import mx.events.CalendarLayoutChangeEvent;
import mx.events.DateChooserEvent;
import mx.events.DropdownEvent;
import mx.events.FlexEvent;
import mx.events.FlexMouseEvent;
import mx.events.InterManagerRequest;
import mx.events.SandboxMouseEvent;
import mx.managers.IFocusManagerComponent;
import mx.managers.ISystemManager;
import mx.managers.PopUpManager;
import mx.resources.ResourceManager;
import mx.styles.CSSStyleDeclaration;
import mx.styles.StyleManager;
import mx.styles.StyleProxy;
import mx.utils.ObjectUtil;
use namespace mx_internal;
//--------------------------------------
// Events
//--------------------------------------
/**
* Dispatched when a date is selected or changed,
* and the DateChooser control closes.
*
* @eventType mx.events.CalendarLayoutChangeEvent.CHANGE
* @helpid 3613
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Event(name="change", type="mx.events.CalendarLayoutChangeEvent")]
/**
* Dispatched when a date is selected or the user clicks
* outside the drop-down list.
*
* @eventType mx.events.DropdownEvent.CLOSE
* @helpid 3615
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Event(name="close", type="mx.events.DropdownEvent")]
/**
* Dispatched when the <code>data</code> property changes.
*
* <p>When you use a component as an item renderer,
* the <code>data</code> property contains the data to display.
* You can listen for this event and update the component
* when the <code>data</code> property changes.</p>
*
* @eventType mx.events.FlexEvent.DATA_CHANGE
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Event(name="dataChange", type="mx.events.FlexEvent")]
/**
* Dispatched when a user selects the field to open the drop-down list.
*
* @eventType mx.events.DropdownEvent.OPEN
* @helpid 3614
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Event(name="open", type="mx.events.DropdownEvent")]
/**
* Dispatched when the month changes due to user interaction.
*
* @eventType mx.events.DateChooserEvent.SCROLL
* @helpid 3616
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Event(name="scroll", type="mx.events.DateChooserEvent")]
//--------------------------------------
// Styles
//--------------------------------------
include "../styles/metadata/FocusStyles.as"
include "../styles/metadata/IconColorStyles.as"
include "../styles/metadata/LeadingStyle.as"
include "../styles/metadata/PaddingStyles.as"
include "../styles/metadata/TextStyles.as"
/**
* Color of the border.
* The following controls support this style: Button, CheckBox,
* ComboBox, MenuBar,
* NumericStepper, ProgressBar, RadioButton, ScrollBar, Slider, and any
* components that support the <code>borderStyle</code> style.
* The default value depends on the component class;
* if not overridden for the class, the default value is <code>0xB7BABC</code>
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="borderColor", type="uint", format="Color", inherit="no", theme="halo")]
/**
* The bounding box thickness of the DateChooser control.
* The default value is 1.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="borderThickness", type="Number", format="Length", inherit="no", theme="halo")]
/**
* Name of the CSS Style declaration to use for the styles for the
* DateChooser control's drop-down list.
* By default, the DateChooser control uses the DateField control's
* inheritable styles.
*
* <p>You can use this class selector to set the values of all the style properties
* of the DateChooser class, including <code>cornerRadius</code>,
* <code>fillAlphas</code>, <code>fillColors</code>, <code>headerColors</code>, <code>headerStyleName</code>,
* <code>highlightAlphas</code>, <code>todayStyleName</code>, and <code>weekdayStyleName</code>.</p>
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="dateChooserStyleName", type="String", inherit="no")]
/**
* Color of the highlight area of the date when the user holds the
* mouse pointer over a date in the DateChooser control.
*
* The default value for the Halo theme is <code>0xB2E1FF</code>.
* The default value for the Spark theme is <code>0xCEDBEF</code>.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="rollOverColor", type="uint", format="Color", inherit="yes")]
/**
* Color of the highlight area of the currently selected date
* in the DateChooser control.
*
* The default value for the Halo theme is <code>0x7FCEFF</code>.
* The default value for the Spark theme is <code>0xA8C6EE</code>.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="selectionColor", type="uint", format="Color", inherit="yes")]
/**
* Name of the class to use as the default skin for the background and border.
* For the DateField class, there is no default value.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="skin", type="Class", inherit="no", states=" up, over, down, disabled")]
/**
* Color of the highlight of today's date in the DateChooser control.
* The default value is <code>0x2B333</code>.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="todayColor", type="uint", format="Color", inherit="yes")]
//--------------------------------------
// Excluded APIs
//--------------------------------------
[Exclude(name="selectedIndex", kind="property")]
[Exclude(name="selectedItem", kind="property")]
[Exclude(name="borderThickness", kind="style")]
[Exclude(name="editableUpSkin", kind="style")]
[Exclude(name="editableOverSkin", kind="style")]
[Exclude(name="editableDownSkin", kind="style")]
[Exclude(name="editableDisabledSkin", kind="style")]
//--------------------------------------
// Other metadata
//--------------------------------------
[AccessibilityClass(implementation="mx.accessibility.DateFieldAccImpl")]
[DefaultBindingProperty(source="selectedDate", destination="selectedDate")]
[DefaultTriggerEvent("change")]
[IconFile("DateField.png")]
[RequiresDataBinding(true)]
[ResourceBundle("controls")]
[ResourceBundle("SharedResources")]
/**
* The DateField control is a text field that shows the date
* with a calendar icon on its right side.
* When the user clicks anywhere inside the bounding box
* of the control, a DateChooser control pops up
* and shows the dates in the month of the current date.
* If no date is selected, the text field is blank
* and the month of the current date is displayed
* in the DateChooser control.
*
* <p>When the DateChooser control is open, the user can scroll
* through months and years, and select a date.
* When a date is selected, the DateChooser control closes,
* and the text field shows the selected date.</p>
*
* <p>The user can also type the date in the text field if the <code>editable</code>
* property of the DateField control is set to <code>true</code>.</p>
*
* <p>The DateField has the same default characteristics (shown below) as the DateChooser for its expanded date chooser.</p>
* <table class="innertable">
* <tr>
* <th>Characteristic</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>Default size</td>
* <td>A size large enough to hold the calendar, and wide enough to display the day names</td>
* </tr>
* <tr>
* <td>Minimum size</td>
* <td>0 pixels</td>
* </tr>
* <tr>
* <td>Maximum size</td>
* <td>No limit</td>
* </tr>
* </table>
*
* <p>The DateField has the following default characteristics for the collapsed control:</p>
* <table class="innertable">
* <tr>
* <th>Characteristic</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>Default size</td>
* <td>A size large enough to hold the formatted date and the calendar icon</td>
* </tr>
* <tr>
* <td>Minimum size</td>
* <td>0 pixels</td>
* </tr>
* <tr>
* <td>Maximum size</td>
* <td>No limit</td>
* </tr>
* </table>
*
* @mxml
*
* <p>The <code>&lt;mx:DateField&gt</code> tag inherits all of the tag attributes
* of its superclass, and adds the following tag attributes:</p>
*
* <pre>
* &lt;mx:DateField
* <strong>Properties</strong>
* dayNames="["S", "M", "T", "W", "T", "F", "S"]"
* disabledDays="<i>No default</i>"
* disabledRanges="<i>No default</i>"
* displayedMonth="<i>Current month</i>"
* displayedYear="<i>Current year</i>"
* dropdownFactory="<i>ClassFactory that creates an mx.controls.DateChooser</i>"
* firstDayOfWeek="0"
* formatString="MM/DD/YYYY"
* labelFunction="<i>Internal formatter</i>"
* maxYear="2100"
* minYear="1900"
* monthNames="["January", "February", "March", "April", "May",
* "June", "July", "August", "September", "October", "November",
* "December"]"
* monthSymbol=""
* parseFunction="<i>Internal parser</i>"
* selectableRange="<i>No default</i>"
* selectedDate="<i>No default</i>"
* showToday="true|false"
* yearNavigationEnabled="false|true"
* yearSymbol=""
*
* <strong>Styles</strong>
* borderColor="0xAAB3B3"
* borderThickness="1"
* color="0x0xB333C"
* dateChooserStyleName="dateFieldPopup"
* disabledColor="0xAAB3B3"
* disabledIconColor="0x999999"
* focusAlpha="0.5"
* focusRoundedCorners="tl tr bl br"
* fontAntiAliasType="advanced"
* fontFamily="Verdana"
* fontGridFitType="pixel"
* fontSharpness="0"
* fontSize="10"
* fontStyle="normal|italic"
* fontThickness="0"
* fontWeight="normal|bold"
* iconColor="0x111111"
* leading="2"
* paddingLeft="0"
* paddingRight="0"
* rollOverColor="0xE3FFD6"
* selectionColor="0xB7F39B"
* textAlign="left|right|center"
* textDecoration="none|underline"
* textIndent="0"
* todayColor="0x2B333C"
*
* <strong>Events</strong>
* change="<i>No default</i>"
* close="<i>No default</i>"
* dataChange="<i>No default</i>"
* open="<i>No default</i>"
* scroll="<i>No default</i>"
* /&gt;
* </pre>
*
* @see mx.controls.DateChooser
* @includeExample examples/DateFieldExample.mxml
*
* @helpid 3617
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public class DateField extends ComboBase
implements IDataRenderer, IDropInListItemRenderer,
IFocusManagerComponent, IListItemRenderer
{
include "../core/Version.as";
//--------------------------------------------------------------------------
//
// Class mixins
//
//--------------------------------------------------------------------------
/**
* @private
* Placeholder for mixin by DateFieldAccImpl.
*/
mx_internal static var createAccessibilityImplementation:Function;
//--------------------------------------------------------------------------
//
// Class methods
//
//--------------------------------------------------------------------------
/**
* Parses a String object that contains a date, and returns a Date
* object corresponding to the String.
* The <code>inputFormat</code> argument contains the pattern
* in which the <code>valueString</code> String is formatted.
* It can contain <code>"M"</code>, <code>"MM"</code>,
* <code>"MMM"</code> (3 letter month names), <code>"MMMM"</code> (month names),
* <code>"D"</code>, <code>"DD"</code>, <code>"YY"</code>, <code>"YYYY"</code>
* and delimiter and punctuation characters.
*
* <p>Only upper case characters are supported.</p>
*
* <p>The function does not check for the validity of the Date object.
* If the value of the date, month, or year is NaN, this method returns null.</p>
*
* <p>For example:
* <pre>var dob:Date = DateField.stringToDate("06/30/2005", "MM/DD/YYYY");</pre>
* </p>
*
* @param valueString Date value to format.
*
* @param inputFormat String defining the date format.
*
* @return The formatted date as a Date object.
*
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public static function stringToDate(valueString:String, inputFormat:String):Date
{
var maskChar:String
var dateChar:String;
var dateString:String;
var monthString:String;
var yearString:String;
var dateParts:Array = [];
var maskParts:Array = [];
var part:int = 0;
var length:int;
var position:int = 0;
if (valueString == null || inputFormat == null)
return null;
var monthNames:Array = ResourceManager.getInstance()
.getStringArray("SharedResources", "monthNames");
var noMonths:int = monthNames.length;
for (var i:int = 0; i < noMonths; i++) {
valueString = valueString.replace(monthNames[i], (i+1).toString());
valueString = valueString.replace(monthNames[i].substr(0,3), (i+1).toString());
}
length = valueString.length;
dateParts[part] = "";
for (i = 0; i < length; i++)
{
dateChar = valueString.charAt(i);
if (isNaN(Number(dateChar)) || dateChar == " ")
{
part++;
dateParts[part] = dateChar;
part++;
dateParts[part] = "";
}
else
{
dateParts[part] += dateChar;
}
}
length = inputFormat.length;
part = -1;
var lastChar:String;
for (i = 0; i < length; i++)
{
maskChar = inputFormat.charAt(i);
if (maskChar == "Y" || maskChar == "M" || maskChar == "D")
{
if (maskChar != lastChar)
{
part++;
maskParts[part] = "";
}
maskParts[part] += maskChar;
}
else
{
part++;
maskParts[part] = maskChar;
}
lastChar = maskChar;
}
length = maskParts.length;
if (dateParts.length != length)
{
if (valueString.length != inputFormat.length) {
return null;
}
for (i = 0; i < length; i++) {
dateParts[i] = valueString.substr(position, maskParts[i].length);
position += maskParts[i].length;
}
}
if (dateParts.length != length)
{
return null;
}
for (i = 0; i < length; i++) {
maskChar = maskParts[i].charAt(0);
if (maskChar == "D") {
dateString = dateParts[i];
}
else if (maskChar == "M") {
monthString = dateParts[i];
}
else if (maskChar == "Y") {
yearString = dateParts[i];
}
}
if (dateString == null || monthString == null || yearString == null)
return null;
var dayNum:Number = Number(dateString);
var monthNum:Number = Number(monthString);
var yearNum:Number = Number(yearString);
if (isNaN(yearNum) || isNaN(monthNum) || isNaN(dayNum))
return null;
if (yearString.length == 2)
yearNum += 2000;
var newDate:Date = new Date(yearNum, monthNum - 1, dayNum);
if (dayNum != newDate.getDate() || (monthNum - 1) != newDate.getMonth())
return null;
return newDate;
}
/**
* Formats a Date into a String according to the <code>outputFormat</code> argument.
* The <code>outputFormat</code> argument contains a pattern in which
* the <code>value</code> String is formatted.
* It can contain <code>"M"</code>, <code>"MM"</code>,
* <code>"MMM"</code> (3 letter month names), <code>"MMMM"</code> (month names),
* <code>"D"</code>, <code>"DD"</code>, <code>"YY"</code>, <code>"YYYY"</code>
* and delimiter and punctuation characters.
*
* <p>Only upper case characters are supported.</p>
*
* @param value Date value to format.
*
* @param outputFormat String defining the date format.
*
* @return The formatted date as a String.
*
* @example <pre>var todaysDate:String = DateField.dateToString(new Date(), "MM/DD/YYYY");</pre>
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public static function dateToString(value:Date, outputFormat:String):String
{
var maskChar:String;
var maskParts:Array = [];
var part:int = -1;
var length:int;
var lastChar:String;
if (!value || isNaN(value.getTime()) || !outputFormat)
return "";
length = outputFormat.length;
for (var i:int = 0; i < length; i++)
{
maskChar = outputFormat.charAt(i);
if (maskChar == "Y" || maskChar == "M" || maskChar == "D")
{
if (maskChar != lastChar)
{
part++;
maskParts[part] = "";
}
maskParts[part] += maskChar;
}
else
{
part++;
maskParts[part] = maskChar;
}
lastChar = maskChar;
}
var date:String = String(value.getDate());
var month:String = String(value.getMonth() + 1);
var year:String = String(value.getFullYear());
var mask:String;
var fullMask:String;
var maskLength:int
var output:String = "";
//TODO Support changing locale at runtime
var monthNames:Array =
ResourceManager.getInstance().getStringArray(
"SharedResources", "monthNames");
length = maskParts.length;
for (i = 0; i < length; i++)
{
fullMask = maskParts[i];
mask = fullMask.charAt(0);
maskLength = maskParts[i].length;
if (mask == "D")
{
if (maskLength > 1 && date.length == 1)
date = "0" + date;
output += date;
}
else if (fullMask == "MMM")
{
output += monthNames[value.getMonth()].substr(0,3);
}
else if (fullMask == "MMMM")
{
output += monthNames[value.getMonth()];
}
else if (mask == "M")
{
if (maskLength > 1 && month.length == 1)
month = "0" + month;
output += month;
}
else if (mask == "Y")
{
if (maskLength == 2)
output += year.substr(2,2);
else
output += year;
}
else
{
output += mask;
}
}
return output;
}
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function DateField()
{
super();
addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
*/
private var creatingDropdown:Boolean = false;
/**
* @private
*/
mx_internal var showingDropdown:Boolean = false;
/**
* @private
*/
private var inKeyDown:Boolean = false;
/**
* @private
*/
private var isPressed:Boolean;
/**
* @private
*/
private var openPos:Number = 0;
/**
* @private
*/
private var lastSelectedDate:Date;
/**
* @private
*/
private var updateDateFiller:Boolean = false;
/**
* @private
*/
private var addedToPopupManager:Boolean = false;
/**
* @private
*/
private var isMouseOver:Boolean = false;
/**
* @private
*/
private var yearChangedWithKeys:Boolean = false;
/**
* @private
* Flag that will block default data/listData behavior
*/
private var selectedDateSet:Boolean;
//--------------------------------------------------------------------------
//
// Overridden properties
//
//--------------------------------------------------------------------------
//----------------------------------
// enabled
//----------------------------------
/**
* @private
* Storage for the enabled property.
*/
private var _enabled:Boolean = true;
/**
* @private
*/
private var enabledChanged:Boolean = false;
[Bindable("enabledChanged")]
[Inspectable(category="General", enumeration="true,false", defaultValue="true")]
/**
* @private
*/
override public function get enabled():Boolean
{
return _enabled;
}
/**
* @private
*/
override public function set enabled(value:Boolean):void
{
if (value == _enabled)
return;
_enabled = value;
super.enabled = value;
enabledChanged = true;
invalidateProperties();
}
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// data
//----------------------------------
/**
* @private
* Storage for the data property
*/
private var _data:Object;
[Bindable("dataChange")]
[Inspectable(environment="none")]
/**
* The <code>data</code> property lets you pass a value
* to the component when you use it in an item renderer or item editor.
* You typically use data binding to bind a field of the <code>data</code>
* property to a property of this component.
*
* <p>When you use the control as a drop-in item renderer or drop-in
* item editor, Flex automatically writes the current value of the item
* to the <code>selectedDate</code> property of this control.</p>
*
* @default null
* @see mx.core.IDataRenderer
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get data():Object
{
return _data;
}
/**
* @private
*/
public function set data(value:Object):void
{
var newDate:Date;
_data = value;
if (_listData && _listData is DataGridListData)
newDate = _data[DataGridListData(_listData).dataField];
else if (_listData is ListData && ListData(_listData).labelField in _data)
newDate = _data[ListData(_listData).labelField];
else if (_data is String)
if (_parseFunction != null)
newDate = _parseFunction(data as String, formatString);
else
newDate = new Date(Date.parse(data as String));
else
newDate = _data as Date;
if (!selectedDateSet)
{
selectedDate = newDate;
selectedDateSet = false;
}
dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
}
//----------------------------------
// dayNames
//----------------------------------
/**
* @private
* Storage for the dayNames property.
*/
private var _dayNames:Array;
/**
* @private
*/
private var dayNamesChanged:Boolean = false;
/**
* @private
*/
private var dayNamesOverride:Array;
[Bindable("dayNamesChanged")]
[Inspectable(arrayType="String", defaultValue="null")]
/**
* Weekday names for DateChooser control.
* Setting this property changes the day labels
* of the DateChooser control.
* Sunday is the first day (at index 0).
* The rest of the week names follow in the normal order.
*
* @default [ "S", "M", "T", "W", "T", "F", "S" ]
* @helpid 3626
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get dayNames():Array
{
return _dayNames;
}
/**
* @private
*/
public function set dayNames(value:Array):void
{
dayNamesOverride = value;
_dayNames = value != null ?
value :
resourceManager.getStringArray(
"controls", "dayNamesShortest");
// _dayNames will be null if there are no resources.
_dayNames = _dayNames ? _dayNames.slice(0) : null;
dayNamesChanged = true;
invalidateProperties();
}
//----------------------------------
// disabledDays
//----------------------------------
/**
* @private
* Storage for the disabledDays property.
*/
private var _disabledDays:Array = [];
/**
* @private
*/
private var disabledDaysChanged:Boolean = false;
[Bindable("disabledDaysChanged")]
[Inspectable(arrayType="int")]
/**
* Days to disable in a week.
* All the dates in a month, for the specified day, are disabled.
* This property immediately changes the user interface
* of the DateChooser control.
* The elements of this Array can have values from 0 (Sunday)
* to 6 (Saturday).
* For example, a value of <code>[0, 6]</code> disables
* Sunday and Saturday.
*
* @default []
* @helpid 3627
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get disabledDays():Array
{
return _disabledDays;
}
/**
* @private
*/
public function set disabledDays(value:Array):void
{
_disabledDays = value;
disabledDaysChanged = true;
updateDateFiller = true;
invalidateProperties();
}
//----------------------------------
// disabledRanges
//----------------------------------
/**
* @private
* Storage for the disabledRanges property.
*/
private var _disabledRanges:Array = [];
/**
* @private
*/
private var disabledRangesChanged:Boolean = false;
[Bindable("disabledRangesChanged")]
[Inspectable(arrayType="Object")]
/**
* Disables single and multiple days.
*
* <p>This property accepts an Array of objects as a parameter.
* Each object in this Array is a Date object that specifies a
* single day to disable; or an object containing one or both
* of the <code>rangeStart</code> and <code>rangeEnd</code> properties,
* each of whose values is a Date object.
* The value of these properties describes the boundaries
* of the date range.
* If either is omitted, the range is considered
* unbounded in that direction.
* If you specify only <code>rangeStart</code>,
* all the dates after the specified date are disabled,
* including the <code>rangeStart</code> date.
* If you specify only <code>rangeEnd</code>,
* all the dates before the specified date are disabled,
* including the <code>rangeEnd</code> date.
* To disable a single day, use a single Date object that specifies a date
* in the Array. Time values are zeroed out from the Date object if
* they are present.</p>
*
* <p>The following example, disables the following dates: January 11
* 2006, the range January 23 - February 10 2006, and March 1 2006
* and all following dates.</p>
*
* <pre>disabledRanges="{[new Date(2006,0,11), {rangeStart:
* new Date(2006,0,23), rangeEnd: new Date(2006,1,10)},
* {rangeStart: new Date(2006,2,1)}]}"</pre>
*
* <p>Setting this property immediately changes the appearance of the
* DateChooser control, if the disabled dates are included in the
* <code>displayedMonth</code> and <code>displayedYear</code>
* properties.</p>
*
* @default []
* @helpid 3629
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get disabledRanges():Array
{
return _disabledRanges;
}
/**
* @private
*/
public function set disabledRanges(value:Array):void
{
_disabledRanges = scrubTimeValues(value);
disabledRangesChanged = true;
updateDateFiller = true;
invalidateProperties();
}
//----------------------------------
// displayedMonth
//----------------------------------
/**
* @private
* Storage for the displayedMonth property.
*/
private var _displayedMonth:int = (new Date()).getMonth();
/**
* @private
*/
private var displayedMonthChanged:Boolean = false;
[Bindable("displayedMonthChanged")]
[Inspectable(category="General")]
/**
* Used with the <code>displayedYear</code> property,
* the <code>displayedMonth</code> property
* specifies the month displayed in the DateChooser control.
* Month numbers are zero-based, so January is 0 and December is 11.
* Setting this property immediately changes the appearance
* of the DateChooser control.
* The default value is the month number of today's date.
*
* <p>The default value is the current month.</p>
*
* @helpid 3624
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get displayedMonth():int
{
if (dropdown && dropdown.displayedMonth != _displayedMonth)
return dropdown.displayedMonth;
else
return _displayedMonth;
}
/**
* @private
*/
public function set displayedMonth(value:int):void
{
_displayedMonth = value;
displayedMonthChanged = true;
invalidateProperties();
}
//----------------------------------
// displayedYear
//----------------------------------
/**
* @private
* Storage for the displayedYear property.
*/
private var _displayedYear:int = (new Date()).getFullYear();
/**
* @private
*/
private var displayedYearChanged:Boolean = false;
[Bindable("displayedYearChanged")]
[Inspectable(category="General")]
/**
* Used with the <code>displayedMonth</code> property,
* the <code>displayedYear</code> property determines
* which year is displayed in the DateChooser control.
* Setting this property immediately changes the appearance
* of the DateChooser control.
*
* <p>The default value is the current year.</p>
*
* @helpid 3625
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get displayedYear():int
{
if (dropdown && dropdown.displayedYear != _displayedYear)
return dropdown.displayedYear;
else
return _displayedYear;
}
/**
* @private
*/
public function set displayedYear(value:int):void
{
_displayedYear = value;
displayedYearChanged = true;
invalidateProperties();
}
//----------------------------------
// dropdown
//----------------------------------
/**
* @private
* Storage for the dropdown property.
*/
private var _dropdown:DateChooser;
/**
* Contains a reference to the DateChooser control
* contained by the DateField control. The class used
* can be set with <code>dropdownFactory</code> as long as
* it extends <code>DateChooser</code>.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get dropdown():DateChooser
{
return _dropdown;
}
//----------------------------------
// dropdownFactory
//----------------------------------
/**
* @private
* Storage for the dropdownFactory property.
*/
private var _dropdownFactory:IFactory = new ClassFactory(DateChooser);
[Bindable("dropdownFactoryChanged")]
/**
* The IFactory that creates a DateChooser-derived instance to use
* as the date-chooser
* The default value is an IFactory for DateChooser
*
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get dropdownFactory():IFactory
{
return _dropdownFactory;
}
/**
* @private
*/
public function set dropdownFactory(value:IFactory):void
{
_dropdownFactory = value;
dispatchEvent(new Event("dropdownFactoryChanged"));
}
//----------------------------------
// firstDayOfWeek
//----------------------------------
/**
* @private
* Storage for the firstDayOfWeek property.
*/
private var _firstDayOfWeek:Object
/**
* @private
*/
private var firstDayOfWeekChanged:Boolean = false;
[Bindable("firstDayOfWeekChanged")]
[Inspectable(defaultValue="0")]
/**
* @private
*/
private var firstDayOfWeekOverride:Object;
/**
* Day of the week (0-6, where 0 is the first element
* of the dayNames Array) to display in the first column
* of the DateChooser control.
* Setting this property changes the order of the day columns.
*
* @default 0 (Sunday)
* @helpid 3623
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get firstDayOfWeek():Object
{
return _firstDayOfWeek;
}
/**
* @private
*/
public function set firstDayOfWeek(value:Object):void
{
firstDayOfWeekOverride = value;
_firstDayOfWeek = value != null ?
int(value) :
resourceManager.getInt(
"controls", "firstDayOfWeek");
firstDayOfWeekChanged = true;
invalidateProperties();
}
//----------------------------------
// formatString
//----------------------------------
/**
* @private
* Storage for the formatString property.
*/
private var _formatString:String = null;
[Bindable("formatStringChanged")]
[Inspectable(defaultValue="null")]
/**
* @private
*/
private var formatStringOverride:String;
/**
* The format of the displayed date in the text field.
* This property can contain any combination of <code>"M"</code>,
* <code>"MM"</code>, <code>"MMM"</code> (3 letter month names),
* <code>"MMMM"</code> (month names), <code>"D"</code>, <code>"DD"</code>,
* <code>"YY"</code>, <code>"YYYY"</code>,
* delimiter, and punctuation characters.
*
* <p>Only upper case characters are supported.</p>
*
* @default "MM/DD/YYYY"
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get formatString():String
{
return _formatString;
}
/**
* @private
*/
public function set formatString(value:String):void
{
formatStringOverride = value;
_formatString = value != null ?
value :
resourceManager.getString(
"SharedResources", "dateFormat");
updateDateFiller = true;
invalidateProperties();
invalidateSize();
dispatchEvent(new Event("formatStringChanged"));
}
//----------------------------------
// labelFunction
//----------------------------------
/**
* @private
* Storage for the labelFunction property.
*/
private var _labelFunction:Function;
[Bindable("labelFunctionChanged")]
[Inspectable(category="Data")]
/**
* Function used to format the date displayed
* in the text field of the DateField control.
* If no function is specified, the default format is used.
*
* <p>The function takes a Date object as an argument,
* and returns a String in the format to be displayed,
* as the following example shows:</p>
* <pre>
* public function formatDate(currentDate:Date):String {
* ...
* return dateString;
* }</pre>
*
* <p>If you allow the user to enter a date in the text field
* of the DateField control, and you define a formatting function using
* the <code>labelFunction</code> property, you should specify a
* function to the <code>parseFunction</code> property that converts
* the input text string to a Date object for use by the DateField control,
* or set the <code>parseFunction</code> property to null.</p>
*
* @default null
* @see mx.controls.DateField#parseFunction
* @helpid 3618
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get labelFunction():Function
{
return _labelFunction;
}
/**
* @private
*/
public function set labelFunction(value:Function):void
{
_labelFunction = value;
updateDateFiller = true;
invalidateProperties();
dispatchEvent(new Event("labelFunctionChanged"));
}
//----------------------------------
// listData
//----------------------------------
/**
* @private
* Storage for the listData property
*/
private var _listData:BaseListData;
[Bindable("dataChange")]
[Inspectable(environment="none")]
/**
* When a component is used as a drop-in item renderer or drop-in
* item editor, Flex initializes the <code>listData</code> property
* of the component with the appropriate data from the List control.
* The component can then use the <code>listData</code> property
* to initialize the <code>data</code> property of the drop-in
* item renderer or drop-in item editor.
*
* <p>You do not set this property in MXML or ActionScript;
* Flex sets it when the component is used as a drop-in item renderer
* or drop-in item editor.</p>
*
* @default null
* @see mx.controls.listClasses.IDropInListItemRenderer
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get listData():BaseListData
{
return _listData;
}
/**
* @private
*/
public function set listData(value:BaseListData):void
{
_listData = value;
}
//----------------------------------
// maxYear
//----------------------------------
/**
* @private
* Storage for the maxYear property.
*/
private var _maxYear:int = 2100;
/**
* @private
*/
private var maxYearChanged:Boolean = false;
/**
* The last year selectable in the control.
* @default 2100
*
* @helpid
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get maxYear():int
{
if (dropdown)
return dropdown.maxYear;
else
return _maxYear;
}
/**
* @private
*/
public function set maxYear(value:int):void
{
if (_maxYear == value)
return;
_maxYear = value;
maxYearChanged = true;
invalidateProperties();
}
//----------------------------------
// minYear
//----------------------------------
/**
* @private
* Storage for the minYear property.
*/
private var _minYear:int = 1900;
/**
* @private
*/
private var minYearChanged:Boolean = false;
/**
* The first year selectable in the control.
* @default 1900
*
* @helpid
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get minYear():int
{
if (dropdown)
return dropdown.minYear;
else
return _minYear;
}
/**
* @private
*/
public function set minYear(value:int):void
{
if (_displayedYear == value)
return;
_minYear = value;
minYearChanged = true;
invalidateProperties();
}
//----------------------------------
// monthNames
//----------------------------------
/**
* @private
* Storage for the monthNames property.
*/
private var _monthNames:Array;
/**
* @private
*/
private var monthNamesChanged:Boolean = false;
/**
* @private
*/
private var monthNamesOverride:Array;
[Bindable("monthNamesChanged")]
[Inspectable(category="Other", arrayType="String", defaultValue="null")]
/**
* Names of the months displayed at the top of the control.
* The <code>monthSymbol</code> property is appended to the end of
* the value specified by the <code>monthNames</code> property,
* which is useful in languages such as Japanese.
*
* @default [ "January", "February", "March", "April", "May", "June",
* "July", "August", "September", "October", "November", "December" ]
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get monthNames():Array
{
return _monthNames;
}
/**
* @private
*/
public function set monthNames(value:Array):void
{
monthNamesOverride = value;
_monthNames = value != null ?
value :
resourceManager.getStringArray(
"SharedResources", "monthNames");
// _monthNames will be null if there are no resources.
_monthNames = _monthNames ? _monthNames.slice(0) : null;
monthNamesChanged = true;
invalidateProperties();
}
//----------------------------------
// monthSymbol
//----------------------------------
/**
* @private
* Storage for the monthSymbol property.
*/
private var _monthSymbol:String;
/**
* @private
*/
private var monthSymbolChanged:Boolean = false;
/**
* @private
*/
private var monthSymbolOverride:String;
[Bindable("monthSymbolChanged")]
[Inspectable(defaultValue="")]
/**
* This property is appended to the end of the value specified
* by the <code>monthNames</code> property to define the names
* of the months displayed at the top of the control.
* Some languages, such as Japanese, use an extra
* symbol after the month name.
*
* @default ""
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get monthSymbol():String
{
return _monthSymbol;
}
/**
* @private
*/
public function set monthSymbol(value:String):void
{
monthSymbolOverride = value;
_monthSymbol = value != null ?
value :
resourceManager.getString(
"SharedResources", "monthSymbol");
monthSymbolChanged = true;
invalidateProperties();
}
//----------------------------------
// parseFunction
//----------------------------------
/**
* @private
* Storage for the parseFunction property.
*/
private var _parseFunction:Function = DateField.stringToDate;
[Bindable("parseFunctionChanged")]
/**
* Function used to parse the date entered as text
* in the text field area of the DateField control and return a
* Date object to the control.
* If no function is specified, Flex uses
* the default function.
* If you set the <code>parseFunction</code> property, it should
* typically perform the reverse of the function specified to
* the <code>labelFunction</code> property.
*
* <p>The function takes two arguments
* and returns a Date object to the DateField control,
* as the following example shows:</p>
* <pre>
* public function parseDate(valueString:String, inputFormat:String):Date {
* ...
* return newDate
* }</pre>
*
* <p>Where the <code>valueString</code> argument contains the text
* string entered by the user in the text field, and the <code>inputFormat</code>
* argument contains the format of the string. For example, if you
* only allow the user to enter a text sting using two characters for
* month, day, and year, then pass "MM/DD/YY" to
* the <code>inputFormat</code> argument.</p>
*
* @see mx.controls.DateField#labelFunction
*
* @helpid
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get parseFunction():Function
{
return _parseFunction;
}
/**
* @private
*/
public function set parseFunction(value:Function):void
{
_parseFunction = value;
dispatchEvent(new Event("parseFunctionChanged"));
}
//----------------------------------
// selectableRange
//----------------------------------
/**
* @private
* Storage for the selectableRange property.
*/
private var _selectableRange:Object = null;
/**
* @private
*/
private var selectableRangeChanged:Boolean = false;
[Bindable("selectableRangeChanged")]
[Inspectable(arrayType="Date")]
/**
* Range of dates between which dates are selectable.
* For example, a date between 04-12-2006 and 04-12-2007
* is selectable, but dates out of this range are disabled.
*
* <p>This property accepts an Object as a parameter.
* The Object contains two properties, <code>rangeStart</code>
* and <code>rangeEnd</code>, of type Date.
* If you specify only <code>rangeStart</code>,
* all the dates after the specified date are enabled.
* If you only specify <code>rangeEnd</code>,
* all the dates before the specified date are enabled.
* To enable only a single day in a DateChooser control,
* you can pass a Date object directly. Time values are
* zeroed out from the Date object if they are present.</p>
*
* <p>The following example enables only the range
* January 1, 2006 through June 30, 2006. Months before January
* and after June do not appear in the DateChooser.</p>
*
* <pre>selectableRange="{{rangeStart : new Date(2006,0,1),
* rangeEnd : new Date(2006,5,30)}}"</pre>
*
* @default null
* @helpid 3628
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get selectableRange():Object
{
return _selectableRange;
}
/**
* @private
*/
public function set selectableRange(value:Object):void
{
_selectableRange = scrubTimeValue(value);
selectableRangeChanged = true;
updateDateFiller = true;
invalidateProperties();
}
//----------------------------------
// selectedDate
//----------------------------------
/**
* @private
* Storage for the selectedDate property.
*/
private var _selectedDate:Date = null;
/**
* @private
*/
private var selectedDateChanged:Boolean = false;
[Bindable("change")]
[Bindable("valueCommit")]
[Bindable("selectedDateChanged")]
[Inspectable(category="General")]
/**
* Date as selected in the DateChooser control.
* Accepts a Date object as a parameter. If the incoming Date
* object has any time values, they are zeroed out.
*
* <p>Holding down the Control key when selecting the currently selected date deselects it,
* sets the <code>selectedDate</code> property to <code>null</code>,
* and then dispatches the <code>change</code> event.</p>
*
* @default null
* @helpid 3630
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get selectedDate():Date
{
return _selectedDate;
}
/**
* @private
*/
public function set selectedDate(value:Date):void
{
if (ObjectUtil.dateCompare(_selectedDate, value) == 0)
return;
selectedDateSet = true;
checkYearSetSelectedDate(scrubTimeValue(value) as Date);
updateDateFiller = true;
selectedDateChanged = true;
invalidateProperties();
// Trigger bindings to 'selectedData'.
dispatchEvent(new Event("selectedDateChanged"));
dispatchEvent(new FlexEvent(FlexEvent.VALUE_COMMIT));
}
//----------------------------------
// showToday
//----------------------------------
/**
* @private
* Storage for the showToday property.
*/
private var _showToday:Boolean = true;
/**
* @private
*/
private var showTodayChanged:Boolean = false;
[Bindable("showTodayChanged")]
[Inspectable(category="General", defaultValue="true")]
/**
* If <code>true</code>, specifies that today is highlighted
* in the DateChooser control.
* Setting this property immediately changes the appearance
* of the DateChooser control.
*
* @default true
* @helpid 3622
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get showToday():Boolean
{
return _showToday;
}
/**
* @private
*/
public function set showToday(value:Boolean):void
{
_showToday = value;
showTodayChanged = true;
invalidateProperties();
}
//----------------------------------
// yearNavigationEnabled
//----------------------------------
/**
* @private
* Storage for the yearNavigationEnabled property.
*/
private var _yearNavigationEnabled:Boolean = false;
/**
* @private
*/
private var yearNavigationEnabledChanged:Boolean = false;
[Bindable("yearNavigationEnabledChanged")]
[Inspectable(defaultValue="false")]
/**
* Enables year navigation. When <code>true</code>
* an up and down button appear to the right
* of the displayed year. You can use these buttons
* to change the current year.
* These button appear to the left of the year in locales where year comes
* before the month in the date format.
*
* @default false
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get yearNavigationEnabled():Boolean
{
return _yearNavigationEnabled;
}
/**
* @private
*/
public function set yearNavigationEnabled(value:Boolean):void
{
_yearNavigationEnabled = value;
yearNavigationEnabledChanged = true;
invalidateProperties();
}
//----------------------------------
// yearSymbol
//----------------------------------
/**
* @private
* Storage for the yearSymbol property.
*/
private var _yearSymbol:String;
/**
* @private
*/
private var yearSymbolChanged:Boolean = false;
/**
* @private
*/
private var yearSymbolOverride:String;
[Bindable("yearSymbolChanged")]
[Inspectable(defaultValue="")]
/**
* This property is appended to the end of the year
* displayed at the top of the control.
* Some languages, such as Japanese,
* add a symbol after the year.
*
* @default ""
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get yearSymbol():String
{
return _yearSymbol;
}
/**
* @private
*/
public function set yearSymbol(value:String):void
{
yearSymbolOverride = value;
_yearSymbol = value != null ?
value :
resourceManager.getString(
"controls", "yearSymbol");
yearSymbolChanged = true;
invalidateProperties();
}
//--------------------------------------------------------------------------
//
// Overridden methods: UIComponent
//
//--------------------------------------------------------------------------
/**
* @private
*/
override protected function initializeAccessibility():void
{
if (DateField.createAccessibilityImplementation != null)
DateField.createAccessibilityImplementation(this);
}
/**
* @private
* Create subobjects in the component.
*/
override protected function createChildren():void
{
super.createChildren();
createDropdown();
downArrowButton.setStyle("paddingLeft", 0);
downArrowButton.setStyle("paddingRight", 0);
textInput.editable = false;
textInput.mouseChildren = true;
textInput.mouseEnabled = true;
textInput.addEventListener(TextEvent.TEXT_INPUT, textInput_textInputHandler);
// hide the border, we use the text input's border
if (border)
border.visible = false;
}
/**
* @private
*/
override protected function commitProperties():void
{
if (enabledChanged)
{
enabledChanged = false;
dispatchEvent(new Event("enabledChanged"));
}
if (dayNamesChanged)
{
dayNamesChanged = false;
// _dayNames will be null if there are no resources.
dropdown.dayNames = _dayNames ? _dayNames.slice(0) : null;
dispatchEvent(new Event("dayNamesChanged"));
}
if (disabledDaysChanged)
{
disabledDaysChanged = false;
dropdown.disabledDays = _disabledDays.slice(0);
dispatchEvent(new Event("disabledDaysChanged"));
}
if (disabledRangesChanged)
{
disabledRangesChanged = false;
dropdown.disabledRanges = _disabledRanges.slice(0);
dispatchEvent(new Event("disabledRangesChanged"));
}
if (displayedMonthChanged)
{
displayedMonthChanged = false;
dropdown.displayedMonth = _displayedMonth;
dispatchEvent(new Event("displayedMonthChanged"));
}
if (displayedYearChanged)
{
displayedYearChanged = false;
dropdown.displayedYear = _displayedYear;
dispatchEvent(new Event("displayedYearChanged"));
}
if (firstDayOfWeekChanged)
{
firstDayOfWeekChanged = false;
dropdown.firstDayOfWeek = _firstDayOfWeek;
dispatchEvent(new Event("firstDayOfWeekChanged"));
}
if (minYearChanged)
{
minYearChanged = false;
dropdown.minYear = _minYear;
}
if (maxYearChanged)
{
maxYearChanged = false;
dropdown.maxYear = _maxYear;
}
if (monthNamesChanged)
{
monthNamesChanged = false;
// _monthNames will be null if there are no resources.
dropdown.monthNames = _monthNames ? _monthNames.slice(0) : null;
dispatchEvent(new Event("monthNamesChanged"));
}
if (selectableRangeChanged)
{
selectableRangeChanged = false;
dropdown.selectableRange = _selectableRange is Array ? _selectableRange.slice(0) : _selectableRange;
dispatchEvent(new Event("selectableRangeChanged"));
}
if (selectedDateChanged)
{
selectedDateChanged = false;
dropdown.selectedDate = _selectedDate;
}
if (showTodayChanged)
{
showTodayChanged = false;
dropdown.showToday = _showToday;
dispatchEvent(new Event("showTodayChanged"));
}
if (updateDateFiller)
{
updateDateFiller = false;
dateFiller(_selectedDate);
}
if (yearNavigationEnabledChanged)
{
yearNavigationEnabledChanged = false;
dropdown.yearNavigationEnabled = _yearNavigationEnabled;
dispatchEvent(new Event("yearNavigationEnabledChanged"));
}
if (yearSymbolChanged)
{
yearSymbolChanged = false;
dropdown.yearSymbol = _yearSymbol;
dispatchEvent(new Event("yearSymbolChanged"));
}
if (monthSymbolChanged)
{
monthSymbolChanged = false;
dropdown.monthSymbol = _monthSymbol;
dispatchEvent(new Event("monthSymbolChanged"));
}
super.commitProperties();
}
/**
* @private
*/
override protected function measure():void
{
// skip base class, we do our own calculation here
// super.measure();
var buttonWidth:Number = downArrowButton.getExplicitOrMeasuredWidth();
var buttonHeight:Number = downArrowButton.getExplicitOrMeasuredHeight();
var bigDate:Date;
var txt:String;
var textWidth:Number;
var maxWidth:Number = 0;
// Width may vary based on date format
for (var month:int = 0; month < 12; month++) {
bigDate = new Date(2000, month, 28); // day 28 exist in all months
txt = (_labelFunction != null) ? _labelFunction(bigDate) : dateToString(bigDate, formatString);
textWidth = measureText(txt).width;
if (textWidth > maxWidth) {
maxWidth = textWidth;
}
}
measuredMinWidth = measuredWidth = maxWidth + 8 + buttonWidth +
+ getStyle("paddingLeft") + getStyle("paddingRight")
+ textInput.getStyle("paddingLeft") + textInput.getStyle("paddingRight");
measuredMinHeight = measuredHeight = textInput.getExplicitOrMeasuredHeight();
}
/**
* @private
*/
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
var w:Number = unscaledWidth;
var h:Number = unscaledHeight;
var arrowWidth:Number = downArrowButton.getExplicitOrMeasuredWidth();
var arrowHeight:Number = downArrowButton.getExplicitOrMeasuredHeight();
downArrowButton.setActualSize(arrowWidth, arrowHeight);
downArrowButton.move(w - arrowWidth, Math.round((h - arrowHeight) / 2));
textInput.setActualSize(w - arrowWidth - 2, h);
}
/**
* @private
*/
override public function styleChanged(styleProp:String):void
{
super.styleChanged(styleProp);
if (dropdown)
dropdown.styleChanged(styleProp);
if (styleProp == null ||
styleProp == "styleName" ||
styleProp == "dateChooserStyleName")
{
if (dropdown)
{
var dateChooserStyleName:String = getStyle(
"dateChooserStyleName");
if (dateChooserStyleName)
{
var styleDecl:CSSStyleDeclaration =
styleManager.getMergedStyleDeclaration("." + dateChooserStyleName);
if (styleDecl)
{
_dropdown.styleDeclaration = styleDecl;
_dropdown.regenerateStyleCache(true);
}
}
}
}
}
/**
* @private
*/
override public function notifyStyleChangeInChildren(
styleProp:String, recursive:Boolean):void
{
super.notifyStyleChangeInChildren(styleProp, recursive);
if (dropdown)
dropdown.notifyStyleChangeInChildren(styleProp, recursive);
}
/**
* @private
*/
override public function regenerateStyleCache(recursive:Boolean):void
{
super.regenerateStyleCache(recursive);
if (dropdown)
dropdown.regenerateStyleCache(recursive);
}
/**
* @private
*/
override protected function resourcesChanged():void
{
super.resourcesChanged();
dayNames = dayNamesOverride;
firstDayOfWeek = firstDayOfWeekOverride;
formatString = formatStringOverride;
monthNames = monthNamesOverride;
monthSymbol = monthSymbolOverride;
yearSymbol = yearSymbolOverride;
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* Opens the DateChooser control.
*
* @helpid 3620
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function open():void
{
displayDropdown(true);
}
/**
* Closes the DateChooser control.
*
* @helpid 3621
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function close():void
{
displayDropdown(false);
}
private function checkYearSetSelectedDate(value:Date):void {
if (value != null)
{
var year:int = value.getFullYear();
if (year >= _minYear && year <= _maxYear)
_selectedDate = value;
}
else
{
_selectedDate = null;
}
}
/**
* @private
*/
private function displayDropdown(show:Boolean, triggerEvent:Event = null):void
{
if (!_enabled)
return;
if (show == showingDropdown)
return;
if (!addedToPopupManager)
{
addedToPopupManager = true;
PopUpManager.addPopUp(_dropdown, this, false);
}
else
{
PopUpManager.bringToFront(_dropdown);
}
// Subclasses may extend to do pre-processing
// before the dropdown is displayed
// or override to implement special display behavior.
//var point = {};
// point x will exactly appear on the icon.
// Leaving 1 pixel for the border to appear.
var xPos:Number = (layoutDirection == LayoutDirection.RTL ?
dropdown.getExplicitOrMeasuredWidth() : 0)
+ unscaledWidth - downArrowButton.width;
var point:Point = new Point(xPos, 0);
point = localToGlobal(point);
if (show)
{
if (_parseFunction != null)
checkYearSetSelectedDate(_parseFunction(text, formatString));
lastSelectedDate = _selectedDate;
selectedDate_changeHandler(triggerEvent);
var dd:DateChooser = dropdown;
if (_dropdown.selectedDate)
{
_dropdown.displayedMonth = _dropdown.selectedDate.getMonth();
_dropdown.displayedYear = _dropdown.selectedDate.getFullYear();
}
dd.visible = show;
dd.scaleX = scaleX;
dd.scaleY = scaleY;
var xVal:Number = point.x;
var yVal:Number = point.y;
//handling of dropdown position
// A. Bottom Left Placment
// B. Bottom Right Placement
// C. Top Right Placement
var sm:ISystemManager = systemManager.topLevelSystemManager;
var screen:Rectangle = sm.getVisibleApplicationRect(null, true);
if (screen.right > dd.getExplicitOrMeasuredWidth() + point.x &&
screen.bottom < dd.getExplicitOrMeasuredHeight() + point.y)
{
xVal = point.x
yVal = point.y - dd.getExplicitOrMeasuredHeight();
openPos = 1;
}
else if (screen.right < dd.getExplicitOrMeasuredWidth() + point.x &&
screen.bottom < dd.getExplicitOrMeasuredHeight() + point.y)
{
xVal = point.x - dd.getExplicitOrMeasuredWidth() + downArrowButton.width;
yVal = point.y - dd.getExplicitOrMeasuredHeight();
openPos = 2;
}
else if (screen.right < dd.getExplicitOrMeasuredWidth() + point.x &&
screen.bottom > dd.getExplicitOrMeasuredHeight() + point.y)
{
xVal = point.x - dd.getExplicitOrMeasuredWidth() + downArrowButton.width;
yVal = point.y + unscaledHeight;
openPos = 3;
}
else
{
// Why do we need to disable downArrowButton when its hidden?
//downArrowButton.enabled = false;
openPos = 0;
}
xVal = Math.max(screen.left, xVal);
point.x = xVal;
point.y = yVal;
point = dd.parent.globalToLocal(point);
UIComponentGlobals.layoutManager.validateClient(dd, true);
dd.move(point.x, point.y);
Object(dd).setActualSize(dd.getExplicitOrMeasuredWidth(),dd.getExplicitOrMeasuredHeight());
}
else
{
_dropdown.visible = false;
}
showingDropdown = show;
var event:DropdownEvent =
new DropdownEvent(show ? DropdownEvent.OPEN : DropdownEvent.CLOSE);
event.triggerEvent = triggerEvent;
dispatchEvent(event);
}
/**
* @private
*/
private function createDropdown():void
{
if (creatingDropdown)
return;
creatingDropdown = true;
_dropdown = dropdownFactory.newInstance();
_dropdown.focusEnabled = false;
_dropdown.owner = this;
_dropdown.moduleFactory = moduleFactory;
var todaysDate:Date = new Date();
_dropdown.displayedMonth = todaysDate.getMonth();
_dropdown.displayedYear = todaysDate.getFullYear();
_dropdown.styleName = new StyleProxy(this, {});
var dateChooserStyleName:Object = getStyle("dateChooserStyleName");
if (dateChooserStyleName)
{
var styleDecl:CSSStyleDeclaration =
styleManager.getMergedStyleDeclaration("." + dateChooserStyleName);
if (styleDecl)
_dropdown.styleDeclaration = styleDecl;
}
_dropdown.visible = false;
_dropdown.addEventListener(CalendarLayoutChangeEvent.CHANGE,
dropdown_changeHandler);
_dropdown.addEventListener(DateChooserEvent.SCROLL,
dropdown_scrollHandler);
_dropdown.addEventListener(FlexMouseEvent.MOUSE_DOWN_OUTSIDE,
dropdown_mouseDownOutsideHandler);
_dropdown.addEventListener(FlexMouseEvent.MOUSE_WHEEL_OUTSIDE,
dropdown_mouseDownOutsideHandler);
_dropdown.addEventListener(SandboxMouseEvent.MOUSE_DOWN_SOMEWHERE,
dropdown_mouseDownOutsideHandler);
_dropdown.addEventListener(SandboxMouseEvent.MOUSE_WHEEL_SOMEWHERE,
dropdown_mouseDownOutsideHandler);
creatingDropdown = false;
}
/**
* @private
* This is the default date format that is displayed
* if labelFunction is not defined.
*/
private function dateFiller(value:Date):void
{
if (_labelFunction != null)
textInput.text = labelFunction(value);
else
textInput.text = dateToString(value, formatString);
}
/**
* @private
* This method scrubs out time values from incoming date objects
*/
private function scrubTimeValue(value:Object):Object
{
if (value is Date)
{
return new Date(value.getFullYear(), value.getMonth(), value.getDate());
}
else if (value is Object)
{
var range:Object = {};
if (value.rangeStart)
{
range.rangeStart = new Date(value.rangeStart.getFullYear(),
value.rangeStart.getMonth(),
value.rangeStart.getDate());
}
if (value.rangeEnd)
{
range.rangeEnd = new Date(value.rangeEnd.getFullYear(),
value.rangeEnd.getMonth(),
value.rangeEnd.getDate());
}
return range;
}
return null;
}
/**
* @private
* This method scrubs out time values from incoming date objects
*/
private function scrubTimeValues(values:Array):Array
{
var dates:Array = [];
for (var i:int = 0; i < values.length; i++)
{
dates[i] = scrubTimeValue(values[i]);
}
return dates;
}
//--------------------------------------------------------------------------
//
// Overridden event handlers: UIComponent
//
//--------------------------------------------------------------------------
/**
* @private
*/
override protected function focusOutHandler(event:FocusEvent):void
{
if (showingDropdown && event != null &&
this.contains(DisplayObject(event.target)))
displayDropdown(false);
super.focusOutHandler(event);
if (_parseFunction != null)
checkYearSetSelectedDate(_parseFunction(text, formatString));
selectedDate_changeHandler(event);
}
/**
* @private
*/
override protected function keyDownHandler(event:KeyboardEvent):void
{
if (event.ctrlKey && event.keyCode == Keyboard.DOWN)
{
displayDropdown(true, event);
event.stopPropagation();
}
else if (event.ctrlKey && event.keyCode == Keyboard.UP)
{
if (showingDropdown)
selectedDate = lastSelectedDate;
displayDropdown(false, event);
event.stopPropagation();
}
else if (event.keyCode == Keyboard.ESCAPE)
{
if (showingDropdown) {
selectedDate = lastSelectedDate;
displayDropdown(false, event);
if (!editable)
event.stopPropagation();
}
}
else if (event.keyCode == Keyboard.ENTER)
{
if (showingDropdown)
{
checkYearSetSelectedDate(_dropdown.selectedDate);
displayDropdown(false, event);
event.stopPropagation();
}
else if (editable)
{
if (_parseFunction != null)
checkYearSetSelectedDate(_parseFunction(text, formatString));
}
selectedDate_changeHandler(event);
}
else if (event.keyCode == Keyboard.UP ||
event.keyCode == Keyboard.DOWN ||
event.keyCode == Keyboard.LEFT ||
event.keyCode == Keyboard.RIGHT ||
event.keyCode == Keyboard.PAGE_UP ||
event.keyCode == Keyboard.PAGE_DOWN ||
event.keyCode == 189 || // - or _ key used to step down year
event.keyCode == 187 || // + or = key used to step up year
event.keyCode == Keyboard.HOME ||
event.keyCode == Keyboard.END)
{
if (showingDropdown)
{
if (yearNavigationEnabled &&
(event.keyCode == 189 || event.keyCode == 187))
yearChangedWithKeys = true;
inKeyDown = true;
// Redispatch the event to the DateChooser
// and let its keyDownHandler() handle it.
dropdown.dispatchEvent(event);
inKeyDown = false;
// Prevent keys from moving scrollBars.
event.stopPropagation();
}
}
}
//--------------------------------------------------------------------------
//
// Overridden event handlers: ComboBase
//
//--------------------------------------------------------------------------
/**
* @private
*/
override protected function downArrowButton_buttonDownHandler(
event:FlexEvent):void
{
// The down arrow should always toggle the visibility of the dropdown.
callLater(displayDropdown, [ !showingDropdown, event ]);
// We hide the down arrow with the dropdown so the down arrow
// never gets a release, so it is in the wrong state.
// Force the state to be released:
downArrowButton.phase = "up";
}
/**
* @private
*/
override protected function textInput_changeHandler(event:Event):void
{
super.textInput_changeHandler(event);
var inputDate:Date = _parseFunction(text, formatString);
if (inputDate)
checkYearSetSelectedDate(inputDate);
}
//--------------------------------------------------------------------------
//
// Event handlers
//
//--------------------------------------------------------------------------
/**
* @private
*/
private function removedFromStageHandler(event:Event):void
{
// Ensure we've unregistered ourselves from PopupManager, else
// we'll be leaked.
addedToPopupManager = false;
PopUpManager.removePopUp(_dropdown);
}
/**
* @private
*/
private function dropdown_changeHandler(
event:CalendarLayoutChangeEvent):void
{
// If this was generated by the dropdown as a result of a keystroke,
// it is likely a Page-Up or Page-Down, or Arrow-Up or Arrow-Down.
// If the selection changes due to a keystroke,
// we leave the dropdown displayed.
// If it changes as a result of a mouse selection,
// we close the dropdown.
if (!inKeyDown)
displayDropdown(false);
// Nothing to do if the dates are the same.
if (ObjectUtil.dateCompare(_selectedDate, dropdown.selectedDate) == 0)
return;
checkYearSetSelectedDate(dropdown.selectedDate);
if (_selectedDate)
dateFiller(_selectedDate);
else
textInput.text = "";
var e:CalendarLayoutChangeEvent = new
CalendarLayoutChangeEvent(CalendarLayoutChangeEvent.CHANGE);
e.newDate = event.newDate;
e.triggerEvent = event.triggerEvent;
dispatchEvent(e);
}
/**
* @private
*/
private function dropdown_scrollHandler(event:DateChooserEvent):void
{
dispatchEvent(event);
}
/**
* @private
*/
private function dropdown_mouseDownOutsideHandler(event:Event):void
{
if (event is MouseEvent)
{
var mouseEvent:MouseEvent = MouseEvent(event);
if (! hitTestPoint(mouseEvent.stageX, mouseEvent.stageY, true))
displayDropdown(false, event);
}
else if (event is SandboxMouseEvent)
{
displayDropdown(false, event);
}
}
/**
* @private
* Handling change in selectedDate due to user interaction.
*/
private function selectedDate_changeHandler(triggerEvent:Event):void
{
if (!dropdown.selectedDate && !_selectedDate)
return;
if (_selectedDate)
dateFiller(_selectedDate);
if (dropdown.selectedDate && _selectedDate &&
dropdown.selectedDate.getFullYear() == _selectedDate.getFullYear() &&
dropdown.selectedDate.getMonth() == _selectedDate.getMonth() &&
dropdown.selectedDate.getDate() == _selectedDate.getDate())
return;
dropdown.selectedDate = _selectedDate;
var changeEvent:CalendarLayoutChangeEvent =
new CalendarLayoutChangeEvent(CalendarLayoutChangeEvent.CHANGE);
changeEvent.newDate = _selectedDate;
changeEvent.triggerEvent = triggerEvent;
dispatchEvent(changeEvent);
}
/**
* @private
*/
private function textInput_textInputHandler(event:TextEvent):void
{
if (yearChangedWithKeys)
{
event.preventDefault();
yearChangedWithKeys = false;
}
}
/**
* @private
*/
mx_internal function isShowingDropdown():Boolean
{
return showingDropdown;
}
}
}