-
Notifications
You must be signed in to change notification settings - Fork 228
/
openfb.js
306 lines (258 loc) · 12.1 KB
/
openfb.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
/**
* OpenFB is a micro-library that lets you integrate your JavaScript application with Facebook.
* OpenFB works for both BROWSER-BASED apps and CORDOVA/PHONEGAP apps.
* This library has no dependency: You don't need (and shouldn't use) the Facebook SDK with this library. Whe running in
* Cordova, you also don't need the Facebook Cordova plugin. There is also no dependency on jQuery.
* OpenFB allows you to login to Facebook and execute any Facebook Graph API request.
* @author Christophe Coenraets @ccoenraets
* @version 0.5
*/
var openFB = (function () {
var loginURL = 'https://www.facebook.com/dialog/oauth',
logoutURL = 'https://www.facebook.com/logout.php',
// By default we store fbtoken in sessionStorage. This can be overridden in init()
tokenStore = window.sessionStorage,
// The Facebook App Id. Required. Set using init().
fbAppId,
context = window.location.pathname.substring(0, window.location.pathname.lastIndexOf("/")),
baseURL = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '') + context,
// Default OAuth redirect URL. Can be overriden in init()
oauthRedirectURL = baseURL + '/oauthcallback.html',
// Default Cordova OAuth redirect URL. Can be overriden in init()
cordovaOAuthRedirectURL = "https://www.facebook.com/connect/login_success.html",
// Default Logout redirect URL. Can be overriden in init()
logoutRedirectURL = baseURL + '/logoutcallback.html',
// Because the OAuth login spans multiple processes, we need to keep the login callback function as a variable
// inside the module instead of keeping it local within the login function.
loginCallback,
// Indicates if the app is running inside Cordova
runningInCordova,
// Used in the exit event handler to identify if the login has already been processed elsewhere (in the oauthCallback function)
loginProcessed;
// MAKE SURE YOU INCLUDE <script src="cordova.js"></script> IN YOUR index.html, OTHERWISE runningInCordova will always by false.
// You don't need to (and should not) add the actual cordova.js file to your file system: it will be added automatically
// by the Cordova build process
document.addEventListener("deviceready", function () {
runningInCordova = true;
}, false);
/**
* Initialize the OpenFB module. You must use this function and initialize the module with an appId before you can
* use any other function.
* @param params - init paramters
* appId: (Required) The id of the Facebook app,
* tokenStore: (optional) The store used to save the Facebook token. If not provided, we use sessionStorage.
* loginURL: (optional) The OAuth login URL. Defaults to https://www.facebook.com/dialog/oauth.
* logoutURL: (optional) The logout URL. Defaults to https://www.facebook.com/logout.php.
* oauthRedirectURL: (optional) The OAuth redirect URL. Defaults to [baseURL]/oauthcallback.html.
* cordovaOAuthRedirectURL: (optional) The OAuth redirect URL. Defaults to https://www.facebook.com/connect/login_success.html.
* logoutRedirectURL: (optional) The logout redirect URL. Defaults to [baseURL]/logoutcallback.html.
* accessToken: (optional) An already authenticated access token.
*/
function init(params) {
if (params.appId) {
fbAppId = params.appId;
} else {
throw 'appId parameter not set in init()';
}
if (params.tokenStore) {
tokenStore = params.tokenStore;
}
if (params.accessToken) {
tokenStore.fbAccessToken = params.accessToken;
}
loginURL = params.loginURL || loginURL;
logoutURL = params.logoutURL || logoutURL;
oauthRedirectURL = params.oauthRedirectURL || oauthRedirectURL;
cordovaOAuthRedirectURL = params.cordovaOAuthRedirectURL || cordovaOAuthRedirectURL;
logoutRedirectURL = params.logoutRedirectURL || logoutRedirectURL;
}
/**
* Checks if the user has logged in with openFB and currently has a session api token.
* @param callback the function that receives the loginstatus
*/
function getLoginStatus(callback) {
var token = tokenStore.fbAccessToken,
loginStatus = {};
if (token) {
loginStatus.status = 'connected';
loginStatus.authResponse = {accessToken: token};
} else {
loginStatus.status = 'unknown';
}
if (callback) callback(loginStatus);
}
/**
* Login to Facebook using OAuth. If running in a Browser, the OAuth workflow happens in a a popup window.
* If running in Cordova container, it happens using the In-App Browser. Don't forget to install the In-App Browser
* plugin in your Cordova project: cordova plugins add org.apache.cordova.inappbrowser.
*
* @param callback - Callback function to invoke when the login process succeeds
* @param options - options.scope: The set of Facebook permissions requested
* @returns {*}
*/
function login(callback, options) {
var loginWindow,
startTime,
scope = '',
redirectURL = runningInCordova ? cordovaOAuthRedirectURL : oauthRedirectURL;
if (!fbAppId) {
return callback({status: 'unknown', error: 'Facebook App Id not set.'});
}
// Inappbrowser load start handler: Used when running in Cordova only
function loginWindow_loadStartHandler(event) {
var url = event.url;
if (url.indexOf("access_token=") > 0 || url.indexOf("error=") > 0) {
// When we get the access token fast, the login window (inappbrowser) is still opening with animation
// in the Cordova app, and trying to close it while it's animating generates an exception. Wait a little...
var timeout = 600 - (new Date().getTime() - startTime);
setTimeout(function () {
loginWindow.close();
}, timeout > 0 ? timeout : 0);
oauthCallback(url);
}
}
// Inappbrowser exit handler: Used when running in Cordova only
function loginWindow_exitHandler() {
console.log('exit and remove listeners');
// Handle the situation where the user closes the login window manually before completing the login process
if (loginCallback && !loginProcessed) loginCallback({status: 'user_cancelled'});
loginWindow.removeEventListener('loadstop', loginWindow_loadStopHandler);
loginWindow.removeEventListener('exit', loginWindow_exitHandler);
loginWindow = null;
console.log('done removing listeners');
}
if (options && options.scope) {
scope = options.scope;
}
loginCallback = callback;
loginProcessed = false;
startTime = new Date().getTime();
loginWindow = window.open(loginURL + '?client_id=' + fbAppId + '&redirect_uri=' + redirectURL +
'&response_type=token&scope=' + scope, '_blank', 'location=no,clearcache=yes');
// If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error
if (runningInCordova) {
loginWindow.addEventListener('loadstart', loginWindow_loadStartHandler);
loginWindow.addEventListener('exit', loginWindow_exitHandler);
}
// Note: if the app is running in the browser the loginWindow dialog will call back by invoking the
// oauthCallback() function. See oauthcallback.html for details.
}
/**
* Called either by oauthcallback.html (when the app is running the browser) or by the loginWindow loadstart event
* handler defined in the login() function (when the app is running in the Cordova/PhoneGap container).
* @param url - The oautchRedictURL called by Facebook with the access_token in the querystring at the ned of the
* OAuth workflow.
*/
function oauthCallback(url) {
// Parse the OAuth data received from Facebook
var queryString,
obj;
loginProcessed = true;
if (url.indexOf("access_token=") > 0) {
queryString = url.substr(url.indexOf('#') + 1);
obj = parseQueryString(queryString);
tokenStore.fbAccessToken = obj['access_token'];
if (loginCallback) loginCallback({status: 'connected', authResponse: {accessToken: obj['access_token']}});
} else if (url.indexOf("error=") > 0) {
queryString = url.substring(url.indexOf('?') + 1, url.indexOf('#'));
obj = parseQueryString(queryString);
if (loginCallback) loginCallback({status: 'not_authorized', error: obj.error});
} else {
if (loginCallback) loginCallback({status: 'not_authorized'});
}
}
/**
* Logout from Facebook, and remove the token.
* IMPORTANT: For the Facebook logout to work, the logoutRedirectURL must be on the domain specified in "Site URL" in your Facebook App Settings
*
*/
function logout(callback) {
var logoutWindow,
token = tokenStore.fbAccessToken;
/* Remove token. Will fail silently if does not exist */
tokenStore.removeItem('fbtoken');
if (token) {
logoutWindow = window.open(logoutURL + '?access_token=' + token + '&next=' + logoutRedirectURL, '_blank', 'location=no,clearcache=yes');
if (runningInCordova) {
setTimeout(function() {
logoutWindow.close();
}, 700);
}
}
if (callback) {
callback();
}
}
/**
* Lets you make any Facebook Graph API request.
* @param obj - Request configuration object. Can include:
* method: HTTP method: GET, POST, etc. Optional - Default is 'GET'
* path: path in the Facebook graph: /me, /me.friends, etc. - Required
* params: queryString parameters as a map - Optional
* success: callback function when operation succeeds - Optional
* error: callback function when operation fails - Optional
*/
function api(obj) {
var method = obj.method || 'GET',
params = obj.params || {},
xhr = new XMLHttpRequest(),
url;
params['access_token'] = tokenStore.fbAccessToken;
url = 'https://graph.facebook.com' + obj.path + '?' + toQueryString(params);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
if (obj.success) obj.success(JSON.parse(xhr.responseText));
} else {
var error = xhr.responseText ? JSON.parse(xhr.responseText).error : {message: 'An error has occurred'};
if (obj.error) obj.error(error);
}
}
};
xhr.open(method, url, true);
xhr.send();
}
/**
* Helper function to de-authorize the app
* @param success
* @param error
* @returns {*}
*/
function revokePermissions(success, error) {
return api({method: 'DELETE',
path: '/me/permissions',
success: function () {
success();
},
error: error});
}
function parseQueryString(queryString) {
var qs = decodeURIComponent(queryString),
obj = {},
params = qs.split('&');
params.forEach(function (param) {
var splitter = param.split('=');
obj[splitter[0]] = splitter[1];
});
return obj;
}
function toQueryString(obj) {
var parts = [];
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
}
}
return parts.join("&");
}
// The public API
return {
init: init,
login: login,
logout: logout,
revokePermissions: revokePermissions,
api: api,
oauthCallback: oauthCallback,
getLoginStatus: getLoginStatus
}
}());