<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-3011483083044505303</atom:id><lastBuildDate>Sun, 29 Jan 2012 16:06:28 +0000</lastBuildDate><category>regex</category><category>apex</category><category>Social</category><category>popup</category><category>wrapper</category><category>CSS</category><category>attribute</category><category>Visualforce</category><category>reRender</category><category>Error</category><category>email service</category><category>Rating</category><category>chart</category><category>Pattern</category><category>matcher</category><title>CRM Science</title><description>Working with apex and visualforce to make Salesforce.com better!</description><link>http://blog.crmscience.com/</link><managingEditor>noreply@blogger.com (Ami Assayag)</managingEditor><generator>Blogger</generator><openSearch:totalResults>8</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/CrmScience" /><feedburner:info uri="crmscience" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:browserFriendly></feedburner:browserFriendly><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-3586695695509241293</guid><pubDate>Tue, 24 Jan 2012 15:10:00 +0000</pubDate><atom:updated>2012-01-29T10:54:25.561-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">popup</category><category domain="http://www.blogger.com/atom/ns#">CSS</category><category domain="http://www.blogger.com/atom/ns#">Visualforce</category><title>Handy Hover Popup CSS for Salesforce Lists/Tables</title><description>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-M-9gqrKolo4/Tx4meBJUv2I/AAAAAAAAAEs/WLsjOSBgX9Y/s1600/hover+popup.png" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" nfa="true" src="http://2.bp.blogspot.com/-M-9gqrKolo4/Tx4meBJUv2I/AAAAAAAAAEs/WLsjOSBgX9Y/s1600/hover+popup.png" /&gt;&lt;/a&gt;&lt;/div&gt;
Hover popups are a quick way to spruce up your salesforce.com interfaces while providing your users valuable information that does not require a new page to load. This simple hover popup is using cascading style sheets, and is very easy to add to lists and tables in your visualforce pages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Step one:&lt;/strong&gt;&lt;br /&gt;
Add the following styles to a css file. Add the css file to a static resource zip (in this example, I am using crmscience_resources.zip and crmscience.css). &lt;br /&gt;
These classes work nicely with the standard pageBlockTable styles as they are set to a height that allows you to see the detail in the popup for each row as you move your mouse down the rows. You can change the look and feel by changing the styles - the last two styles are for the hidden section. &lt;br /&gt;
&lt;pre class="java" name="code"&gt;.HoverPopup {
    position: relative;
    z-index: 0;
    }

.HoverPopup:hover {
    background-color: #eeeeee;
    Text-decoration: none;
    z-index: 50;
    }

.HoverPopup div {
    position: absolute;
    visibility: hidden;
    }

.HoverPopup:hover div {
    visibility: visible;
    top: 20px;
    left: 0px;
    border: 1px solid black;
    background-color: #eeeeee;
    padding: 10px;
    color: black;
    Text-decoration: none;
    white-space: pre;
    }
&lt;/pre&gt;
&lt;br /&gt;
&lt;strong&gt;Step two:&lt;/strong&gt;&lt;br /&gt;
In the visualforce page you are going to include the hover popups, add the following right after the &amp;lt;apex:page&amp;gt; (change the resource and css file names to what you created). Note that this should go in the top level page, even if you include the code in step 3 in a separate component. &lt;br /&gt;
&lt;pre class="java" name="code"&gt;&lt;stylesheet value="{!URLFOR($Resource.crmscience_resources, 'crmscience.css')}"&gt;&lt;/stylesheet&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;strong&gt;Step three:&lt;/strong&gt;&lt;br /&gt;
Add the following to your visualforce component or page. The {!c.Name} is the text/link that shows up in the table, and everything inside the div will show up in the hover popup. Be careful though... Salesforce adds a bunch of divs and spans everywhere, but as long as you use a div inside the outputLink you should be fine. &lt;br /&gt;
&lt;pre class="java" name="code"&gt;&lt;pageblocktable styleclass="list" value="{!Contacts}" var="c"&gt;
    &lt;column headervalue="Contact Name"&gt;
        &lt;outputlink styleclass="HoverPopup" value="/{!c.Id}"&gt;{!c.Name}
            &lt;div style="text-decoration: none; white-space: pre;"&gt;
&lt;outputfield value="{!c.Description}"&gt;&lt;/outputfield&gt;&lt;/div&gt;
&lt;/outputlink&gt;
    &lt;/column&gt;
    &lt;column value="{!c.SomeField1__c}"&gt;&lt;/column&gt;
    &lt;column value="{!c.SomeField2__c}"&gt;&lt;/column&gt;
&lt;/pageblocktable&gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3011483083044505303-3586695695509241293?l=blog.crmscience.com' alt='' /&gt;&lt;/div&gt;</description><link>http://blog.crmscience.com/2012/01/handy-hover-popup-css-for-salesforce.html</link><author>noreply@blogger.com (Ami Assayag)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-M-9gqrKolo4/Tx4meBJUv2I/AAAAAAAAAEs/WLsjOSBgX9Y/s72-c/hover+popup.png" height="72" width="72" /><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-5825242616880515313</guid><pubDate>Thu, 12 Jan 2012 20:23:00 +0000</pubDate><atom:updated>2012-01-29T10:54:57.877-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">wrapper</category><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">Visualforce</category><category domain="http://www.blogger.com/atom/ns#">chart</category><title>Chart Control to Add Charts Without Writing New Code</title><description>&lt;br /&gt;
&lt;div class="separator" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em; text-align: center;"&gt;
&lt;img border="0" kba="true" src="http://1.bp.blogspot.com/-ATMsL-qFsXM/TxBjOwK00LI/AAAAAAAAAEg/wM_ZMBB78eo/s1600/Chart.png" /&gt;&lt;/div&gt;
&lt;br /&gt;
A couple of years ago, I created a control that took chart data and used the Google Chart API to create a custom chart image inside Salesforce. That worked nicely, but I was happy to see that Salesforce finally added charting elements to visualforce in Winter '12. &lt;br /&gt;
&lt;br /&gt;
Once I was added to the charting pilot, I spent some time exploring the new elements. Generally, it is a good start, but there are several features I would like to see (like customizable tooltips), and there are a few bugs that need to be cleaned up (for example, long labels are chopped when displayed in slice tooltips). &lt;br /&gt;
&lt;br /&gt;
When I finished exploring and started creating some of these charts for a customer, I realized that most of the code behind for gathering and displaying chart data is almost identical. I like modular code, so I saw this as an opportunity to create a wrapper control that can take a few parameters and create the chart for you without having to write new apex/soql. &lt;br /&gt;
&lt;br /&gt;
This code sample creates a pie chart when you give it the following parameters: &lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Field - The field name (standard or custom) that is grouped into pie slices.&lt;/li&gt;
&lt;li&gt;Object - The object (standard or custom) that includes the above field.&lt;/li&gt;
&lt;li&gt;Conditions - A SOQL string that contains conditions for the query (if needed).&lt;/li&gt;
&lt;li&gt;Title - A title to display above the chart.&lt;/li&gt;
&lt;li&gt;Height - The height of the chart area.&lt;/li&gt;
&lt;li&gt;Width - The width of the chart area.&lt;/li&gt;
&lt;/ul&gt;
This control takes care of the null group (no value set), empty dataset,&amp;nbsp;and allows you to add a good range of conditions. Other than that, it is pretty simple.&amp;nbsp;Once set up though, it is easy to add some more bells and whistles. For example, in a later version, I added the ability to reference lookup fields for labels, and the ability to use the data with different chart types. &lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Step one:&lt;/strong&gt;&lt;br /&gt;
Create an apex class Chart.cls to hold the code for the visualforce components:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;public with sharing class Chart {

    // constructor
    public Chart() { }
    
    // set up properties to get the values from the calling vf page
    public string fld { get; set; }
    public string obj { get; set; }
    public string conditions { get; set; }
    public string title { get; set; }
    public string width { get; set; }
    public string height { get; set; }

    // class to hold data for the display 
    public class ChartData {

        public String label { get; set; }
        public Integer value { get; set; }

        public ChartData(String label, Integer value) {
            this.label = label;
            this.value = value;
        }
    }

    private List&lt;chartdata&gt; Counts;
    public List&lt;chartdata&gt; getCounts() {
        if (Counts == null) {
            if (fld !=null &amp;amp;&amp;amp; obj != null) {
                Counts = new List&lt;chartdata&gt;();
             
                // construct the query for the results. add escape chars to conditions
                string strQuary = 'SELECT Count(Id), ' + fld + ' FROM ' + obj;
                if (conditions != null &amp;amp;&amp;amp; conditions.length() &amp;gt; 0)
                    strQuary += ' WHERE ' + conditions.replaceall('\'', '\\\'');
                strQuary += ' GROUP BY ' + fld;

                AggregateResult[] groupedResults = Database.query(strQuary);
 
                if (groupedResults == null || groupedResults.IsEmpty())
                    // no results, just create a dummy chart
                    Counts.add(new ChartData('No Data', 1));
                else
                    for (AggregateResult ar : groupedResults)
                        // construct a list of the counts
                        if (string.valueof(ar.get(fld)) == null)
                            // capture the count for no value
                            Counts.add(new ChartData('No Value', integer.valueof(ar.get('expr0'))));
                        else
                            Counts.add(new ChartData(string.valueof(ar.get(fld)), integer.valueof(ar.get('expr0'))));
            }
        }
        return Counts;
    }
}
&lt;/pre&gt;
&lt;strong&gt;Step two:&lt;/strong&gt;&lt;br /&gt;
Create a component Chart.component:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;&amp;lt;apex:component controller="Chart"&amp;gt;
    &amp;lt;apex:attribute name="Field" type="String" required="true" assignTo="{!fld}"
                    description="The field name (standard or custom) that is grouped into pie slices." /&amp;gt;
    &amp;lt;apex:attribute name="Object" type="String" required="true" assignTo="{!obj}"
                    description="The object (standard or custom) that includes the above field." /&amp;gt;
    &amp;lt;apex:attribute name="LookupField" type="String" required="false" assignTo="{!lookupFld}"
                    description="If the DataField is a lookup, this is the field holds the values that the lookup resolve to." /&amp;gt;
    &amp;lt;apex:attribute name="LookupObject" type="String" required="false" assignTo="{!lookupObj}"
                    description="If the Field is a lookup, this is the object that LookupField is in." /&amp;gt;
    &amp;lt;apex:attribute name="Conditions" type="String" required="false" assignTo="{!conditions}"
                    description="A SOQL string that contains conditions for the query (if needed)." /&amp;gt;
    &amp;lt;apex:attribute name="Title" type="String" required="false" assignTo="{!title}"
                    description="A title to display above the chart." /&amp;gt;
    &amp;lt;apex:attribute name="height" type="String" required="false" assignTo="{!height}" default="220"
                    description="The height of the chart area." /&amp;gt;
    &amp;lt;apex:attribute name="width" type="String" required="false" assignTo="{!width}" default="300"
                    description="The width of the chart area." /&amp;gt;

    &amp;lt;span style="font-size: 14px; font-weight: bold;"&amp;gt;{!Title}&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;
    &amp;lt;apex:chart height="{!height}" width="{!width}" data="{!Counts}"&amp;gt;
        &amp;lt;apex:pieSeries dataField="value" labelField="label"/&amp;gt;
        &amp;lt;apex:legend position="right"/&amp;gt;
    &amp;lt;/apex:chart&amp;gt;

&amp;lt;/apex:component&amp;gt;
&lt;/pre&gt;
&lt;strong&gt;Step three:&lt;/strong&gt;&lt;br /&gt;
Include the component in your visualforce page like that: &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;&amp;lt;c:Chart Field="Status__c" Object="CustomObj__c" Conditions="IsArchived__c = False" title="My Status" /&amp;gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3011483083044505303-5825242616880515313?l=blog.crmscience.com' alt='' /&gt;&lt;/div&gt;</description><link>http://blog.crmscience.com/2012/01/chart-control-to-add-charts-without.html</link><author>noreply@blogger.com (Ami Assayag)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-ATMsL-qFsXM/TxBjOwK00LI/AAAAAAAAAEg/wM_ZMBB78eo/s72-c/Chart.png" height="72" width="72" /><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-4970550751682801864</guid><pubDate>Tue, 03 Jan 2012 23:04:00 +0000</pubDate><atom:updated>2012-01-29T10:55:25.751-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Rating</category><category domain="http://www.blogger.com/atom/ns#">reRender</category><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">Social</category><category domain="http://www.blogger.com/atom/ns#">Visualforce</category><title>Contact Rating in Salesforce (Better Version)</title><description>&lt;div style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;
&lt;img border="0" src="http://3.bp.blogspot.com/-W0ZRXf7LdcM/TvyypGysqvI/AAAAAAAAADw/banTeIo04_g/s1600/Rating.png" /&gt; &lt;/div&gt;
A few weeks ago I posted code for a rating control that allows users to easily rate a contact. The finished control looks like the image on the left, where each star is clickable and will set the rating to that many stars. &lt;br /&gt;
&lt;br /&gt;
The control was working great, but it was using two components instead of one, and also needed a page reload to work. It wasn't as elegant as I would like it to be, so I reworked the control (and it only took 10 minutes to rework...) Now the control is using the reRender attribute to refresh without reloading the page, and there is no need for the nested component. &lt;br /&gt;
&lt;br /&gt;
Here are a few other things you should know about this code sample:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;This code example is using the control with the Contact object although you can adjust it to use with any object.&lt;/li&gt;
&lt;li&gt;To get the nodes to the visualforce page, I construct and populate a list of Contact objects with the node information. I did that because I am lazy - instead, you can easily create a class to hold the right info and make the field names make more sense. &lt;/li&gt;
&lt;li&gt;The way I set it up, the rating range is set up by the control as opposed to hard code a one to five range.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;strong&gt;Step one:&lt;/strong&gt;&lt;br /&gt;
Create a zip with two images called RatingOn.png and RatingOff.png (I created a colored star and a grey star), and upload as a static resource.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Step two:&lt;/strong&gt;&lt;br /&gt;
Create an apex class Rating.cls to hold the code for the visualforce components:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;public with sharing class Rating {
 
    // set up properties to get the values from the calling vf page
    public string contactId { get; set; }
    public integer maxRating { get; set; }
    public integer Location { get; set; }
    public string ImageURL { get; set; }
    
    // Class constructor
    public Rating() { }

    //getter for the current rating of the contact
    private integer CurrentRating;
    public integer getCurrentRating() {
        if (CurrentRating == null) {
         Contact c = [SELECT Id, Rating__c FROM Contact WHERE Id = :contactId LIMIT 1];
         CurrentRating = (integer.valueOf(c.Rating__c) == null) ? 0 : integer.valueOf(c.Rating__c);
        }
        return CurrentRating;
    }

    public List&lt;contact&gt; Nodes;
    public Contact[] getNodes() {
        if (Nodes == null) {
            Nodes = new List&lt;contact&gt;();
   for (Integer i = 1; i &amp;lt;= maxRating; i++) {
    contact c = new Contact();
    c.FirstName=string.valueOf(i);
       c.LastName = '/resource/crmscience_resources/';
       c.LastName += (i &amp;lt;= getCurrentRating()) ? 'RatingOn' : 'RatingOff';
       c.LastName += '.png';
       c.Title = 'Set rating to ' + string.valueof(i);
       Nodes.add(c);
   }            
        }
        return Nodes;
    }

    // save the new rating and reload the page
    public PageReference SaveRating() {
        Contact c = [SELECT Id, Rating__c FROM Contact WHERE Id = :contactId LIMIT 1];
        c.Rating__c = Location;
        update c;    

        PageReference callPage = new PageReference('/' + contactId);
        callPage.setRedirect(true);
        return callpage;
    }
}
&lt;/pre&gt;
&lt;br /&gt;
&lt;strong&gt;Step three:&lt;/strong&gt;&lt;br /&gt;
Create a visualforce component called Rating.component:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;&amp;lt;apex:component controller="Rating" allowDML="True"&amp;gt;
    &amp;lt;apex:attribute name="contactId" type="String" required="true" assignTo="{!contactId}"
                    description="This is the contact Id to bind the results to." /&amp;gt;
    &amp;lt;apex:attribute name="maxRating" type="integer" required="true" assignTo="{!maxRating}"
                    description="This is the desired maximum rating." /&amp;gt;

&amp;lt;apex:form &amp;gt;
    &amp;lt;apex:outputPanel id="Rating"&amp;gt;
        &amp;lt;apex:repeat value="{!Nodes}" var="node" id="RatingRepeat2"&amp;gt;            
      &amp;lt;apex:commandLink action="{!SaveRating}" rerender="Rating" title="{!node.Title}" &amp;gt;
                &amp;lt;apex:param name="Location" assignTo="{!Location}" value="{!node.FirstName}" /&amp;gt;
          &amp;lt;apex:image url="{!node.LastName}" /&amp;gt;
      &amp;lt;/apex:commandLink&amp;gt;
        &amp;lt;/apex:repeat&amp;gt;
    &amp;lt;/apex:outputPanel&amp;gt;
&amp;lt;/apex:form&amp;gt;
&amp;lt;/apex:component&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;strong&gt;Step four:&lt;/strong&gt;&lt;br /&gt;
Include the component in your visualforce page like that: &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;&amp;lt;Rating contactId="{!Contact.Id}" maxRating="5" &amp;gt;
&lt;/pre&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3011483083044505303-4970550751682801864?l=blog.crmscience.com' alt='' /&gt;&lt;/div&gt;</description><link>http://blog.crmscience.com/2012/01/contact-rating-in-salesforce-better.html</link><author>noreply@blogger.com (Ami Assayag)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-W0ZRXf7LdcM/TvyypGysqvI/AAAAAAAAADw/banTeIo04_g/s72-c/Rating.png" height="72" width="72" /><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-1289170089477318575</guid><pubDate>Mon, 02 Jan 2012 14:38:00 +0000</pubDate><atom:updated>2012-01-29T10:55:37.876-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">email service</category><category domain="http://www.blogger.com/atom/ns#">Pattern</category><category domain="http://www.blogger.com/atom/ns#">regex</category><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">matcher</category><title>Custom Salesforce Email Service</title><description>Email to Salesforce is a nice shrink-wrapped feature, but it lacks some functionality that I think is very necessary. For example, when Highrise CRM users using&amp;nbsp;the Highrise dropbox feature, the email service looks for matching email addresses in the body of the email in addition to&amp;nbsp;the TO and CC lists. To create that functionality in Salesforce, you need to write your own email service. &lt;br /&gt;
&lt;br /&gt;
In this post I am going to concentrate on what I wrote to parse the email addresses out of the TO and CC lists as well as the body of the email. Parsing the TO and CC lists is necessary because these arrays usually include texts that looks like this - "John Doe &amp;lt;john@doe.com&amp;gt;".&lt;br /&gt;
&lt;br /&gt;
I was able to create one method that will do the work for both the lists and the email body. To do that I used the apex classes Pattern and Matcher, which are very useful, but pretty confusing to work with. These classes give you the ability to search through strings and return matches based on a regex (regular expression). I always find it very tedious to write regexes, so I borrowed an email regex from &lt;a href="http://www.regular-expressions.info/email.html"&gt;Jan Goyvaerts&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
This method is pretty handy. I also used it to find the&amp;nbsp;"from:" email address of a forwarded email so I can create a contact if needed (I didn't include that piece of code as it is using&amp;nbsp;the same stuff - Pattern, Matcher, and my handy method).&amp;nbsp;Note that if you only want to find the first email address in a given string, you&amp;nbsp;only need to change the while to an if.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;
global class MyEmailService implements Messaging.InboundEmailHandler {

    global Messaging.InboundEmailResult handleInboundEmail(Messaging.inboundEmail email, Messaging.InboundEnvelope env) {
 
        Messaging.InboundEmailResult result = new Messaging.InboundEmailResult();
  
        // declare an array to hold all the email addresses that we find
        String[] emailAddresses = new String[0];

        // get all the to and cc addresses
        emailAddresses.addall(getEmails(email.toAddresses));
        emailAddresses.addall(getEmails(email.ccAddresses));

        // get all email addresses from the body of the email
        emailAddresses.addall(getEmails(new string[]{email.plainTextBody}));


        ....... Do something with the email addresses we found ......


        return result;
    }

    // get email addresses from an array of strings
    public String[] getEmails(String[] strings) { 
 
        // set up an array to hold the emails
        String[] emailAddresses = new String[0];

        if (strings != null) {
            
            // set up a pattern with an email regex (assume lower case)
            Pattern emailPattern = Pattern.compile('\\b[a-z0-9._%-]+@[a-z0-9.-]+\\.[a-z]{2,4}\\b');
            Matcher emailMatcher;

            // go through each string and add any valid email address to the return array
            for (string str : strings) {
             emailMatcher = emailPattern.matcher(str.toLowerCase());
             while (emailMatcher.find())
                 emailAddresses.add(str.substring(emailMatcher.start(), emailMatcher.end()));
            }
        }
        return emailAddresses; 
    }
}

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3011483083044505303-1289170089477318575?l=blog.crmscience.com' alt='' /&gt;&lt;/div&gt;</description><link>http://blog.crmscience.com/2012/01/custom-salesforce-email-service.html</link><author>noreply@blogger.com (Ami Assayag)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-3631998609010949676</guid><pubDate>Fri, 30 Dec 2011 14:13:00 +0000</pubDate><atom:updated>2012-01-29T10:58:16.709-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Error</category><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">attribute</category><category domain="http://www.blogger.com/atom/ns#">Visualforce</category><title>Can't assign a default value to apex:attribute of type boolean</title><description>A couple of weeks ago I wrote a component that included several apex attribute tags. One of them was a flag that tells the control if it should be shown in a "disabled" mode. The normal mode for the control is enabled so I set the Type attribute to "boolean" and the Default attribute to "false". When I saved the control, I got the error "Literal value is required for attribute". At first, I didn't know what it was talking about, but after some experimentation, I realized that the Default attribute was causing the problem. I tried 0/1 and several true/false capitalizations, but nothing worked. That led me to the conclusion that in the case of boolean apex:attribute tags, SF does not cast the defaule value it gets into a boolean correctly (it expects a boolean value but tries to put a literal in it).&lt;br /&gt;
&lt;br /&gt;
I still needed that to work, so instead of using the Default attribute, I set up a property in the class to handle the default value, and it worked like a charm...&lt;br /&gt;

&lt;pre class="java" name="code"&gt;
Visualforce page:

&amp;lt;apex:attribute name=&amp;quot;enabled&amp;quot; type=&amp;quot;boolean&amp;quot; required=&amp;quot;false&amp;quot; assignTo=&amp;quot;{!controlEnabled}&amp;quot; /&amp;gt;


Class:

public boolean controlEnabled { get { if(controlEnabled == null) controlEnabled = true; return controlEnabled; } set; }

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3011483083044505303-3631998609010949676?l=blog.crmscience.com' alt='' /&gt;&lt;/div&gt;</description><link>http://blog.crmscience.com/2011/12/cant-assign-default-value-to.html</link><author>noreply@blogger.com (Ami Assayag)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-8776223679746033818</guid><pubDate>Fri, 23 Dec 2011 17:34:00 +0000</pubDate><atom:updated>2012-01-03T18:09:43.937-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Social</category><title>Graphic Contact Ratings in Salesforce</title><description>&lt;i&gt;&lt;b&gt;Stop reading!
&lt;br/&gt;
I improved this control in a later post... &lt;a href=" http://blog.crmscience.com/2012/01/contact-rating-in-salesforce-better.html"&gt;Find it here&lt;/a&gt;.&lt;/b&gt;&lt;/i&gt;
&lt;br/&gt;
&lt;br/&gt;
As part of my ongoing effort to spruce up the look and feel of salesforce pages, I created a rating control that allows users to easily rate a contact. The finished control looks like the following image, where each star is clickable and will set the rating to that many stars. &lt;br /&gt;
&lt;br /&gt;
A few things you should know about this code sample:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;This code example is using the control with the Contact object although you can adjust it to use with any object.&lt;/li&gt;
&lt;li&gt;To get the nodes to the visualforce page, I construct and populate a list of Contacts with the node information. I did that because I am lazy - instead, you can easily create a class to hold the right info and make the field names make more sense. &lt;/li&gt;
&lt;li&gt;The way I set it up, the rating range is set up by the control as opposed to hard code a one to five range.&lt;/li&gt;
&lt;li&gt;The page reloads after a user selection. That's not great, and at some point I'll try to make this dynamic and repost.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;strong&gt;Step one:&lt;/strong&gt;&lt;br /&gt;
Create a zip with two images called RatingOn.png and RatingOff.png (I created a colored star and a grey star), and upload as a static resource.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Step two:&lt;/strong&gt;&lt;br /&gt;
Create an apex class Rating.cls to hold the code for the visualforce components:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;public with sharing class Rating {
 
    // set up properties to get the values from the calling vf page
    public string contactId { get; set; }   // used by Rating.component and RatingNode.component
    public integer maxRating { get; set; }  // used by Rating.component
    public integer Location { get; set; }   // used by RatingNode.component
    public string ImageURL { get; set; }   // used by RatingNode.component
    
    // Calss constructors
    public Rating() { }
    public Rating(ApexPages.StandardController stdController) { }

////////////////////////////////////////
//  Methods for Rating.component
////////////////////////////////////////

    //getter for the current rating of the contact
    private integer CurrentRating;
    public integer getCurrentRating() {
        if (CurrentRating == null) {
            Contact c = [SELECT Id, Rating__c FROM Contact WHERE Id = :contactId LIMIT 1];
     CurrentRating = (integer.valueOf(c.Rating__c) == null) ? 0 : integer.valueOf(c.Rating__c);
        }
        return CurrentRating;
    }

    public List&amp;lt;Contact&amp;gt; Nodes;
    public Contact[] getNodes() {
        if (Nodes == null) {
            Nodes = new List&amp;lt;Contact&amp;gt;();
     for (Integer i = 1; i &amp;lt;= maxRating; i++) {
  contact c = new Contact(LastName=string.valueOf(i));
  c.FirstName = '/resource/MyReatingResource/';
  c.FirstName += (i &amp;lt;= getCurrentRating()) ? 'RatingOn' : 'RatingOff';
  c.FirstName += '.png';
  Nodes.add(c);
     }            
        }
        return Nodes;
    }

////////////////////////////////////////
//  Methods for RatingNodes.component
////////////////////////////////////////

    public string getTooltip() {
        return 'Set rating to ' + string.valueof(location);
    }
    
    // save the new rating and reload the page
    public PageReference SaveRating() {
        Contact c = [SELECT Id, Rating__c FROM Contact WHERE Id = :contactId LIMIT 1];
        c.Rating__c = Location;
        update c;    

        PageReference callPage = new PageReference('/' + contactId);
        callPage.setRedirect(true);
        return callpage;
    }
}
&lt;/pre&gt;
&lt;br /&gt;
&lt;strong&gt;Step three:&lt;/strong&gt;&lt;br /&gt;
Create a visualforce component called RatingNode.component (used for each node in the rating):&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;&amp;lt;apex:component controller="Rating" allowDML="True"&amp;gt;
    &amp;lt;apex:attribute name="contactId" type="String" required="true" assignTo="{!contactId}"
                    description="This is the contact Id to bind the results to." /&amp;gt;
    &amp;lt;apex:attribute name="location" type="integer" required="true" assignTo="{!Location}"
                    description="The location of this node in the rating." /&amp;gt;
    &amp;lt;apex:attribute name="ImageURL" type="string" required="true" assignTo="{!ImageURL}"
                    description="The url for this node image (already set to off/on)" /&amp;gt;

 &amp;lt;apex:commandLink action="{!SaveRating}" title="{!Tooltip}" &amp;gt;
     &amp;lt;apex:image url="{!ImageURL}" /&amp;gt;
 &amp;lt;/apex:commandLink&amp;gt;

&amp;lt;/apex:component&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;strong&gt;Step four:&lt;/strong&gt;&lt;br /&gt;
Create a visualforce component called Rating.component (used to assemble all the nodes together):&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;&amp;lt;apex:component controller="Rating"&amp;gt;
    &amp;lt;apex:attribute name="contactId" type="String" required="true" assignTo="{!contactId}"
                    description="This is the contact Id to bind the results to." /&amp;gt;
    &amp;lt;apex:attribute name="maxRating" type="integer" required="true" assignTo="{!maxRating}"
                    description="This is the desired maximum rating." /&amp;gt;

    &amp;lt;apex:form &amp;gt;
     &amp;lt;apex:repeat value="{!Nodes}" var="node" id="RatingRepeat"&amp;gt;
         &amp;lt;c:RatingNode contactId="{!contactId}" Location="{!node.LastName}" ImageURL="{!node.FirstName}" /&amp;gt;
     &amp;lt;/apex:repeat&amp;gt;
    &amp;lt;/apex:form&amp;gt;
    
&amp;lt;/apex:component&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;strong&gt;Step five:&lt;/strong&gt;&lt;br /&gt;
Include the component in your visualforce page like that: &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="java" name="code"&gt;&amp;lt;c:Rating contactId="{!Contact.Id}" maxRating="5" /&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3011483083044505303-8776223679746033818?l=blog.crmscience.com' alt='' /&gt;&lt;/div&gt;</description><link>http://blog.crmscience.com/2011/12/graphic-contact-ratings-in-salesforce.html</link><author>noreply@blogger.com (Ami Assayag)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-2852091678569872205</guid><pubDate>Tue, 13 Dec 2011 01:26:00 +0000</pubDate><atom:updated>2012-01-03T20:27:22.273-05:00</atom:updated><title>About CRM Science</title><description>&lt;div class="separator" style="border-bottom: medium none; border-left: medium none; border-right: medium none; border-top: medium none; clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em; text-align: center;"&gt;
&lt;img border="0" rea="true" src="http://3.bp.blogspot.com/-DNeDIYVmpEE/TwOn2rB5rCI/AAAAAAAAAEE/v-C5N6hl5pw/s1600/CRMScience_165x165.png" width="150" /&gt;&lt;/div&gt;
&lt;br /&gt;
CRM Science is a full service Salesforce consultancy with extensive expertise in building CRM and native Force.com applications. &lt;br /&gt;
&lt;br /&gt;
We concentrate on Salesforce.com projects that improve relationship management and enhance business workflows. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style="border-bottom: medium none; border-left: medium none; border-right: medium none; border-top: medium none;"&gt;
&lt;a href="http://2.bp.blogspot.com/-u5DFQnJRJXM/TwOoHPdcqlI/AAAAAAAAAEQ/QgrVa1DFK7w/s1600/Ami_20110101.jpg" imageanchor="1" style="clear: left; cssfloat: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" rea="true" src="http://2.bp.blogspot.com/-u5DFQnJRJXM/TwOoHPdcqlI/AAAAAAAAAEQ/QgrVa1DFK7w/s1600/Ami_20110101.jpg" /&gt;&lt;/a&gt;&lt;b&gt;About Ami Assayag, Founder and Chief Architect&lt;/b&gt;&lt;/div&gt;
&lt;div style="border-bottom: medium none; border-left: medium none; border-right: medium none; border-top: medium none;"&gt;
&lt;br /&gt;&lt;/div&gt;
I am a seasoned entrepreneur and CRM specialist who spent many years architecting enterprise CRM applications, both proprietary and on existing CRM platforms.&lt;br /&gt;
&lt;br /&gt;
I spent several years developing a proprietary SaaS CRM solution for the alternative asset management market, which was built exclusively on Force.com. The solution offered a single portal through which both investors and investments can be managed, and information can be easily collected and disseminated. The solution is now part of a full service fund management firm.&lt;br /&gt;
&lt;br /&gt;
I co-founded a venture backed CRM solution for individuals and small businesses that provided value throughout their sales and business development processes by incorporating networking activities, social infusion, intelligence, and workflow into traditional CRM.&lt;br /&gt;
&lt;br /&gt;
I also served as an Entrepreneur in Residence at an east coast venture fund exploring the CRM space.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3011483083044505303-2852091678569872205?l=blog.crmscience.com' alt='' /&gt;&lt;/div&gt;</description><link>http://blog.crmscience.com/2011/12/about-crm-science.html</link><author>noreply@blogger.com (Ami Assayag)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-DNeDIYVmpEE/TwOn2rB5rCI/AAAAAAAAAEE/v-C5N6hl5pw/s72-c/CRMScience_165x165.png" height="72" width="72" /><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3011483083044505303.post-5004209157996089723</guid><pubDate>Tue, 25 May 2010 14:35:00 +0000</pubDate><atom:updated>2012-01-06T10:30:27.294-05:00</atom:updated><title>How to Build a Well Architected SaaS Solution</title><description>About a year ago, I attended Cloudforce in New York City.&amp;nbsp; There were several interesting presentations, including the first peek at Salesforce CRM Content (which I believe is the foundation to Chatter).&amp;nbsp; The most impressive presentation by far, was the one given by Salesforce.com's Chief Software Architect, Craig Weissman, titled &lt;a href="http://www.youtube.com/watch?v=Q9hKeA06j-w&amp;amp;feature=PlayList&amp;amp;p=EE9D8B07E9E5580C&amp;amp;playnext_from=PL&amp;amp;index=7"&gt;True Multi-tenancy: A New Architecture&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
This is a good video for any entrepreneur that is contemplating a new SaaS startup (the good stuff starts five minutes into the video).&amp;nbsp; I don't think that Salesforce.com is doing everything right, but the bottom line is that their system was architected with scalability in mind from the very beginning, and it obviously paid off for them. It seems obvious that you would build a company thinking about that stuff, but it seems like many platforms out there that are not scalable, and once you get trapped with scalability issues, it is hard to fix the problem effectively.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3011483083044505303-5004209157996089723?l=blog.crmscience.com' alt='' /&gt;&lt;/div&gt;</description><link>http://blog.crmscience.com/2010/05/how-to-build-well-architected-saas.html</link><author>noreply@blogger.com (Ami Assayag)</author><thr:total>0</thr:total></item></channel></rss>

