/*
Copyright (c) 2009 Yahoo! Inc. All rights reserved.
The copyrights embodied in the content of this file are licensed under the BSD (revised) open source license
*/
package com.yahoo.astra.managers {
import com.yahoo.astra.containers.formClasses.FormItem;
import com.yahoo.astra.containers.formClasses.FormLayoutStyle;
import com.yahoo.astra.events.FormDataManagerEvent;
import com.yahoo.astra.utils.IValueParser;
import com.yahoo.astra.utils.ValueParser;
import flash.display.DisplayObject;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
/**
* Collects user input data and validate it before you submit the data to the server.
* Astra does not provide a separate validation class, but there are compatible validation classes available from Adobe.
* Another option for the validation is the mx.validators distributed in the Flex SDK. For convenient use of Flex validators, you can use the Astra MXValidatorHelper
class.
* Flex MXvalidator provides a variety of validation types and detailed error messages. However, the use of the MXvalidator will increase your overall file size by approximately 20K.
* @example The following code shows a use of FormDataManager
:
*
customValuePaser
, com.yahoo.astra.utils.ValuePaser
will be used to strip input data.
*/
public function FormDataManager(customValuePaser : Class = null) {
valueParser = (customValuePaser) ? customValuePaser : ValueParser;
managerArray = [];
}
//--------------------------------------
// Properties
//--------------------------------------
/**
* @private
*/
private var valueParser : Class = null;
/**
* @private
*/
private var managerArray : Array = [];
/**
* @private
*/
private var validFunction : Function = null;
/**
* @private
*/
private var inValidFunction : Function = null;
/**
* @private
*/
private var idToRemove : String ;
/**
* @private
*/
private var _functionValidationPassed : Function = null;
/**
* Sets the method to be called as a handler function, when validation is success(FormDataManagerEvent.VALIDATION_PASSED).
*/
public function get functionValidationPassed() : Function {
return _functionValidationPassed;
}
/**
* @private
*/
public function set functionValidationPassed(value : Function) : void {
_functionValidationPassed = value;
}
/**
* @private
*/
private var _functionValidationFailed : Function = null;
/**
* Gets and sets the method to be called as a handler function, when validation is failed(FormDataManagerEvent.VALIDATION_FAILED).
*/
public function get functionValidationFailed() : Function {
return _functionValidationFailed;
}
/**
* @private
*/
public function set functionValidationFailed(value : Function) : void {
_functionValidationFailed = value;
}
/**
* @private
*/
private var _errorString : String = FormLayoutStyle.DEFAULT_ERROR_STRING;
/**
* Gets and sets the text representing error.
*
* @default "Invalid input"
*/
public function get errorString() : String {
return _errorString;
}
/**
* @private
*/
public function set errorString(value : String) : void {
_errorString = value;
}
/**
* @private
*/
private static var _collectedData : Object;
/**
* Collection of form input data variables object array.
* The "id"
will be the key and the user input from the "source"
will be value of the array.(e.g. collectedData["zip"] = "94089")
* You can loop over each value within the collectedData
object instance by using a for..in loop.
*
* @example The following code configures shows usage of collectedData
:
* errorString
will be collected as a object array with "id"
as a key and the message as value.
*
* * @example The following code configures shows usage of failedData
:
* Form
.
* id
and source
are required.
*
* Property Options:
*id
: String(or an Array of String)FormDataManager.collectedData
["zip"] = "94089")source
: Object(or Object Array)property
: Object(or Object Array)source
. If you defined valuePaser
of FormDataManager as FlValueParser
, don't need to set this property in general(e.g. source:[comboBox, textInput] , property:["abbreviation","text"]validator
: Function(or Function Array)source
.(e.g. validator:validator.isZip)validatorExtraParam
: Object(or Object Array)validator
.(e.g. validator:validator.isIntegerInRange, validatorExtraParam:[1, 20])required
: Boolean(or Boolean Array)validator
).(e.g. id:["stateComboBox", "zipcodeInput"], required:[false, true]) errorString
: StringshowErrorMessageText
is set true
. If there is existing instructionText
, will be replaced by errorString
.(e.g. errorString:"What kind of zipcode is that?.")targetObj
: DisplayObjectFormDataManagerEvent
type of FormDataManagerEvent.VALIDATION_PASSED
and FormDataManagerEvent.VALIDATION_FAILED
functionValidationPassed
: FunctionFormDataManagerEvent
type of FormDataManagerEvent.VALIDATION_PASSED
functionValidationFailed
: FunctionFormDataManagerEvent
type of FormDataManagerEvent.VALIDATION_FAILED
dataSource
:
* Registers items into the FormDataManager with it's properties. * Since FormDataManager collects and saves data as form of associative arrays, "id" will be used as a property of the array. (e.g. collectedData["zip"] = "94089")
*id
and source
are mandatory.
*
* @param id String to be a property of the data array(collectedData or failedData)
* @param source Object contains form input.
* @param property Object property of the source
.
* @param required Boolean determinds to be validated or not.
* @param validation Function to be used for validation of the source
.
* @param validatorExtraParam Object extra parameter(beside the first parameter) of the validation.
* @param eventTargetObj DisplayObject to be listen FormDataManagerEvent
(FormDataManagerEvent.VALIDATION_PASSED
and FormDataManagerEvent.VALIDATION_FAILED
)
* @param functionValidationPassed Function Object to be triggered when eventTargetObj
gets FormDataManagerEvent.VALIDATION_PASSED
event.
* @param functionValidationFailed Function Object to be triggered when eventTargetObj
gets FormDataManagerEvent.VALIDATION_FAILED
event.
*/
public function addItem(id : String, source : Object, property : Object = null , required : Boolean = false , validation : Function = null, validatorExtraParam : Object = null,eventTargetObj : DisplayObject = null,functionValidationPassed : Function = null,functionValidationFailed : Function = null, errorString : String = null) : void {
var valueParserObject : * = new valueParser();
var valueParser : IValueParser = ( valueParserObject is IValueParser) ? valueParserObject : new ValueParser();
managerArray.push({id:id, value : valueParser.setValue(source, property), validation:validation, validatorExtraParam:validatorExtraParam, required:required, eventTargetObj:eventTargetObj, errorString:errorString});
if(eventTargetObj ) {
var handlerSuccessFunction : Function = (functionValidationPassed is Function) ? functionValidationPassed : this.functionValidationPassed;
var handlerFailFunction : Function = (functionValidationFailed is Function) ? functionValidationFailed : this.functionValidationFailed;
if(handlerSuccessFunction is Function) eventTargetObj.addEventListener(FormDataManagerEvent.VALIDATION_PASSED, handlerSuccessFunction);
if(handlerFailFunction is Function) eventTargetObj.addEventListener(FormDataManagerEvent.VALIDATION_FAILED, handlerFailFunction);
}
}
/**
* Unregisters items from the FormDataManager
*
* @param id String
*/
public function removeItem(id : String) : void {
if(!managerArray) return;
idToRemove = id;
managerArray = managerArray.filter(removeFromArray);
}
/**
* Starts collecting and validating data.
* If there is registered trigger(addTrigger
), this function will be called by MouseEvent.CLICK
event of the button.
*
* @param e MouseEvent
*/
public function collectData(e : MouseEvent = null) : void {
var arrLeng : Number = managerArray.length;
FormDataManager.collectedData = FormDataManager.failedData = null;
FormDataManager.collectedData = {};
FormDataManager.failedData = {};
var passedBool : Boolean = true;
for (var j : Number = 0;j < arrLeng; j++) {
if(managerArray[j].eventTargetObj is FormItem) {
var curFormItme : FormItem = managerArray[j].eventTargetObj as FormItem;
curFormItme.gotResultBool = true;
}
}
for (var i : Number = 0;i < arrLeng; i++) {
var result : Boolean = validateAndStore(managerArray[i].id, managerArray[i].value, managerArray[i].validation, managerArray[i].validatorExtraParam, managerArray[i].required, managerArray[i].eventTargetObj, managerArray[i].errorString);
passedBool &&= result;
}
(passedBool) ? this.dispatchEvent(new FormDataManagerEvent(FormDataManagerEvent.DATACOLLECTION_SUCCESS, false, false, null, FormDataManager.collectedData)) : this.dispatchEvent(new FormDataManagerEvent(FormDataManagerEvent.DATACOLLECTION_FAIL, false, false, FormDataManager.failedData, collectedData));
}
/**
* Registers a button(DisplayObject) to trigger collectData
by MouseEvent.CLICK event.
* Also sets functionDataCollectionSuccess
and functionDataCollectionFail
to be triggered when FormDataManagerEvent.DATACOLLECTION_SUCCESS
or FormDataManagerEvent.DATACOLLECTION_FAIL
happens.
*
* @param button DisplayObject button to be clicked.
* @param functionDataCollectionSuccess Function to be triggered when all the forms passed validation(FormDataManagerEvent.DATACOLLECTION_SUCCESS
)
* @param functionDataCollectionFail Function to be triggered when any the forms failed validation(FormDataManagerEvent.DATACOLLECTION_FAIL
)
*/
public function addTrigger(button : DisplayObject, functionDataCollectionSuccess : Function = null, functionDataCollectionFail : Function = null) : void {
if(functionDataCollectionSuccess is Function) {
validFunction = functionDataCollectionSuccess;
this.addEventListener(FormDataManagerEvent.DATACOLLECTION_SUCCESS, functionDataCollectionSuccess);
}
if(functionDataCollectionFail is Function) {
inValidFunction = functionDataCollectionFail;
this.addEventListener(FormDataManagerEvent.DATACOLLECTION_FAIL, functionDataCollectionFail);
}
if(button is DisplayObject) {
button.addEventListener(MouseEvent.CLICK, collectData);
}
}
/**
* Unregisters the button(DisplayObject calling collectData
).
* Also removes FormDataManagerEvent listeners : FormDataManagerEvent.DATACOLLECTION_SUCCESS
and FormDataManagerEvent.DATACOLLECTION_FAIL
.
* @param button DisplayObject
*/
public function removeTrigger(button : DisplayObject) : void {
if(button) button.removeEventListener(MouseEvent.CLICK, collectData);
if(validFunction is Function) this.removeEventListener(FormDataManagerEvent.DATACOLLECTION_SUCCESS, validFunction);
if(inValidFunction is Function) this.removeEventListener(FormDataManagerEvent.DATACOLLECTION_FAIL, inValidFunction);
}
//--------------------------------------
// Private Methods
//--------------------------------------
/**
* @private
*/
private function removeFromArray(element : *, index : int, arr : Array) : Boolean {
return (element.id.toString() != idToRemove);
}
/**
* @private
*/
private function buildFromDataSource() : void {
var dataLength : int = dataSource.length;
for (var i : int = 0;i < dataLength; i++) {
var curData : Object = dataSource[i];
/*
* no Id, no collection
*/
var curId : String = curData["id"] as String;
var curSource : Object = curData["source"] as Object;
if(!curId || !curSource) {
throw new Error("id and source are needed.");
continue;
} else {
addItem( curId, curSource, curData["property"], curData["required"], curData["validator"], curData["validatorExtraParam"], curData["eventTargetObj"], curData["functionValidationPassed"], curData["functionValidationFailed"], curData["errorString"]);
}
}
}
/**
* @private
*/
private function validateAndStore(id : String , value : Object , validation : Function = null, validatorExtraParam : Object = null,required : Boolean = false,eventTargetObj : DisplayObject = null, errorString : String = null) : Boolean {
var curErrStr : String = this.errorString;
if(value == null) {
if(required) {
FormDataManager.failedData[id] = curErrStr;
if(eventTargetObj) eventTargetObj.dispatchEvent(new FormDataManagerEvent(FormDataManagerEvent.VALIDATION_FAILED, false, false, curErrStr));
return false;
}
// prevent storing null.
FormDataManager.collectedData[id] = "";
if(eventTargetObj)eventTargetObj.dispatchEvent(new FormDataManagerEvent(FormDataManagerEvent.VALIDATION_PASSED, false, false, null, value));
return true;
}
if(value is Function) {
var func : Function = value as Function;
value = func();
}
var tempResult : Boolean = true;
if(validation != null && value != null) {
var validationResult : Object;
if(validatorExtraParam is Array) {
var arrLeng : int = validatorExtraParam.length;
switch(arrLeng) {
case 1:
validationResult = validation(value, validatorExtraParam[0]);
break;
case 2:
validationResult = validation(value, validatorExtraParam[0], validatorExtraParam[1]);
break;
default:
validationResult = validation(value, validatorExtraParam[0], validatorExtraParam[1], validatorExtraParam[2]);
break;
}
} else {
validationResult = (validatorExtraParam) ? validation(value, validatorExtraParam) : validation(value);
}
if(required) {
tempResult = false;
//ADOBE Validator result
if(validationResult is Boolean ) {
if(validationResult) tempResult = true;
} else {
//MX Validator result
if(validationResult is Array) {
if(validationResult.length > 0) {
//trace(validationResult[0] ["subField"], validationResult[0] ["errorCode"], validationResult[0] ["isError"])
var errMsg : String = validationResult[0].errorMessage;
var subField : String = validationResult[0].subField;
if(errMsg) curErrStr = (subField) ? subField + errMsg : errMsg;
} else {
tempResult = true;
}
}
//ADOBE Validator result
if(validationResult.errorStr) curErrStr = validationResult.errorStr;
if(validationResult.result) tempResult = true;
}
}
}
if(errorString) curErrStr = errorString;
if(eventTargetObj is FormItem) {
var formItem : FormItem = eventTargetObj as FormItem;
if(formItem.errorString != FormLayoutStyle.DEFAULT_ERROR_STRING) curErrStr = formItem.errorString;
}
if(tempResult) {
FormDataManager.collectedData[id] = value;
if(eventTargetObj)eventTargetObj.dispatchEvent(new FormDataManagerEvent(FormDataManagerEvent.VALIDATION_PASSED, false, false, null, value));
return true;
} else {
FormDataManager.failedData[id] = curErrStr;
if(eventTargetObj) eventTargetObj.dispatchEvent(new FormDataManagerEvent(FormDataManagerEvent.VALIDATION_FAILED, false, false, curErrStr));
return false;
}
}
}
}