<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:salesforce="http://www.salesforce.com/"
xmlns:flexlib="http://code.google.com/p/flexlib/"
xmlns:view="view.*"
layout="absolute"
applicationComplete="handleApplicationComplete(event)"
backgroundColor="#FFFFFF"
backgroundGradientColors="[#FFFFFF,#F3F3F3]"
width="100%"
height="100%"
minHeight="500"
minWidth="700"
pageTitle="SalesForce Account Detail Demo"
viewSourceURL="srcview/index.html"
horizontalScrollPolicy="off"
verticalScrollPolicy="off"
>
<mx:Style source="./assets/Style.css" />
<mx:Script>
<![CDATA[
import vo.StageSetVO;
import model.Model;
import constants.ViewIndexes;
import vo.AccountVO;
import constants.QueryConstants;
import mx.utils.StringUtil;
import mx.rpc.AsyncRequest;
import com.salesforce.objects.SObject;
import mx.events.CollectionEvent;
import mx.events.DataGridEvent;
import mx.controls.dataGridClasses.DataGridColumn;
import mx.controls.DataGrid;
import vo.OpportunityVO;
import mx.collections.ArrayCollection;
import com.salesforce.results.QueryResult;
import mx.utils.ObjectUtil;
import mx.controls.Alert;
import com.salesforce.AsyncResponder;
import com.salesforce.objects.LoginRequest;
import utils.ParsingUtils;
[Bindable]
/**
* the model is a holder for variables we need to share
* amongst other components... its an easy way instead of passing
* all the variables through component to component, the model
* lets us easily update one place, and get all the information
* we need.
**/
private var _model:Model = Model.getInstance();
/**
* the login function gets called from the <mx:Application /> tag
*
* from the event "applicationComplete", this tells the program to run this
* function on applicationComplete.
*
* you'll notice in the function that we setup a "callback" that callback is what is
* called when the result of the function comes back, whether its a good result from
* salesforce or a bad one... (example: a bad login attempt), we do this with the class
* AsyncResponder... its really not that complicated, its simple, all it is, is what
* gets called when we get data back from the salesforce, it takes 2 arguments,
* one is a result function, another is a fault function, the fault gets called when
* the call is bad, and fails, the result is called when its good...
*
**/
private function login():void {
_model.apex.protocol = 'http';
var lr:LoginRequest = new LoginRequest();
if( _model.server_url )
_model.apex.serverUrl = _model.server_url;
if( !_model.session_id )
{
lr.username = 'yourUserName@yahoo.com';
lr.password = 'passwordAndSecurityKey'
}
else
{
trace( '[session_id]' + _model.session_id );
lr.session_id = _model.session_id;
lr.server_url = _model.server_url;
}
lr.callback = new AsyncResponder(handleLoadData, handleFault);
_model.apex.login(lr);
}
/**
* handleApplicationComplete is called on applicationComplete, we will
* use this to get the variables passed into the application
**/
private function handleApplicationComplete( event:Event ):void
{
var o:Object = Application.application.parameters;
if( o.hasOwnProperty('session_id') && StringUtil.trim(o.session_id) )
{
_model.session_id = o.session_id;
}
if( o.hasOwnProperty('server_url') && StringUtil.trim(o.server_url) )
{
_model.server_url = o.server_url;
}
if( o.hasOwnProperty('account_id') && StringUtil.trim(o.account_id) )
{
_model.account_id = o.account_id;
}
else
{
_model.account_id = '0018000000R7uwB';
}
login();
}
/**
* handleFault gets called from the login() function
* and is called because we setup a callback to call it when
* the call fails... see the line that has lr.callback = new AsyncResponder( loadData, handleFault );
*
* we use this to simply let us know it failed, this isn't something you would usually show
* to the user, but as a programmer, we like to see the error popup at us while we are programming
* to know something failed... so we setup an Alert to do that by calling Alert.show( string );
**/
private function handleFault(fault:Object):void
{
trace( ObjectUtil.toString(fault) );
}
/**
* handleLoadData is called from our callback that is setup in the login() function as well
* the same as handleFault, this is called when the request is good from the login function, as
* long as its successful, we then query salesforce to get our data,
*
* we also setup a new AsyncResponder to call a function when the data returns
**/
private function handleLoadData(lr:Object):void
{
var sAccountById:String = QueryConstants.ACCOUNT_OPPORTUNITIES_BY_ID;
var replacement:String = "'" + _model.account_id + "'";
sAccountById = ParsingUtils.stringReplaceAll( sAccountById,'@ID',replacement );
_model.apex.query( sAccountById, new AsyncResponder( handleAccountResult,handleFault) );
}
/**
* handleAccountResult gets called when we return data from our query
* we use this to parse the data and convert it to classes that our
* application understands... we could use generic objects that are
* returned from the query, but it's a lot nicer to use vo's or ValueObjects
* because as a programmer, it allows us to get code hints for properties
* in the object
**/
private function handleAccountResult( event:QueryResult ):void
{
if (event.size > 0)
{
_model.acAccounts.source = ParsingUtils.convertToArrayCollection( event.records.source,vo.AccountVO ).source;
_model.accountVO = _model.acAccounts.getItemAt(0) as AccountVO;
_model.acOpportunities.source = ParsingUtils.convertToArrayCollection( event.records[0].Opportunities.records.source,vo.OpportunityVO ).source;
var stageNames:Object = {};
for( var i:int = 0; i < _model.acOpportunities.length; i++ )
{
var tempVO:OpportunityVO = _model.acOpportunities.getItemAt(i) as OpportunityVO;
var stageSetVO:StageSetVO;
if( !stageNames.hasOwnProperty(tempVO.StageName) )
{
stageSetVO = StageSetVO.buildObject();
stageSetVO.StageName = tempVO.StageName;
stageNames[tempVO.StageName] = stageSetVO;
stageSetVO.acOpportunities.addItem( tempVO );
}
else
{
stageSetVO = stageNames[tempVO.StageName];
stageSetVO.acOpportunities.addItem( tempVO );
}
}
for each( var stageSet:StageSetVO in stageNames )
{
_model.acStageSets.addItem( stageSet );
}
} }
/**
* handleSaveAll is called when we click the btnSaveAll
*
* when we edit each item in the datagrid, we store those edited items
* in an array to be ran through an updated
**/
private function handleSaveAll():void
{
trace('save all');
var a:Array = [];
for( var i:int = 0; i < _model.acDirtyOpportunities.length; i++ )
{
var tempVO:OpportunityVO = _model.acDirtyOpportunities.getItemAt(i) as OpportunityVO;
var o:Object = tempVO.toObject();
var so:SObject = new SObject(o);
a.push( so );
}
_model.apex.update( a,new AsyncResponder(handleSaveAllResult,handleFault) );
}
/**
* handleSaveAllResult is called from handleSaveAll, we created an AsyncResponder
* in the class that gets called when the data is returned from salesforce
**/
private function handleSaveAllResult( event:* ):void
{
Alert.show( 'All items saved successfully');
}
]]>
</mx:Script>
<mx:ApplicationControlBar
left="5"
right="5"
top="5"
height="80"
>
<mx:Image
source="@Embed(source='./assets/images/mmlogo.gif')"
/>
<mx:HBox
width="50%"
height="30"
>
<mx:Spacer width="80%" />
<mx:Label text="Double click to edit, or edit Probabilty and Amount on the fly, click on the chart to drill down" />
<mx:Button
id="btnSaveAll"
label="Save All"
click="handleSaveAll()"
/>
</mx:HBox>
</mx:ApplicationControlBar>
<mx:Parallel id="showEffect">
<mx:Dissolve />
<mx:Blur />
</mx:Parallel>
<mx:Parallel id="hideEffect">
<mx:Blur />
<mx:Dissolve />
</mx:Parallel>
<mx:DateFormatter
id="dateFormatter"
formatString="MM/DD/YYYY"
/>
<mx:VBox
left="5"
right="5"
top="100"
bottom="0"
horizontalScrollPolicy="off"
verticalScrollPolicy="off"
>
<mx:HDividedBox
width="100%"
height="100%"
>
<view:AccountView
width="350"
height="100%"
accountVO="{_model.accountVO}"
minWidth="350"
/>
<mx:VBox
width="40%"
height="100%"
minWidth="200"
>
<flexlib:WindowShade
width="100%"
label="Opportunities"
resizeEffect="Resize"
>
<view:Opportunities
width="100%"
height="150"
/>
</flexlib:WindowShade>
<flexlib:WindowShade
width="100%"
label="Contacts"
opened="false"
resizeEffect="Resize"
>
<mx:Label text="Nothing in here, but you can see how it would grow" width="100%"/>
</flexlib:WindowShade>
<flexlib:WindowShade
width="100%"
label="Case"
opened="false"
resizeEffect="Resize"
>
<mx:Label text="Nothing in here, but you can see how it would grow" width="100%"/>
</flexlib:WindowShade>
<flexlib:WindowShade
width="100%"
label="Opened Activities"
opened="false"
resizeEffect="Resize"
>
<mx:Label text="Nothing in here, but you can see how it would grow" width="100%"/>
</flexlib:WindowShade>
<flexlib:WindowShade
width="100%"
label="Notes and Attachments"
opened="false"
resizeEffect="Resize"
>
<mx:Label text="Nothing in here, but you can see how it would grow" width="100%"/>
</flexlib:WindowShade>
</mx:VBox>
<mx:ViewStack
width="60%"
height="100%"
selectedIndex="{_model.idxPodSelectedIndex}"
minWidth="300"
creationPolicy="all"
>
<view:PodContainer
width="100%"
height="100%"
showEffect="{showEffect}"
hideEffect="{hideEffect}"
/>
<view:OpportunityForm
id="opportunityForm"
width="100%"
height="100%"
showEffect="{showEffect}"
hideEffect="{hideEffect}"
includeInLayout="false"
show="btnSaveAll.visible=false"
hide="btnSaveAll.visible=true"
opportunityVO="{_model.selectedOpportunity}"
/>
</mx:ViewStack>
</mx:HDividedBox>
<mx:Spacer height="10"/>
</mx:VBox>
</mx:Application>