Skip to content
fb.js 10.4 KiB
Newer Older
/**
 * @file
 * Javascript behaviors and helpers for modules/fb.
 */

FB_JS = function(){};
FB_JS.fbu = null;

/**
 * Drupal behaviors hook.
 *
 * Called when page is loaded, or content added via javascript.
 */
Drupal.behaviors.fb = function(context) {
  // Respond to our jquery pseudo-events
  var events = jQuery(document).data('events');
  if (!events || !events.fb_session_change) {
    jQuery(document).bind('fb_session_change', FB_JS.sessionChangeHandler);
  }

  // Once upon a time, we initialized facebook's JS SDK here, but now that is done in fb_footer().
  if (typeof(FB) != 'undefined') {
    // Render any XFBML markup that may have been added by AJAX.
    $(context).each(function() {
      var elem = $(this).get(0);
      FB.XFBML.parse(elem);
    });
  }

  FB_JS.showConnectedMarkup(Drupal.settings.fb.fbu, context);

  // Markup with class .fb_show should be visible if javascript is enabled.  .fb_hide should be hidden.
  jQuery('.fb_hide', context).hide();
  jQuery('.fb_show', context).show();
};

if (typeof(window.fbAsyncInit) != 'undefined') {
  // There should be only one definition of fbAsyncInit!
  debugger;
};
Dave Cohen's avatar
Dave Cohen committed
// This function called by facebook's javascript when it is loaded.
// http://developers.facebook.com/docs/reference/javascript/
window.fbAsyncInit = function() {
Dave Cohen's avatar
Dave Cohen committed

Dave Cohen's avatar
Dave Cohen committed
  if (Drupal.settings.fb) {
    FB.init(Drupal.settings.fb.fb_init_settings);
  }
    if (typeof(Drupal.settings.fb.fb_init_settings.authResponse) == 'undefined') {
      // Check the login status.  If offline_access granted, this
      // is the only way to know if user has logged out of facebook.
      FB.getLoginStatus(function(response) {
        FB_JS.initFinal(response);
      });
    }
    else {
      // With third party cookies disabled, calling getLoginStatus doesnt seem to work.
      // @TODO: figure out why getLoginStatus fails!  Bug on facebook's side?
      FB_JS.initFinal({'authResponse' : Drupal.settings.fb.fb_init_settings.authResponse});
      FB.api('/me', function(response) {
        // Calling FB.api is unfortunate overhead, but no other way to detect if user has logged out of facebook.
        if (typeof(response.error) != 'undefined') {
          // Fake an auth response change so Drupal knows user is logged out.
          FB_JS.authResponseChange({'authResponse' : null});
        }
      });
    }
  }
  else {
    // No application.  Not safe to call FB.getLoginStatus().
    // We still want to initialize XFBML, third-party modules, etc.
    FB_JS.initFinal({'authResponse' : null});
/**
 * Finish initializing, whether there is an application or not.
 */
FB_JS.initFinal = function(response) {
  var status = {
    'auth': response.authResponse,
    'response': response
  };
  jQuery.event.trigger('fb_init', status);  // Trigger event for third-party modules.
  FB_JS.authResponseChange(response); // This will act only if fbu changed.
/**
 * Tell facebook to notify us of events we may need to act on.
 */
FB_JS.eventSubscribe = function() {
  // Use FB.Event to detect Connect login/logout.
  FB.Event.subscribe('auth.authResponseChange', FB_JS.authResponseChange);

  // Q: what the heck is "edge.create"? A: the like button was clicked.
  FB.Event.subscribe('edge.create', FB_JS.edgeCreate);

}

/**
 * Helper parses URL params.
 *
 * http://jquery-howto.blogspot.com/2009/09/get-url-parameters-values-with-jquery.html
 */
  var vars = [], hash;
  var hashes = href.slice(href.indexOf('?') + 1).split('&');
  for(var i = 0; i < hashes.length; i++)
  {
    hash = hashes[i].split('=');
    vars[hash[0]] = hash[1];
      vars.push(hashes[i]); // i.e. "foo=bar"
  }
  return vars;
}

/**
 * Reload the current page, whether on canvas page or facebook connect.
 *
 * append fbsig, a hash of the session data, to avoid infinite reloads
 * in some cases.
FB_JS.reload = function(destination) {
  if (auth != null)
    fbhash = auth.signedRequest; // Use sig rather than compute a new hash.
  // Avoid infinite reloads.  Still needed? It would be nice to do away with this code if not needed.
  ///@TODO - does not work on iframe because facebook does not pass url args to canvas frame when cookies not accepted.  http://forum.developers.facebook.net/viewtopic.php?id=77236
  var vars = FB_JS.getUrlVars(window.location.href);
    return; // Do not reload (again)
  }

  // Determine where to send user.
  if (typeof(destination) != 'undefined' && destination) {
    // Use destination passed in.
  }
  else if (typeof(Drupal.settings.fb.reload_url) != 'undefined') {
    destination = Drupal.settings.fb.reload_url;
Dave Cohen's avatar
Dave Cohen committed
    destination = window.location.href;
  // Split and parse destination
  var path;
  if (destination.indexOf('?') == -1) {
    vars = [];
    path = destination;
  }
  else {
    vars = FB_JS.getUrlVars(destination);
    path = destination.substr(0, destination.indexOf('?'));
  }
  // Add fbhash to params before reload.
  if (Drupal.settings.fb.reload_url_append_hash) {
    vars.push('fbhash=' + fbhash);
  }

  // Use window.top for iframe canvas pages.
  destination = vars.length ? (path + '?' + vars.join('&')) : path;
  if (Drupal.settings.fb.reload_url_fragment) {
    destination = destination + "#" + Drupal.settings.fb.reload_url_fragment;
  }
Dave Cohen's avatar
Dave Cohen committed

  // Feedback that entire page may be reloading.
  // @TODO improve the appearance of this, make it customizable.
  jQuery('body').prepend('<div id="fb_js_pb" class="progress"><div class="bar"><div class="filled"></div></div></div>');

  window.top.location = destination;
// Facebook pseudo-event handlers.
FB_JS.authResponseChange = function(response) {
  //debugger;
  if (response.status == 'unknown') {
    // @TODO can we test if third-party cookies are disabled?
  }

  var status = {
    'changed': false,
    'fbu': null,
    'session': response.authResponse, // deprecated,  still needed???
    'auth': response.authResponse, // still needed???
    'response' : response
  };
  if (response.authResponse) {
    status.fbu = response.authResponse.userID;
    if (Drupal.settings.fb.fbu != status.fbu) {
      // A user has logged in.
      status.changed = true;
    }
  }
Dave Cohen's avatar
Dave Cohen committed
  else if (Drupal.settings.fb && Drupal.settings.fb.fbu) {
  if (status.changed) {
    // fbu has changed since server built the page.
    jQuery.event.trigger('fb_session_change', status);

    // Remember the fbu.
    Drupal.settings.fb.fbu = status.fbu;
FB_JS.edgeCreate = function(href, widget) {
  var status = {'href': href};
Dave Cohen's avatar
Dave Cohen committed
  FB_JS.ajaxEvent('edge.create', status);
Dave Cohen's avatar
Dave Cohen committed
// JQuery pseudo-event handler.
FB_JS.sessionChangeHandler = function(context, status) {
  // Pass data to ajax event.
    'event_type': 'session_change',
    'is_anonymous': Drupal.settings.fb.is_anonymous
    // Suppress facebook-controlled session.
    data.fb_session_handoff = true;

    // Facebook's PHP SDK should find this.  We can't rely on cookies being set.
    //data.signed_request = status.response.authResponse.signedRequest;
  FB_JS.ajaxEvent(data.event_type, data);
  // No need to call window.location.reload().  It will be called from ajaxEvent, if needed.
// Helper to pass events via AJAX.
// A list of javascript functions to be evaluated is returned.
FB_JS.ajaxEvent = function(event_type, request_data) {
  if (Drupal.settings.fb.ajax_event_url) {
    // Session data helpful in ajax callbacks.  See fb_settings.inc.
    // request_data.fb_js_session = JSON.stringify(FB.getSession()); // FB.getSession() FAILS! REMOVE or REPLACE.
    if (typeof(Drupal.settings.fb_page_type) != 'undefined') {
      request_data.fb_js_page_type = Drupal.settings.fb_page_type;
    // FB._apikey might be an apikey or might be an appid!
    if (FB._apiKey == Drupal.settings.fb.fb_init_settings.appId ||
        FB._apiKey == Drupal.settings.fb.fb_init_settings.apiKey) {
      request_data.apikey = Drupal.settings.fb.fb_init_settings.apiKey; // deprecated
      request_data.appId = Drupal.settings.fb.fb_init_settings.appId;
    }

    // Other values to pass to ajax handler.
    if (Drupal.settings.fb.controls) {
      request_data.fb_controls = Drupal.settings.fb.controls;
    // In case cookies are not accurate, always pass in signed request.
    response = FB.getAuthResponse();
    if (response) {
      request_data.signed_request = response.signedRequest;
    }
    else {
      request_data.signedRequest = '';
    }

    jQuery.ajax({
      url: Drupal.settings.fb.ajax_event_url + '/' + event_type,
      data : request_data,
      type: 'POST',
      dataType: 'json',
      success: function(js_array, textStatus, XMLHttpRequest) {
        if (js_array.length > 0) {
          for (var i = 0; i < js_array.length; i++) {
            eval(js_array[i]);
          }
        }
        else {
          if (event_type == 'session_change') {
            // No instructions from ajax.  Notify interested parties
            jQuery.event.trigger('fb_session_change_done');
          }
        }
      },
      error: function(jqXHR, textStatus, errorThrown) {
        // Unexpected error (i.e. ajax did not return json-encoded data).
        var headers = jqXHR.getAllResponseHeaders(); // debug info.
        var responseText = jqXHR.responseText; // debug info.
        debugger;
        // @TODO: handle error, but how?
      }
    });

/**
 * Called when we first learn the currently logged in user's Facebook ID.
 *
 * Responsible for showing/hiding markup not intended for the current
 * user.  Some sites will choose to render pages with fb_connected and
 * fb_not_connected classes, rather than reload pages when user's
 * connect/disconnect.
 */
FB_JS.showConnectedMarkup = function(fbu, context) {
  if (context || fbu != FB_JS.fbu) {
    if (fbu) {
      FB_JS.fbu = fbu;
      // Show markup intended only for connected users.
      jQuery('.fb_not_connected', context).hide();
      jQuery('.fb_connected', context).show();
    }
    else {
      FB_JS.fbu = null;
      // Show markup intended only for not connected users.
      jQuery('.fb_connected', context).hide();
      jQuery('.fb_not_connected', context).show();
    }
  }