// TRAPEZE // Copyright 2006 Trapeze, Inc. All Rights Reserved. // This file is proprietary and confidential; unauthorized use or redistribution is prohibited. /** * @class FormManager / modded from SimplyFormed v1.0, by Adrian Stiegler * @version 1.0 * @author Adrian Stiegler * @availability Flash Player 8.0 * @edition Flash 8.0 / AS2 * ============================================ * Creates and manages Forms and Form Data * ============================================ */ // Import Statements: import com.trapeze.utils.Delegate; import com.trapeze.utils.collections.HashMap; import com.trapeze.bango.api.*; class com.trapeze.managers.FormManager { // ::: PRIVATE PROPERTIES static private var _instance:FormManager; // main container arrays for objects and displayable movieclips for forms public var _formsObjectArray:Array; public var _formsDisplayArray:Array; private var _formsDepth:Number; /*===================================== * getInstance * */ static public function getInstance():FormManager { if(_instance == undefined) { _instance = new FormManager(); } return _instance; } /* Constructor ======================== * */ private function FormManager() { _formsObjectArray = new Array(); _formsDisplayArray = new Array(); _formsDepth = 0; _global.formsArray = _formsDisplayArray; } /* MATCH FORM TYPE ================================================================================================================================================================ Provide a formInstance to parse the Bango XML and produce a form, using 'matchFormType' to create field_types ================================================================================================================================================================ */ public function createForm( formTarget:MovieClip, formName:String, formID:Number, userCallBack:Function, displayableForm:Boolean):Array { // check for user callback if ( userCallBack == undefined ) userCallBack = null; if ( displayableForm == undefined || displayableForm == null) { var _displayableForm = false; } else { var _displayableForm = displayableForm; } // create clip and form object inside var _form = formTarget.createEmptyMovieClip(formName, _formsDepth++); var _formBg = _form.attachMovie("_container", "back_mc", 0); /* SETUP FORM FUCNTIONS ================================================================================================================================================================ Next three functions set up the basic Form template ================================================================================================================================================================ */ setupFormObjectTemplate( _form, formID, userCallBack); // set's up form object specific variables setFormDisplayables( _form ); // set's up form displayable variables setupFormAssets( _form ); // set's the physical movieclip assets /* ================================================================================================================================================================ */ // .. now get Form Data _global.functionManager.getFormData( _form, formID, userCallBack ); // add form into our 'formsArray' _formsDisplayArray.push(_form); // show / hide the form to additional params _form._visible = _displayableForm; // send to debugger _global.debugManager.traceMsg("FORM CREATED AT: " + _form); return _form; } /* REMOVE FORM ================================================================================================================================================================ Provide a formInstance, and the form is removed from Display and the formDisplayArray ================================================================================================================================================================ */ public function removeForm( formInstance:MovieClip ) { _global.debugManager.traceMsg("DELETING FORM: " + formInstance); for (var i = 0; i < _formsDisplayArray.length; i++) { if (_formsDisplayArray[i] == formInstance) { _formsDisplayArray.splice(i,i + 1); } } formInstance.removeMovieClip(); } /* REFRESH FORM INSTANCE ================================================================================================================================================================ Provide a formInstance, will refresh the form for re-usability purposes ================================================================================================================================================================ */ public function refreshFormInstance( formInstance:MovieClip ) { /* This function will refresh a currently setup form */ // reset all data , array , object vars } /* SETUP FORM OBJECT TEMPLATE ================================================================================================================================================================ Creates all the required Objects, Hashmaps, Arrays, LoadVars, Listeners and variables for each basic form template ================================================================================================================================================================ */ private function setupFormObjectTemplate( formInstance:MovieClip, formID:Number, userCallBack:Function):Void { formInstance['formParams'] = new Object(); // displayable params for this form (used in setFormDisplayables) formInstance['formID'] = formID; // contains unique FormID formInstance['formUserCallBack'] = userCallBack; // contains the user specificed call back function (in case of overriding) formInstance['attributeVarTable'] = new HashMap(); // contains all form specific attributes like sizing, spacing , inital FormID formInstance['hiddenVarTable'] = new HashMap(); // contains all hidden data types for each form (used for cross referencing vars coming from Bango and sending back into Bango) formInstance['attributeVarTable'].name = 'attributeVarTable' formInstance['hiddenVarTable'].name = 'hiddenVarTable' formInstance['formData'] = new Array(); // will contain the formData after calling to Bango formInstance['formSendVars'] = new LoadVars(); // will contain all the formData variables to send out to Bango formInstance['xPosition'] = 0; // used later in matchFormType for positioning formElements formInstance['yPosition'] = 0; // '' formInstance['elementCount'] = 0; // used to set relative ID's to both the Label and Field pair for any field type formInstance['lastFocused'] = undefined; // used to hold as instance placeholder when swapping depths on focus // listeners formInstance['formListeners'] = new Object(); // used for all listeners of this form formInstance['formCreateSuccess'] = false; // used to tell the managers if the initial form call was successful and created, if so, any other bangoCallComplete's will just be signal handled, not parsed into a new form on screen } /* SETUP FORM DISPLAYABLES ================================================================================================================================================================ Parses some initial XML based params for each Form, using a rich Hash Map and storing them in the formInstance's 'attributesVarTable' object ================================================================================================================================================================ */ public function setFormDisplayables( formInstance:MovieClip ) { var _formParams = formInstance['formParams']; // set each form's defaults var _formID = getFormID( formInstance ); var formParamsXML = new XML('' +'' +'' +'' +'' +'' ); /* Default values: formID, recipient, from, action, cellPadding, cellSpacing, formWidth, formHeight Later when speaking to Bango, new key's are added into the varTable on any formInstance, rewriting a FormID, or any specific additional variables with Data_Type as hidden) from Bango */ // set up keys into varTable for(var i in formParamsXML.childNodes) { var theParam:XMLNode = formParamsXML.childNodes[i]; var key:String = theParam.attributes.name; var value:String = theParam.firstChild.nodeValue; // add key / value formInstance['attributeVarTable'].addItem(key, value); // another example of using the internal functions to get values //getAttributesValue( formInstance, key )); } } /* SETUP FORM DISPLAYABLES ================================================================================================================================================================ Phsyically adjusts all the form clips using the 'attributeVarTable' previously to style visual elements ================================================================================================================================================================ */ private function setupFormAssets( formInstance:MovieClip ) { // get our vars var _formWidth = Number(getAttributesValue( formInstance, "formWidth" )); var _formHeight = Number(getAttributesValue( formInstance, "formHeight" )); var _cellPadding = Number(getAttributesValue( formInstance, "cellPadding" )); var _cellSpacing = Number(getAttributesValue( formInstance, "cellSpacing" )); var _colLabelWidth = Number(getAttributesValue( formInstance, "colLabelWidth" )); // set size of background formInstance['back_mc']._width = _formWidth; formInstance['back_mc']._height = _formHeight; formInstance['back_mc']._alpha = 0; // create two columns inside container for labels and field types var col_left = formInstance.attachMovie("_container", "col_left", 1); // visual placeholder (to line stuff up) var col_right = formInstance.attachMovie("_container", "col_right", 2); // '' var formTextLabels = formInstance.attachMovie("_blank", "labels_mc", 3); var formFields = formInstance.attachMovie("_blank", "fields_mc", 4); // left column col_left.back_mc._width = _colLabelWidth - _cellSpacing; col_left.back_mc._height = formInstance['back_mc']._height; col_left._alpha = 0; // right column col_right.back_mc._width = _formWidth - _colLabelWidth; col_right.back_mc._height = formInstance['back_mc']._height; col_right._x = col_left._width + _cellSpacing; col_right._alpha = 0; // position form labels with left column formTextLabels._x = col_left._x; formTextLabels._y = col_left._y; // position form fields with right column formFields._x = col_right._x; formFields._y = col_right._y; } /* MATCH FORM TYPE ================================================================================================================================================================ Provide a formInstance to parse the Bango XML and produce a form, using 'matchFormType' to create field_types ================================================================================================================================================================ */ public function parseFormData( formInstance:MovieClip ) { var _cellSpacing = Number(getAttributesValue( formInstance, "cellSpacing" )); var formData = formInstance['formData']; // internal data array var refer = this; // MATCH TYPES WITH ELEMENTS for (var i = 0; i < formData.length; i++) { matchFormType( formInstance, formData[i] ); } // ::: SUBMIT var field_type = formInstance['fields_mc'].attachMovie("Button", "submit", formInstance['fields_mc'].getNextHighestDepth()); field_type._type = "button"; field_type.label = "Submit"; field_type.setSize(72,22); // position field_type._y = formInstance['yPosition']; field_type.onPress = function() { refer.sendFormData( formInstance ); } // ::: RESET var field_type = formInstance['fields_mc'].attachMovie("Button", "submit", formInstance['fields_mc'].getNextHighestDepth()); field_type._type = "button"; field_type.label = "Reset"; field_type.setSize(72,22); // ::: POSITION field_type._y = formInstance['yPosition']; field_type._x = formInstance['fields_mc']['submit'].x + formInstance['fields_mc']['submit'].width + _cellSpacing; formInstance['yPosition'] += field_type._height; field_type.onPress = function() { refer.clearFormData( formInstance ); } } /* MATCH FORM TYPE ================================================================================================================================================================ Pass a formInstance, and the XML element from a series, or a single and proper form types are created and displayed on screen ================================================================================================================================================================ */ private function matchFormType( formInstance:MovieClip, formElement:Object ) { /* -------------------------------- INDEX OF ELEMENT -------------------------------- trace(formElement.Name); trace(formElement.Data_Type); trace(formElement.Value); trace(formElement.Options); trace(formElement.Label); trace(formElement.Required); trace(formElement.Row_); trace(formElement.Column_); trace(formElement.Tab_Index); trace(formElement.Field_Size); trace(formElement.Restriction); -------------------------------- */ var _Name = formElement.Name; var _DataType = formElement.Data_Type.toString().toLowerCase(); var _TabIndex = formElement.Tab_Index; var _Value = formElement.Value; var _FieldSize = Number( formElement.Field_Size ); var _cellSpacing = Number(getAttributesValue( formInstance, "cellSpacing" )); // HIDDEN ATTRIBUTE if (_DataType == "hidden") { // let's add into our 'hiddenVarTable' formInstance['hiddenVarTable'].addItem(formElement.Name, formElement.Value); } // TEXT LABEL if (_DataType == "text" || _DataType == "password") { // label var field_label = formInstance["labels_mc"].attachMovie("Label", "label" + formInstance['labels_mc'].getNextHighestDepth(), formInstance['labels_mc'].getNextHighestDepth()); field_label.myID = formInstance['elementCount']; field_label.text = formElement.Label; field_label.setSize(formInstance["col_left"].back_mc._width); // field var field_type = formInstance['fields_mc'].attachMovie("TextInput", "input" + formInstance['fields_mc'].getNextHighestDepth(), formInstance['fields_mc'].getNextHighestDepth()); field_type.myID = formInstance['elementCount']; field_type._type = "text"; // set formElement default settings (Tab Index, Field Size, Required, Restrictions, Row and Column (not being used in Version 1.0) field_type.border = true; field_type.setSize(_FieldSize, 22); // position field_label._y = formInstance['yPosition']; field_type._y = formInstance['yPosition']; formInstance['yPosition'] += field_type.height + _cellSpacing; if (_DataType == "password") field_type.password = true; } // TEXT AREA if (_DataType == "textarea") { // label var field_label = formInstance["labels_mc"].attachMovie("Label", "label" + formInstance['labels_mc'].getNextHighestDepth(), formInstance['labels_mc'].getNextHighestDepth()); field_label.myID = formInstance['elementCount']; field_label.text = formElement.Label; field_label.setSize(formInstance["col_left"].back_mc._width); // textarea var field_type = formInstance['fields_mc'].attachMovie("TextArea", "input" + formInstance['fields_mc'].getNextHighestDepth(), formInstance['fields_mc'].getNextHighestDepth()); field_type.myID = formInstance['elementCount']; field_type._type = "textarea"; // set properties field_type.editable = true; field_type.wordWrap = true; field_type.border = true; field_type.text = ""; field_type.setSize(formElement.Field_Size, 50); field_label._y = formInstance['yPosition']; field_type._y = formInstance['yPosition']; formInstance['yPosition'] += field_type.height + _cellSpacing; } // CHECKBOX / RADIO if (_DataType == "checkbox" || _DataType == "radio") { // checkbox field / label var field_type = formInstance['fields_mc'].attachMovie("CheckBox", "checkbox" + formInstance['fields_mc'].getNextHighestDepth(), formInstance['fields_mc'].getNextHighestDepth()); field_type.myID = formInstance['elementCount']; field_type._type = "checkbox"; // set properties field_type.label = formElement.Label; field_type.labelPlacement = "right"; field_type.setSize(formElement.Field_Size, 22); field_type._y = formInstance['yPosition']; formInstance['yPosition'] += field_type.height + _cellSpacing; if (_Value == 1) field_type.selected = true; } // DROP DOWN (ComboBox) if (_DataType == "select") { // label var field_label = formInstance["labels_mc"].attachMovie("Label", "label" + formInstance['labels_mc'].getNextHighestDepth(), formInstance['labels_mc'].getNextHighestDepth()); field_label.myID = formInstance['elementCount']; field_label.text = formElement.Label; field_label.setSize(formInstance["col_left"].back_mc._width); // field var field_type = formInstance['fields_mc'].attachMovie("ComboBox", "combobox" + formInstance['fields_mc'].getNextHighestDepth(), formInstance['fields_mc'].getNextHighestDepth()); field_type.myID = formInstance['elementCount']; field_type._type = "select"; // set properties field_type.setSize(_FieldSize, 22); field_type.editable = false; // get value | label from element var _fieldOptions = formElement.Options.split(","); for (var i = 0; i < _fieldOptions.length; i++) { var _fieldAttributes = _fieldOptions[i].split('|'); var _itemValue = _fieldAttributes[0]; var _itemLabel = _fieldAttributes[1]; field_type.addItem({data:_itemValue, label:_itemLabel}); } // position field_label._y = formInstance['yPosition']; field_type._y = formInstance['yPosition']; formInstance['yPosition'] += field_type.height + _cellSpacing; } // RADIO GROUP if (_DataType == "radio-group") {} /* FORM COMMON VARIABLES These variables will be checked on sendFormData ================================================================================================================================================================ Below are the common variables each field_type owns, this is cross referenced with 'matchFormErrors' and other 1:1 relationships of Data to Clips ================================================================================================================================================================ */ field_type.varName = formElement.Name; field_type.varValue = formElement.Value; field_type.required = formElement.Required; field_type.restrictions = formElement.Restriction; field_type.tabIndex = _TabIndex; // set tab Index /* LISTENERS for each form type ================================================================================================================================================================ Each field_type has a listener for focusIn and onChanged ================================================================================================================================================================ */ field_type.addEventListener("focusIn", formInstance['formListeners']); formInstance['formListeners'].focusIn = function( evtObj:Object ) { // swap depths var _field = evtObj.target; var _fieldContainer = _field._parent; if (_fieldContainer._parent['lastFocused'] != undefined) { _field.swapDepths(_fieldContainer._parent['lastFocused']); } // set to last focused object _fieldContainer._parent['lastFocused'] = _field; } // increment the element count for this form formInstance['elementCount']++; } /* MATCH FORM ERRORS ================================================================================================================================================================ This function is used to match any improper field's requested by Bango to adjust ================================================================================================================================================================ */ private function matchFormErrors( formInstance:MovieClip, formErrors:Object ) { // parse errors and highlight fields for (var obj in formErrors) { var _errorName = formErrors[obj].Name; var _errorMessage = formErrors[obj].Message.toString(); // find matching field for (var field_type in formInstance['fields_mc']) { if (formInstance['fields_mc'][field_type]._type != 'button') { if (formInstance['fields_mc'][field_type].varName == _errorName) { var _clipInstance = formInstance['fields_mc'][field_type]; // found our matching varName to errorName _global.debugManager.traceMsg("BANGO VALIDATION ISSUE AT: " + _clipInstance + " with errorMessage " + _errorMessage); } } } } } /* CLEAR FORM DATA ================================================================================================================================================================ Provide a formInstance and all the field types will be cleared /reset ================================================================================================================================================================ */ private function clearFormData( formInstance:MovieClip ) { for (var clip in formInstance["fields_mc"]) { // catalogue all fields, except any buttons if (formInstance["fields_mc"][clip]._type != "button") { if (formInstance["fields_mc"][clip]._type != "select") { // clear text formInstance["fields_mc"][clip].text = ""; // clear varValue formInstance["fields_mc"][clip].varValue = undefined; } else { // set to start index formInstance["fields_mc"][clip].selectedIndex = 0; } } } } /* SEND FORM DATA ================================================================================================================================================================ Provide a formInstance, will parse the varName / varValue's iand send the form data to Bango ================================================================================================================================================================ */ private function sendFormData( formInstance:MovieClip ) { /* Setup with varName and varValue for each field_type formInstance["fields_mc"][clip].varName formInstance["fields_mc"][clip].varValue */ // clean the loadVars formInstance['formSendVars'] = new LoadVars(); // run through all clips and create seamless string to send to form URL for (var clip in formInstance["fields_mc"]) { // catalogue all fields, except any buttons if (formInstance["fields_mc"][clip]._type != "button") { // IF TEXT / TEXT AREA if (formInstance["fields_mc"][clip]._type == "text" || formInstance["fields_mc"][clip]._type == "textarea") { formInstance["fields_mc"][clip].varValue = formInstance["fields_mc"][clip].text; } // IF DROP DOWN if (formInstance["fields_mc"][clip]._type == "select") { formInstance["fields_mc"][clip].varValue = formInstance["fields_mc"][clip].getItemAt(formInstance["fields_mc"][clip].selectedIndex).data; } // IF CHECKBOX if (formInstance["fields_mc"][clip]._type == "checkbox") { formInstance["fields_mc"][clip].varValue = formInstance["fields_mc"][clip].selected; } // IF RADIO-GROUP if (formInstance["fields_mc"][clip]._type == "radio-group") { // ToDo: This is not yet tested, since we don't have any radio-groups in Bango yet. // if radio button is set to true, set value to label formInstance["fields_mc"][clip].varValue = null; if (formInstance["fields_mc"][clip].groupName != null && formInstance["fields_mc"][clip].selected == true) { formInstance["fields_mc"][clip].varValue = formInstance["col_right"][clip].label; } } // APPLY variables into formInstance's 'formSendVars' LoadVars object to send out if (formInstance["fields_mc"][clip].varValue != null && formInstance["fields_mc"][clip].varValue != "") { var _sendVarName = formInstance["fields_mc"][clip].varName.toString(); var _sendVarValue = formInstance["fields_mc"][clip].varValue; // apply varName into formSendVars, and set to varValue formInstance['formSendVars'][_sendVarName] = _sendVarValue; } } } // add hidden attributes into formSendVars var _hiddenVariableTableLength = formInstance['hiddenVarTable'].getLength(); var _keyArray = formInstance['hiddenVarTable'].getKeys(); var _valueArray = formInstance['hiddenVarTable'].getValues(); // add hidden variables into our 'formSendVars' LoadVars object for (var i = 0; i < _hiddenVariableTableLength; i++) { if (_keyArray[i] == "Form_Submit_To") { // let's rewrite our 'Form_Submit_To' key to 'func' (This is sort of a small security gate in itself) formInstance['formSendVars']['func'] = _valueArray[i]; } else { formInstance['formSendVars'][_keyArray[i]] = _valueArray[i]; } } // send to debugger _global.debugManager.traceMsg("CONSTRUCTED VAR OBJECT 'formSendVars' for: " + formInstance); // let's send out now _global.functionManager.sendFormData( formInstance ); } /* GET ATTRIBUTES VALUE ================================================================================================================================================================ Provide a formInstance and a searchable key to return a Form Attribute of choice ( displayable params only, etc. Spacing, Padding ) ================================================================================================================================================================ */ private function getAttributesValue( formInstance:MovieClip, key:String):String{ var value:String = String(formInstance['attributeVarTable'].getValue(key)); return value; } /* GET HIDDEN VALUE ================================================================================================================================================================ Provide a formInstance and a searchable key to return a Form Hidden Value of choice ( Form_Submit_To (func), Headers, Recipients etc ) ================================================================================================================================================================ */ private function getHiddenValue( formInstance:MovieClip, key:String):String{ var value:String = String(formInstance['hiddenVarTable'].getValue(key)); return value; } /* GET FORM ID ================================================================================================================================================================ Returns the proper ID number of the passed formInstance param ================================================================================================================================================================ */ public function getFormID( formInstance:MovieClip ):Number { return formInstance['formID']; } }