Oh my god. It's full of code!

Posts tagged “javascript

Mimicking callback functions for Visualforce ActionFuncitons

Hey everyone. So I’ve got a nifty ‘approach’ for you this time around. So let me give you a quick run down on what I was doing, the problem I encountered and how I decided to solve it using what I believe to be a somewhat novel approach. The deal is that I have been working on a fairly complicated ‘one page’ app for mobile devices. What I decided to do was have one parent visualforce page, and a number of components that are hidden and shown depending on what ‘page’ the user is on. This allows for a global javascript scope to be shared between the components and also for them to have their own unique namespaces as well. I may cover the pros and cons of this architecture later.

The issue I started to have, is that I wanted some action functions on the main parent container page to be used by the components in the page. That’s fine, no problem there. The issue becomes the fact that since actionFunctions are asynchronous, and do not allow for dynamic callback functions anything that wants to invoke your actionFunction is stuck having the same oncomplete function as all the functions that may want to invoke it. So if component A and component B both want to invoke ActionFunctionZ they both are stuck with the same oncomplete function, and since it’s async there is no good way to know when it’s done. Or is there?

My solution to this problem doesn’t use any particularity amazing hidden features, just a bit of applied javascript knowledge. What we are going to do is create a javascript object in the global/top level scope. That object is going to have properties that match the names of action functions. The properties will contain the function to run once the action function is complete. Then that property will be deleted to clean up the scope for the next caller. That might sound a little whack. Here let’s check an example.

    <style>
        #contentLoading
        {
            height: 100%;
            width: 100%;
            left: 0;
            top: 0;
            overflow: hidden;
            position: fixed; 
            display: table;
            background-color: rgba(9, 9, 12, 0.5);  
              
        }
        #spinnerContainer
        {
            display: table-cell;
            vertical-align: middle;        
            width:200px;
            text-align:center;
            margin-left:auto;
            margin-right:auto;
        }

        div.spinner {
          position: relative;
          width: 54px;
          height: 54px;
          display: inline-block;
        }
        
        div.spinner div {
          width: 12%;
          height: 26%;
          background: #fff;
          position: absolute;
          left: 44.5%;
          top: 37%;
          opacity: 0;
          -webkit-animation: fade 1s linear infinite;
          -webkit-border-radius: 50px;
          -webkit-box-shadow: 0 0 3px rgba(0,0,0,0.2);
        }
        
        div.spinner div.bar1 {-webkit-transform:rotate(0deg) translate(0, -142%); -webkit-animation-delay: 0s;}    
        div.spinner div.bar2 {-webkit-transform:rotate(30deg) translate(0, -142%); -webkit-animation-delay: -0.9167s;}
        div.spinner div.bar3 {-webkit-transform:rotate(60deg) translate(0, -142%); -webkit-animation-delay: -0.833s;}
        div.spinner div.bar4 {-webkit-transform:rotate(90deg) translate(0, -142%); -webkit-animation-delay: -0.75s;}
        div.spinner div.bar5 {-webkit-transform:rotate(120deg) translate(0, -142%); -webkit-animation-delay: -0.667s;}
        div.spinner div.bar6 {-webkit-transform:rotate(150deg) translate(0, -142%); -webkit-animation-delay: -0.5833s;}
        div.spinner div.bar7 {-webkit-transform:rotate(180deg) translate(0, -142%); -webkit-animation-delay: -0.5s;}
        div.spinner div.bar8 {-webkit-transform:rotate(210deg) translate(0, -142%); -webkit-animation-delay: -0.41667s;}
        div.spinner div.bar9 {-webkit-transform:rotate(240deg) translate(0, -142%); -webkit-animation-delay: -0.333s;}
        div.spinner div.bar10 {-webkit-transform:rotate(270deg) translate(0, -142%); -webkit-animation-delay: -0.25s;}
        div.spinner div.bar11 {-webkit-transform:rotate(300deg) translate(0, -142%); -webkit-animation-delay: -0.1667s;}
        div.spinner div.bar12 {-webkit-transform:rotate(330deg) translate(0, -142%); -webkit-animation-delay: -0.0833s;}
    
         @-webkit-keyframes fade {
          from {opacity: 1;}
          to {opacity: 0.25;}
        }    	
	</style>
	
		var globalScope = new Object();
		
		function actionFunctionOnCompleteDispatcher(functionName)
		{
			console.log('Invoking callback handler for ' +functionName);
			console.log(globalScope.actionFunctionCallbacks);
			
			if(globalScope.actionFunctionCallbacks.hasOwnProperty(functionName))
			{
				console.log('Found registered function. Calling... ');
				console.log(globalScope.actionFunctionCallbacks.functionName);
				globalScope.actionFunctionCallbacks[functionName]();
				delete globalScope.actionFunctionCallbacks.functionName;
			}
			else
			{
				console.log('No callback handler found for ' + functionName);
			}    
		}         
		
		function registerActionFunctionCallback(functionName, callback)
		{
			console.log('Registering callback function for ' + functionName + ' as ' + callback);
			globalScope.actionFunctionCallbacks[functionName] = callback;
			
			console.log(globalScope.actionFunctionCallbacks);
		} 
		
		function linkActionOne(dataValue)
		{
			registerActionFunctionCallback('doThing', function(){
				console.log('Link Action Two was clicked. Then doThing action function was called. Once that was done this happened');
				alert('I was spawened from link action 1!');
			});		
			
			doThing(dataValue);
		}
		
		function linkActionTwo(dataValue)
		{
			registerActionFunctionCallback('doThing', function(){
				console.log('Link Action Two was clicked. Then doThing action function was called. Once that was done this happened');
				alert('I was spawened from link action 2!');
			});		

			doThing(dataValue);
		}

		function loading(isLoading) {
			if (isLoading) 
			{            
				$('#contentLoading').show();
			}
			else {
				$('#contentLoading').hide();
			}	
		}		
    
	
	<apex:form >
		<apex:actionFunction name="doThing" action="{!DoTheThing}" reRender="whatever" oncomplete="actionFunctionOnCompleteDispatcher('doThing');">
			<apex:param name="some_data"  value="" />
		</apex:actionFunction>
		
		<apex:actionStatus id="loading" onstart="loading(true)" onstop="loading(false)" />
	
		<a href="#" onclick="linkActionOne('Link1!')">Link One!</a>
		<a href="#" onclick="linkActionTwo('Link2!')">Link Two!</a>

		
id="contentLoading" style="display:none">
id="spinnerContainer">
class="spinner">
class="bar1">
class="bar2">
class="bar3">
class="bar4">
class="bar5">
class="bar6">
class="bar7">
class="bar8">
class="bar9">
class="bar10">
class="bar11">
class="bar12">
</div> </div> </div> </apex:form>

So what the hell is going on here? Long story short we have two links which both call the same actionFunction but have different ‘callbacks’ that happen when that actionFunction is complete. I was trying to come up with a more interesting example, but I figured I should keep it simple for sake of explanation.  You click link one, the doThing action is called. Then it calls the actionFunctionOnCompleteDispatcher function with it’s own name. That function looks to see if any callbacks have been registered for that function name. If so, it is called. If not, it just doesn’t do anything. Pretty slick eh? You may be wondering why I included all that code with the action status, the loading animation, the overlay and all that. Not really relevant to what we are doing right (though the animation is cool.)? The answer to that is (other than the fact you get a cool free loading mechanism), this approach as it stands will start to run into odd issues if you users clicks link2 before link1 has finished doing it’s work. The callback function registered by 2 would get called twice. Once the call to doThing from link1 one its going to call whatever function is registered, even if that means the click from link2 overwrote what link1 set.  I am thinking you could probably get around this by making the property of the global object an array instead of just a reference to a function. Each call would just push it’s requested callback into the array and then as they were called they would be removed from the array, but I haven’t played with this approach yet (‘I’m pretty sure it would work, I’m just too lazy and tired to write it up for this post. If there is interest I’ll do it later). In any case putting up a blocking loading screen while the action function does its work ensures that the user cannot cause any chaos by mashing links and overwriting callbacks.

The thing that is kind of cool about this which becomes clear pretty quick is that you can start ‘chaining’ callbacks. So you can have a whole series of action functions that all execute in sequence instead of just running async all over the place. So you can do things like this. Also make note of the commenting. The thing about callbacks is you can quickly end up ‘callback hell’ where it gets very difficult to track what is happening in what order. So I at least attempt to label them in an effort to stem the madness. This is just a quick copy paste from the thing I’m actually working on to give you a flavor of how the chaining can work.

//once a project has been created we need to clear out any existing temp record, then set the type of the new/current temp record as being tpe. Then finally
//we have to set the project Id on that temp record as the one we created. Then finally we can change page to the select accounts screen.
VSD_SelectProject.addNewTpeComplete = function()
{

	//order 2: happens after clearTempRecord is done 
	//once the existing temp record has been cleared and a new one is created, get a new temp record and set the type as tpe
	registerActionFunctionCallback('clearTempRecord', function(){
		setRequestType('tpe');
	});
				
	//order 3: happens after setRequestType is done 
	//once set request type is done (which means we should now have a temp record in the shared scope, then call set project id
	registerActionFunctionCallback('setRequestType', function(){
		setProjectId('{!lastCreatedProjectId}');
	});

	//order 4: happens after setProjectId is done 
	//once set project id is called and completed change the page to the new_pcr_start (poorly named, it should actually be called select_accounts
	registerActionFunctionCallback('setProjectId', function(){
		setTitle('New TPE Request');
		setSubHeader('Select Accounts');
					
		changePage('new_pcr_start');
	});
	 
	//order 1: happens first. Kicks off the callback chain defined above.                                                
	clearTempRecord();                
}

Anyway, I hope this might help some folks. I know it would be easy to get around this issue in many cases by just creating many of the ‘same’ actionFunction just with different names and callbacks but who want’s dirty repetitive code like that?

Tune in next time as I reveal the solution to an odd ‘bug’ that prevents apex:inputFields from binding to their controller values. Till next time!

-Kenji


Building a Better WordCloud

Hey all,

I know it’s been a while since my last post. Fun projects with cool end results have been rare and I’m not the type to post stuff just to fill space so I’ve kinda just been chillin recently. Though that changed when I was asked to take another whack at putting together a word cloud app, this time for Salesforce. You may or may not remember that I created a small word cloud app a while ago that didn’t have much anything to do with Salesforce and used a PHP back end that took free text replies from lime survey and created a real time word cloud. This time the task is a little different. I was asked to create a word cloud application that would take data from multiple records, and multiple fields, aggregate it all together and create a cloud from the resulting text blob. Real time updating was not requested, so I had some more flexibility in architecture. I also wanted to take this change to upgrade the actual display a bit since I wasn’t very pleased with my last attempt (it was functional, but a little clunky. Manual CSS rules specified formatting, etc).

Since I knew there must be a good word cloud generator out there I did a bit of searching and decided on the jQuery plugin ‘awesomeCloud’ which makes very stylish clouds without being overly complex. It’s licensing is pretty open (GPL v3) so it looked like a good fit. You can check out some of the sample word clouds in generates on the awesomeCloud demo page. It’s got some nice options for themeing, cloud shape, normalization and more.

So invocation is the word cloud is pretty easy, you just need to create a div with spans in it that have a data-weight attribute that specifies the frequency of that word. You then just call the plugin with the options you want on the container div. Like so

Example of creating a wordcloud (taken from the github page of awesomeCloud)

Example of creating a wordcloud (taken from the github page of awesomeCloud)

Easy enough? But now comes the tricky part, how do we get the data from the objects and fields count the word frequencies and then insert them into the DOM? That is where we come in. I decided that since this is going to be a pretty light weight application with most likely fairly small queries we could get away with using the ajax toolkit thus avoiding the extra complexities of Apex controllers. As usual I’m defaulting to using javascript where I can. You could of course modify the approach below to use Apex if it makes you happier. Whatever works for you. Anyway, lets get on with it.

I decided that since this code may be used in different places to do different things (maybe some inline pages, a stand alone VF page, a dashboard component maybe?), it made sense to make it into a component. Makes it easier to pass in configuration parameters as well, which I figured people would want to do. I’d recommend doing the same. First up lets go ahead of define the parameters we are going to allow to be passed into the component. Most of these are for configuring the word cloud itself, but there are a few others.

    <apex:attribute name="objectType" description="type of records to get data from" type="String" required="true"/>
    <apex:attribute name="records" description="records to get data from" type="String" required="false"/>
    <apex:attribute name="fields" description="fields on records to aggregate data from" type="String" required="true" default="Name"/> 

    <apex:attribute name="lowerbound" description="words below this frequency will not be dipslayed" type="String" required="false" default="0"/> 
    <apex:attribute name="skipwords" description="words not to display regardless of frequency" type="String" required="false" default="and,the,to,a,of,for,as,i,with,it,is,on,that,this,can,in,be,has,if"/> 

    <apex:attribute name="grid" description="word spacing; smaller is more tightly packed but takes longer" type="integer" required="false" default="8"/>    
    <apex:attribute name="factor" description="font resizing factor; default 0 means automatically fill the container" type="integer" required="false" default="0"/>
    <apex:attribute name="normalize" description="reduces outlier weights for a more attractive output" type="boolean" required="false" default="false"/> 

    <apex:attribute name="font" description=" font family, identical to CSS font-family attribute" type="string" required="false" default="Futura, Helvetica, sans-serif"/> 
    <apex:attribute name="shape" description="one of 'circle', 'square', 'diamond', 'triangle', 'triangle-forward', 'x', 'pentagon' or 'star'" type="string" required="false" default="circle"/> 

    <apex:attribute name="backgroundColor" description="background color" type="string" required="false" default="transparent"/>
    <apex:attribute name="colorTheme" description="dark or light" type="string" required="false" default="light"/>

    <apex:attribute name="width" description="how wide should the cloud be (css values such as a pixel or inch amount)?" type="string" required="false" default="600px"/>  
    <apex:attribute name="height" description="how tal; should the cloud be (css values such as a pixel or inch amount)?" type="string" required="false" default="400px"/>  
    <apex:attribute name="autoRefresh" description="should the wordcloud automatically refresh every so often?" type="boolean" required="false" default="false"/>

    <apex:attribute name="refreshInterval" description="how often shold the cloud refresh? In seconds" type="integer" required="false" default="5"/>

Of course you’ll need to include the required javascript libraries.

<script src="//code.jquery.com/jquery-latest.js"></script>
<script src="{!$Resource.jQueryWordCloud}"/>
<apex:includeScript value="/soap/ajax/15.0/connection.js"/>
<apex:includeScript value="/soap/ajax/15.0/apex.js"/>

Now we’ll need to start putting together the javascript functions to get the data and do the word frequnecy analysis. First up, lets create a javascript method that can build a dynamic query to get all the required data. Using the ajax toolkit it looks something like this

function getData(objectType,recordIds, fields)
{
    //build the basic SOQL query string
    var queryString = "Select "+fields+" from "+objectType;

    //if we are limiting the query by searching for specific object ids then add that condition
    if(recordIds.length > 0)
    {
        var whereStatment = "('" + recordIds.split("','") + "')";
        queryString += ' where id in ' + whereStatment;
    }
    //make sure to put a limit on there to stop big query errors.
    queryString += ' limit 2000';

    //run the query
    result = sforce.connection.query(queryString);

    //get the results
    records = result.getArray("records");

    //lets aggregate all the fetched data into one big string
    var wordArray = [];

    //we want to build an array that contains all the words in any of the requested fields. So we will
    //put all the desired fields into an array, iterate over all the records, then over all the fields
    //and stash all the data in another array.

    //fields is a comma separated string. Lets split it into an array so we can iterate over them easily 
    var fieldsArray = fields.split(',');

    //loop over all the records
    for (var i=0; i< records.length; i++)
    {
        var record = records[i];
        //loop over all the fields that we care about
        for(var j=0; j<fieldsArray.length; j++)
        {
            //get the value of this field from this record and add it to the array
            wordArray.push(record[fieldsArray[j]]);
        }
    }  
    //we will now pass in all the words from all the records fields into the getWordFrequnecy function. By calling join
    //on the array with a space character we get one big ass text chunk with all the words from all the records.

    var frequencyResult = getWordFrequency(wordArray.join(' '));

    //pass our frequnecy result data into the load cloud function
    loadCloud(frequencyResult); 
}

With that we can pass in an sObject type, an optional list of record ids (comma separated) and a list of fields to get data from on those records (also comma separated). Now we need to build the getWordFrequency function. That’s going to take a chunk of text and return an array of objects that contain a tag property, and a freq property. That data then gets fed into awesomeCloud to generate the cloud.

            //takes a string and counts the freqnecy of each word in it. Returns array of objects with tag and freq properties.
            //words should be space separated
            function getWordFrequency(wordString){

                //convert string to lower case, trims spaces, cleans up some special chars and splits it into an array using spaces and delimiter.
                var sWords = wordString.toLowerCase().trim().replace(/[,;.]/g,'').split(/[\s\/]+/g).sort();
                var iWordsCount = sWords.length; // count w/ duplicates

                // array of words to ignore
                var ignore = '{!skipwords}'.split(',');
                ignore = (function(){
                    var o = {}; // object prop checking > in array checking
                    var iCount = ignore.length;
                    for (var i=0;i<iCount;i++){
                        o[ignore[i]] = true;
                    }
                    return o;
                }());

                var counts = {}; // object for math
                for (var i=0; i<iWordsCount; i++) {
                    var sWord = sWords[i];
                    if (!ignore[sWord]) {
                        counts[sWord] = counts[sWord] || 0;
                        counts[sWord]++;
                    }
                }

                //get the lower bound as an integer. Lower bound controls the minimum frequnecy a word/tag can have for it to appear in the cloud
                var lowerBound = parseInt({!lowerbound},10);
                var arr = []; // an array of objects to return
                for (sWord in counts) {
                    if(counts[sWord] > lowerBound)
                    {
                        arr.push({
                            tag: sWord,
                            freq: counts[sWord]
                        });
                    }
                }

                /* Sorting code, not really required for this purpose but kept in case it is decided that we want it for some reason.
                // sort array by descending frequency | http://stackoverflow.com/a/8837505
                return arr.sort(function(a,b){
                    return (a.freq > b.freq) ? -1 : ((a.freq < b.freq) ? 1 : 0);
                });
                */

                return arr;

            }

Alright, so now we have all the data from all the records analyzed and the frequency of each word is known. Words we have decided to skip have been left out and those that don’t make the cut from the lower bound are also excluded hopefully leaving us only with actually interesting words. Now we have to pass in the that data to awesomeCloud along with our settings.

function loadCloud(data) 
{ 
    //wordcloud settings
    var settings = {
            size : {
                grid : {!grid},
                factor : {!factor},
                normalize: {!normalize}
            },
            color : {
                background: "{!backgroundColor}"
            },
            options : {
                color : "random-{!colorTheme}",
                rotationRatio : 0.5
            },
            font : "{!font}",
            shape : "{!shape}"
    } 

    //create array for tag spans
    var wordStringArray = [];

    //evaluate each array element, create a span with the data from the object
    $.each(data, function(i, val)
    {
        wordStringArray.push('<span data-weight="'+val.freq+'">'+val.tag+'</span>');
    });

    //join all the array elements into a string. I've heard to push stuff into array and join then push to the DOM is faster than
    //than modifying a string (since strings are unmutable) or modifying the DOM a ton, which makes sense.
    $( "#wordcloud" ).html(wordStringArray.join(''));

    //setup our word cloud
    $( "#wordcloud" ).awesomeCloud( settings );
}

Alright, so now we just need to invoke all this these crazy functions. We’ll do that with a functional call in the document onready to make sure everything is loaded before we start going all crazy modifying the DOM and such.

//login to salesforce API so we can run query
sforce.connection.sessionId = '{!$Api.Session_ID}';
$(document).ready(function() {
    //make an immediate call to getData with the info we need from the config params.
    getData('{!objectType}', '{!records}', '{!fields}');

    //if we are doing an auto refresh, rig that up now using the setInterval method
    if({!autoRefresh})
    {
        setInterval ( "getData('{!objectType}', '{!records}', '{!fields}')", parseInt({!refreshInterval},10) * 1000 );
    }
});

Finally we just need to create our HTML container for the wordcloud and setup the CSS style.

    <style>

    .wordcloud {
        /*border: 1px solid #036;*/
        height: {!height};
        margin: 0.5in auto;
        padding: 0;
        page-break-after: always;
        page-break-inside: avoid;
        width: {!width};

    }

    </style>
    <div id="container" title="wordcloud with the content of fields {!fields} for objects {!records}"> 

        <div id="wordcloud" class="wordcloud" ></div>
    </div>

Whew, alright so that’s it for our component. Now we just need a visualforce page to invoke it. That part is easy. Although our word cloud is capable of aggreating data from multiple objects, for this demo we’ll keep it simple. We will create a little inline visualforce page that can live on the account object. It will create a wordcloud from the description, name, type and ownership fields. To do that, create a visualforce page like this

<apex:page standardController="account">
    <!--- 
    WordCloud comes as a component that can be invoked from any visualforce page. You must pass it the object type to build the cloud for. The rest is optional.
    objectType: the type of sObject to get data from to power the word cloud
    fields: the records on the objects who's content will be used to create the cloud. Must be comma separated
    records: a list of ids which to query for. If none is provided all records of the objectType are queried
    skipwords: words that will not be included in the word cloud no matter how many times they appear. 
    lowerbound: the minimum number of times a word must appear in the text before it is displayed in the cloud.
    grid: word spacing; smaller is more tightly packed but takes longer
    factor: font resizing factor; default "0" means automatically fill the container
    normalize: reduces outlier weights for a more attractive output
    shape: shape of the cloud. Must be one of "circle", "square", "diamond", "triangle", "triangle-forward", "x", "pentagon" or "star"
    font: font family, identical to CSS font-family attribute
    width: width of the cloud. Can be a percent or pixel/inch amount.
    height: height of the cloud. Must be a pixel or inch amount.
    backgroundColor: a hexidecimal (#000000) or string color value. Use 'transparent' for no background
    colorTheme: theme for word colors. Use 'dark' or 'light'
    autoRefresh: automatically refresh the cloud after a specified interval?
    refreshInterval: interval (in seconds) after which the cloud is automatically refreshed
    --->
    <c:wordCloud objectType="account" 
                 records="{!account.id}" 
                 fields="Name,Type,Ownership,Description"
                 lowerbound="1"
                 skipwords="and,an,any,so,or,are,the,to,a,of,for,as,i,with,it,is,on,that,this,can,in,be,has,if"
                 grid="8"
                 factor="0"
                 normalize="false"
                 font="Futura, Helvetica, sans-serif"
                 shape="triangle"
                 width="100%"
                 height="400px" 
                 backgroundColor="black"
                 colorTheme="light" 
                 autoRefresh="false" 
                 refreshInterval="15" />
</apex:page>

Save that page and add it to the page layout of the account. Put a nice big blob of text in the description of an account and see what happens. For my example I figured it would be fitting to copy and paste text from the frequency analysis page of wikipedia. The result looks like this.

Result of WordCloud

Pretty cool eh? Anyway this was just something I threw together in an hour or two, hopefully it’s useful to someone out there. Let me know what ya think!


Javascript Console

So I just wrapped up another Cloudspokes challenge.I spent way too much time on this. Really it’s just a dumb little $300 dollar challenge, and I think I put like 10 or so hours into this, but whatever, it was fun. I probably went overboard, but I think I made something actually kind of useful. First, before I get too deep into it, check out the challenge details.

http://www.cloudspokes.com/challenges/1999

The basic idea being that they wanted a way to run javascript on a web page, similar to Firebug or the Chrome developer tools. They also suggested adding a list of the user/developer defined functions and maybe an auto complete system to make entering the code to run easier. I wanted to take it a step further and build it all as pure javascript so that it could be turned into a bookmarklet. With it all delivered as a bookmarklet that means you can inject this console on any webpage anywhere without needing access to the source and start running functions on it. You don’t need to include any additional libraries or hooks or anything. You need NO access to the source code of the webpage for this to work, which is what really makes it cool.

It does this by using javascript to dynamically inject jQuery, jQuery UI, and bootstrap (only if needed, it’s smart enough not to double include libraries), and builds the console directly by inserting it into the DOM. It uses some tricky looping and evaluation to find all exisitng functions, list them, and get the function bodies as well. It creates an input area where javascript code can be entered, and the results are displayed in a console using intelligent return type handling. Using a bit of bootstrap for autocomplete, buttons, and the collapsible side list view it creates a simple yet powerful interface. As a neat side effect I found what is probably the end all, be all way to inject scripts that may or may not be present and rely on each other. I’m hoping to make a blog post out of that technique pretty soon. It uses some neat recursion and callbacks to work it’s magic and the end result is very efficient and reliable.

Anyway, check out the video for a better understanding/demo of what it can do.

http://www.screencast.com/t/jVUo5Qsh5 <- Demo video

To try it out, make a bookmark a new bookmark, and set it’s path to this. Sorry I can’t make a bookmarklet link here for you, wordpress keeps killing the link.  It might take a little bit of time to load on very complicated pages. Also it does support pressing up and down in the input box to flip between previously entered commands.

javascript: (function(){var jsCode=document.createElement('script');jsCode.setAttribute('src','https://dl.dropbox.com/u/65280390/jsConsoleScript.js');document.body.appendChild(jsCode);}());

Apex Captcha with Javascript Remoting and jQuery

So at one time or another, we’ll likely all have to create a public facing form to collect data. We will also find about 2 seconds afterwards that it is getting spammed to hell. To stop the flood of crap, we have reCaptcha. An awesome little utility that will prevent bots from submitting forms. You already know what captcha is though, that’s probably how you found this post, by googling for apex and captcha. First off, there is already an awesome post on how to do with by Ron Hess (Here), but his approach is a bit complicated, and visualforce heavy. Of course being kind of anti visualforce, and the complexities of properties and all that, I made my own little approach. So here we go.

This is assuming you already signed up with reCaptcha. You can go here and sign up for recaptcha (yes you can just enter force.com as the domain)
After that, course add an entry for google to your remote sites in the admin setup under security. Disable protocol security.
Then create your visualforce page, and apex class. I called my class utilities, since this is kind of a re-usable function and I wanted to keep it generic.

Now put this crap in your controller. Also, your controller needs to be global (to use javascript/apex remoting)

@RemoteAction
    global static boolean validCaptcha(string challenge, string response)
    {
      boolean correctResponse = false;
      string secret = 'your recaptcha secret key here. Maybe make this into a custom setting?';
      string publicKey = 'your recaptcha public key here. Maybe make this into a custom setting?';
      string baseUrl = 'http://www.google.com/recaptcha/api/verify'; 

      string body ='privatekey='+ secret +  '&remoteip=' + remoteHost() + '&challenge=' + challenge + '&response=' + response + '&error=incorrect-captcha-sol';
      
      HttpRequest req = new HttpRequest();   
      req.setEndpoint( baseUrl );
      req.setMethod('POST');
      req.setBody ( body);
      try 
      {
        Http http = new Http();
        HttpResponse captchaResponse = http.send(req);
        System.debug('response: '+ captchaResponse);
        System.debug('body: '+ captchaResponse.getBody());
        if ( captchaResponse != null ) 
        {  
            correctResponse = ( captchaResponse.getBody().contains('true') );
        }          
       
      } 
      catch( System.Exception e) 
      {
         System.debug('ERROR: '+ e);
      }                             
      return correctResponse;
    }

    global static string remoteHost() 
    { 
        string ret = '127.0.0.1';
        // also could use x-original-remote-host 
        try
        {
            map<string , string> hdrs = ApexPages.currentPage().getHeaders();
            if ( hdrs.get('x-original-remote-addr') != null)
            {
                ret =  hdrs.get('x-original-remote-addr');
            }
            else if ( hdrs.get('X-Salesforce-SIP') != null)
            {   
                ret =  hdrs.get('X-Salesforce-SIP');
            }
        }
        catch(exception e)
        {
        
        }
        return ret;
    }

Ok, great, now your controller is ready. You just need to pass the right info and it will tell you if it’s right or wrong. Lets get a visualforce page set up to do that.

<apex:page controller="utilities" standardStylesheets="false" sidebar="false"  >

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" />


<script>
$(function() {

    $( "#validateButton" ).click(function(){
        
        validCaptcha(function(valid){
            if(valid)
            {
                $('#validationResultDiv').html('Valid Captcha!');
                
                //Do whatever here now that we know the captcha is good.
            }
            else
            {
                $('#validationResultDiv').html('Invalid Captcha Entered');
            }
           
        });           
    });
});

function validCaptcha(callback)
{
    var challenge = document.getElementById('recaptcha_challenge_field').value;
    var response = document.getElementById('recaptcha_response_field').value;

    utilities.validCaptcha(challenge,response, function(result, event)
    {
        if(event.status)
        {
           callback(result);
        }
    }, {escape:true});
}

</script>

<div id="captchaEnter" title="Form Submission Validation">
    <center>
    <script type="text/javascript" src="https://www.google.com/recaptcha/api/challenge?k=YOUR PUBLIC KEY GOES HERE DONT FORGET IT"></script>
    <noscript>
       https://www.google.com/recaptcha/api/noscript?k=YOUR_PUBLIC_KEY
     </noscript>  
     <div id="validationResultDiv"></div>   
     <button id="validateButton" class="inline">Submit</button>
       
     </center>
</div>


</apex:page>

Boom! Just that easy. Hook up an event handler to the submit button that runs the validCaptcha function. It will get the proper values, and send them to the apex class, which sends them to reCaptcha to verify. Once an answer comes back, it is passed into the callback function, which the can run whatever action you require. Don’t forget to replace the place holder public key in the script line above. Have fun!



Reliably injecting jQuery and jQuery UI with callback!

Hey all,
So this is kind of a cool thing. Sometimes you end up needing to inject jQuery in a page (like with advanced custom buttons in Salesforce) or in other cirumstances where you can write scripts, but you don’t have direct access to the source doc. Some of these times you want to include jQuery, along with jQuery UI and it’s CSS. Most of us know you can use the head.addScript function of javascript to inject the code, but how do you know when it’s loaded? How do you make sure you only load the UI library after the core library has loaded? Well worry no more, as I have an awesome javascript function here to reliably inject jQuery and the UI and then call a function of your choosing. Here ya go!

function loadJQuery(callback)
{
    try
    {
        if(typeof jQuery == "undefined" || typeof jQuery.ui == "undefined")
        {
            var maxLoadAttempts = 10;
            var jQueryLoadAttempts = 0;
            //We want to use jQuery as well as the UI elements, so first lets load the stylesheet by injecting it into the dom.
            var head= document.getElementsByTagName('head')[0];
            var v_css  = document.createElement('link');
            v_css.rel = 'stylesheet'
            v_css.type = 'text/css';
            v_css.href = 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/redmond/jquery-ui.css';
            head.appendChild(v_css);

            //Okay, now we need the core jQuery library, lets fetch that and inject it into the dom as well
            var script= document.createElement('script');
            script.type= 'text/javascript';
            script.src= 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js';
            head.appendChild(script);
                    
            checkjQueryLoaded = setInterval(function()
            {             
                if(typeof jQuery != "undefined")
                {
                    //Okay, now we need the core jQuery UI library, lets fetch that and inject it into the dom as well
                    var script= document.createElement('script');
                    script.type= 'text/javascript';
                    script.src= 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js';
                    head.appendChild(script);
                    window.clearInterval(checkjQueryLoaded);
                }
                else if(maxLoadAttempts < jQueryLoadAttempts)
                {
                    window.clearInterval(checkjQueryLoaded);
                }
                jQueryLoadAttempts++;
            },300);
            
            jQueryLoadAttempts = 0;        
        
            checkLoaded = setInterval(function()
            {             
                if(typeof jQuery != "undefined" && typeof jQuery.ui != "undefined")
                {
                    window.clearInterval(checkLoaded);
                    callback(true);
                }
                else if(maxLoadAttempts < jQueryLoadAttempts)
                {
                    window.clearInterval(checkLoaded);
                    callback(false);
                }
                jQueryLoadAttempts++;
            },500);
        }
    }
    catch(exception)
    {
        callback(false);
    }
}

Then you can invoke it and have a callback like this

loadJQuery(function(loadSuccess){
    if(loadSuccess)
    {
	//Do your jQuery stuff here. Basically you can think of this as a replacement for your 
	//document.onReady code
        $(document.getElementsByTagName('body')[0]).append("<div id=infoNotice title='Success'>jQuery and jQuery UI loaded!</div>"); 
        $( "#infoNotice" ).dialog({ modal: true});  
    }
    else
    {
        alert('Couldn\'t load jQuery :(');    
    }
});

Have fun!


Salesforce Call Apex Code From Hompeage Component

So this is something I had to do for a challenge recently, where I wanted to invoke my Apex class/method from a home page component. I had heard some solutions involving a link that called a visualforce page (nice thought, but a little clunky and hard to pass parameters) or loading a visualforce page tied to the controller in an iframe (again, works but not the most elegant). I remembered that there is a connection library that allows javascript to call Apex, that is normally used for custom buttons and back in the day s-controls. I putzed around with the syntax some and realized I was making it way more complicated than it needed to be. Below is my solution that I think is pretty slick.

1) Write an apex method that is set as a webservice so it can be called by the library (example below)

    webservice static string createLinkSimple(string url, string title)
    {
          string returnVar = 'Link added!';
          try
          {
               favLink__c thisLink = new favLink__c();
               thisLink.location__c = url;
               thisLink.name = title;
               thisLink.owner__c = UserInfo.getUserId();
               insert thisLink;
           }
           catch(Exception e)
           {
               returnVar = 'Error adding link: ' + e.getMessage();
           }    
           return returnVar;
    }

2) Create a home page link (setup->customize->home-> custom links)
3) Create a link link. Set the content source as ‘onClick javascript’
4) Enter code similar to the following

{!REQUIRESCRIPT("/soap/ajax/10.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/10.0/apex.js")}

var result = sforce.apex.execute("favLinks","createLinkSimple", {url: document.location.href, name: document.title});
alert(result);

(The first param is the class name, the second is the method name, and then pass the arguments in the {} brackets)

5) Save it and add the link to a homepage component and display it in the sidebar. You are done!

The will allow you to invoke Apex classes and store the result in a variable to do whatever you want with. Combine this with my Salesforce – Pushing Custom Buttons to the Limit With jQuery and Apex article and you can build some pretty powerful cool stuff.

Hope this helps someone out there.