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:
1public class AccountsVisualContacts {
2
3 public Account acct {get; set;}
4 public Id acctid {get; set;}
5 public List<Contact> allContacts { get; set;}
6
7 public AccountsVisualContacts(ApexPages.StandardController stdController) {
8 this.acct = (Account)stdController.getRecord();
9 allContacts = [select id, Name, FirstName, LastName, Wiki_Link__c, Image_URL__c from Contact where Accountid = :acct.id];
10 }
11}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)
1<apex:page standardController="Account" extensions="AccountsVisualContacts" sidebar="false" >
2
3 <style type="text/css">
4
5 body {
6 background-color: #E9E9E9;
7 color: #333;
8 font-family:"Lucida handwriting", "Snell Roundhand", "Helvetica Neue",Arial,Helvetica,sans-serif;
9 font-size: 16px;
10 }
11
12 .amp {
13 font-family:Garamond,Baskerville,Georgia,serif !important;
14 font-style:italic;
15 font-weight:normal;
16 border: none;
17 }
18
19 a.polaroid {
20 display: block;
21 text-decoration: none;
22 color: #333;
23 padding: 10px 10px 20px 10px;
24 width: 150px;
25 border: 1px solid #BFBFBF;
26 background-color: white;
27 z-index: 2;
28 font-size: 0.7em;
29 -webkit-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
30 -moz-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
31 box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
32 -webkit-transition: -webkit-transform 0.5s ease-in;
33 }
34 a.polaroid:hover,
35 a.polaroid:focus,
36 a.polaroid:active {
37 z-index: 999;
38 border-color: #6A6A6A;
39 -webkit-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
40 -moz-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
41 box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
42 -webkit-transform: rotate(0deg);
43 -moz-transform: rotate(0deg);
44 transform: rotate(0deg);
45 }
46 .polaroid img {
47 margin: 0 0 15px;
48 width: 150px;
49 height: 150px;
50 }
51
52 a img {
53 border: none;
54 display: block;
55 }
56
57 .photo-album {
58 position: relative;
59 width: 80%;
60 margin: 0 auto;
61 max-width: 70em;
62 height: 450px;
63 margin-top: 5em;
64 min-width: 800px;
65 max-width: 900px;
66 }
67 .photo-album .polaroid {
68 position: absolute;
69 }
70 .photo-album h1 {
71 position: absolute;
72 z-index: 5;
73 top: 150px;
74 text-align: center;
75 width: 100%;
76 line-height: 1.9;
77 }
78 .photo-album h1 span {
79 background-color: white;
80 font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;
81 padding: 0.4em 0.8em 0.3em 0.8em;
82 -webkit-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
83 -moz-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
84 box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
85 border: 1px solid #6A6A6A;
86 }
87 .photo-album .small {
88 width: 75px;
89 padding: 6px 6px 12px 6px;
90 font-size: 0.6em;
91 }
92 .photo-album .small img {
93 width: 75px;
94 height: 75px;
95 }
96 .photo-album .medium {
97 width: 200px;
98 padding: 13px 13px 26px 13px;
99 font-size: 0.8em;
100 }
101 .photo-album .medium img {
102 width: 200px;
103 height: 200px;
104 }
105 .photo-album .large {
106 width: 300px;
107 padding: 20px 20px 30px 20px;
108 font-size: 1em;
109 }
110 .photo-album .large img {
111 width: 300px;
112 height: 300px;
113 }
114 .photo-album .img1 {
115 bottom: 10px;
116 right: 365px;
117 -webkit-transform: rotate(10deg);
118 -moz-transform: rotate(10deg);
119 transform: rotate(10deg);
120 }
121 .photo-album .img2 {
122 top: 50px;
123 right: 20px;
124 -webkit-transform: rotate(-4deg);
125 -moz-transform: rotate(-4deg);
126 transform: rotate(-4deg);
127 }
128 .photo-album .img3 {
129 left: 400px;
130 top: 0;
131 -webkit-transform: rotate(-5deg);
132 -moz-transform: rotate(-5deg);
133 transform: rotate(-5deg);
134 }
135 .photo-album .img4 {
136 top: 10px;
137 left: 495px;
138 -webkit-transform: rotate(-20deg);
139 -moz-transform: rotate(-20deg);
140 transform: rotate(-20deg);
141 }
142 .photo-album .img5 {
143 bottom: 0;
144 right: 0;
145 -webkit-transform: rotate(1deg);
146 -moz-transform: rotate(1deg);
147 transform: rotate(1deg);
148 }
149 .photo-album .img6 {
150 bottom: 10px;
151 right: 156px;
152 -webkit-transform: rotate(6deg);
153 -moz-transform: rotate(6deg);
154 transform: rotate(6deg);
155 }
156 .photo-album .img7 {
157 bottom:0;
158 left:400px;
159 -webkit-transform: rotate(-10deg);
160 -moz-transform: rotate(-10deg);
161 transform: rotate(-10deg);
162 }
163 .photo-album .img8 {
164 bottom: -20px;
165 left: 700px;
166 -webkit-transform: rotate(-8deg);
167 -moz-transform: rotate(-8deg);
168 transform: rotate(-8deg);
169 }
170 .photo-album .img9 {
171 bottom: 0;
172 left: 0;
173 -webkit-transform: rotate(-8deg);
174 -moz-transform: rotate(-8deg);
175 transform: rotate(-8deg);
176 }
177 .photo-album .img10 {
178 top: 0;
179 left: 20px;
180 -webkit-transform: rotate(8deg);
181 -moz-transform: rotate(8deg);
182 transform: rotate(8deg);
183 }
184
185 a:hover,
186 a:focus {
187 z-index: 5;
188 }
189
190 </style>
191
192 <div>
193
194 <h1><span>Contacts of {!account.name}</span></h1>
195
196 <apex:variable var="count" value="{!1}"/>
197 <apex:repeat value="{!allContacts}" var="c">
198
199 <apex:outputLink value="/{!c.id}" styleClass="medium polaroid img{!Round(count,0)}"
200 target="_blank"><img src="{!c.Image_URL__C}" alt="{!c.Name}" />{!c.Name}</apex:outputLink>
201
202 <apex:variable var="count" value="{!count + 1}"/>
203 </apex:repeat>
204
205 </div>
206
207</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!