Created
May 19, 2017 00:39
-
-
Save georgeportillo/c24ab323a7e562bcaef9cb56529925b6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = "facebook"; | |
(function(window, angular, undefined) { | |
'use strict'; | |
// Module global settings. | |
var settings = {}; | |
// Module global flags. | |
var flags = { | |
sdk: false, | |
ready: false | |
}; | |
// Deferred Object which will be resolved when the Facebook SDK is ready | |
// and the `fbAsyncInit` function is called. | |
var loadDeferred; | |
/** | |
* @name facebook | |
* @kind function | |
* @description | |
* An Angularjs module to take approach of Facebook javascript sdk. | |
* | |
* @author Luis Carlos Osorio Jayk <[email protected]> | |
*/ | |
angular.module('facebook', []). | |
// Declare module settings value | |
value('settings', settings). | |
// Declare module flags value | |
value('flags', flags). | |
/** | |
* Facebook provider | |
*/ | |
provider('Facebook', [ | |
function() { | |
/** | |
* Facebook appId | |
* @type {Number} | |
*/ | |
settings.appId = null; | |
this.setAppId = function(appId) { | |
settings.appId = appId; | |
}; | |
this.getAppId = function() { | |
return settings.appId; | |
}; | |
/** | |
* Locale language, english by default | |
* @type {String} | |
*/ | |
settings.locale = 'en_US'; | |
this.setLocale = function(locale) { | |
settings.locale = locale; | |
}; | |
this.getLocale = function() { | |
return settings.locale; | |
}; | |
/** | |
* Set if you want to check the authentication status | |
* at the start up of the app | |
* @type {Boolean} | |
*/ | |
settings.status = true; | |
this.setStatus = function(status) { | |
settings.status = status; | |
}; | |
this.getStatus = function() { | |
return settings.status; | |
}; | |
/** | |
* Adding a Channel File improves the performance of the javascript SDK, | |
* by addressing issues with cross-domain communication in certain browsers. | |
* @type {String} | |
*/ | |
settings.channelUrl = null; | |
this.setChannel = function(channel) { | |
settings.channelUrl = channel; | |
}; | |
this.getChannel = function() { | |
return settings.channelUrl; | |
}; | |
/** | |
* Enable cookies to allow the server to access the session | |
* @type {Boolean} | |
*/ | |
settings.cookie = true; | |
this.setCookie = function(cookie) { | |
settings.cookie = cookie; | |
}; | |
this.getCookie = function() { | |
return settings.cookie; | |
}; | |
/** | |
* Parse XFBML | |
* @type {Boolean} | |
*/ | |
settings.xfbml = true; | |
this.setXfbml = function(enable) { | |
settings.xfbml = enable; | |
}; | |
this.getXfbml = function() { | |
return settings.xfbml; | |
}; | |
/** | |
* Auth Response | |
* @type {Object} | |
*/ | |
this.setAuthResponse = function(obj) { | |
settings.authResponse = obj || true; | |
}; | |
this.getAuthResponse = function() { | |
return settings.authResponse; | |
}; | |
/** | |
* Frictionless Requests | |
* @type {Boolean} | |
*/ | |
settings.frictionlessRequests = false; | |
this.setFrictionlessRequests = function(enable) { | |
settings.frictionlessRequests = enable; | |
}; | |
this.getFrictionlessRequests = function() { | |
return settings.frictionlessRequests; | |
}; | |
/** | |
* HideFlashCallback | |
* @type {Object} | |
*/ | |
settings.hideFlashCallback = null; | |
this.setHideFlashCallback = function(obj) { | |
settings.hideFlashCallback = obj || null; | |
}; | |
this.getHideFlashCallback = function() { | |
return settings.hideFlashCallback; | |
}; | |
/** | |
* Custom option setting | |
* key @type {String} | |
* value @type {*} | |
* @return {*} | |
*/ | |
this.setInitCustomOption = function(key, value) { | |
if (!angular.isString(key)) { | |
return false; | |
} | |
settings[key] = value; | |
return settings[key]; | |
}; | |
/** | |
* get init option | |
* @param {String} key | |
* @return {*} | |
*/ | |
this.getInitOption = function(key) { | |
// If key is not String or If non existing key return null | |
if (!angular.isString(key) || !settings.hasOwnProperty(key)) { | |
return false; | |
} | |
return settings[key]; | |
}; | |
/** | |
* load SDK | |
*/ | |
settings.loadSDK = true; | |
this.setLoadSDK = function(a) { | |
settings.loadSDK = !!a; | |
}; | |
this.getLoadSDK = function() { | |
return settings.loadSDK; | |
}; | |
/** | |
* SDK version | |
*/ | |
settings.version = 'v2.0'; | |
this.setSdkVersion = function(version) { | |
settings.version = version; | |
}; | |
this.getSdkVersion = function() { | |
return settings.version; | |
}; | |
/** | |
* Init Facebook API required stuff | |
* This will prepare the app earlier (on settingsuration) | |
* @arg {Object/String} initSettings | |
* @arg {Boolean} _loadSDK (optional, true by default) | |
*/ | |
this.init = function(initSettings, _loadSDK) { | |
// If string is passed, set it as appId | |
if (angular.isString(initSettings)) { | |
settings.appId = initSettings; | |
} | |
if(angular.isNumber(initSettings)) { | |
settings.appId = initSettings.toString(); | |
} | |
// If object is passed, merge it with app settings | |
if (angular.isObject(initSettings)) { | |
angular.extend(settings, initSettings); | |
} | |
// Set if Facebook SDK should be loaded automatically or not. | |
if (angular.isDefined(_loadSDK)) { | |
settings.loadSDK = !!_loadSDK; | |
} | |
}; | |
/** | |
* This defined the Facebook service | |
*/ | |
this.$get = [ | |
'$q', | |
'$rootScope', | |
'$timeout', | |
'$window', | |
function($q, $rootScope, $timeout, $window) { | |
/** | |
* This is the NgFacebook class to be retrieved on Facebook Service request. | |
*/ | |
function NgFacebook() { | |
this.appId = settings.appId; | |
} | |
/** | |
* Ready state method | |
* @return {Boolean} | |
*/ | |
NgFacebook.prototype.isReady = function() { | |
return flags.ready; | |
}; | |
NgFacebook.prototype.login = function () { | |
var d = $q.defer(), | |
args = Array.prototype.slice.call(arguments), | |
userFn, | |
userFnIndex; // Converts arguments passed into an array | |
// Get user function and it's index in the arguments array, | |
// to replace it with custom function, allowing the usage of promises | |
angular.forEach(args, function(arg, index) { | |
if (angular.isFunction(arg)) { | |
userFn = arg; | |
userFnIndex = index; | |
} | |
}); | |
// Replace user function intended to be passed to the Facebook API with a custom one | |
// for being able to use promises. | |
if (angular.isFunction(userFn) && angular.isNumber(userFnIndex)) { | |
args.splice(userFnIndex, 1, function(response) { | |
$timeout(function() { | |
if (response && angular.isUndefined(response.error)) { | |
d.resolve(response); | |
} else { | |
d.reject(response); | |
} | |
if (angular.isFunction(userFn)) { | |
userFn(response); | |
} | |
}); | |
}); | |
} | |
// review(mrzmyr): generalize behaviour of isReady check | |
if (this.isReady()) { | |
$window.FB.login.apply($window.FB, args); | |
} else { | |
$timeout(function() { | |
d.reject("Facebook.login() called before Facebook SDK has loaded."); | |
}); | |
} | |
return d.promise; | |
}; | |
/** | |
* Map some asynchronous Facebook SDK methods to NgFacebook | |
*/ | |
angular.forEach([ | |
'logout', | |
'api', | |
'ui', | |
'getLoginStatus' | |
], function(name) { | |
NgFacebook.prototype[name] = function() { | |
var d = $q.defer(), | |
args = Array.prototype.slice.call(arguments), // Converts arguments passed into an array | |
userFn, | |
userFnIndex; | |
// Get user function and it's index in the arguments array, | |
// to replace it with custom function, allowing the usage of promises | |
angular.forEach(args, function(arg, index) { | |
if (angular.isFunction(arg)) { | |
userFn = arg; | |
userFnIndex = index; | |
} | |
}); | |
// Replace user function intended to be passed to the Facebook API with a custom one | |
// for being able to use promises. | |
if (angular.isFunction(userFn) && angular.isNumber(userFnIndex)) { | |
args.splice(userFnIndex, 1, function(response) { | |
$timeout(function() { | |
if (response && angular.isUndefined(response.error)) { | |
d.resolve(response); | |
} else { | |
d.reject(response); | |
} | |
if (angular.isFunction(userFn)) { | |
userFn(response); | |
} | |
}); | |
}); | |
} | |
$timeout(function() { | |
// Call when loadDeferred be resolved, meaning Service is ready to be used. | |
loadDeferred.promise.then(function() { | |
$window.FB[name].apply(FB, args); | |
}); | |
}); | |
return d.promise; | |
}; | |
}); | |
/** | |
* Map Facebook sdk XFBML.parse() to NgFacebook. | |
*/ | |
NgFacebook.prototype.parseXFBML = function() { | |
var d = $q.defer(); | |
$timeout(function() { | |
// Call when loadDeferred be resolved, meaning Service is ready to be used | |
loadDeferred.promise.then(function() { | |
$window.FB.XFBML.parse(); | |
d.resolve(); | |
}); | |
}); | |
return d.promise; | |
}; | |
/** | |
* Map Facebook SDK subscribe/unsubscribe method to NgFacebook. | |
* Use it as Facebook.subscribe / Facebook.unsubscribe in the service. | |
*/ | |
angular.forEach([ | |
'subscribe', | |
'unsubscribe', | |
], function(name) { | |
NgFacebook.prototype[name] = function() { | |
var d = $q.defer(), | |
args = Array.prototype.slice.call(arguments), // Get arguments passed into an array | |
userFn, | |
userFnIndex; | |
// Get user function and it's index in the arguments array, | |
// to replace it with custom function, allowing the usage of promises | |
angular.forEach(args, function(arg, index) { | |
if (angular.isFunction(arg)) { | |
userFn = arg; | |
userFnIndex = index; | |
} | |
}); | |
// Replace user function intended to be passed to the Facebook API with a custom one | |
// for being able to use promises. | |
if (angular.isFunction(userFn) && angular.isNumber(userFnIndex)) { | |
args.splice(userFnIndex, 1, function(response) { | |
$timeout(function() { | |
if (response && angular.isUndefined(response.error)) { | |
d.resolve(response); | |
} else { | |
d.reject(response); | |
} | |
if (angular.isFunction(userFn)) { | |
userFn(response); | |
} | |
}); | |
}); | |
} | |
$timeout(function() { | |
// Call when loadDeferred be resolved, meaning Service is ready to be used | |
loadDeferred.promise.then(function() { | |
$window.FB.Event[name].apply(FB, args); | |
}); | |
}); | |
return d.promise; | |
}; | |
}); | |
return new NgFacebook(); // Singleton | |
} | |
]; | |
} | |
]). | |
/** | |
* Module initialization | |
*/ | |
run([ | |
'$rootScope', | |
'$q', | |
'$window', | |
'$timeout', | |
function($rootScope, $q, $window, $timeout) { | |
// Define global loadDeffered to notify when Service callbacks are safe to use | |
loadDeferred = $q.defer(); | |
var loadSDK = settings.loadSDK; | |
delete(settings['loadSDK']); // Remove loadSDK from settings since this isn't part from Facebook API. | |
/** | |
* Define fbAsyncInit required by Facebook API | |
*/ | |
$window.fbAsyncInit = function() { | |
// Initialize our Facebook app | |
$timeout(function() { | |
if (!settings.appId) { | |
throw 'Missing appId setting.'; | |
} | |
FB.init(settings); | |
flags.ready = true; | |
/** | |
* Subscribe to Facebook API events and broadcast through app. | |
*/ | |
angular.forEach({ | |
'auth.login': 'login', | |
'auth.logout': 'logout', | |
'auth.prompt': 'prompt', | |
'auth.sessionChange': 'sessionChange', | |
'auth.statusChange': 'statusChange', | |
'auth.authResponseChange': 'authResponseChange', | |
'xfbml.render': 'xfbmlRender', | |
'edge.create': 'like', | |
'edge.remove': 'unlike', | |
'comment.create': 'comment', | |
'comment.remove': 'uncomment' | |
}, function(mapped, name) { | |
FB.Event.subscribe(name, function(response) { | |
$timeout(function() { | |
$rootScope.$broadcast('Facebook:' + mapped, response); | |
}); | |
}); | |
}); | |
// Broadcast Facebook:load event | |
$rootScope.$broadcast('Facebook:load'); | |
loadDeferred.resolve(FB); | |
}); | |
}; | |
/** | |
* Inject Facebook root element in DOM | |
*/ | |
(function addFBRoot() { | |
var fbroot = document.getElementById('fb-root'); | |
if (!fbroot) { | |
fbroot = document.createElement('div'); | |
fbroot.id = 'fb-root'; | |
document.body.insertBefore(fbroot, document.body.childNodes[0]); | |
} | |
return fbroot; | |
})(); | |
/** | |
* SDK script injecting | |
*/ | |
if(loadSDK) { | |
(function injectScript() { | |
var src = '//connect.facebook.net/' + settings.locale + '/sdk.js', | |
script = document.createElement('script'); | |
script.id = 'facebook-jssdk'; | |
script.async = true; | |
// Prefix protocol | |
// for sure we don't want to ignore things, but this tests exists, | |
// but it isn't recognized by istanbul, so we give it a 'ignore if' | |
/* istanbul ignore if */ | |
if ($window.location.protocol.indexOf('file:') !== -1) { | |
src = 'https:' + src; | |
} | |
script.src = src; | |
script.onload = function() { | |
flags.sdk = true; | |
}; | |
// Fix for IE < 9, and yet supported by latest browsers | |
document.getElementsByTagName('head')[0].appendChild(script); | |
})(); | |
} | |
} | |
]); | |
})(window, angular); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment