Self executing recursive javascript functions

Posted in development by Kris Gray on December 28th, 2009

The title is intimidating, but fear not. This will be short, sweet and probably really easy to understand. And you'll have something to impress me with in interviews if you ever have the pleasure.

Why?

A while back I was writing some code and it turned out it was executed by two different code paths. In one case, the control was all ready and the code needed to be executed right away. In the other case, the control wasn't ready but would be shortly after the window.load event has been fired. Yea I'm not explaining it very well, but really it doesn't matter, lets see code.

Code

JavaScript:
  1. var isLoaded = false;
  2.     (function() {
  3.         if(isLoaded) {
  4.             document.getElementById("out").innerHTML = "Loaded";
  5.             return;
  6.         }
  7.        
  8.         // Every 10th of a second call this method again.
  9.         document.getElementById("out").innerHTML += "Trying Again<br/>";
  10.         setTimeout(arguments.callee, 100);
  11.        
  12.         // If your inside an object, you probably want to keep the THIS pointer.
  13.         // For that, you would do the following.
  14.         // var self = this, fn = arguments.callee;
  15.         // setTimeout(function() { fn.call(self); }, 100);
  16.        
  17.         // The page will be loaded in 3 seconds
  18.         // We would probably want to wait for something like
  19.         // a DOM event, but its just sample code. So...
  20.         setTimeout(function() { isLoaded = true; }, 3000);
  21.     })();

We have both techniques of the example in use here, a self executing anonymous function, and a recursive function.

For the self executing anonymous function, we are wrapping our function in parenthesis and then calling it just like any other function.

JavaScript:
  1. // The anonymous part
  2. (function(){})();

For the self executing part, we get a reference to the function using arguments.callee, which just so happens to be itself. With it we can use a setTimeout to have the function try again later. We could have just kept calling it, but with javascripts single threaded nature, I would think nothing would happen while your calling your function over and over.

JavaScript:
  1. (function(){
  2. // BAD
  3. // At least in our case. You could have
  4. // a perfectly justifiable reason for doing this
  5. // though.
  6. arguments.callee();
  7. })();

You can see a live example of this code here

No comments

IE 6, 7, 8 Only CSS

Posted in development by Kris Gray on December 22nd, 2009

Introduction

This topic doesn't really need an introduction, so lets move on!

Options

DOM wrappers using Conditional Comments

This is the technique used by the jQuery UI site. The basics are that if you wrap your entire page in a DIV with the browser version as the class name, you can just add extra rules to your one stylesheet that will get picked up. Then you can use conditional comments to show the appropriate DIV when necessary.

HTML:
  1. <body id="home">
  2. <!--[if IE 5]><div id="ie5" class="ie"><![endif]-->
  3. <!--[if IE 6]><div id="ie6" class="ie"><![endif]-->
  4. <!--[if IE 7]><div id="ie7" class="ie"><![endif]-->
  5.  
  6.  
  7. <!--[if lte IE 7]></div><![endif]-->
  8. </body>

With this solution, you can include all your CSS in one file, so everything is tidy and theres no extra web requests necessary.

It comes at the cost of your HTML cleanliness, but its overall very minimal.

Conditional Stylesheets

Using the same trick as above, you can include stylesheets conditionally on IE with conditional comments. The abilities of the conditional comment syntax is quite powerful, it seems like its wasted doing just stylesheet inclusion.

HTML:
  1. <!--[if IE]> <link href="ie_only.css" rel="stylesheet" type="text/css"> <![endif]-->

This is probably what I would suggest to most of you out there. Its quick, un-invasive and you can pretty much throw it out there and only worry about it when you really have to do something for just IE.

Let the server do it

I only mention this because I work in an enterprise environment that does just that. It includes an IE version of the stylesheet you referenced if the user is browsing in IE.

So if you have a stylesheet Calendar.css and you navigated to the page using IE, you would get tags for both Calendar.css and Calendar_ie.css. If of course Calendar_ie.css exists.

CSS Hacks, Syntax and Selector

So I'm regurgitating a bunch of information from this Web Dev Out CSS Hacks page which is that there are some CSS hacks based on selector engine parsing issues that are possible.

The primary options are those which are valid CSS, as invalid CSS is much more likely to cause you problems down the line.

Here's some of the selectors from that article.

IE 6 and below
* html {}

IE 7 and below
*:first-child+html {} * html {}

IE 7 only
*:first-child+html {}

IE 7 and modern browsers only
html>body {}

Modern browsers only (not IE 7)
html>/**/body {}

Recent Opera versions 9 and below
html:first-child {}

Its perfectly understandable that these may be your only options at the moment, but the chance they come back to bite you is so much higher as to make conditional comments worth your effort.

So, what to use?

Well, I tend to use the conditional extra stylesheet method, but between that and the DOM inclusion which are both good options its really up to you. You'll still have the comfort of knowing that your doing things the right way, and that the next .0.0.1 version of FireFox, IE, or WebKit won't break your site and bring down the internet.

2 comments

Google Sites Data API Prototype

Posted in development by Kris Gray on December 19th, 2009

I've made note of my fondness of Google sites before.

This project originated from the need to consolidate our JSDocs into a single search able source with all our other data. As that data is all in Google Sites at the moment, integration with Google Sites seemed the sensible choice.

Last thing I want to mention is that I don't claim to be super knowledgable on this topic, I'm only going to talk about what I've experienced in developing this prototype.

High Level

Google provides REST API's for a lot of its services as well several different client libraries to interact with said REST API's without having to worry to much about xml, namespaces and such.

I used the gdata-javascript-client in this example as its more my specialty.

In the js client, for getting the content feed (which is the listing of your sites information) you'll want to login, instantiate a GoogleService, and make a getFeed call using the GoogleService instance. Lets get to the prototype to see how we do that.

Prototype

In my prototype, I have 3 buttons that allow you to login, get your content feed, and then update one of the pages with new HTML.

Here's a link to the Prototype. Be aware, you'll need to to change the URL's to a google site you control (probably), otherwise you won't be able interact with its API. (At least not the update, the get should work)

Here's the full text of that prototype.

HTML:
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  3. <title>Sample using the Google data JavaScript client library</title>
  4. <link rel="stylesheet" type="text/css" href="http://code.google.com/css/dev_docs.css">
  5.     blockquote { margin: 2px 6px; padding: 0; border: 1px solid silver; }
  6.     span { display: block; font: 11px Arial; color: #999; }
  7.     input { border: 1px solid #333; margin: 3px 0 12px 0; width: 600px; }
  8.     textarea { width: 600px; height: 300px; }
  9.     h3 { display: block; margin: 0; padding: 0; height: 25px;}
  10.     #out { margin: 10px 0 0 0; border: 2px solid #F00; }
  11. </style>
  12. <script type="text/javascript" src="http://www.google.com/jsapi"></script>
  13. <script type="text/javascript">
  14.  
  15. /* Loads the Google data JavaScript client library */
  16. google.load("gdata", "2.x");
  17.  
  18. function init() {}
  19.  
  20. function logMeIn() {
  21.     var nameOfMyGoogleServiceThatIsTotallyMadeUp = "test-app";
  22.     var scope = "http://sites.google.com/feeds/";
  23.     var token = google.accounts.user.login(scope);
  24.    
  25.     service = new google.gdata.client.GoogleService("jotspot", nameOfMyGoogleServiceThatIsTotallyMadeUp);
  26. }
  27.  
  28. function get() {
  29.     var feed = document.getElementById("siteUrl").value;
  30.     logMeIn();
  31.     // Call the content feed, pass the result to the output function
  32.     service.getFeed(feed, output);
  33. }
  34.  
  35. function update() { 
  36.     var pageId = document.getElementById("pageId").value;
  37.     logMeIn();
  38.     // Get an entry object for the page
  39.     service.getEntry(pageId, function(entryRoot) {
  40.    
  41.         // $t indicates the text of the content node.
  42.         // We are setting it to whats in the textarea.
  43.         entryRoot.entry.content.$t = txt();
  44.         service.updateEntry(pageId, entryRoot.entry, output, output);
  45.     });
  46. }
  47.  
  48. function output(obj) {
  49.     if(!obj) { out('Watch was passed nothing');}
  50.     out((function(o) {
  51.         var s = [];
  52.         for(var i in o) {
  53.             s.push([i, '=', o[i]].join(''));
  54.             if(!o[i]) {
  55.                 continue;
  56.             } else if(o[i].constructor == Object) {
  57.                 s.push('<blockquote>' + arguments.callee(o[i]) + '</blockquote>');
  58.             } else if(o[i].constructor == Array) {
  59.                 for(var c=0;c<o[i].length;c++) {
  60.                     s.push('<blockquote>' + arguments.callee(o[i][c]) + '</blockquote>');
  61.                 }
  62.             }
  63.         }
  64.         return s.join('<br/>');
  65.     })(obj));
  66. }
  67.  
  68. function out(str){ document.getElementById("out").innerHTML = str; }
  69. function txt() { return document.getElementById("updateText").value; }
  70.  
  71. google.setOnLoadCallback(init);
  72.  
  73. </script>
  74. </head>
  75. <body>
  76.     <button onclick="logMeIn()">Login</button>
  77.     <button onclick="get()">Get Content of Site</button>
  78.     <button onclick="update()">Update</button>
  79.     <br/>
  80.     <h3>Site Id</h3>
  81.     <input type="text" id="siteUrl" value="http://sites.google.com/feeds/content/site/justisetest"/>
  82.     <br/>
  83.     <h3>Page Id</h3>
  84.     <span>Obviously you should get this programmatically, but its a prototype so yea...</span>
  85.     <input type="text" id="pageId" value="http://sites.google.com/feeds/content/site/justisetest/8416968326017325843"/>
  86.     <br/>
  87.     <textarea id="updateText"><h1>updated!</h1></textarea>
  88.     <div id="out">
  89.    
  90.     </div>
  91.     <img src="bullet.jpg" border="0"/>
  92.    
  93. </body>
  94. </html>

Login and instantiate a service

JavaScript:
  1. var scope = "http://sites.google.com/feeds/";
  2.     var token = google.accounts.user.login(scope);
  3.    
  4.     service = new google.gdata.client.GoogleService("jotspot", nameOfMyGoogleServiceThatIsTotallyMadeUp);

Here we are logging into the google service using oAuth, then we create a new GoogleService object, passing the type of service we want to interact with. (Which is jotspot) Then we supply just some name for our application.

Getting the content

JavaScript:
  1. var feed = document.getElementById("siteUrl").value;
  2.     logMeIn();
  3.     // Call the content feed, pass the result to the output function
  4.     service.getFeed(feed, output);

The feed URL for my little public site is http://sites.google.com/feeds/content/site/justisetest

So thats what I plug into our service's get feed. (It gets declared as a global variable in the logMeIn() call)

Its an async call, so it doesn't return anything, it passes the result to an onSuccess function.

My onSuccess function is just a method that takes something and outputs it to a div, so its basically a kind of a little watch window.

Updating content

JavaScript:
  1. var pageId = document.getElementById("pageId").value;
  2.     logMeIn();
  3.     // Get an entry object for the page
  4.     service.getEntry(pageId, function(entryRoot) {
  5.    
  6.         // $t indicates the text of the content node.
  7.         // We are setting it to whats in the textarea.
  8.         entryRoot.entry.content.$t = txt();
  9.         service.updateEntry(pageId, entryRoot.entry, output, output);
  10.     });

The Page id I just stole from the content field, which I'm basically hard-coding.

Ensure I'm logged in, and then I make a call to the service to request the entry object.

Once my onSuccess function is called, I update the entry's page text, and then use the service to update the entry again.

Those two output calls are the onSuccess and onError functions, which right now just output the result.

Thats it

Obviously a lot left to figure out, but I think once you've got to this point, you can actually start exploring the features of the API without having to figure out how to the most basic of operations.

No comments

I moved desks, Upgrade? Strangely yes.

Posted in development by Kris Gray on September 23rd, 2009

At Salesforce, we have a 3 building setup here at One Market, there's two gray ugly towers, and one nicer brick building. The towers are named Spear and Steuart for the streets they are on, and then the nice brick building we call Landmark, I'm not exactly sure why. The Development teams were spread out over two of the buildings Spear and Landmark and someone decided it would be good to get the teams as close together as possible. It was decided that all us devs would consolidate to the Landmark building, which meant I had to move from my Spear tower desk. Here's a picture of spear here (Its the taller one on the right).

The Spear Tower

I had a nice spot too, a pretty good view, quick access to the beer fridge, and close to the team. Here's my desk.

Desk in Spear Tower

Yes its one small side desk with two gigantic 24" monitors on it, and I'm in a small corner with a large palm. But it has a nice view!

Spear Tower View

I was a mixed bag of emotions. I did have some nice perks; good view, was sitting right next to the important members of my team, and then there was that I wasn't sure where we were headed. But since I had about 10" of desk space after all my computer equipment, I figured the trade off might be worth it.

We ended up on the 3rd floor of the Landmark building at One Market Plaza in San Francisco, which you can't deny is a sexier building.

Landmark at One Market

Here's my new desk.

IMG_0378

And my new view! Yay! (Sarcasm!)

Landmark View

As you can expect, being here only a half dozen months the re-org was able to give the better window seats to the more senior developers, though I would expect nothing less especially if I was one of those senior developers myself.

The move turned out much better then I imagined. I'm amazed that any company gets anything like this right when presented with an opportunity, but Salesforce did a really good job. The manual labor was provided for us, all we had to do was box and label our personal items, computer equipment and chairs and it showed up at our designated cubes the next morning with our computer equipment already setup.

The Landmark building was as big a character upgrade inside as it was outside. Its colored better, its got exposed brick walls, and its just a better feel.

Our desks are great, they went from an ugly gray (or white in my case) to a nice speckled wood color, the cubicle walls are a bit lower so you can see peoples top of their heads but looking around doesn't weird anyone out and make them stop working. Also with the open desk layout vs enclosed cubicles, we have a tendency to converse from our chairs and break out in random friendly conversations a bit more. We still get just as much work done so its not at the expense of work, but I think its more efficient conversation time.

So even though I lost out on my nice view, a larger desk, an office with some character, a much better color scheme and better cube layout won out.

No comments

Adding your logo to the page in an SEO optimized way.

Posted in Markup, SEO, development by Kris Gray on September 19th, 2009

Everyone has one, either your name, your logo or some cute picture you use to discern that the user has landed on your little piece of the web. Here's mine just for reference.

But there is a specific optimal way to include it on your page.

The things to concern here.

  • Any images you add to page that are not content related but are theme related pollutes your markup with un-necessary elements and makes it harder to re-skin in the future.
  • Search engines can't read text from an image, so your primary identification doesn't get indexed.
  • If images aren't loaded (hey it happens, really!) they the visitor doesn't know where they are. There is the alt text of the image that doesn't load, but its size in comparison to the rest of the page is very poor.
  • What if you want to change your logo based on the page your on, or user activity, you'll need to change the img src, meaning script, or markup changes per page.

There's probably a few more, but you get the idea, beyond the Happy Path, using an image for your logo starts to cause problems.

The solution is actually beautiful in its simplicity, here's the markup you'll want to generate.

HTML:
  1. <a id="logo" href="[Your Site Address Here]" title="[Your Site Name Here]">
  2.         <h1>
  3.             [Your Site Name Here]
  4.         </h1>
  5.     </a>

and then you can pair this with some simple CSS to add our logo image.

CSS:
  1. a#logo { display:block; width: '[logo width]'; height: '[logo height]'; background: url('[logourl]') no-repeat; }
  2. a#logo h1,
  3. a#logo h2 { display: none; }

And then your pretty much done, here's what I would end up with for my site.

HTML:
  1. <a id="logo" href="http://www.justise.com" title="Kris Gray">
  2.         <h1>
  3.             Kris "Justise" Gray
  4.         </h1>
  5.     </a>

CSS:
  1. body { background: maroon; }
  2. a#logo { display:block; width: 185px; height: 63px; background: url(http://www.justise.com/wp-content/themes/justise/images/headerLogo.png) no-repeat; }
  3. a#logo h1,
  4. a#logo h2 { display: none; }

Why is this markup preferable?

If we render without images, and CSS, we still get a very big peice of text that lets the user know where they are.

What the Logo Looks like without CSS

What the Logo Looks like without CSS

We also use an H1 or an H2 (more on that later) to mark our logo text so that search engines realize that the text is important and they should give a large amount of weight to that text.

It was a question of mine at some point writing this if Search Engines really do index text that is hidden with display none? So I went and looked it up, and according to this SEO optimization post on "Do search engines index that" the answer is Yes, so lets move on.

We attach the image of our logo to the background image of the logo link, so we still have the flexibility of changing our logo at any time by just updating the CSS, while also being able to change the logo link based on its context in the document, such as a different parent class.

We will obviously want our logo linked back to the main page, its just a common standard, and so you'd need pretty much the same amount of markup if you were going to just insert an image.

Lastly, this w3c article on using the H1 tells us that we want to mark the most important text on the page with the H1 element. Since on the main page, that is most likely our logo this is fine, but on sub pages, we'll probably want the title of each blog post as the H1, so we'll want to make our logo now an H2. With the technique we are using here, it requires no change to the CSS, just a simple markup change.

No comments

Next Page »