I’ve been working on code and content updates to our Force.com Architecture Workshop over the past few weeks. Today I was working on the Visualforce section. It’s easy to forget that Visualforce is a container for just about any web library you can think of. Too often we get stuck on the 80+ tags provided by Salesforce. But in the world of jQuery, HTML5, CSS3 etc, we can do some really cool things.

I’ll be the first to admit I am not a ‘scripting’ expert, but it doesn’t take much work to combine some style, with Salesforce data to produce something like this:

 

The effect is pretty cool, and amazingly simple to do. Let’s start with the controller extension. There is nothing fancy here, just grab all the Contacts for a particular Account:

 

public class AccountsVisualContacts {

    public Account acct {get; set;}
    public Id acctid {get; set;}
    public List<Contact> allContacts { get; set;}

     public AccountsVisualContacts(ApexPages.StandardController stdController) {
        this.acct = (Account)stdController.getRecord();
         allContacts = [select id, Name, FirstName, LastName, Wiki_Link__c, Image_URL__c from Contact where Accountid = :acct.id];
    }
}

Now, we can add the Visualforce page. I ‘borrowed’ the CSS from the net, and added it to the top of my Visualforce page. The rest of the code is leveraging the styles defined within an apex:repeat tag. The only other trick here to include a variable to dynamically increment a counter to allow me to reference the correct CSS style. For this simple example, I am using a predefined number of styles, but there is no reason I could not use the same incrementing variable trick to dynamically set the width and height of my polaroids.

You will also notice that I am using the standard Account controller, and my custom controller as an extension. Using the standard Account controller allows me to link directly to my Visualforce page from a custom button on the Account layout. We’ll see why this is important a bit later. I also added a custom field on the Contact object, Image_URL__c to point to an image source on the internet (specifically, images from wikipedia as we can be pretty comfortable they are not going anywhere)

<apex:page standardController="Account" extensions="AccountsVisualContacts" sidebar="false" >

    <style type="text/css">

    body {
        background-color: #E9E9E9;
        color: #333;
        font-family:"Lucida handwriting", "Snell Roundhand", "Helvetica Neue",Arial,Helvetica,sans-serif;
        font-size: 16px;
    }

    .amp {
        font-family:Garamond,Baskerville,Georgia,serif !important;
        font-style:italic;
        font-weight:normal;
        border: none;
    }

    a.polaroid {
        display: block;
        text-decoration: none;
        color: #333;
        padding: 10px 10px 20px 10px;
        width: 150px;
        border: 1px solid #BFBFBF;
        background-color: white;
        z-index: 2;
        font-size: 0.7em;
        -webkit-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
        -moz-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
        box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
        -webkit-transition: -webkit-transform 0.5s ease-in;
    }
    a.polaroid:hover,
    a.polaroid:focus,
    a.polaroid:active {
        z-index: 999;
        border-color: #6A6A6A;
        -webkit-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
        -moz-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
        box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
        -webkit-transform: rotate(0deg);
        -moz-transform: rotate(0deg);
        transform: rotate(0deg);
    }
    .polaroid img {
        margin: 0 0 15px;
        width: 150px;
        height: 150px;
    }

    a img {
        border: none;
        display: block;
    }

    .photo-album {
        position: relative;
        width: 80%;
        margin: 0 auto;
        max-width: 70em;
        height: 450px;
        margin-top: 5em;
        min-width: 800px;
        max-width: 900px;
    }
    .photo-album .polaroid {
        position: absolute;
    }
    .photo-album h1 {
        position: absolute;
        z-index: 5;
        top: 150px;
        text-align: center;
        width: 100%;
        line-height: 1.9;
    }
    .photo-album h1 span {
        background-color: white;
        font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;
        padding: 0.4em 0.8em 0.3em 0.8em;
        -webkit-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
        -moz-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
        box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
        border: 1px solid #6A6A6A;
    }
    .photo-album .small {
        width: 75px;
        padding: 6px 6px 12px 6px;
        font-size: 0.6em;
    }
    .photo-album .small img {
        width: 75px;
        height: 75px;
    }
    .photo-album .medium {
        width: 200px;
        padding: 13px 13px 26px 13px;
        font-size: 0.8em;
    }
    .photo-album .medium img {
        width: 200px;
        height: 200px;
    }
    .photo-album .large {
        width: 300px;
        padding: 20px 20px 30px 20px;
        font-size: 1em;
    }
    .photo-album .large img {
        width: 300px;
        height: 300px;
    }
    .photo-album .img1 {
        bottom: 10px;
        right: 365px;
        -webkit-transform: rotate(10deg);
        -moz-transform: rotate(10deg);
        transform: rotate(10deg);
    }
    .photo-album .img2 {
        top: 50px;
        right: 20px;
        -webkit-transform: rotate(-4deg);
        -moz-transform: rotate(-4deg);
        transform: rotate(-4deg);
    }
    .photo-album .img3 {
        left: 400px;
        top: 0;
        -webkit-transform: rotate(-5deg);
        -moz-transform: rotate(-5deg);
        transform: rotate(-5deg);
    }
    .photo-album .img4 {
        top: 10px;
        left: 495px;
        -webkit-transform: rotate(-20deg);
        -moz-transform: rotate(-20deg);
        transform: rotate(-20deg);
    }
    .photo-album .img5 {
        bottom: 0;
        right: 0;
        -webkit-transform: rotate(1deg);
        -moz-transform: rotate(1deg);
        transform: rotate(1deg);
    }
    .photo-album .img6 {
        bottom: 10px;
        right: 156px;
        -webkit-transform: rotate(6deg);
        -moz-transform: rotate(6deg);
        transform: rotate(6deg);
    }
    .photo-album .img7 {
        bottom:0;
        left:400px;
        -webkit-transform: rotate(-10deg);
        -moz-transform: rotate(-10deg);
        transform: rotate(-10deg);
    }
    .photo-album .img8 {
        bottom: -20px;
        left: 700px;
        -webkit-transform: rotate(-8deg);
        -moz-transform: rotate(-8deg);
        transform: rotate(-8deg);
    }
    .photo-album .img9 {
        bottom: 0;
        left: 0;
        -webkit-transform: rotate(-8deg);
        -moz-transform: rotate(-8deg);
        transform: rotate(-8deg);
    }
    .photo-album .img10 {
        top: 0;
        left: 20px;
        -webkit-transform: rotate(8deg);
        -moz-transform: rotate(8deg);
        transform: rotate(8deg);
    }

    a:hover,
    a:focus {
        z-index: 5;
    }

    </style>

    <div class="photo-album">

        <h1><span>Contacts of {!account.name}</span></h1>

        <apex:variable var="count" value="{!1}"/>
        <apex:repeat value="{!allContacts}" var="c">

        <apex:outputLink value="/{!c.id}" styleClass="medium polaroid img{!Round(count,0)}"
         target="_blank"><img src="{!c.Image_URL__C}" alt="{!c.Name}" />{!c.Name}</apex:outputLink>

        <apex:variable var="count" value="{!count + 1}"/>
        </apex:repeat>

    </div>

</apex:page>

Ok, all the hard stuff is done. All that is left is to add a custom button to our Account Details, and point it to the Visualforce page:


That’s it. Load this into your Salesforce org, and you are good to go!

tagged , , Bookmark the permalink. Trackbacks are closed, but you can post a comment.
  • http://twitter.com/forceguru Ankit Arora

    Creative and awesome post! Thanks for sharing this.

  • Jitendra Zaa

    Nice, innovative article and cool effect.

  • http://siddheshkabe.co.in Siddhesh Kabe

    good one

  • http://www.facebook.com/rgao2009 Raymond Gao

    awesome write up. I have been drooling over a good css3 article. :-)

  • 昭宏 岩谷

    Thank for your sharing!!
    I make package for this app so please follow steps below.

    Installation URL https://login.salesforce.com/packaging/installPackage.apexp?p0=04t10000000Lj07
    1. Add “Visual Contacts” custom button to your layout at Account detail page
    2. Add Image_URL filed to your layout at Contact detail page
    3. Fill out value at Image_URL field
    4. Go to an Account detail page and press “Visual Contracts” button

  • Abhinav Gupta

    Awesome post Quinton

  • Antony Gomes

    Nwebie question: So can we use the same kind of code to display in organized square the lastest 10 contact for example. ( my users aren’t friend with computer i have to create something more “Visual”)