Archive for November, 2009

A very big stack

Monday, November 30th, 2009

In an article about Google’s choice of switching from Gears to the upcoming HTML5 for offline access, Red Write Web referred to a previous post they made about going offline:

We question whether offline access is even necessary. After all… in today’s world, you’re never too far from an internet connection. We concluded that offline access is important now, but less important with each passing day.

In the US and Europe that may be the case, but I’m realizing just how much we take for granted with technology. We talk about turning computing into a utility, while in many places the utilities don’t even run like utilities. It’s been a good shift to start thinking about what we need to do so that the rest of the world can take advantage of the cloud.

The cloud is actually way up on top of a very tall stack of infrastructure that includes:

  • clean water
  • social stability
  • reliable power
  • functioning local economies
  • accessible banking systems
  • and then, finally, affordable, redundant Internet access

That’s quite an infrastructure just to get a service like Salesforce.com or Amazon EC2 to run. And most of the people in the world live in places that are missing big pieces of this stack, so we’ve got lots of work to do before the world can make powerful use of cloud computing, the least of which is HTML5-based offline access.

My Nonprofit Starter Pack Session from Dreamforce 2009

Saturday, November 28th, 2009

Getting the Most of of the Nonprofit Starter Pack. We cover 3 main things:

  1. Configuring the Starter Pack
  2. Importing Contacts via the wizard
  3. Upgrading a package

Feel free to fast forward through the first 4 minutes, where we’re getting 110 people logged into their orgs…

Infographic on the Internet in Africa

Friday, November 27th, 2009

africa-infographic

Great infographic documenting the current state and near future of Internet access in Africa. What I see in these numbers is amazing growth that is poised to explode as the cost per MBPS is expected to drop 90% in the next year. Wow. Another amazing stat–27% of African Internet users are in South Africa.

From Appfrica an entrepreneurial incubator in Uganda.

Inflection Point

Sunday, November 22nd, 2009

Dreamforce is a 4 day software user conference. It’s easy to look at it from afar and see only that–money to be made, customers to retain, sales to be won. And it’s absolutely true that Dreamforce is about all of that. Customers want value. Salesforce.com wants to give it to them. Partners want to get the word out about their solutions. All of that is true.

But I left Dreamforce feeling transformed–personally and professionally. I didn’t expect it. And I’m not exactly sure what to do with it.

I realized last week the reason I took my current job. People ask me all the time. It was clearly a good fit for my skills. The people are great. And it’s a lot of fun. But I realized the real reason last week.

I took this job so that I can help create better lives for millions of people.

Not tens, not hundreds, but millions. Even hundreds of millions. That’s why I’m on this earth. That’s what I think I can contribute to our shared existence. And I think I can do that in my job.

What brought about this clarity? I met some amazing people. I met one woman who has an amazingly clarity of her purpose in life, and that purpose is to help Africa transform itself. To break the colonial, top-down models and return to self-organized, systemic change, completely in partnership with Africans. No more $1M schools dropped from the sky. Holistic, collaborative, community-based change. Generational change. She burns with this goal, and nothing will stand in her way.

Her passion lit a fire in me. And caused me to ask questions of myself. How does my bug fixing contribute to the reemergence of Africa? Am I making the kind of difference I need to make? What can I do differently?

I met a man who has a full-time job and volunteers with a group working in the Sudan. They are building a school from compressed soil, hand dug, hand compressed, and it will be hand built. I had talked to him about his Salesforce needs before I realized he was a volunteer. I thought he was an employee. But it turns out his organization only has one employee. He quietly does this work in his spare time, because he can’t possibly not do it. That wouldn’t make sense to him. And his work is infectious. He asked me, “do you want to go to the Sudan?” Hell yes I want to go to the Sudan.

I met a woman who is taking a holistic approach to education in Tanzania. Children found abandoned in garbage heaps find a home with her organization. They learn and grow because of her work. Their lives are forever changed. She does this work which has nothing to do with her professional history. She was called to it. And is phenomenal.

These people showed me their fire, their passion, the absolute unacceptability of doing nothing. The necessity of action today. The absolute need for impatience and patience all at once. It bowled me over. I’m reeling from it still.

It has caused me to look at my work differently. I will continue to do the best work I possibly can with the responsibilities I have. And I feel compelled to start initiatives of my own. The first thoughts I’ve had is to make Salesforce.com the absolute standard for use in Africa. Here’s what I think needs to be done to show that Salesforce.com can excel for nonprofits in Africa:

Nonprofit Starter Pack

I need to make this code base the best it can be. I want no software bugs standing in the way of this work. It’s the easiest place for me to make an impact on Monday, and I will.

Language Support

Salesforce is translatable into many languages. At this writing, that list includes 20 languages. English, French and Spanish are official languages in many African countries, and those languages are supported currently. I want Salesforce.com to be available in the next tier of African languages: Arabic, Swahili, Portuguese (Brazilian Portuguese is currently available, and maybe that’s close enough?), and perhaps Afrikaans. There are over 2000 languages spoken in Africa, so we may never get to support Berber, Hausa, Xhosa, and the countless others.

Are these the right languages? I’m new to this, but Arabic, Swahili, and Portuguese seem like the place to start. Arabic is a right to left language, so Salesforce.com first must be able to be switched to that mode, but once that’s possible, I want Arabic the next day.

And as soon as Salesforce.com supports a language, we’ll start the work to translate the Nonprofit Starter Pack to that language.

Offline Support

As you know, much of Africa lacks reliable Internet access. Much of Africa lacks clean water, electricity, and other services much more basic than that. So to support Africans working to transform their countries, we need rock-solid offline tools. Salesforce.com has had offline support in Internet Explorer for years, and many African nonprofits are currently using that to successfully support their work.

Salesforce.com recently released Adobe Flashbuilder for Salesforce a toolkit that includes easy to use offline support. I think we need to build some killer offline apps with this toolkit to show the way in this space. Classroom attendance, health clinic service tracking, micro-finance payment collection. We need to build these and share the source code.

Deep Case Studies

I want to work with a few nonprofits in Africa to go deep in their usage of Salesforce.com. I want to hear the stories of how this helps them achieve their goals, and I want to share those stories with the world. Knowing what’s possible is an important step in the path to impact and excellence. We need to prove it, show it, tell it.

I normally don’t share my goals publicly. I like to under promise and over deliver. That’s worked for me for years. But I can’t seem to contain this new fire I feel. So I’m laying out what I want to see happen and I’ll do what I can to bring it about.

If you feel a stirring when you read this, join me. What will we do? I don’t know. How will we do it? We’ll figure it out. But I need to act today. If you feel that need, drop me a line, and we’ll help Africa together.

Using Javascript to validate an Apex form

Monday, November 16th, 2009

Recently I came into a project where an Apex form on a Sites page had to validate itself in Javascript before sending an email via a controller method. I hadn’t ever done this before, so after some digging and some help, I thought I’d share the solution.

First, here is the VisualForce form:

<apex:form id="emailform"  >

<input type="hidden" id="redirect" name="redirect" value="contactus">
Your Email: <apex:inputText value="{!youremail}" id="youremail" maxlength="80" size="40" /><br/>

Subject: <apex:inputText value="{!subject}" id="Subject" maxlength="80" size="40" /><br/>

Message: <apex:inputTextarea value="{!body}" id="Body" rows="6" cols="40"/><br/>
<apex:commandButton value="Send" id="sendButton" onclick="validate3()"/>

	<apex:actionFunction id="emailSendFunction" name="sendEmail" action="{!send}">
		<apex:param name="youremailparam" assignTo="{!youremail}" value=""/>
		<apex:param name="subjectparam" assignTo="{!subject}" value=""/>
		<apex:param name="topicparam" assignTo="{!topic}" value=""/>
		<apex:param name="bodyparam" assignTo="{!body}" value=""/>
	</apex:actionFunction>
</apex:form>

Note that the form doesn’t have an action: we’re invoking code via the onclick action of the command button. When the button is clicked, we’re calling Validate() a Javascript function on the page that looks like this:

function validate() {
     var errorMessage = "Please fix the following errors: \n\n";
     var errorFound = 0; 

     if (!isValidEmail(document.getElementById("about_contact:emailform:youremail").value)) { errorMessage += "Enter a Valid Email Address\n"; errorFound = 1; }
     if (document.getElementById("about_contact:emailform:Subject").value.length == 0) {errorMessage += "Enter a Subject\n"; errorFound = 1; }
     if (document.getElementById("about_contact:emailform:Body").value.length == 0) {errorMessage += "Enter your Message\n"; errorFound = 1; }    

     if (errorFound == 1) {
	alert(errorMessage);
     } else {
	sendEmail();
     }
}

It’s a simple validation scheme. Check a bunch of fields and if they don’t look right, add a message and pop it up to the user. If everything is successful, we call sendEmail().

SendEmail() is the tricky part. It’s actually an Apex controller method exposed as a Javascript function so that it can be called by Javascript. This is done via the ActionFunction tag in Visualforce. You can see it in the VisualForce form above, but I’ll reproduce it here:

	<apex:actionFunction id="emailSendFunction" name="sendEmail" action="{!send}">
		<apex:param name="youremailparam" assignTo="{!youremail}" value=""/>
		<apex:param name="subjectparam" assignTo="{!subject}" value=""/>
		<apex:param name="topicparam" assignTo="{!topic}" value=""/>
		<apex:param name="bodyparam" assignTo="{!body}" value=""/>
	</apex:actionFunction>

The controller’s send method is exposed and 4 parameters are asked for. Each of these parameters are mapped to public variables in the controller, where they are then used by the send method.

public class sffSendEmail {

	public String youremail { get; set; }
	public String subject { get; set; }
	public String topic { get; set; }
	public String body { get; set; }
	public String redirect { get; set; }	// Value tells us where to redirect

	// Constructor
	public sffSendEmail() {
	}

	public PageReference send() {
	 // Define the email
	 Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();

	 String[] toAddresses = new String[] { 'destination@email.com' };

	 // Sets the paramaters of the email
	 email.setSubject( subject );
	 email.setToAddresses( toAddresses );
	 email.setPlainTextBody( 'From: ' + youremail + '\n\n\r' + 'Subject: ' + subject + '\n\n\r' + 'Message: ' + body + '\n\n\r' );

	 // Sends the email
	 Messaging.SendEmailResult [] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {email});

	 PageReference secondPage = Page.confirmation_page;

	 secondPage.setRedirect(true);
	 return secondPage;

	}
}

If you don’t use the param tags and explicitly map the form fields to the public variables, I found that the send method is invoked before the setters have run on your form, leaving you with null variables. Using the params gets the values into those variables for use.

Update: From the comments, Andrew Waite has a better way of constructing the validate() javaScript:

FYI, it’s a best practice to avoid the dependency on the generated DOM ID, i.e.: document.getElementById(”about_contact:emailform:youremail”. You’ve qualified every element in your path which is good but your code is still susceptible to being broken by a new layer in the hierarchy.

The better approach is to define your validation function to accept the DOM IDs as args and use $Component. For example, assume the validate function took one arg for the “youremail” field: function validate(emailid) {….}, and then your onclick would be something like: onclick=”validate({!$component.youremail});”.