Oh my god. It's full of code!


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.


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);}());

Cloudspokes Rocks

So, a bit of an exiting milestone today. I am the first developer to break the $20,000 mark on Cloudspokes.com, just one day short of the year anniversary of Cloudspokes itself, and what a crazy year it has been. I feel like I have learned more in this last year than I have in the last several combined! I’ve had some really good competition, put together some awesome applications, and been blown away by some of the things I’ve seen other competitors put together. Thanks to Cloudspokes I’ve I wrote my first Python and Google apps application, broke into jQuery mobile development, learned integration with Twilio, google maps, and so much more. I suppose at a time like this, it’s a bit natural to reflect on where I came from and how I got here.

It’s funny, I’ve come this far, and I still feel like I know nothing. I really am just some chump who pretends he is some kind of programmer. I don’t really have a software design pattern (outside of scribble some shit on paper then start writing code), I don’t use git or even really any kind of version control. I never took programming classes in college, or even been part of a team outside of a small web dev gig back in my mid teens. I don’t understand machine language, and never got pointers. Polymorphism, introspection, and reflection are all concepts I barely grasp. The highest level math course I took in college was college algebra. I fell into development, just as a natural evolution of my love for computers. I guess what I’m really getting at here is ‘If I can do it, anyone can’. You wanna write code? Do it. You don’t need some impressive pedigree or a an expensive degree. It couldn’t be any easier to start than it is today. Go fire up a Salesforce dev org. Maybe get a google app engine app going. Get some free web hosting somewhere. Just… do it.

More important than anything else is just being tenacious, knowing the answer is out there somewhere you just have to find it. Then, once you find it, make it better. Make it faster, sleeker, more efficient. For all my shortcomings, these are the two attributes I claim to have that if anything in myself have carried me this far. I’m stubborn as a mule, but clever as fox. I don’t accept answers I don’t like, and am willing to try shit that seems impossible. Everything that seems nuts just looks like another opportunity to do something no-one else wants to. Perhaps because I’m not bogged down with all the traditional developmental knowledge and mentality I see things a bit different. Who knows?

I want to give a shout out to some of the people who have helped make me the developer I am. Guys like Jason Venable, Simon Fell, Jeff Douglas, Ritesh Aswaney, Matthew Lamb, Andy Boettcher, Daniel Hoechst, Richard Tuttle, and many many more. Here’s hoping one day I can be even half as skilled as you guys are. It’s thanks to guys like these, that dudes like me even have a shot; because they are out there helping us. Of course, thanks to Cloudspokes itself for pushing me to see what I can do when challenged. I never would have guessed I was capable of half the things I produced in the last year. It’s truly an amazing community and a great tool for personal, and professional development.

Looking forward to the next year. See you all in the cloud.

Cloudspokes Simple Timer & Timecard System for Salesforce

Hey all,
Well another week another Cloudspokes challenge. Sadly it seems the judges were not impressed by my last submission of my jQuery google maps salesforce mashup, so let’s hope this week goes better. This time around we have a Timer/Timecard system that should allow users in Salesforce to track their interactions with any record during the day, which all rollup and aggregate to a daily timecard. There are some validations that prevent a user from racking up too many hours (based on a field in their profile), having more than one timecard running, and playing with submitted timecards.

The actual link to the challenge is here http://www.cloudspokes.com/challenges/1358

This time I also made two videos. One that highlights the functionality, and another that is a quick tech overview of how the thing works.

See it in action!

See how it works!

If there are any questions I’d be happy to talk about how I built this, but other than that, I think the videos do a decent job of covering the high points. If they don’t like this one, well I give up. If I don’t place, I’ll be releasing the source code and installable package link. Anyway, wish me luck!

Salesforce, google maps, and jQuery fun

Another Cloudspokes challenge entry submission. This one was for the challenge http://www.cloudspokes.com/challenges/1345. Basically the idea is get Sales data from Salesforce, plot it on a google map using geocoding without creating duplicate map points and allow a user to click one of the points to see all the sales data for it. The tricky part here is that the data comes from different objects based on what country you are filtering on (oh yeah, it has to support multiple countries). So data for the united states comes from a custom object called Sales Orders, while data for Japan and Germany come from opportunities. It had to allow to be easily expanded for more countries in the future as well with an easy way to set the data source. It was recommended to use address tools (an application from the app exchange that has prepopulated lists of countries and their states, along with some other data) for country and state data, but then there was some confusion because address tools is a for pay app with a 14 day trial. What is a developer to do?

I decided to try and make the best of both worlds. Using a flag in the javascript you can tell the controlling class whether to try and pull country and state data from address tools, or return a hard coded set of data (which was said to be an acceptable alternative in the comments of the challenge). The bummer here is that the org does at least have to have the address tools objects otherwise the class won’t compile. Nice thing is my installable package does include the objects and fields, so while it doesn’t have all the data that a full functionally addressTools would have it should at least install and not error. If you do have a functional addressTools install then no need to worry at all. The application will just work, because it defaults to attempting to pull it’s data from there.

To solve the issue of pulling data from different objects with different field names, I decided to create a wrapper object. A simple class that contains only the data needed to plot the address on the map. So whether the data be originally coming from Sales Orders or opportunities, they both end up returning a list of salesData objects (which is what I ended up calling my wrapper class). I created two separate methods (though they probably could have been consolidated into one, but it would have been a bit messy) for getting data from either object. The correct method was called by another which gets invoked by the user interface. Something like

User picks country
Javascript uses apex remoting to call getSales(string formData);
deserialize the form data from a url query string into a map of string to string (key to value)
find useOpp key in the deserialized data (this got set by the javascript in the application before the request was sent)
call the buildQueryFilter method and pass the form data. This method evaluates the data passed in the form and creates a SOQL where condition that will filter the records as the user has requested.
If useOpp is true call the getOpportunitySales() method. If not, call the getSalesOrderSales() method.
Both methods return a map of address (string) to salesData objects, using the filter created above.
Return the map of addresses to salesData objects to the javascript to be plotted on the map.

Those few parts where really the trickiest part of this challenge. I feel creating the wrapper object was probably the slickest solution, and even allows for other potential data sources in the future, and easily expand-ability to return more data to the front end if desired. I’ll be honest and stay a little bit of my code is redundant because of a feature I added at the very last moment, so I end up deserializing the form data twice, which I should really only need to do once, but it’s a short string of data so it’s not a big deal. I also not 100% sure the application is safe from SOQL injection. You could probably get the application to error by passing junk data with firebug or something, but I doubt you could make it do anything besides just error. I mean SOQL is select only anyway, and the filters it runs through and the way the query string gets built is pretty solid. So I am pretty sure at worst an attack could just get the application to toss some errors for their instance of it. Nothing that should be able to bring the app down, especially with governor limits in place.

As usual, I can’t release the source code myself until I have lost, or Cloudspokes gives me the okay. They generally host all code on their github anyway so in that case I’ll updated this post with the link to it.

Anyway you can see the video here: http://www.screencast.com/t/cLUc7dqpHEkC
Or play with the Demo App!

CloudVote emerges as Appirio Social Enterprise Toolkit

Today is a bit of a proud moment for me. My entry for the CloudSpkes contest Social Enterprise Toolkit Ideas App has graduated and been deployed for use by the public. Marketwatch a nice little write did a up on the application. I’ve been helping the Appirio team make the last required tweaks, as well as overhaul the design for the last few days (their graphic design team is quite awesome) and it looks like it is now live. You can check it out http://m.socialenterprisetoolkit.com. It’s pretty cool to see my work move from concept, to beta, to production in a span of like 3 weeks. Although most will never know who wrote it, and won’t care I’ll at least now, and that’s good enough for me 🙂

Cloudspokes Challenge jQuery Clone and Configure Records

Hey everyone,
Just wrapped up another CloudSpokes contest entry. This one was the clone and configure records (with jQuery) challenge. The idea was to allow a user to copy a record that had many child records attached, then allow the user to easily change which child records where related via a drag and drop interface. I have a bit of jQuery background so I figured I’d give this a whack. The final result I think was pretty good. I’d like to have been able to display more information about the child records, but the plugin i used was a wrapper for a select list so the only data available was the label. Had I had more time I maybe could have hacked the plugin some to get extra data, or maybe even written my own, but drag and drop is a bit of a complicated thing (though really not too bad with jQuery) so I had to use what I could get in the time available. Anyway, you can see the entry below.

jQuery Clone and Configure Record

Cloudspokes Challenge, QuickLinks

Cloudspokes wanted a simple bookmark replacer. Something a little easier to use, maybe a little faster. I had been working on this for a while, stepped away to work on the open social voting challenge and forgot how bad of shape I had left this in only hours before the due date. So in a hurry I tried to finish it up and at least have something worth submitting. You can see a video of it in action below. Again, I think they’ll be releasing the code later, not that there is much to see.

Watch the video