Facebook New JavaScript App


フェイスブックの新しいアプリは古いものとは大きく違って、シンプルで実用的な傾向があり、古いコードの肥大さや煩わしさを捨ててしまう傾向があります.Cross-Domain Receiver Pageを捨てました.古いCross Domainはいつもxdにカードがあります.receiver.httmページが反応していない状況が発生しました.新しいappiはこの問題をよく解決しました.
初期化、ログイン、ライセンス、FQL、UIなどの各方面に大きな変化があります.まず初期化の違いを見ます.
 
Old API:
<script type="text/javascript" src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php">
<script language="javascript">
FB_RequireFeatures(["Api"], function() {
    FB.Facebook.init('api_key', 'xd_receiver.htm', {
        "ifUserConnected": function(){
            // -- connected
        },
        "ifUserNotConnected": function(){
            // -- not connected
        }
    });
});
 
New Appi(JS初期化時は、2つの方式、非同期に分けることができます):
非同期方式:
<div id="fb-root"></div>
<script language="javascript">
window.fbAsyncInit = function() {
      FB.init({appId: facebook.facebook_app_id, status: true, cookie: true, xfbml: true});
      FB.Event.subscribe('auth.sessionChange', facebook.api_sessionChange);
      FB.getLoginStatus(facebook.api_sessionChange);
};

(function() {
    var e = document.createElement('script');
    e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
    e.async = true;
    document.getElementById('fb-root').appendChild(e);
}());
 
同期方式:
<div id="fb-root"></div>
<script language="JavaScript" src="http://connect.facebook.net/en_US/all.js">

<script language="javascript">
  FB.init({appId: facebook.facebook_app_id, status: true, cookie: true, xfbml: true});
  FB.Event.subscribe('auth.sessionChange', facebook.api_sessionChange);
  FB.getLoginStatus(facebook.api_sessionChange);
</script>
 
新しいアプリは、関数FB.Event.subscribe()を提供し、facebook登録状態の変化を検出する.
新しいappiがユーザの授権を必要とする場合、呼び出しの関数はLoginと同じです.ただし、認証が必要なパラメータが多くなります.
FB.login(function(response) {
  if (response.session) {
    if (response.perms) {
      // user is logged in and granted some permissions.
      // perms is a comma separated list of granted permissions
    } else {
      // user is logged in, but did not grant any permissions
    }
  } else {
    // user is not logged in
  }
}, {perms:'read_stream,publish_stream,offline_access'});
 
新しいアプリは簡略化された後、多くの不便をもたらしました.まず、feedが発表される時、いくつかのbugがあります.facebookはfeedの長さが1000を超える文字を規定する時、postでデータを伝えますが、facebookはデータを伝える時、値を間違えて伝えました.encodeの後で手渡して、直接対象を着て過去に行って、feedが発表できないことを招いて、修正の方式は、source codeを参考にしてFB.C.ontent.postTarget関数の定義を改正します.
 
FB.Content.postTarget = function(opts) {
    var form = document.createElement('form');
    form.action = opts.url;
    form.target = opts.target;
    form.method = 'POST';
    FB.Content.appendHidden(form);

    FB.Array.forEach(opts.params, function(val, key) {
      if (val !== null && val !== undefined) {
        var input = document.createElement('input');
        input.name = key;
        if (typeof val == "object" || typeof val == "array") {
		        input.value = FB.JSON.stringify(val);
		    } else {
		    		input.value = val;
		    }
        form.appendChild(input);
      }
    });

    form.submit();
    form.parentNode.removeChild(form);
};
 
本来のコードは:
postTarget: function(opts) {
    var form = document.createElement('form');
    form.action = opts.url;
    form.target = opts.target;
    form.method = 'POST';
    FB.Content.appendHidden(form);

    FB.Array.forEach(opts.params, function(val, key) {
      if (val !== null && val !== undefined) {
        var input = document.createElement('input');
        input.name = key;
        input.value = val;
        form.appendChild(input);
      }
    });

    form.submit();
    form.parentNode.removeChild(form);
}
 
facebookのfbmlは実際にiframeをローディングしています.ローディング前にloadingを表示しています.フェイスブックはここでhtml 5を採用しています.フェイスブックの実現はたまに問題が発生します.ずっとloadingしています.iframeは表示されません.フェイスブック開発チームはまだ解決方法を提供していません.また、js sourceを修正して解決します.
まず変数を追加します.
/********* fix fbjs api start:{set method used for FB.UIServer.iframe} *************/
FB.UIServer._SDialogMethod   = '';
/********* fix fbjs api end *************/
 FB.UICServer.prepare Call方法を修正し、以下のコードを追加して、現在のui methodを記録します.
/********* fix fbjs api start:{set method used for FB.UIServer.iframe} *************/
  FB.UIServer._SDialogMethod = params.method.toLowerCase();
/********* fix fbjs api end *************/
 FB.UICServer.iframeメソッドを修正し、iframeをロードする時、直接表示します.
 
/********* fix fbjs api start:{dialog loading bug,set default iframe and float div size} *************/
if ('stream.publish' == FB.UIServer._SDialogMethod) {
    var _SLoaderState    = false;	// --     loading,    false,   
    var _SVisibleState   = true;	// -- ui dialog    ,  true,  
    // -- set iframe background default size,only set width so it will show at center,if set height, the background can't resize if iframe size changed
    var _SInitSize  = { width: 575, height:'100%'};
    call.size.height    = 290;
} else if ('bookmark.add' == FB.UIServer._SDialogMethod) {
	var _SLoaderState    = false;
    var _SVisibleState   = true;
    // -- set iframe default size
    var _SInitSize  = { width: 460, height:'100%' };
} else if ('auth.permission' == FB.UIServer._SDialogMethod) {
    var _SLoaderState    = false;
    var _SVisibleState   = true;
    // -- set iframe default size
    if ('email' == call.params.ext_perm) {
  	var _SInitSize  = { width: 627, height:200};
      call.size.height    = 200;
    } else {
    	var _SInitSize  = { width: 627, height:350};
        call.size.height    = 350;
    }
} else {
    var _SLoaderState    = true;
    var _SVisibleState   = false;
    var _SInitSize  = false;
}
/********* fix fbjs api end *************/
 FB.Dialog.reate方法を修正して、初期サイズがあれば、アスペクト値を設定します.
if (opts.visible) {
	  /********* fix fbjs api start:{dialog loading bug,set default iframe size} *************/
    try {
      if (opts._SInit) {
          dialog.style.width  = opts._SInit.width + 'px';
            dialog.style.height  = opts._SInit.height + 'px';
      }
    } catch (e) {}
    /********* fix fbjs api end *************/
    FB.Dialog.show(dialog);
}
 
このように修正した後、feedやbook markが発表された時、ずっとloadingのところにカードがないです.特にバックグランドには大量のデータがロードされています.
最後に授権時のポップアップウィンドウの問題を修正しました.現在授権する時はログイン時と同じインターフェースを呼び出すので、ライセンスインターフェースは新しいウィンドウで開きます.これで大部分のブラウザによってブロックされます.ユーザが一番上の現在では、明らかに受け入れられません.古いアプリを参考にして、一つのui methodをカスタマイズします.
 
/************* fix fbjs api start: {permission dialog} ******************/
FB.provide('UIServer.Methods', {
  'auth.permission': {
    size      : { width: 627, height: 350 },
    url       : 'connect/prompt_permissions.php',
    transform : function(call) {
      //FIXME
      if (!FB._apiKey) {
        FB.log('FB.login() called before calling FB.init().');
        return;
      }

      // if we already have a session and permissions are not being requested,
      // we just fire the callback
      if (FB._session && !call.params.perms) {
        FB.log('FB.login() called when user is already connected.');
        call.cb && call.cb({ status: FB._userStatus, session: FB._session });
        return;
      }
      
      var
        xdHandler = FB.Auth.xdHandler,
        cb        = call.cb,
        id        = call.id,
        session   = FB._session,
        cancel    = xdHandler(
          cb,
          id,
          'parent',
          true, // isDefault
          FB._userStatus,
          session),
        next      = xdHandler(
          cb,
          id,
          'parent',
          false, // isDefault
          'connected',
          session);

      FB.copy(call.params, {
        cancel_url              : cancel,
        channel_url             : window.location.toString(),
        next                    : next,
        ext_perm                : call.params.perms
      });
      delete call.cb;
      delete call.params.perms; //TODO fix name to be the same on server
      return call;
    }
  }
});
/************* fix fbjs api end ******************/
 授権が必要な場合は、以下の関数を呼び出します.
FB.ui(
   {
     method: 'auth.permission',
     perms: p_permissions
   },
   function(response){
      if ('' == response) {
          p_callback('failed');
          return false;
      }
      if (response.perms && egi.test(response.perms)) {
          // -- success
          var p_state = 'success';
      } else {
          var p_state = 'failed';
      }
      if (typeof p_callback == 'function') {
          p_callback(p_state);
      }
  }
);