Facebookifying Pages

I became really sick of Google Chrome because of its crashing every now and then. Somebody informed me about SRWare Iron which is basically Chrome-like browser and I really like it for personal use, it has never crashed for the last few months I have been using it.

Though this browser works fine, I noticed that on some sites where there is facebook connect, you get “FB is not defined”, this seemed to happen only with this browser. I figured out that  for some reason, it does not fetch the FB’s JS API file eg http://connect.facebook.net/en_US/all.js. Now I love this browser for personal use but I was unable to use on some sites such as slideshare.net.

This made me inject FB object manually in the page which produced above error. For that I created bookmarklet which injected FB script in current page and told about that status. Here is the code for that bookmarklet you can add to your bookmarks toolbar:

</pre>
javascript: function loadScript(src, callback) {
 var s,
 r,
 root_node = document.createElement('div');
 s = document.createElement('script');
 s.src = src;
 s.onload = s.onreadystatechange = function() {
 if (!r && (!this.readyState || this.readyState === 'complete')) {
 r = true;
 callback()
 }
 };
 root_node.id = 'fb-root';
 document.body.appendChild(root_node);
 document.body.appendChild(s)
 }
loadScript('http://connect.facebook.net/en_US/all.js', function() {
 var el = document.createElement('div');
 el.style.position = 'fixed';
 el.style.textAlign = 'center';
 el.style.fontWeight = 'bold';
 el.style.MozBorderRadius = '5px';
 el.style.WebkitBorderRadius = '5px';
 el.style.borderRadius = '5px';
 el.style.margin = '0 auto 0 auto';
 el.style.top = '0';
 el.style.left = '40%';
 el.style.color = '#fff';
 el.style.padding = '5px 10px 5px 10px';
 el.style.backgroundColor = (typeof window.FB === 'object') ? 'green': 'red';
 el.innerHTML = (typeof window.FB == 'object') ? 'Page Facebookified :)': 'Unable to Facebookfiy :(';
 document.body.appendChild(el);
 window.setTimeout(function() {
 document.body.removeChild(el)
 }, 2500)
 });
<pre>

However, with this one would have to press Facebookify bookmarklet button manually. I then thought of auto-inserting FB object in each page I visited, so I went on developing a Greasemonkey addon for this which  automatically inserts FB object into visited page as soon as DOM is available. You can download it here if you want:

Greasemonkey Facebookify Userscript

This way, the FB problem is no more there and I continue to use this nice browser.
This post can be helpful for anyone who is also using SRWare Iron browser or anyone who wants to play around with FB JS API by injecting it on any page.

Outputting PHP To Browser Console

Although there exist classes for outputting PHP to browser console such as Google’s PHP Console and certain others, I was looking for a way to output PHP to browser console without including those classes in my PHP files or installing any browsesr plugin to do the same. Currently, I am working on facebook application development in which you have to commit/upload the code to check certain output out of PHP unlike offline development where you check the code output before committing it up. This makes facebook application development a longer process for a developer but you got to live with it because you don’t have a choice.

Anyways, to speed up the code output checking process a little and rather using debug_backtrace, print_r, print/echo, var_dump, etc which you need to remove/comment again, I created a function to get output of PHP on the browser console. One could use error_log function but even that makes you go to your log file and then see the output. Of course, browser needs to support/have the console so that code result is output there. Because IE less than 8 doesn’t have console, this won’t work in IE less than 8, though result won’t be affected in it. Notice that you can see console in IE=>8 by pressing F12 key and then going to Script tab where you need to make sure Console tab is selected on the right side.

Here is the function:

     /**
     * Logs messages/variables/data to browser console from within php
     *
     * @param $name: message to be shown for optional data/vars
     * @param $data: variable (scalar/mixed) arrays/objects, etc to be logged
     * @param $jsEval: whether to apply JS eval() to arrays/objects
     *
     * @return none
     * @author Sarfraz
     */
     function logConsole($name, $data = NULL, $jsEval = FALSE)
     {
          if (! $name) return false;

          $isevaled = false;
          $type = ($data || gettype($data)) ? 'Type: ' . gettype($data) : '';

          if ($jsEval && (is_array($data) || is_object($data)))
          {
               $data = 'eval(' . preg_replace('#[\s\r\n\t\0\x0B]+#', '', json_encode($data)) . ')';
               $isevaled = true;
          }
          else
          {
               $data = json_encode($data);
          }

          # sanitalize
          $data = $data ? $data : '';
          $search_array = array("#'#", '#""#', "#''#", "#\n#", "#\r\n#");
          $replace_array = array('"', '', '', '\\n', '\\n');
          $data = preg_replace($search_array,  $replace_array, $data);
          $data = ltrim(rtrim($data, '"'), '"');
          $data = $isevaled ? $data : ($data[0] === "'") ? $data : "'" . $data . "'";

$js = <<<JSCODE
\n<script>
     // fallback - to deal with IE (or browsers that don't have console)
     if (! window.console) console = {};
     console.log = console.log || function(name, data){};
     // end of fallback

     console.log('$name');
     console.log('------------------------------------------');
     console.log('$type');
     console.log($data);
     console.log('\\n');
</script>
JSCODE;

          echo $js;
     } # end logConsole

Here is an example of how to use it:

$name = 'sarfraz';

$fruits = array("banana", "apple", "strawberry", "pineaple");

$user = new stdClass;
$user->name = "Sarfraz";
$user->desig = "Sr. Software Engineer";
$user->lang = "PHP";

logConsole('$name var', $name, true);
logConsole('An array of fruits', $fruits, true);
logConsole('$user object', $user, true);

Above code will result in what is shown in the image above. Although this does not prevent committing code first to see the code output if you are on facebook application development but it defintely does save some time. I have been using this function successfully so far, please let me know your ideas if any on how to improve this piece of code further. Have fun !

Custom Facebook Connect Image

One of the ways you can put facebook connect button on your site is to use <fb:login-button> fbml tag something like this:

  <fb:login-button onlogin="window.location='www.example.com'"></fb:login-button>

That will show default facebook button with a rather small image. You can make the button little larger by specifying length and size attributes like this:

  <fb:login-button onlogin="window.location='www.example.com'" length="long" size="large"></fb:login-button>

However, the requirement in my case was that the button should be even bigger. I searched through the facebook connect docs and elsewhere but did not find a way to customize the facebook connect image (it is rendered directly by facebook; let me know if there is a way via comments please). I thought why I can’t force the facebook connect button to use the image that I specify. I fired up firebug (the addon of firefox) and this is what it showed for the <fb:login-button> fbml tag:

As can be seen, facebook automatically applies FB_login_button class amongst others to the connect button. As you can see, there is an img tag inside, that was all I needed to get my own image for the connect button. The idea is to find the image inside connect button and replace with your own once DOM has loaded. Now you get the idea, I wrote this jQuery code to get custom image for the connect button:

<script type="text/javascript">
$(function(){
  // overwrite the fb connect image - let's force it !!
  $('.FB_login_button').find('img').attr('src', 'img/my-custom-image.png');
});
</script>

We use the selector .FB_login_button and then use find method to find the image inside element (<fb:login-button>) having that class and replace its src attribute with the path of our custom image.  Since we have wrapped our code in ready handler $(function(){…}), our code will execute as soon as DOM becomes ready and when you visit the page, it will have your own custom facebook connect button image.

I also noticed that there was a link tag generated with the class of fbconnect_login_button. We could use that just as well like this:

<script type="text/javascript">
$(function(){
  // overwrite the fb connect image - let's force it !!
  $('.fbconnect_login_button').find('img').attr('src', 'img/my-custom-image.png');
});
</script>

Now this is good as long as you are using jQuery on the page where facebook connect button exists. But if you are not using jQuery, you can do the same thing with vanilla javascript albeit with little more code. Here is how you can do the same thing with vanilla javascript:

<script type="text/javascript">
window.onload = function(){
  var ourImg = null; // this will store the facebook connect img tag

  // find all the links on the current page
  var links = document.getElementsByTagName('a');

  // loop over all the links
  for(var i = 0; i < links.length; i++){
    // get class of this link
    var cls = links[i].className;

    // check to see if this is the link with specified class
    if (cls === 'fbconnect_login_button'){
      ourImg = links[i].firstChild; // which is img tag we need
      break;  // done, let's get the hell out of here
    }
  }

  // finally replace with our own image !
  ourImg.src = '<?php echo base_url() ?>images/fb.png';
};
</script>

Ops ! that is a lot of code I have written compared to jQuery’s but that’s what you need if you are not using jQuery on your page. Note that this time, we are using load event of the window window.onload = function(){…} which will fire when all the page resources are loaded including images, frames and the DOM unlike ready handler of jQuery which fires as soon as DOM becomes ready and runs before images, frames or any other external resources loaded into the page.

Finally, this is the page that now uses custom facebook connect button image while using <fb:login-button> fbml tag:

View the Page

Creating Image Maps Using CSS

image_mapI know creating hotspots in an image map using a tool like dreamweaver is not a big deal but if you ever come across a situation where such image maps are not allowed then you have to re-think about it. If you have ever developed a facebook application then you know image maps are not allowed in a FBML application. I was working on a facebook application named Affinity where on a page i needed the image map. I googled a bit but did not find any suitable solution, so I went on to creating my own solution for it using CSS absolute positioning.

Basically, the idea is that main picture goes in background into a main or parent DIV and we place some DIVs with z-index greater than main picture and also set their Top and Left properties. Further, in order to make sure that hotspots are located correctly across all modern browsers, we use a CSS trick which is to make the parent DIV relatively positioned and rest of the DIVs absolute positioned. You need to customize the Top & Left properties of child DIVs (hotspots) to set the correct hot spot positions and also the Height and Width properties to set the size of the hot spots.

<div style="position: relative;">
		<!-- Our Four Hot Spots - Top & Left properties adjusted -->
<div id="ihint1" style="background: none repeat scroll 0% 0% transparent; cursor: pointer; outline: medium none; text-align: center; vertical-align: middle; position: absolute; top: 72px; left: 460px; z-index: 99; padding: 10px;"></div>
<div id="ihint2" style="background: none repeat scroll 0% 0% transparent; cursor: pointer; outline: medium none; text-align: center; vertical-align: middle; position: absolute; top: 11px; left: 635px; z-index: 99; padding: 10px;"></div>
<div id="ihint3" style="background: none repeat scroll 0% 0% transparent; cursor: pointer; outline: medium none; text-align: center; vertical-align: middle; position: absolute; top: 170px; left: 632px; z-index: 99; padding: 10px;"></div>
<div id="ihint4" style="background: none repeat scroll 0% 0% transparent; cursor: pointer; outline: medium none; text-align: center; vertical-align: middle; position: absolute; top: 78px; left: 887px; z-index: 99; padding: 10px;"></div>
		<!-- Main Background Image -->
		<img src="img/first.png" border="0" alt="" align="absbottom" /></div>

You can download it here.