////////////////////////////////////////////////////////////////////////////////
//
// 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 spark.validators
{
import flash.globalization.NumberFormatter;
import flash.globalization.NumberParseResult;
import mx.core.mx_internal;
import mx.formatters.IFormatter;
import mx.managers.ISystemManager;
import mx.managers.SystemManager;
import mx.validators.NumberValidatorDomainType;
import mx.validators.ValidationResult;
import spark.globalization.LastOperationStatus;
import spark.validators.supportClasses.NumberValidatorBase;
import spark.validators.supportClasses.GlobalizationUtils;
import spark.formatters.NumberFormatter;
use namespace mx_internal;
[ResourceBundle("validators")]
/**
* The NumberValidator class ensures that a String represents a valid number
* according to the conventions of a locale. It can validate strings that
* represent int
,uint
, and Number
* objects.
*
*
This class uses the locale
style for specifying the
* requested locale ID.
The validator can ensure that the input falls within a given range
* (specified by minValue
and maxValue
properties),
* is an integer (specified by domain
property),
* is non-negative (specified by allowNegative
property),
* correctly specifies negative and positive numbers,
* and does not exceed the specified number offractionalDigits
.
* The validator sets default property values by making use of the
* flash.globalization.NumberFormatter
and therefore the locale
* specific values are supplied by the operating system.
The NumberValidator
class can be used in MXML declarations
* or in ActionScript code. This class uses the locale style for specifying the
* requested Locale ID required by the
* flash.globalization.NumberFormatter
class, and has methods and
* properties that are bindable.
The <spark:NumberValidator>
tag
* inherits all of the tag attributes of its superclass,
* and adds the following tag attributes:
* <s:NumberValidator * Properties * negativeNumberFormat="locale specified string or customized by user." * negativeNumberFormatError="The negative format of the input number is incorrect." * /> ** * @includeExample examples/NumberValidatorExample1.mxml * * @see flash.globalization.NumberFormatter * * @langversion 3.0 * @playerversion Flash 10.1 * @playerversion AIR 2.5 * @productversion Flex 4.5 */ public class NumberValidator extends NumberValidatorBase { include "../core/Version.as"; //-------------------------------------------------------------------------- // // Class Constants // //-------------------------------------------------------------------------- /** * @private */ private static const NEGATIVE_NUMBER_FORMAT:String = "negativeNumberFormat"; //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructs a new NumberValidator object to validate numbers according * to the conventions of a given locale. *
* The locale for this class is supplied by the locale
style.
* The locale
style can be set in several ways:
*
UIComponent
by calling
* the UIComponent
's addStyleClient
method.
* * <fx:Declarations> * <s:NumberValidator id="nv" /> * </fx:Declarations> **
* <fx:Declarations> * <s:NumberValidator id="nv_French_France" locale="fr_FR" /> * </fx:Declarations> **
setStyle
method.
* For example:
* nv.setStyle("locale", "fr-FR")
*
* If the locale
style is not set by one of the above
* techniques, the instance of this class will be added as a
* StyleClient
to the topLevelApplication
and
* will therefore inherit the locale
style from the
* topLevelApplication
object when the locale
* dependent property getter or locale
dependent method is
* called.
*
The following table summarizes the possible formats for
* negative numbers. When a negative number is validated,
* the minus sign represents the value of
* the negativeSymbol
property and the 'n' character
* represents numeric value.
Negative number format type | *Format | *
0 | *(n) | *
1 | *-n | *
2 | *- n | *
3 | *n- | *
4 | *n - | *
actual locale
and
* operating system
.
*
* @throws ArgumentError if the assigned value is not a number
* between 0 and 4.
*
* @see #negativeSymbol
* @see #format()
*
* @langversion 3.0
* @playerversion Flash 10.1
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public function get negativeNumberFormat():uint
{
return getBasicProperty(properties, NEGATIVE_NUMBER_FORMAT);
}
public function set negativeNumberFormat(value:uint):void
{
if (!g11nWorkingInstance)
{
if (4 < value)
throw new TypeError();
}
setBasicProperty(properties, NEGATIVE_NUMBER_FORMAT, value);
}
//--------------------------------------------------------------------------
//
// Properties: Errors
//
//--------------------------------------------------------------------------
//----------------------------------
// negativeNumberFormat error
//----------------------------------
/**
* @private
* Storage for the negativeNumberFormatError property.
*/
private var _negativeNumberFormatError:String;
private var negativeNumberFormatErrorOverride:String;
[Inspectable(category="Errors", defaultValue="null")]
[Bindable("change")]
/**
* Error message when the input number's negative number format is not
* following the pattern specified by the negativeNumberFormat property.
*
* @default "The negative format of the input number is incorrect."
*
* @langversion 3.0
* @playerversion Flash 10.1
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public function get negativeNumberFormatError():String
{
return _negativeNumberFormatError;
}
public function set negativeNumberFormatError(value:String):void
{
if (negativeNumberFormatErrorOverride &&
(negativeNumberFormatErrorOverride == value))
{
return;
}
negativeNumberFormatErrorOverride = value;
_negativeNumberFormatError = value ? value :
resourceManager.getString("validators", "negativeNumberFormatError");
update();
}
//--------------------------------------------------------------------------
//
// Overridden Methods
//
//--------------------------------------------------------------------------
/**
* @private
*/
override mx_internal function createWorkingInstance():void
{
createWorkingInstanceCore(NUMBER_VALIDATOR_TYPE);
}
/**
* @private
*
* Override of the base class doValidation()
method
* to validate a number.
*
* You do not call this method directly; * Flex calls it as part of performing a validation. * If you create a custom Validator class, you must implement this * method.
* * @param value Object to validate. * * @return AnArray
of ValidationResult
objects,
* with one ValidationResult
object for each field examined
* by the validator.
*
* @langversion 3.0
* @playerversion Flash 10.1
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
override protected function doValidation(value:Object):Array
{
var results:Array = super.doValidation(value);
// Return if there are errors
// or if the required property is set to false
and length
// is 0.
var val:String = value ? String(value) : "";
if (results.length > 0 || ((val.length == 0) && !required))
return results;
else
return validateNumber(value, null);
}
/**
* @private
* Load the error messages from the resource bundle.
*/
override protected function resourcesChanged():void
{
super.resourcesChanged();
loadChangedResources();
negativeNumberFormatError = negativeNumberFormatErrorOverride;
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
[Bindable("change")]
/**
* Convenience method for calling a validator from within a custom
* validation function. Each of the standard Flex validators has a similar
* convenience method. Caller must check the ValidationResult
* objects in the returned array for validation status.
*
* @param value A number string to validate.
*
* @param baseField Text representation of the subfield specified in the
* value
object.
* For example, if the value
parameter specifies value.number,
* the baseField
value is "number".
*
* @return An Array
of ValidationResult
objects,
* with one ValidationResult
object for each field examined
* by the validator.
*
* @see mx.validators.ValidationResult
*
* @langversion 3.0
* @playerversion Flash 10.1
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public function validateNumber(value:Object,
baseField:String):Array
{
const maxValue:Number = Number(maxValue);
const minValue:Number = Number(minValue);
const inputStr:String = String(value);
var results:Array = [];
// if the input can be a null/empty, return no error.
if (!inputStr)
return results;
// If spark formatter is null, no-go-forward. If spark formatter locale
// id is null or last operationstatus has locale undefined, then also
// no forward going situaion.
// The spark formatter createion has a situation where it's localeid is
// null but LasyOperationStatus is not set. TestLocaleUndef.mxml
// testcase has this situation.
if ((!g11nWorkingInstance) || (!g11nWorkingInstance.actualLocaleIDName) ||
(g11nWorkingInstance.lastOperationStatus ==
LastOperationStatus.LOCALE_UNDEFINED_ERROR))
{
results.push(new ValidationResult(
true, baseField, "localeUndefinedError",
localeUndefinedError));
return results;
}
// g11nWorkingInstance for a locale is available.
// strip leading and trailing white spaces.
const input:String = GlobalizationUtils.trim(inputStr);
const len:int = input.length;
// NumberValidatorBase has this method. Unlike flash globalization,
// validator gives error if decimal and grouping separator are same.
if (!validateNumberFormat(input, results, baseField))
return results;
// Parse the number string using the flash globalization NumberFormatter
const nf:spark.formatters.NumberFormatter =
g11nWorkingInstance as spark.formatters.NumberFormatter;
const inputNum:Number = nf.parseNumber(input);
// parseNumber() only returns PARSE_ERROR if it finds any error in input
// string. If there is a PARSE_ERROR, validate the input
// string further, detect and report the error. parse() is lenient than
// parseNumber() and parses to the extent possible without error. Hence
// it is not suitable.
if (nf.lastOperationStatus == LastOperationStatus.PARSE_ERROR)
{
if (!detectAndReportProblem(input, baseField, results))
{
return results;
}
else
{
results.push(new ValidationResult(
true, baseField, "parseError",
parseError));
return results;
}
}
// See if negative number is allowed.
if (!validateNumberNegativity(inputNum, baseField, results))
return results;
var dindex:int;
if (negativeNumberFormat <= 2)
dindex = input.lastIndexOf(decimalSeparator);
else
dindex = input.indexOf(decimalSeparator);
//
// Make sure every character after the decimal is a digit,
// and that there aren't too many digits after the decimal point:
// if domain is int there should be none,
// otherwise there should be no more than specified by fractionalDigits.
//
if (!validateFractionPart(
input, dindex, baseField, results))
{
return results;
}
// Make sure the input is within the specified range.
// Make sure the input is within the specified range.
// check the range of the number.
if (!validateNumberRange(inputNum, baseField, results))
return results;
return results;
}
//--------------------------------------------------------------------------
//
// Private Methods
//
//--------------------------------------------------------------------------
/**
* @private
* If there is a parse error by flash.globalization.NumberFormatter, detect
* the error and report it for user clarity. parse() method does not return
* anything other than PARSE_ERROR.
*/
private function detectAndReportProblem(input:String, baseField:String,
results:Array):Boolean
{
const len:int = input.length;
// Check for invalid characters in input.
// One of the negative format of number is enclosing in parenthesis.
const validChars:String = VALID_CHARS +
decimalSeparator + groupingSeparator;
if (validateInputCharacters(input, len, validChars))
{
results.push(new ValidationResult(
true, baseField, "invalidChar",
invalidCharError));
return false;
}
// Make sure there's only one decimal point.
else if ((decimalSeparator != negativeSymbol) &&
(input.indexOf(decimalSeparator) !=
input.lastIndexOf(decimalSeparator)))
{
results.push(new ValidationResult(
true, baseField, "decimalPointCount",
decimalPointCountError));
return false;
}
var negPosLeft:Boolean = false;
if (negativeNumberFormat <= 2)
negPosLeft = true;
// NumberValidatorBase has this method.
else if (!validateDecimalString(input, baseField, results, negPosLeft))
{
return false;
}
// all errors are already checked. Only remaining error is
// negativeNumberFormat.
else if ((inputHasNegativeSymbol(input)) ||
((input.charAt(0) == "(") && (input.charAt(len-1) == ")")))
{
results.push(new ValidationResult(
true, baseField, "negativeNumberFormat",
negativeNumberFormatError));
return false;
}
return true;
}
}
}