'fb_connect/receiver', 'callback' => 'fb_connect_receiver', 'type' => MENU_CALLBACK, 'access' => TRUE, ); } return $items; } /** * Without a receiver file, cross-domain javascript will not work. * * In their infinite wisdom, facebook has decreed that the URL for * this static page be in the same place as the app's callback URL. * So we have to make a Drupal callback for what would otherwise be a * simple file. */ function fb_connect_receiver() { $output = ' '; print $output; exit(); die(); } /** * Prepare for fbConnect use. Because a single Drupal might support * multiple apps, we don't know in advance which is the fbConnect app. * Theoretically, it might be possible to simultaneously use multiple * apps and fbConnect, but my suspicion is facebook would throw a * total hissy-fit if you tried. */ function fb_connect_app_init($fb_app) { if ($fb = fb_api_init($fb_app, FB_FBU_CURRENT)) { return $fb; } } /** * Which apps are fbConnect enabled? */ function fb_connect_enabled_apps() { // We do a bit of work for each enabled app, so really we want to restrict this list to only apps which have been "turned on". // But for now we're lazy and just get the list of all apps. $apps = fb_get_all_apps(); return $apps; } /** * Implementation of hook_fb(). */ function fb_connect_fb($op, $data, &$return) { //dpm(func_get_args(), "fb_connect_fb($op)"); if ($op == FB_OP_CURRENT_APP && !$return) { // This will cause fb.module to set the global $fb when user is logged in via fbConnect. if ($apikey = variable_get('fb_connect_primary_apikey', NULL)) { $return = fb_get_app(array('apikey' => $apikey)); } } else if ($op == FB_OP_POST_INIT) { if ($apikey = variable_get('fb_connect_primary_apikey', NULL)) { if ($data['fb_app']->apikey == $apikey) { // Init Facebook javascript whenever logged into fbConnect fb_connect_require_feature('XFBML', $fb_app); // fb_connect_init_option('reloadIfSessionStateChanged', TRUE, $fb_app); fb_connect_init_option('ifUserConnected', "{fb_connect_on_connected}", $fb_app); fb_connect_init_option('ifUserNotConnected', "{fb_connect_on_not_connected}", $fb_app); } } } } /** * Implementation of hook_user * * On logout, redirect the user so facebook can expire their session. * Should be a facebook API to do this, but there's none I know of. */ function fb_connect_user($op, &$edit, &$account, $category = NULL) { if ($op == 'logout') { if (isset($GLOBALS['fb_connect_apikey'])) { global $fb, $fb_app; try { if ($fb && $fb->api_client->session_key) { // We will log out of facebook in hook_exit. $GLOBALS['fb_connect_logging_out'] = TRUE; } } catch (Exception $e) { fb_log_exception($e, t('Failed to log out of fbConnect session')); } } } } function fb_connect_exit($url = NULL) { if (isset($GLOBALS['fb_connect_logging_out'])) { global $fb; session_write_close(); // drupal_goto calls this, so why not us? if (!isset($url)) $url = url('', NULL, NULL, TRUE); $fb->logout($url); } } /** * Allows other modules to specify which Facebook Connect features are * required. This will affect how the FB_RequireFeatures javascript method is * called. */ function fb_connect_require_feature($feature = NULL, $fb_app = NULL) { if ($feature && !isset($fb_app)) $fb_app = $GLOBALS['fb_app']; // some features may apply without an app, but for now let's enforce that an app is required. if ($feature && !$fb_app) return; static $features; if (!$features) $features = array(); if ($fb_app && !$features[$fb_app->apikey]) $features[$fb_app->apikey] = array('fb_app' => $fb_app, 'features' => array()); if ($feature) $features[$fb_app->apikey]['features'][$feature] = $feature; return $features; } /** * Add an option when initializing facebook's javascript api. */ function fb_connect_init_option($option = NULL, $value = NULL, $fb_app = NULL) { if ($option && !isset($fb_app)) $fb_app = $GLOBALS['fb_app']; if ($option && !$fb_app) return; static $options; if (!$options) $options = array(); if ($fb_app && !$options[$fb_app->apikey]) { $options[$fb_app->apikey] = array(); } if ($option) $options[$fb_app->apikey][$option] = $value; return $options; } /** * Include facebook javascript in the footer of the current page. */ function fb_connect_footer($is_front) { // Do nothing on FBML pages if (function_exists('fb_canvas_is_fbml') && fb_canvas_is_fbml()) return; global $base_path; $feature_data = fb_connect_require_feature(); $option_data = fb_connect_init_option(); if (count($feature_data)) { foreach ($feature_data as $data) { // Give other modules a chance to add javascript which executes after init. $extra = fb_invoke(FB_OP_CONNECT_JS_INIT, $data, array()); $extra_js = implode("\n", $extra); $fb_app = $data['fb_app']; $features = $data['features']; $options = json_encode($option_data[$fb_app->apikey]); // Hack! What's the way to json_encode a function name? $options = str_replace('"{', '', $options); $options = str_replace('}"', '', $options); // drupal_add_js cannot add external javascript, so we use hook_footer instead. $output = ''; $output .= "\n"; $feature_list = '["' . implode('","', $features) . '"]'; // Put together the URL for the receiver. The prefix must be identical to the apps callback URL. $receiver = fb_get_callback_url($fb_app) . "fb_connect/receiver"; $output .= " \n"; } } return $output; } function _fb_connect_block_login_defaults() { return array('anon_not_connected' => array( 'title' => t('Facebook Connect'), 'body' => t('Facebook users login here. !button', array('!button' => "")), ), 'user_not_connected' => array( 'title' => t('Facebook Connect'), 'body' => t('Link your account with Facebook. !button', array('!button' => "")), ), 'connected' => array( 'title' => t('Facebook Connect'), 'body' => "", ), ); } /** * Implementation of hook_block. */ function fb_connect_block($op = 'list', $delta = 0, $edit = array()) { if ($op == 'list') { $items = array(); foreach (fb_connect_enabled_apps() as $fb_app) { $d = 'login_' . $fb_app->label; $items[$d] = array( 'info' => t('Facebook Connect Login to !app', array('!app' => $fb_app->title)), ); } return $items; } else if ($op == 'configure') { $defaults = variable_get('fb_connect_block_' . $delta, _fb_connect_block_login_defaults()); $form['config'] = array('#tree' => TRUE); foreach(array('anon_not_connected', 'user_not_connected', 'connected') as $key) { $form['config'][$key] = array( '#type' => 'fieldset', // title and description below '#collapsible' => TRUE, '#collapsed' => FALSE, ); $form['config'][$key]['title'] = array( '#type' => 'textfield', '#title' => t('Default title'), //'#description' => t('Default title.'), '#default_value' => $defaults[$key]['title'], ); $form['config'][$key]['body'] = array( '#type' => 'textarea', '#title' => t('Body'), //'#description' => t('Block body'), '#default_value' => $defaults[$key]['body'], ); } $form['config']['anon_not_connected']['#title'] = t('Anonymous user, not connected'); $form['config']['anon_not_connected']['#description'] = t('Settings when local user is Anonymous, and not connected to Facebook. Typically a new account will be created when the user clicks the connect button.'); $form['config']['user_not_connected']['#title'] = t('Registered user, not connected'); $form['config']['user_not_connected']['#description'] = t('Settings when local user is registered, and not connected to Facebook. Typically the facebook id will be linked to the local id after the user clicks the connect button.'); $form['config']['connected']['#title'] = t('Connected user'); $form['config']['connected']['#description'] = t('Settings when local user is connected to Facebook. You may render facebook\'s logout button, and/or information about the user.'); $form['config']['connected']['body']['#description'] .= t('Note that !fbu will be replaced with the user\'s facebook id.'); $form['config']['filter'] = filter_form($defaults['filter']); $form['config']['filter']['#description'] .= t('Format selected will apply to all body fields above. Be sure to select a format which allows FBML tags!'); $form['config']['filter']['#collapsed'] = FALSE; return $form; } else if ($op == 'save') { variable_set('fb_connect_block_' . $delta, $edit['config']); } else if ($op == 'view') { if (strpos($delta, 'login_') === 0) { // Login block $label = substr($delta, 6); // length of 'login_' $fb_app = fb_get_app(array('label' => $label)); $fb = fb_connect_app_init($fb_app); $fbu = $fb->get_loggedin_user(); fb_connect_require_feature('XFBML', $fb_app); //fb_connect_init_option('reloadIfSessionStateChanged', TRUE, $fb_app); //fb_connect_init_option('doNotUseCachedConnectState', TRUE, $fb_app); $base = drupal_get_path('module', 'fb_connect'); drupal_add_js(array('fb_connect' => array( 'fbu' => $fbu ? $fbu : 0, // XXX 'logout_url' => url('logout'), // XXX 'front_url' => url(''), 'enable_login' => TRUE, ), ), 'setting'); drupal_add_js($base . '/fb_connect.js'); $defaults = variable_get('fb_connect_block_' . $delta, _fb_connect_block_login_defaults()); if ($fbu) { $subject = $defaults['connected']['title']; $content = $defaults['connected']['body']; // substitute %fbu $content = str_replace('!fbu', $fbu, $content); } else if ($GLOBALS['user']->uid){ $subject = $defaults['user_not_connected']['title']; $content = $defaults['user_not_connected']['body']; } else { $subject = $defaults['anon_not_connected']['title']; $content = $defaults['anon_not_connected']['body']; } // If user has changed defaults, run filter if ($defaults['filter']) { $subject = check_plain($subject); $content = check_markup($content, $default['filter'], FALSE); } $block = array( 'subject' => $subject, 'content' => $content, ); return $block; } } } function fb_connect_form_alter($form_id, &$form) { // Add our settings to the fb_app edit form. if (is_array($form['fb_app_data'])) { $node = $form['#node']; $fb_app_data = fb_app_get_data($node->fb_app); $fb_connect_data = $fb_app_data['fb_connect']; $form['fb_app_data']['fb_connect'] = array( '#type' => 'fieldset', '#title' => 'Facebook Connect', '#tree' => TRUE, '#collapsible' => TRUE, '#collapsed' => $node->nid ? TRUE : FALSE, ); $form['fb_app_data']['fb_connect']['primary'] = array( '#type' => 'checkbox', '#title' => t('Primary'), '#description' => t('Initialize fbConnect javascript on all (non-canvas) pages. If this site supports multiple Facebook Apps, this may be checked for at most one.'), '#default_value' => $fb_connect_data['primary'], ); if ($primary_apikey = variable_get('fb_connect_primary_apikey', NULL)) { if ($primary_apikey != $node->fb_app->apikey) { $primary = fb_get_app(array('apikey' => $primary_apikey)); $form['fb_app_data']['fb_connect']['primary']['#description'] .= '
' . t('Note that checking this will replace %app as the primary Facebook Connect app.', array('%app' => $primary ? $primary->title : $primary_apikey)); } } } } function fb_connect_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { if (($op == 'insert' || $op == 'update') && $node->type == 'fb_app') { //dpm(func_get_args(), "fb_connect_nodeapi($op)"); // debug if ($node->fb_app_data['fb_connect']['primary']) { variable_set('fb_connect_primary_apikey', $node->fb_app['apikey']); drupal_set_message(t('!node is now the primary Facebook Connect application.', array('!node' => l($node->title, 'node/' . $node->nid)))); } } } ?>