New Developer Library Released
Today, Developer Force (http://developer.force.com) released its new library. Here are a few of them. All can be found at http://wiki.developerforce.com/index.php/Documentation.
Workbook
http://www.salesforce.com/us/developer/docs/workbook/index.htm
Fundamentals
http://www.salesforce.com/us/developer/docs/fundamentals/index.htm
Cookbook
http://www.salesforce.com/us/developer/docs/cookbook/index.htm
Apex Advanced Code Example
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_shopping_cart_example.htm
https://sites.secure.force.com/appexchange/listingDetail?listingId=a0N30000001saDCEAY
And many more to come!
Trigger to help Salesforce for Twitter
Salesforce for Twitter is one of the best AppExchange packages I've seen. It fulfills the promise salesforce.com made to bring the Service Cloud to all orgs of all sizes. And it works well.
Though a supplemental/unofficial guide to customizing SFDC for Twitter will be released soon on this site, I wanted to share a trigger I just wrote to add new Leads to a campaign:
Firstly, thank you to Scott Hemmeter at Arrowpointe, who wrote the original code that I customized.
Secondly, you could easily duplicate this trigger and set it to run on the Contact object as well.
Please don't set the trigger to "after update," as in testing, it ran into problems when converting a Lead and merging with a Contact already on the "Twitter" campaign.
trigger AddToTwitterCampaign on Lead (after insert) {
// List containing each Lead being processed
list<Lead> theLeads = new list<Lead>();
//We only execute if we have a campaign named "Twitter"
if([SELECT Count() FROM Campaign WHERE name = 'Twitter'] == 1){
Campaign TC = [SELECT id, name FROM Campaign WHERE name = 'Twitter' LIMIT 1];
for(Lead l:trigger.new) {
if (l.leadsource.indexOf('Twitter',0 ) >= 0 || l.leadsource.indexOf('Tweet',0 ) >= 0 ){
theLeads.add(l); // add lead to the main lead list
}
}
// List containing Campaign Member records to be inserted
list <CampaignMember> theCampaignMembers = new list<CampaignMember>();
for (Lead ld:theLeads) {
CampaignMember cml = new CampaignMember();
cml.leadid = ld.id;
cml.campaignid = TC.id;
theCampaignMembers.add(cml);
}
//Insert the list of Campaign Members
if(!theCampaignMembers.isEmpty()){
insert theCampaignMembers;
}
}
}
The trigger requires that you have a Campaign called "Twitter," but feel free to change that to anything else you'd like.
Don't worry if you have other triggers that add Leads to Campaigns - this can work alongside them, so you can add Leads to as many Campaigns as you'd like.
A Mention in the Developers Challenge
The salesforce.com Developer Force Challenge has concluded, and the team of Force Squared and The Enforcer won a mention!
Our Daily Shinro site was listed “for sheer exuberance!”
I’m really proud of the site, though the lion’s share of the kudos go to John for the concept and site design. I just coded whatever he told me to code; he’s the creative one!
So if anyone is looking for a custom Force.com Site or website integration to Salesforce, contact us and let’s discuss your needs!
Overload Apex Class to be Controller AND Extension
Wow - today brought an interesting discovery. Here's the situation:
Coding the new premium version of Mass Update Contacts (details to come), I replaced the two parts of the page with Apex Components. This will allow the app to support custom address fields and international address formats.
I didn't want to write one ControllerExtension for the main page, a CustomController for the view section component, and another CustomController for the pageblocktable component. So here is the overloaded class constructor. Note that this works because an extension passes the StandardController to the constructor, and a CustomController passes nothing:
public with sharing class VersatileClass {
private Account account;
public VersatileClass(){
system.debug('OPERATING AS CONTROLLER');
if(System.currentPageReference().getParameters().get('id')==null){
//Include error checking here
} else{
string AId = System.currentPageReference().getParameters().get('id');
account = [select id, name from Account where id = :AId];
//And whatever else you want to do
}
}
public VersatileClass(ApexPages.StandardController controller) {
system.debug('OPERATING AS EXTENSION');
if(System.currentPageReference().getParameters().get('id')==null){
//Include error checking here
} else{
this.account = (Account)controller.getRecord();
//And whatever else you want to do
}
}
}
Enjoy! This should save people a lot of time.
Email Inbox Version 2
Well, it took about ten minutes from the release of Email Inbox Version 1 for people to request additional features, screenshots, etc. Version 2 includes some neat icons, and this post has the multiple-times-requested screenshots we promised.
First, a teaser screenshot. (There's a better one below the code.)

Here's the updated Visualforce code:
<apex:page controller="EmailMessageController" action="{!ViewData}">
<apex:sectionHeader title="Email Messages" subtitle=""></apex:sectionHeader>
<apex:pageblock id="emailblock">
<apex:facet name="header">
<apex:form >
<apex:panelGrid styleClass="list"
columnClasses="pbTitle,pbButton,pbHelp" columns="3" border="0"
cellpadding="0" cellspacing="0">
<apex:outputLabel ><h3>Messages</h3></apex:outputLabel>
<apex:commandButton value=" Refresh " styleClass="btn"
action="{!ViewData}" rerender="emailblock"></apex:commandButton>
<apex:SelectList value="{!wheretext}" size="1" id="controllerselectlist">
<apex:actionSupport event="onchange" action="{!ViewData}"
reRender="emailblock"></apex:actionSupport>
<apex:selectOptions value="{!views}" />
</apex:SelectList>
</apex:panelGrid>
</apex:form>
</apex:facet>
<apex:form >
<apex:pageblocktable value="{!Messages}" var="e" id="emailtable"
bgcolor="#F3F3EC" styleClass="list" rowClasses="dataRow"
onRowMouseOver="hiOn(this);" onRowMouseOut="hiOff(this);">
<apex:column >
<apex:facet name="header">
<apex:commandLink action="{!ViewData}"
value="{!$ObjectType.EmailMessage.fields.Subject.label}{!IF(sortExpression=='Subject',
IF(sortDirection='ASC','▼','▲'),'')}">
<apex:param value="Subject" name="column"
assignTo="{!sortExpression}"></apex:param>
</apex:commandLink>
</apex:facet>
<apex:outputLink value="/{!e.Id}" target="_blank">{!e.Subject}</apex:outputLink>
</apex:column>
<apex:column >
<apex:facet name="header">
{!$ObjectType.Contact.fields.Name.label}
</apex:facet>
<apex:outputLink value="/{!e.Parent.ContactId}" target="_blank"
rendered="{!IF(e.Parent.ContactId != '',true,false)}">{!e.FromName}</apex:outputLink>
<apex:outputtext value="{!e.FromName}"
rendered="{!IF(e.Parent.ContactId != '',false,true)}" />
</apex:column>
<apex:column >
<apex:facet name="header">
{!$ObjectType.Account.fields.Name.label}
</apex:facet>
<apex:outputLink value="/{!e.Parent.AccountId}" target="_blank">{!e.Parent.Account.Name}</apex:outputLink>
</apex:column>
<apex:column value="{!e.FromAddress}">
<apex:facet name="header">
<apex:commandLink action="{!ViewData}"
value="{!$ObjectType.EmailMessage.fields.FromAddress.label}{!IF(sortExpression=='FromAddress',
IF(sortDirection='ASC','▼','▲'),'')}">
<apex:param value="FromAddress" name="column"
assignTo="{!sortExpression}"></apex:param>
</apex:commandLink>
</apex:facet>
</apex:column>
<apex:column value="{!e.Status}">
<apex:facet name="header">
<apex:commandLink action="{!ViewData}"
value="{!$ObjectType.EmailMessage.fields.Status.label}{!IF(sortExpression=='Status',
IF(sortDirection='ASC','▼','▲'),'')}">
<apex:param value="Status" name="column"
assignTo="{!sortExpression}"></apex:param>
</apex:commandLink>
</apex:facet>
</apex:column>
<apex:column value="{!e.MessageDate}">
<apex:facet name="header">
<apex:commandLink action="{!ViewData}"
value="{!$ObjectType.EmailMessage.fields.MessageDate.label}{!IF(sortExpression=='MessageDate',
IF(sortDirection='ASC','▼','▲'),'')}">
<apex:param value="MessageDate" name="column"
assignTo="{!sortExpression}"></apex:param>
</apex:commandLink>
</apex:facet>
</apex:column>
<apex:column >
<apex:facet name="header">
<apex:commandLink action="{!ViewData}"
value="Inbound/Outbound{!IF(sortExpression=='Incoming',
IF(sortDirection='ASC','▼','▲'),'')}">
<apex:param value="Incoming" name="column"
assignTo="{!sortExpression}"></apex:param>
</apex:commandLink>
</apex:facet>
<apex:image url="/img/emailInbound.gif" rendered="{!e.Incoming}" />
<apex:image url="/img/emailOutbound.gif" rendered="{!NOT(e.Incoming)}" />
<!--<apex:outputfield value="{!e.Incoming}" rendered="{!NOT(e.Incoming)}" />-->
</apex:column>
<apex:column >
<apex:facet name="header">
<apex:commandLink action="{!ViewData}"
value="Attachment{!IF(sortExpression=='HasAttachment',
IF(sortDirection='ASC','▼','▲'),'')}">
<apex:param value="HasAttachment" name="column"
assignTo="{!sortExpression}"></apex:param>
</apex:commandLink>
</apex:facet>
<apex:image url="/img/emailHasAttach.gif" rendered="{!e.HasAttachment}"/>
<apex:outputfield value="{!e.HasAttachment}" rendered="{!NOT(e.HasAttachment)}" />
</apex:column>
<apex:column >
<apex:facet name="header">
<apex:commandLink action="{!ViewData}"
value="{!$ObjectType.Case.fields.CaseNumber.label}{!IF(sortExpression=='ParentId',
IF(sortDirection='ASC','▼','▲'),'')}">
<apex:param value="ParentId" name="column"
assignTo="{!sortExpression}"></apex:param>
</apex:commandLink>
</apex:facet>
<apex:outputLink value="/{!e.ParentId}">{!e.Parent.CaseNumber}</apex:outputLink>
</apex:column>
<apex:column value="{!e.ToAddress}">
<apex:facet name="header">
<apex:commandLink action="{!ViewData}"
value="{!$ObjectType.EmailMessage.fields.ToAddress.label}{!IF(sortExpression=='ToAddress',
IF(sortDirection='ASC','▼','▲'),'')}">
<apex:param value="ToAddress" name="column"
assignTo="{!sortExpression}"></apex:param>
</apex:commandLink>
</apex:facet>
</apex:column>
</apex:pageblocktable>
</apex:form>
</apex:pageblock>
</apex:page>
The Apex controller code has not changed from Version 1.
Here's the screenshot, which includes some emails from around the Salesforce ecosystem:
- Salesforce will search ANY Email field to match an incoming email to a Contact. (nice job, Salesforce!) - We know because Simon Fell's Contact.Email is sfell at salesforce.com, and his Contact.Secondary_Email__c is simon at fell.com in the sandbox. Ditto (with her own email addresses) for Irene Brodt.
- Auto-response emails will be included. We turned off auto-response after a few emails came in.
- Though the Email Address field is coded just to show the field value, Salesforce includes the Gmail link. (We assume that's because we activated the integration, but we may be wrong. Has anyone not activated that?)
- We did not (yet) implement the super Email/Web2Case trigger code that Marco Casalaina posted in the Salesforce Support Blog, but if we had, then every email in the list would be associated with a Contact. (Example: Michael Smith of Force2b.net, who will be a Contact from now on!)





