├── .nvmrc ├── .gitignore ├── src └── angularjs-facebook-sdk │ ├── angularjs-facebook-sdk.suffix │ ├── angularjs-facebook-sdk.prefix │ ├── directives │ ├── facebook_logout_directive.js │ ├── facebook_share_directive.js │ ├── facebook_follow_directive.js │ ├── facebook_login_directive.js │ ├── facebook_send_directive.js │ ├── facebook_profile_pic_directive.js │ ├── facebook_comments_directive.js │ └── facebook_like_directive.js │ ├── angularjs-facebook-sdk.js │ └── services │ ├── facebook_config_provider.js │ └── facebook_service.js ├── .editorconfig ├── .jshintrc ├── bower.json ├── README.md ├── test └── unit │ └── angularjs-facebook-sdk │ ├── angularjs-facebook-sdk.js │ └── services │ ├── facebook_service.js │ └── facebook_config_provider.js ├── example ├── app.css ├── index.html ├── home.html └── app.js ├── LICENSE ├── package.json ├── karma-unit.conf.js ├── Gruntfile.js └── dist ├── angularjs-facebook-sdk.min.js └── angularjs-facebook-sdk.js /.nvmrc: -------------------------------------------------------------------------------- 1 | 0.10.0 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /src/angularjs-facebook-sdk/angularjs-facebook-sdk.suffix: -------------------------------------------------------------------------------- 1 | })(window, document); 2 | -------------------------------------------------------------------------------- /src/angularjs-facebook-sdk/angularjs-facebook-sdk.prefix: -------------------------------------------------------------------------------- 1 | (function(window, document) { 2 | 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "es5": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 4, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "white": true 22 | } 23 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angularjs-facebook-sdk", 3 | "version": "1.1.0", 4 | "main": "dist/angularjs-facebook-sdk.js", 5 | "moduleType": [ 6 | "global" 7 | ], 8 | "dependencies": { 9 | "jquery": "~2.1.0", 10 | "angular": "~1.6.4", 11 | "highlightjs": "^9.10.0", 12 | "cssreset": "^1.0.0", 13 | "angular-route": "1.6.4" 14 | }, 15 | "ignore": [ 16 | "bower_components", 17 | "test", 18 | "src", 19 | "example", 20 | "Gruntfile.js", 21 | "karma-unit.conf.js", 22 | "LICENSE", 23 | "package.json", 24 | "README.md", 25 | ".gitignore", 26 | ".jshintrc", 27 | ".editorconfig" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /src/angularjs-facebook-sdk/directives/facebook_logout_directive.js: -------------------------------------------------------------------------------- 1 | function FacebookLogoutDirective(facebookService) { 2 | return { 3 | restrict: 'E', 4 | replace: true, 5 | template: '', 6 | scope: { 7 | label: '@label' 8 | }, 9 | link: function (scope, element) { 10 | scope.dispatchLogout = function dispatchLogin() { 11 | facebookService.logout(); 12 | }; 13 | } 14 | }; 15 | } 16 | 17 | FacebookLogoutDirective.$inject = ['facebookService']; 18 | 19 | angular.module('angularjs-facebook-sdk.directives') 20 | .directive('afbLogout', FacebookLogoutDirective); 21 | -------------------------------------------------------------------------------- /src/angularjs-facebook-sdk/directives/facebook_share_directive.js: -------------------------------------------------------------------------------- 1 | function FacebookShareDirective(facebookService) { 2 | return { 3 | restrict: 'E', 4 | replace: true, 5 | template: '', 6 | scope: { 7 | href: '@href', 8 | type: '@type' 9 | }, 10 | link: function (scope, element) { 11 | facebookService.ready.then(function () { 12 | FB.XFBML.parse(element[0]); 13 | }); 14 | } 15 | }; 16 | } 17 | 18 | FacebookShareDirective.$inject = ['facebookService']; 19 | 20 | angular.module('angularjs-facebook-sdk.directives') 21 | .directive('afbShareButton', FacebookShareDirective); 22 | -------------------------------------------------------------------------------- /src/angularjs-facebook-sdk/directives/facebook_follow_directive.js: -------------------------------------------------------------------------------- 1 | function FacebookFollowDirective(facebookService) { 2 | return { 3 | restrict: 'E', 4 | replace: true, 5 | template: '', 6 | scope: { 7 | href: '@href', 8 | colorschema: '@colorschema', 9 | layout: '@layout', 10 | showFaces: '@showFaces' 11 | }, 12 | link: function (scope, element) { 13 | facebookService.ready.then(function () { 14 | FB.XFBML.parse(element[0]); 15 | }); 16 | } 17 | }; 18 | } 19 | 20 | FacebookFollowDirective.$inject = ['facebookService']; 21 | 22 | angular.module('angularjs-facebook-sdk.directives') 23 | .directive('afbFollow', FacebookFollowDirective); 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | angularjs-facebook-sdk 2 | ====================== 3 | 4 | Integration between AngularJS and Facebook SDK for Javascript. 5 | 6 | ### Documentation 7 | 8 | [wlepinski.github.io/angularjs-facebook-sdk/](http://wlepinski.github.io/angularjs-facebook-sdk/) 9 | 10 | ### Compiling from source 11 | 12 | You'll need [NodeJS](http://nodejs.org) installed to compile the source-code. 13 | 14 | Clone the project and run npm install && npm run build on the root folder. 15 | The compiled and minified files will be generated under dist folder 16 | 17 | ### Running the examples 18 | 19 | To see the examples run npm start ( Make sure you define your appId in the file examples/app.js ). 20 | 21 | ### Running tests 22 | 23 | To execute the unit tests run npm test. 24 | 25 | ### Contributing 26 | 27 | Use the issue tracker to send PRs. 28 | -------------------------------------------------------------------------------- /src/angularjs-facebook-sdk/angularjs-facebook-sdk.js: -------------------------------------------------------------------------------- 1 | // Create all modules and define dependencies to make sure they exist 2 | // and are loaded in the correct order to satisfy dependency injection 3 | // before all nested files are concatenated by Grunt 4 | 5 | // Config 6 | angular.module('angularjs-facebook-sdk.config', []) 7 | .value('angularjs-facebook-sdk.config', { 8 | debug: true 9 | }); 10 | 11 | // Modules 12 | angular.module('angularjs-facebook-sdk.directives', []); 13 | angular.module('angularjs-facebook-sdk.services', []); 14 | angular.module('angularjs-facebook-sdk', [ 15 | 'angularjs-facebook-sdk.config', 16 | 'angularjs-facebook-sdk.directives', 17 | 'angularjs-facebook-sdk.services' 18 | ]); 19 | 20 | angular.module('angularjs-facebook-sdk').run(['facebookConfig', 21 | function (facebookConfig) { 22 | if (facebookConfig.autoInit) { 23 | facebookConfig.init(); 24 | } 25 | } 26 | ]); 27 | -------------------------------------------------------------------------------- /test/unit/angularjs-facebook-sdk/angularjs-facebook-sdk.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Set the jasmine fixture path 4 | // jasmine.getFixtures().fixturesPath = 'base/'; 5 | 6 | describe('angularjs-facebook-sdk', function() { 7 | 8 | var module; 9 | var dependencies; 10 | dependencies = []; 11 | 12 | var hasModule = function(module) { 13 | return dependencies.indexOf(module) >= 0; 14 | }; 15 | 16 | beforeEach(function() { 17 | module = angular.module('angularjs-facebook-sdk'); 18 | dependencies = module.requires; 19 | }); 20 | 21 | it('should load config module', function() { 22 | expect(hasModule('angularjs-facebook-sdk.config')).toBeTruthy(); 23 | }); 24 | 25 | it('should load directives module', function() { 26 | expect(hasModule('angularjs-facebook-sdk.directives')).toBeTruthy(); 27 | }); 28 | 29 | it('should load services module', function() { 30 | expect(hasModule('angularjs-facebook-sdk.services')).toBeTruthy(); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /example/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Roboto, sans-serif; 3 | } 4 | 5 | body h1 { 6 | font-size: 40px; 7 | font-weight: 100; 8 | letter-spacing: -2px; 9 | margin: 20px; 10 | } 11 | 12 | .component { 13 | border: 1px solid #DDD; 14 | margin: 20px; 15 | border-radius: 5px; 16 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); 17 | } 18 | 19 | .component header h2 { 20 | font-size: 30px; 21 | font-weight: 300; 22 | line-height: 1; 23 | letter-spacing: -1px; 24 | padding: 10px; 25 | border-bottom: 1px dotted #DDD; 26 | } 27 | 28 | .component .result, 29 | .component .usage { 30 | position: relative; 31 | background: #EEE; 32 | padding: 29px 20px 10px; 33 | } 34 | 35 | .component .result h4, 36 | .component .usage h4 { 37 | background: #CCC; 38 | display: inline-block; 39 | position: absolute; 40 | top: -1px; 41 | left: 20px; 42 | padding: 3px 10px; 43 | font-weight: 100; 44 | font-size: 12px; 45 | } 46 | 47 | .component .usage { 48 | background: #FFF; 49 | border-radius: 5px; 50 | } 51 | 52 | .component .usage pre { 53 | min-height: 10px; 54 | } 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 William Albino Lepinski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /test/unit/angularjs-facebook-sdk/services/facebook_service.js: -------------------------------------------------------------------------------- 1 | describe('FacebookService', function () { 2 | var _facebookService; 3 | var _$q; 4 | 5 | //excuted before each "it" is run. 6 | beforeEach(function () { 7 | // Initialize the service provider by injecting it to a fake module's config block 8 | angular.module('testApp', []) 9 | .config(function (facebookConfigProvider) { 10 | facebookConfigProvider.setAppId(12345); 11 | }); 12 | 13 | //load the module. 14 | module('angularjs-facebook-sdk', 'testApp'); 15 | 16 | //inject your service for testing. 17 | inject(function (facebookService, $q) { 18 | _facebookService = facebookService; 19 | _$q = $q; 20 | }); 21 | }); 22 | 23 | it('should export the correct api', function () { 24 | expect(_facebookService.ready).not.toBe(null); 25 | expect(_facebookService.api).toEqual(jasmine.any(Function)); 26 | expect(_facebookService.ui).toEqual(jasmine.any(Function)); 27 | expect(_facebookService.login).toEqual(jasmine.any(Function)); 28 | expect(_facebookService.logout).toEqual(jasmine.any(Function)); 29 | expect(_facebookService.getLoginStatus).toEqual(jasmine.any(Function)); 30 | }); 31 | 32 | it('should return a promise on the api method', function () { 33 | expect(_facebookService.api().then).toBeDefined(); 34 | }) 35 | }); 36 | -------------------------------------------------------------------------------- /src/angularjs-facebook-sdk/directives/facebook_login_directive.js: -------------------------------------------------------------------------------- 1 | function FacebookLoginDirective(facebookService) { 2 | return { 3 | restrict: 'E', 4 | replace: true, 5 | template: '', 6 | scope: { 7 | label: '@label', 8 | scope: '@scope', 9 | enableProfileSelector: '@enableProfileSelector', 10 | profileSelectorIds: '@profileSelectorIds' 11 | }, 12 | compile: function (tElement, tAttrs) { 13 | var loginOpts = {}; 14 | 15 | if (tAttrs.scope) { 16 | loginOpts.scope = tAttrs.scope; 17 | } 18 | if (tAttrs.enableProfileSelector) { 19 | loginOpts.enable_profile_selector = true; 20 | } 21 | if (tAttrs.profileSelectorIds) { 22 | loginOpts.profile_selector_ids = true; 23 | } 24 | 25 | return function linkFn(scope, element) { 26 | scope.dispatchLogin = function dispatchLogin() { 27 | facebookService.login(loginOpts); 28 | }; 29 | }; 30 | } 31 | }; 32 | } 33 | 34 | FacebookLoginDirective.$inject = ['facebookService']; 35 | 36 | angular.module('angularjs-facebook-sdk.directives') 37 | .directive('afbLogin', FacebookLoginDirective); 38 | -------------------------------------------------------------------------------- /src/angularjs-facebook-sdk/directives/facebook_send_directive.js: -------------------------------------------------------------------------------- 1 | function FacebookSendDirective(facebookService) { 2 | return { 3 | restrict: 'E', 4 | replace: true, 5 | template: '', 6 | scope: { 7 | href: '@href', 8 | colorschema: '@colorschema', 9 | width: '@width', 10 | height: '@height', 11 | // Events 12 | messageSend: '@onMessageSend' 13 | }, 14 | link: function (scope, element) { 15 | function messageSendHandler(url) { 16 | if (url === scope.href) { 17 | // Call the scope event if the htmlElement match 18 | scope.messageSend({ url: url }); 19 | } 20 | } 21 | 22 | facebookService.ready.then(function () { 23 | FB.XFBML.parse(element[0]); 24 | facebookService.Event.subscribe('message.send', messageSendHandler); 25 | }); 26 | 27 | scope.$on('$destroy', function () { 28 | facebookService.Event.unsubscribe('message.send', messageSendHandler); 29 | }); 30 | } 31 | }; 32 | } 33 | 34 | FacebookSendDirective.$inject = ['facebookService']; 35 | 36 | angular.module('angularjs-facebook-sdk.directives') 37 | .directive('afbSend', FacebookSendDirective); 38 | -------------------------------------------------------------------------------- /src/angularjs-facebook-sdk/directives/facebook_profile_pic_directive.js: -------------------------------------------------------------------------------- 1 | function FacebookProfilePicDirective(facebookService) { 2 | return { 3 | restrict: 'E', 4 | replace: true, 5 | template: '', 6 | scope: { 7 | uid: '@uid', 8 | type: '@type', 9 | width: '@width', 10 | height: '@height' 11 | }, 12 | compile: function compileFn(tElement, tAttrs) { 13 | return function linkFn(scope, element) { 14 | facebookService.ready.then(function () { 15 | var pictureUrl = (scope.uid) ? scope.uid + "/picture" : "/me/picture"; 16 | 17 | var apiCall = facebookService.api(pictureUrl, { 18 | redirect: false, 19 | type: scope.type, 20 | width: scope.width, 21 | height: scope.height 22 | }); 23 | 24 | apiCall.then(function (response) { 25 | if (response && !response.error) { 26 | element.attr('src', response.data.url); 27 | } 28 | }); 29 | }); 30 | }; 31 | } 32 | }; 33 | } 34 | 35 | FacebookProfilePicDirective.$inject = ['facebookService']; 36 | 37 | angular.module('angularjs-facebook-sdk.directives') 38 | .directive('afbProfilePic', FacebookProfilePicDirective); 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angularjs-facebook-sdk", 3 | "version": "1.1.0", 4 | "dependencies": { 5 | "jquery": "~2.1.0", 6 | "angular": "~1.4.4" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/wlepinski/angularjs-facebook-sdk" 11 | }, 12 | "license": "MIT", 13 | "devDependencies": { 14 | "grunt": "~0.4.1", 15 | "grunt-contrib-copy": "~0.4.1", 16 | "grunt-contrib-concat": "~0.3.0", 17 | "grunt-contrib-coffee": "~0.7.0", 18 | "grunt-contrib-uglify": "~0.2.0", 19 | "grunt-contrib-compass": "~0.3.0", 20 | "grunt-contrib-jshint": "~0.6.0", 21 | "grunt-contrib-cssmin": "~0.6.0", 22 | "grunt-contrib-connect": "~0.6.0", 23 | "grunt-contrib-clean": "~0.4.1", 24 | "grunt-contrib-htmlmin": "~0.1.3", 25 | "grunt-contrib-imagemin": "~0.1.4", 26 | "grunt-contrib-watch": "~0.4.0", 27 | "grunt-usemin": "~0.1.11", 28 | "grunt-svgmin": "~0.2.0", 29 | "grunt-rev": "~0.1.0", 30 | "grunt-karma": "~0.4.3", 31 | "grunt-open": "~0.2.0", 32 | "grunt-concurrent": "~0.3.0", 33 | "matchdep": "~0.1.2", 34 | "connect-livereload": "~0.2.0", 35 | "grunt-google-cdn": "~0.2.0", 36 | "grunt-ngmin": "~0.0.2", 37 | "karma": "~0.9", 38 | "karma-jasmine": "~0.0.3", 39 | "karma-chrome-launcher": "~0.0.2", 40 | "angular-mocks": "~1.4.4", 41 | "angular-scenario": "~1.4.4" 42 | }, 43 | "scripts": { 44 | "test": "karma start karma-unit.conf.js", 45 | "build": "grunt", 46 | "start": "grunt serve:examples" 47 | }, 48 | "engines": { 49 | "node": ">=0.8.0" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angularjs-facebook-sdk example 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 17 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/angularjs-facebook-sdk/directives/facebook_comments_directive.js: -------------------------------------------------------------------------------- 1 | function FacebookCommentsDirective(facebookService) { 2 | return { 3 | restrict: 'E', 4 | replace: true, 5 | template: '', 6 | scope: { 7 | href: '@href', 8 | colorschema: '@colorschema', 9 | numposts: '@numposts', 10 | // Events 11 | commentCreated: '&onCommentCreated', 12 | commentRemoved: '&onCommentRemoved' 13 | }, 14 | link: function (scope, element) { 15 | function commentCreatedHandler(data) { 16 | if (data.href === scope.href) { 17 | // Call the scope event if the htmlElement match 18 | scope.commentCreated(data); 19 | } 20 | } 21 | 22 | function commentRemovedHandler(data) { 23 | if (data.href === scope.href) { 24 | // Call the scope event if the htmlElement match 25 | scope.commentRemoved(data); 26 | } 27 | } 28 | 29 | facebookService.ready.then(function () { 30 | FB.XFBML.parse(element[0]); 31 | 32 | facebookService.Event.subscribe('comment.create', commentCreatedHandler); 33 | facebookService.Event.subscribe('comment.remove', commentRemovedHandler); 34 | }); 35 | 36 | // Listen for scope removal and unsubscribe some previously added events. 37 | scope.$on('$destroy', function () { 38 | facebookService.Event.unsubscribe('comment.create', commentCreatedHandler); 39 | facebookService.Event.unsubscribe('comment.remove', commentRemovedHandler); 40 | }); 41 | } 42 | }; 43 | } 44 | 45 | FacebookCommentsDirective.$inject = ['facebookService']; 46 | 47 | angular.module('angularjs-facebook-sdk.directives') 48 | .directive('afbComments', FacebookCommentsDirective); 49 | -------------------------------------------------------------------------------- /src/angularjs-facebook-sdk/directives/facebook_like_directive.js: -------------------------------------------------------------------------------- 1 | function FacebookLikeDirective(facebookService) { 2 | return { 3 | restrict: 'E', 4 | replace: true, 5 | template: '', 6 | scope: { 7 | href: '@href', 8 | layout: '@layout', 9 | action: '@action', 10 | show_faces: '@showFaces', 11 | share: '@share', 12 | // Events 13 | edgeCreated: '&onEdgeCreated', 14 | edgeRemoved: '&onEdgeRemoved' 15 | }, 16 | link: function (scope, element, attrs) { 17 | function edgeCreatedHandler(url, htmlElement) { 18 | if (htmlElement === element[0]) { 19 | // Call the scope event if the htmlElement match 20 | scope.edgeCreated({url: url}); 21 | } 22 | } 23 | 24 | function edgeRemovedHandler(url, htmlElement) { 25 | if (htmlElement === element[0]) { 26 | // Call the scope event if the htmlElement match 27 | scope.edgeRemoved({url: url}); 28 | } 29 | } 30 | 31 | facebookService.ready.then(function () { 32 | FB.XFBML.parse(element[0]); 33 | facebookService.Event.subscribe('edge.create', edgeCreatedHandler); 34 | facebookService.Event.subscribe('edge.remove', edgeRemovedHandler); 35 | }); 36 | 37 | // Listen for scope removal and unsubscribe some previously added events. 38 | scope.$on('$destroy', function () { 39 | facebookService.Event.unsubscribe('edge.create', edgeCreatedHandler); 40 | facebookService.Event.unsubscribe('edge.remove', edgeRemovedHandler); 41 | }); 42 | } 43 | }; 44 | } 45 | 46 | FacebookLikeDirective.$inject = ['facebookService']; 47 | 48 | angular.module('angularjs-facebook-sdk.directives') 49 | .directive('afbLike', FacebookLikeDirective); 50 | -------------------------------------------------------------------------------- /karma-unit.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | 4 | // base path, that will be used to resolve files and exclude 5 | basePath: '', 6 | 7 | frameworks: ['jasmine'], 8 | 9 | plugins: [ 10 | 'karma-jasmine', 11 | 'karma-chrome-launcher' 12 | ], 13 | 14 | // list of files / patterns to load in the browser 15 | files: [ 16 | 'node_modules/angular/angular.js', 17 | 'node_modules/angular-mocks/angular-mocks.js', 18 | 'src/angularjs-facebook-sdk/angularjs-facebook-sdk.js', 19 | 'src/angularjs-facebook-sdk/directives/*.js', 20 | 'src/angularjs-facebook-sdk/services/*.js', 21 | 'test/unit/**/*.js' 22 | ], 23 | 24 | 25 | // list of files to exclude 26 | exclude: [], 27 | 28 | 29 | // test results reporter to use 30 | // possible values: 'dots', 'progress', 'junit' 31 | reporters: ['progress'], 32 | 33 | 34 | // web server port 35 | port: 9876, 36 | 37 | 38 | // cli runner port 39 | runnerPort: 9100, 40 | 41 | 42 | // enable / disable colors in the output (reporters and logs) 43 | colors: true, 44 | 45 | 46 | // level of logging 47 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 48 | logLevel: config.LOG_INFO, 49 | 50 | 51 | // enable / disable watching file and executing tests whenever any file changes 52 | autoWatch: true, 53 | 54 | 55 | // Start these browsers, currently available: 56 | // - Chrome 57 | // - ChromeCanary 58 | // - Firefox 59 | // - Opera 60 | // - Safari (only Mac) 61 | // - PhantomJS 62 | // - IE (only Windows) 63 | browsers: ['Chrome'], 64 | 65 | 66 | // If browser does not capture in given timeout [ms], kill it 67 | captureTimeout: 60000, 68 | 69 | 70 | // Continuous Integration mode 71 | // if true, it capture browsers, run tests and exit 72 | singleRun: false 73 | 74 | }); 75 | }; 76 | 77 | -------------------------------------------------------------------------------- /example/home.html: -------------------------------------------------------------------------------- 1 |
2 |

Documentation: angularjs.facebook.sdk

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 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 65 | 66 | 67 | 68 | 69 | 70 |
-------------------------------------------------------------------------------- /test/unit/angularjs-facebook-sdk/services/facebook_config_provider.js: -------------------------------------------------------------------------------- 1 | describe('FacebookConfigProvider', function () { 2 | 3 | var _facebookConfigProvider; 4 | 5 | beforeEach(function () { 6 | // Initialize the service provider by injecting it to a fake module's config block 7 | angular.module('testApp', []) 8 | .config(function (facebookConfigProvider) { 9 | _facebookConfigProvider = facebookConfigProvider; 10 | }); 11 | 12 | // Initialize myApp injector 13 | module('angularjs-facebook-sdk', 'testApp'); 14 | 15 | // Kickstart the injectors previously registered with calls to angular.mock.module 16 | inject(function () {}); 17 | }); 18 | 19 | describe('with custom configuration', function () { 20 | it('tests the providers internal function', inject(function ($injector) { 21 | // check sanity 22 | expect(_facebookConfigProvider).not.toBeUndefined(); 23 | 24 | // configure the provider 25 | _facebookConfigProvider.setAppId('12345'); 26 | _facebookConfigProvider.setSdkVersion('v2.2'); 27 | _facebookConfigProvider.setDebug(true); 28 | _facebookConfigProvider.setLanguage('pt_BR'); 29 | 30 | // Invoke the provider factory function 31 | var instance = $injector.invoke(_facebookConfigProvider.$get); 32 | 33 | // test an instance of the provider for 34 | // the custom configuration changes 35 | expect(instance.appId).toBe('12345'); 36 | expect(instance.sdkVersion).toBe('v2.2'); 37 | expect(instance.debug).toBe(true); 38 | expect(instance.lang).toBe('pt_BR'); 39 | })); 40 | 41 | it('test setting of sdkVersion from user options', inject(function ($injector) { 42 | _facebookConfigProvider.setOptions({ version: 'v1.0' }); 43 | 44 | // Invoke the provider factory function 45 | var instance = $injector.invoke(_facebookConfigProvider.$get); 46 | 47 | expect(instance.sdkVersion).toBe('v1.0'); 48 | })); 49 | 50 | it('should initialize the SDK', inject(function ($injector) { 51 | _facebookConfigProvider.setAppId(1111); 52 | _facebookConfigProvider.setLanguage('pt_BR'); 53 | 54 | // Invoke the provider factory function 55 | var instance = $injector.invoke(_facebookConfigProvider.$get); 56 | 57 | runs(function() { 58 | var promise = instance.init(); 59 | expect(promise.then).toEqual(jasmine.any(Function)); 60 | }); 61 | 62 | waitsFor(function() { 63 | return window.FB != undefined 64 | }, "FB should be defined"); 65 | 66 | runs(function() { 67 | expect(FB).not.toBe(undefined); 68 | expect(instance.lang).toBe('pt_BR'); 69 | // expect(document.getElementsByTagName('script')[0].src).toContain('facebook'); 70 | // expect(document.getElementsByTagName('script')[0].src).toBe('http://connect.facebook.net/pt_BR/all.js'); 71 | }); 72 | })); 73 | }); 74 | 75 | }); 76 | -------------------------------------------------------------------------------- /example/app.js: -------------------------------------------------------------------------------- 1 | angular.module('app', ['angularjs-facebook-sdk', 'ngRoute']) 2 | .config(function facebookConfig(facebookConfigProvider, $routeProvider) { 3 | facebookConfigProvider.setAppId(394254447322921); 4 | facebookConfigProvider.setOptions({ status: false }); 5 | $routeProvider.when('/', { 6 | templateUrl: 'home.html', 7 | controller: 'ComponentsController' 8 | }) 9 | }) 10 | .run(function (facebookConfig, facebookService) { 11 | facebookService.ready.then(function () { 12 | console.log('Facebook is ready!'); 13 | 14 | var statusChangeHandler = function (response) { 15 | if (response.status === 'connected') { 16 | facebookService.api('/me').then(function (response) { 17 | console.log(response); 18 | }); 19 | } 20 | }; 21 | 22 | facebookService.Event.subscribe('auth.statusChange', statusChangeHandler); 23 | }); 24 | }) 25 | .filter('log', function() { 26 | return function () { 27 | console.log(arguments); 28 | } 29 | }) 30 | .controller('ComponentsController', function ($scope, facebookService) { 31 | $scope.onEdgeCreated = function onEdgeCreated (url) { 32 | console.log('onEdgeCreated', arguments); 33 | } 34 | 35 | $scope.onEdgeRemoved = function onEdgeRemoved (url) { 36 | console.log('onEdgeRemoved', arguments); 37 | } 38 | 39 | $scope.onCommentCreated = function onCommentCreated (href, commentID, parentCommentID) { 40 | console.log('onCommentCreated', arguments); 41 | } 42 | 43 | $scope.onCommentRemoved = function onCommentRemoved (href, commentID, parentCommentID) { 44 | console.log('onCommentRemoved', arguments); 45 | } 46 | 47 | facebookService.ready.then(function(){ 48 | FB.Event.subscribe('message.send', function messageSend (argument) { 49 | console.log(arguments); 50 | }); 51 | }) 52 | 53 | $scope.onMessageSend = function onMessageSend (url) { 54 | console.log('onMessageSend', arguments); 55 | } 56 | }) 57 | .directive('component', function ($compile, $sce) { 58 | return { 59 | restrict: 'E', 60 | templateUrl: 'component.tpl', 61 | transclude: true, 62 | scope: { 63 | name: '@name' 64 | }, 65 | compile: function compileFn (tElement, tAttrs, transcludeFn) { 66 | return function linkFn (scope, element) { 67 | scope.component = {}; 68 | 69 | transcludeFn(scope, function (clonedElement, scope) { 70 | var componentDeclaration = clonedElement.find('component\\:declaration').html(); 71 | var componentDocumentation = clonedElement.find('component\\:documentation'); 72 | 73 | if (componentDocumentation.length > 0) { 74 | scope.documentation = componentDocumentation.attr('url'); 75 | } 76 | 77 | // Result 78 | var result = $compile(componentDeclaration)(scope.$parent); 79 | element.find('.result').append(result); 80 | 81 | // Usage 82 | scope.component.usage = $sce.trustAsHtml(hljs.highlight('html', componentDeclaration.trim()).value); 83 | }); 84 | } 85 | } 86 | }; 87 | }); 88 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | 3 | grunt.initConfig({ 4 | pkg: grunt.file.readJSON('package.json'), 5 | library: grunt.file.readJSON('bower.json'), 6 | concat: { 7 | options: { 8 | separator: '' 9 | }, 10 | library: { 11 | src: [ 12 | 'src/<%= library.name %>/<%= library.name %>.prefix', 13 | 'src/<%= library.name %>/<%= library.name %>.js', 14 | 'src/<%= library.name %>/directives/**/*.js', 15 | 'src/<%= library.name %>/filters/**/*.js', 16 | 'src/<%= library.name %>/services/**/*.js', 17 | 'src/<%= library.name %>/<%= library.name %>.suffix' 18 | ], 19 | dest: 'dist/<%= library.name %>.js' 20 | } 21 | }, 22 | uglify: { 23 | options: { 24 | banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n' 25 | }, 26 | jid: { 27 | files: { 28 | 'dist/<%= library.name %>.min.js': ['<%= concat.library.dest %>'] 29 | } 30 | } 31 | }, 32 | jshint: { 33 | beforeConcat: { 34 | src: [ 35 | 'gruntfile.js', 36 | 'src/<%= library.name %>/**/*.js', 37 | ] 38 | }, 39 | afterConcat: { 40 | src: [ 41 | '<%= concat.library.dest %>' 42 | ] 43 | }, 44 | options: { 45 | // options here to override JSHint defaults 46 | globals: { 47 | jQuery: true, 48 | console: true, 49 | module: true, 50 | document: true, 51 | angular: true 52 | }, 53 | globalstrict: false 54 | } 55 | }, 56 | watch: { 57 | options: { 58 | livereload: true 59 | }, 60 | files: [ 61 | 'Gruntfile.js', 62 | 'src/**/*' 63 | ], 64 | tasks: ['default'] 65 | }, 66 | connect: { 67 | example: { 68 | options: { 69 | port: 9001, 70 | base: ['example', 'dist', 'bower_components', 'node_modules'], 71 | keepalive: true, 72 | middleware: function (connect, options) { 73 | var middlewares = []; 74 | 75 | if (!Array.isArray(options.base)) { 76 | options.base = [options.base]; 77 | } 78 | 79 | var directory = options.directory || options.base[options.base.length - 1]; 80 | 81 | options.base.forEach(function (base) { 82 | middlewares.push(connect.static(base)); 83 | }); 84 | 85 | // Make directory browse-able. 86 | middlewares.push(connect.directory(directory)); 87 | return middlewares; 88 | }, 89 | } 90 | } 91 | } 92 | }); 93 | 94 | grunt.loadNpmTasks('grunt-contrib-uglify'); 95 | grunt.loadNpmTasks('grunt-contrib-jshint'); 96 | grunt.loadNpmTasks('grunt-contrib-concat'); 97 | grunt.loadNpmTasks('grunt-contrib-watch'); 98 | grunt.loadNpmTasks('grunt-contrib-connect'); 99 | 100 | grunt.registerTask('default', ['jshint:beforeConcat', 'concat', 'jshint:afterConcat', 'uglify']); 101 | grunt.registerTask('livereload', ['watch']); 102 | grunt.registerTask('serve:examples', ['default', 'connect:example']); 103 | 104 | }; 105 | -------------------------------------------------------------------------------- /src/angularjs-facebook-sdk/services/facebook_config_provider.js: -------------------------------------------------------------------------------- 1 | angular.module('angularjs-facebook-sdk.services') 2 | .provider('facebookConfig', function () { 3 | var _appId = null; 4 | var _sdkVersion = 'v2.9'; 5 | var _userOptions = {}; 6 | var _langCode = 'en_US'; 7 | var _debug = false; 8 | var _autoInit = true; 9 | 10 | /** 11 | * Set the Facebook SDK application ID. 12 | * 13 | * @param {Number} appId The application ID. 14 | */ 15 | this.setAppId = function setAppId(appId) { 16 | _appId = appId; 17 | }; 18 | 19 | /** 20 | * Set the Facebook SDK version. 21 | * 22 | * @param {String} sdkVersion The SDK version. 23 | */ 24 | this.setSdkVersion = function setSdkVersion(sdkVersion) { 25 | _sdkVersion = sdkVersion; 26 | }; 27 | 28 | /** 29 | * Set the language of the framework. 30 | * By default the en_US is used. 31 | * 32 | * @param {String} langCode The language code. 33 | */ 34 | this.setLanguage = function setLanguage(langCode) { 35 | _langCode = langCode; 36 | }; 37 | 38 | /** 39 | * Enable/Disable the debug for Facebook SDK. 40 | * 41 | * @param {Boolean} enableDebug Wheather to enable or disable the debug. 42 | */ 43 | this.setDebug = function setDebug(enableDebug) { 44 | _debug = enableDebug; 45 | }; 46 | 47 | /** 48 | * [setOptions description] 49 | * 50 | * @param {[type]} options [description] 51 | */ 52 | this.setOptions = function setOptions(options) { 53 | _userOptions = options; 54 | }; 55 | 56 | 57 | /** 58 | * Enable/Disable the automatic initialization. 59 | * 60 | * @param {Boolean} enableAutoInit Wheather to enable/disable the auto initialization. 61 | */ 62 | this.autoInit = function autoInit(enableAutoInit) { 63 | _autoInit = enableAutoInit; 64 | }; 65 | 66 | /** 67 | * [FacebookProviderFactoryFn description] 68 | */ 69 | function FacebookProviderFactoryFn($rootScope, $window, $q) { 70 | var defaultOptions = { 71 | appId: _appId, 72 | version: _sdkVersion, 73 | status: true, 74 | xfbml: true 75 | }; 76 | 77 | var initDefer = $q.defer(); 78 | var initOpts = angular.extend(defaultOptions, _userOptions); 79 | 80 | if (initOpts.version != _sdkVersion) { 81 | _sdkVersion = initOpts.version; 82 | } 83 | 84 | /** 85 | * Hook up a method on the window object. This way we can be notified 86 | * when the Facebook SDK is ready to be used. 87 | * 88 | * The initDefer promise is resolved inside this method. 89 | * 90 | * @return {[type]} [description] 91 | */ 92 | $window.fbAsyncInit = function fbAsyncInit() { 93 | FB.init(initOpts); 94 | 95 | $rootScope.$apply(function () { 96 | initDefer.resolve(); 97 | }); 98 | }; 99 | 100 | // The public API 101 | return { 102 | appId: _appId, 103 | sdkVersion: _sdkVersion, 104 | lang: _langCode, 105 | debug: _debug, 106 | autoInit: _autoInit, 107 | 108 | // The initialization promise 109 | initialization: initDefer.promise, 110 | 111 | /** 112 | * Initialize the Facebook SDK for Javascript. 113 | * This will load the SDK using the configuration passed to the provider. 114 | * 115 | * @return {Promise} The initialize Promise instance. 116 | */ 117 | init: function () { 118 | (function (d, s, id) { 119 | var js, fjs = d.getElementsByTagName(s)[0]; 120 | if (d.getElementById(id)) { 121 | return; 122 | } 123 | js = d.createElement(s); 124 | js.id = id; 125 | js.src = "//connect.facebook.net/" + _langCode + (_debug ? "/all/debug.js" : (_sdkVersion.substring(0, 2) == 'v2' ? "/sdk.js" : "/all.js")); 126 | fjs.parentNode.insertBefore(js, fjs); 127 | }(document, 'script', 'facebook-jssdk')); 128 | 129 | return initDefer.promise; 130 | } 131 | }; 132 | } 133 | 134 | FacebookProviderFactoryFn.$inject = ['$rootScope', '$window', '$q']; 135 | 136 | this.$get = FacebookProviderFactoryFn; 137 | }); 138 | -------------------------------------------------------------------------------- /dist/angularjs-facebook-sdk.min.js: -------------------------------------------------------------------------------- 1 | /*! angularjs-facebook-sdk 12-05-2017 */ 2 | !function(a,b){function c(a){return{restrict:"E",replace:!0,template:"",scope:{href:"@href",colorschema:"@colorschema",numposts:"@numposts",commentCreated:"&onCommentCreated",commentRemoved:"&onCommentRemoved"},link:function(b,c){function d(a){a.href===b.href&&b.commentCreated(a)}function e(a){a.href===b.href&&b.commentRemoved(a)}a.ready.then(function(){FB.XFBML.parse(c[0]),a.Event.subscribe("comment.create",d),a.Event.subscribe("comment.remove",e)}),b.$on("$destroy",function(){a.Event.unsubscribe("comment.create",d),a.Event.unsubscribe("comment.remove",e)})}}}function d(a){return{restrict:"E",replace:!0,template:"",scope:{href:"@href",colorschema:"@colorschema",layout:"@layout",showFaces:"@showFaces"},link:function(b,c){a.ready.then(function(){FB.XFBML.parse(c[0])})}}}function e(a){return{restrict:"E",replace:!0,template:"",scope:{href:"@href",layout:"@layout",action:"@action",show_faces:"@showFaces",share:"@share",edgeCreated:"&onEdgeCreated",edgeRemoved:"&onEdgeRemoved"},link:function(b,c,d){function e(a,d){d===c[0]&&b.edgeCreated({url:a})}function f(a,d){d===c[0]&&b.edgeRemoved({url:a})}a.ready.then(function(){FB.XFBML.parse(c[0]),a.Event.subscribe("edge.create",e),a.Event.subscribe("edge.remove",f)}),b.$on("$destroy",function(){a.Event.unsubscribe("edge.create",e),a.Event.unsubscribe("edge.remove",f)})}}}function f(a){return{restrict:"E",replace:!0,template:'',scope:{label:"@label",scope:"@scope",enableProfileSelector:"@enableProfileSelector",profileSelectorIds:"@profileSelectorIds"},compile:function(b,c){var d={};return c.scope&&(d.scope=c.scope),c.enableProfileSelector&&(d.enable_profile_selector=!0),c.profileSelectorIds&&(d.profile_selector_ids=!0),function(b,c){b.dispatchLogin=function(){a.login(d)}}}}}function g(a){return{restrict:"E",replace:!0,template:'',scope:{label:"@label"},link:function(b,c){b.dispatchLogout=function(){a.logout()}}}}function h(a){return{restrict:"E",replace:!0,template:"",scope:{uid:"@uid",type:"@type",width:"@width",height:"@height"},compile:function(b,c){return function(b,c){a.ready.then(function(){var d=b.uid?b.uid+"/picture":"/me/picture",e=a.api(d,{redirect:!1,type:b.type,width:b.width,height:b.height});e.then(function(a){a&&!a.error&&c.attr("src",a.data.url)})})}}}}function i(a){return{restrict:"E",replace:!0,template:"",scope:{href:"@href",colorschema:"@colorschema",width:"@width",height:"@height",messageSend:"@onMessageSend"},link:function(b,c){function d(a){a===b.href&&b.messageSend({url:a})}a.ready.then(function(){FB.XFBML.parse(c[0]),a.Event.subscribe("message.send",d)}),b.$on("$destroy",function(){a.Event.unsubscribe("message.send",d)})}}}function j(a){return{restrict:"E",replace:!0,template:"",scope:{href:"@href",type:"@type"},link:function(b,c){a.ready.then(function(){FB.XFBML.parse(c[0])})}}}function k(a,b,c){c.$new();return{ready:a.initialization,Event:{subscribe:function(a,b){var d=function(){var a=Array.prototype.slice.call(arguments,0);c.$apply(function(){b.apply(null,a)})};b.$$eventHandler=d,FB.Event.subscribe(a,d)},unsubscribe:function(a,b){FB.Event.unsubscribe(a,b.$$eventHandler)}},api:function(a,d,e){var f=Array.prototype.slice.call(arguments,0),g=b.defer();return this.ready.then(function(){f.push(function(a){c.$apply(function(){g.resolve(a)})}),FB.api.apply(null,f)}),g.promise},ui:function(a){var d=Array.prototype.slice.call(arguments,0),e=b.defer();return this.ready.then(function(){d.push(function(a){c.$apply(function(){e.resolve(a)})}),FB.ui.apply(null,d)}),e.promise},login:function(a){a=a||{};var d=b.defer();return this.ready.then(function(){FB.login(function(){var a=arguments;c.$apply(function(){d.resolve.apply(this,a)})},a)}),d.promise},logout:function(){var a=b.defer();return this.ready.then(function(){FB.logout(function(){a.resolve.apply(this,arguments)})}),a.promise},getLoginStatus:function(){var a=b.defer();return this.ready.then(function(){FB.getLoginStatus(function(){a.resolve.apply(this,arguments)})}),a.promise}}}angular.module("angularjs-facebook-sdk.config",[]).value("angularjs-facebook-sdk.config",{debug:!0}),angular.module("angularjs-facebook-sdk.directives",[]),angular.module("angularjs-facebook-sdk.services",[]),angular.module("angularjs-facebook-sdk",["angularjs-facebook-sdk.config","angularjs-facebook-sdk.directives","angularjs-facebook-sdk.services"]),angular.module("angularjs-facebook-sdk").run(["facebookConfig",function(a){a.autoInit&&a.init()}]),c.$inject=["facebookService"],angular.module("angularjs-facebook-sdk.directives").directive("afbComments",c),d.$inject=["facebookService"],angular.module("angularjs-facebook-sdk.directives").directive("afbFollow",d),e.$inject=["facebookService"],angular.module("angularjs-facebook-sdk.directives").directive("afbLike",e),f.$inject=["facebookService"],angular.module("angularjs-facebook-sdk.directives").directive("afbLogin",f),g.$inject=["facebookService"],angular.module("angularjs-facebook-sdk.directives").directive("afbLogout",g),h.$inject=["facebookService"],angular.module("angularjs-facebook-sdk.directives").directive("afbProfilePic",h),i.$inject=["facebookService"],angular.module("angularjs-facebook-sdk.directives").directive("afbSend",i),j.$inject=["facebookService"],angular.module("angularjs-facebook-sdk.directives").directive("afbShareButton",j),angular.module("angularjs-facebook-sdk.services").provider("facebookConfig",function(){function a(a,i,j){var k={appId:c,version:d,status:!0,xfbml:!0},l=j.defer(),m=angular.extend(k,e);return m.version!=d&&(d=m.version),i.fbAsyncInit=function(){FB.init(m),a.$apply(function(){l.resolve()})},{appId:c,sdkVersion:d,lang:f,debug:g,autoInit:h,initialization:l.promise,init:function(){return function(a,b,c){var e,h=a.getElementsByTagName(b)[0];a.getElementById(c)||(e=a.createElement(b),e.id=c,e.src="//connect.facebook.net/"+f+(g?"/all/debug.js":"v2"==d.substring(0,2)?"/sdk.js":"/all.js"),h.parentNode.insertBefore(e,h))}(b,"script","facebook-jssdk"),l.promise}}}var c=null,d="v2.9",e={},f="en_US",g=!1,h=!0;this.setAppId=function(a){c=a},this.setSdkVersion=function(a){d=a},this.setLanguage=function(a){f=a},this.setDebug=function(a){g=a},this.setOptions=function(a){e=a},this.autoInit=function(a){h=a},a.$inject=["$rootScope","$window","$q"],this.$get=a}),k.$inject=["facebookConfig","$q","$rootScope"],angular.module("angularjs-facebook-sdk.services").factory("facebookService",k)}(window,document); -------------------------------------------------------------------------------- /src/angularjs-facebook-sdk/services/facebook_service.js: -------------------------------------------------------------------------------- 1 | function FacebookService(facebookConfig, $q, $rootScope) { 2 | var eventEmitter = $rootScope.$new(); 3 | 4 | return { 5 | ready: facebookConfig.initialization, 6 | 7 | Event: { 8 | /** 9 | * FB.Event.subscribe allows you to define callbacks that will be called when 10 | * certain events take place on your site. These events include: 11 | * 12 | * - Logging in or logging out via Facebook Login 13 | * - Someone likes or unlikes a page via an embedded like button 14 | * - Rendering of social plugins 15 | * - Comments are added or removed 16 | * - Someone sending a message to your page or a friend via an embedded send button 17 | * 18 | * This method is a wrapper for the original event subscriber. We need to wrap the callback 19 | * call in a Scope.prototype.$apply method to let AngularJS know when it need to update bindings, 20 | * dispatch other promises among other things. 21 | * 22 | * @param {String} eventName The event name. 23 | * @return {Promise} 24 | */ 25 | subscribe: function (eventName, callback) { 26 | var eventHandler = function () { 27 | var args = Array.prototype.slice.call(arguments, 0); 28 | 29 | $rootScope.$apply(function () { 30 | callback.apply(null, args); 31 | }); 32 | }; 33 | 34 | // Here we store a reference to the wrapped method so that we can unsubscribe the function correctly. 35 | callback.$$eventHandler = eventHandler; 36 | 37 | // Delegate the subscription to Facebook SDK 38 | FB.Event.subscribe(eventName, eventHandler); 39 | }, 40 | 41 | /** 42 | * Removes handlers on events so that it no longer invokes your callback when the event fires. 43 | * 44 | * @return {[type]} [description] 45 | */ 46 | unsubscribe: function (eventName, callback) { 47 | FB.Event.unsubscribe(eventName, callback.$$eventHandler); 48 | } 49 | }, 50 | 51 | /** 52 | * This method lets you make calls to the Graph API. 53 | * 54 | * @param {string} path 55 | * This is the Graph API endpoint path that you want to call. 56 | * You can read the Graph API reference docs to see which endpoint you want to use. 57 | * This is a required parameter. 58 | * 59 | * @param {enum{get, post, delete}} method 60 | * This is the HTTP method that you want to use for the API request. 61 | * Consult the Graph API reference docs to see which method you need to use. 62 | * Default is get 63 | * 64 | * @param {object} params 65 | * This is an object consisting of any parameters that you want to pass into your Graph API call. 66 | * The parameters that can be used vary depending on the endpoint being called, so check the 67 | * Graph API reference docs for full lists of available parameters. One parameter of note is 68 | * access_token which you can use to make an API call with a Page access token. 69 | * App access tokens should never be used in this SDK as it is client-side, and your app secret would be exposed. 70 | * 71 | * @param {Function} callback 72 | * This is the function that is triggered whenever the API returns a response. 73 | * The response object available to this function contains the API result. 74 | * 75 | * @return {Promise} 76 | */ 77 | api: function (path, method, params) { 78 | var args = Array.prototype.slice.call(arguments, 0); 79 | var defer = $q.defer(); 80 | 81 | this.ready.then(function () { 82 | args.push(function apiCallback(response) { 83 | // We need to use $apply here because the FB.api callback 84 | // is outside the AngularJS kingdom. So we're telling it to 85 | // dispatch the deferred resolution ASAP. 86 | $rootScope.$apply(function () { 87 | defer.resolve(response); 88 | }); 89 | }); 90 | 91 | // Where we delegate the call to the FB.api method. 92 | FB.api.apply(null, args); 93 | }); 94 | 95 | return defer.promise; 96 | }, 97 | 98 | /** 99 | * This method is used to trigger different forms of Facebook created UI dialogs. 100 | * 101 | * @param {[type]} params 102 | * A collection of parameters that control which dialog is loaded, and relevant settings. Click for more info. 103 | * 104 | * @return {Promise} 105 | */ 106 | ui: function (params) { 107 | var args = Array.prototype.slice.call(arguments, 0); 108 | var defer = $q.defer(); 109 | 110 | this.ready.then(function () { 111 | args.push(function apiCallback(response) { 112 | // We need to use $apply here because the FB.api callback 113 | // is outside the AngularJS kingdom. So we're telling it to 114 | // dispatch the deferred resolution ASAP. 115 | $rootScope.$apply(function () { 116 | defer.resolve(response); 117 | }); 118 | }); 119 | 120 | // Where we delegate the call to the FB.api method. 121 | FB.ui.apply(null, args); 122 | }); 123 | 124 | return defer.promise; 125 | }, 126 | 127 | /** 128 | * Calling FB.login prompts the user to authenticate your application using the OAuth Dialog. 129 | * 130 | * Calling FB.login results in the JS SDK attempting to open a popup window. As such, this method should only 131 | * be called after a user click event, otherwise the popup window will be blocked by most browsers. 132 | * 133 | * On Canvas, if the user is 'unknown' (that is, when the login status == 'unknown'), do not use the JS SDK 134 | * to sign in the user, instead do a full redirect of the page to the oauth dialog so that we get a consistent state. 135 | * 136 | * @return {Promise} 137 | */ 138 | login: function (opts) { 139 | opts = opts || {}; 140 | 141 | var defer = $q.defer(); 142 | 143 | this.ready.then(function () { 144 | FB.login(function () { 145 | var loginArgs = arguments; 146 | $rootScope.$apply(function () { 147 | defer.resolve.apply(this, loginArgs); 148 | }); 149 | }, opts); 150 | }); 151 | 152 | return defer.promise; 153 | }, 154 | 155 | /** 156 | * Log the user out of your site and Facebook 157 | * 158 | * @return {Promise} 159 | */ 160 | logout: function () { 161 | var defer = $q.defer(); 162 | 163 | this.ready.then(function () { 164 | FB.logout(function () { 165 | defer.resolve.apply(this, arguments); 166 | }); 167 | }); 168 | 169 | return defer.promise; 170 | }, 171 | 172 | /** 173 | * FB.getLoginStatus allows you to determine if a user is logged in to Facebook and has authenticated your app. 174 | * 175 | * There are three possible states for a user: 176 | * - the user is logged into Facebook and has authenticated your application (connected) 177 | * - the user is logged into Facebook but has not authenticated your application (not_authorized) 178 | * - the user is not logged into Facebook at this time and so we don't know if they've authenticated your 179 | * application or not (unknown) 180 | * - With social application, knowing which of the these three states the user is in is one of the 181 | * first things your application needs to know upon page load. 182 | * 183 | * Reponse example: 184 | * { 185 | * status: 'connected', 186 | * authResponse: { 187 | * accessToken: '...', 188 | * expiresIn:'...', 189 | * signedRequest:'...', 190 | * userID:'...' 191 | * } 192 | * } 193 | * 194 | * @return {Promise} 195 | */ 196 | getLoginStatus: function () { 197 | var defer = $q.defer(); 198 | 199 | this.ready.then(function () { 200 | FB.getLoginStatus(function () { 201 | defer.resolve.apply(this, arguments); 202 | }); 203 | }); 204 | 205 | return defer.promise; 206 | } 207 | }; 208 | } 209 | 210 | FacebookService.$inject = ['facebookConfig', '$q', '$rootScope']; 211 | 212 | angular.module('angularjs-facebook-sdk.services') 213 | .factory('facebookService', FacebookService); 214 | -------------------------------------------------------------------------------- /dist/angularjs-facebook-sdk.js: -------------------------------------------------------------------------------- 1 | (function(window, document) { 2 | 3 | // Create all modules and define dependencies to make sure they exist 4 | // and are loaded in the correct order to satisfy dependency injection 5 | // before all nested files are concatenated by Grunt 6 | 7 | // Config 8 | angular.module('angularjs-facebook-sdk.config', []) 9 | .value('angularjs-facebook-sdk.config', { 10 | debug: true 11 | }); 12 | 13 | // Modules 14 | angular.module('angularjs-facebook-sdk.directives', []); 15 | angular.module('angularjs-facebook-sdk.services', []); 16 | angular.module('angularjs-facebook-sdk', [ 17 | 'angularjs-facebook-sdk.config', 18 | 'angularjs-facebook-sdk.directives', 19 | 'angularjs-facebook-sdk.services' 20 | ]); 21 | 22 | angular.module('angularjs-facebook-sdk').run(['facebookConfig', 23 | function (facebookConfig) { 24 | if (facebookConfig.autoInit) { 25 | facebookConfig.init(); 26 | } 27 | } 28 | ]); 29 | function FacebookCommentsDirective(facebookService) { 30 | return { 31 | restrict: 'E', 32 | replace: true, 33 | template: '', 34 | scope: { 35 | href: '@href', 36 | colorschema: '@colorschema', 37 | numposts: '@numposts', 38 | // Events 39 | commentCreated: '&onCommentCreated', 40 | commentRemoved: '&onCommentRemoved' 41 | }, 42 | link: function (scope, element) { 43 | function commentCreatedHandler(data) { 44 | if (data.href === scope.href) { 45 | // Call the scope event if the htmlElement match 46 | scope.commentCreated(data); 47 | } 48 | } 49 | 50 | function commentRemovedHandler(data) { 51 | if (data.href === scope.href) { 52 | // Call the scope event if the htmlElement match 53 | scope.commentRemoved(data); 54 | } 55 | } 56 | 57 | facebookService.ready.then(function () { 58 | FB.XFBML.parse(element[0]); 59 | 60 | facebookService.Event.subscribe('comment.create', commentCreatedHandler); 61 | facebookService.Event.subscribe('comment.remove', commentRemovedHandler); 62 | }); 63 | 64 | // Listen for scope removal and unsubscribe some previously added events. 65 | scope.$on('$destroy', function () { 66 | facebookService.Event.unsubscribe('comment.create', commentCreatedHandler); 67 | facebookService.Event.unsubscribe('comment.remove', commentRemovedHandler); 68 | }); 69 | } 70 | }; 71 | } 72 | 73 | FacebookCommentsDirective.$inject = ['facebookService']; 74 | 75 | angular.module('angularjs-facebook-sdk.directives') 76 | .directive('afbComments', FacebookCommentsDirective); 77 | function FacebookFollowDirective(facebookService) { 78 | return { 79 | restrict: 'E', 80 | replace: true, 81 | template: '', 82 | scope: { 83 | href: '@href', 84 | colorschema: '@colorschema', 85 | layout: '@layout', 86 | showFaces: '@showFaces' 87 | }, 88 | link: function (scope, element) { 89 | facebookService.ready.then(function () { 90 | FB.XFBML.parse(element[0]); 91 | }); 92 | } 93 | }; 94 | } 95 | 96 | FacebookFollowDirective.$inject = ['facebookService']; 97 | 98 | angular.module('angularjs-facebook-sdk.directives') 99 | .directive('afbFollow', FacebookFollowDirective); 100 | function FacebookLikeDirective(facebookService) { 101 | return { 102 | restrict: 'E', 103 | replace: true, 104 | template: '', 105 | scope: { 106 | href: '@href', 107 | layout: '@layout', 108 | action: '@action', 109 | show_faces: '@showFaces', 110 | share: '@share', 111 | // Events 112 | edgeCreated: '&onEdgeCreated', 113 | edgeRemoved: '&onEdgeRemoved' 114 | }, 115 | link: function (scope, element, attrs) { 116 | function edgeCreatedHandler(url, htmlElement) { 117 | if (htmlElement === element[0]) { 118 | // Call the scope event if the htmlElement match 119 | scope.edgeCreated({url: url}); 120 | } 121 | } 122 | 123 | function edgeRemovedHandler(url, htmlElement) { 124 | if (htmlElement === element[0]) { 125 | // Call the scope event if the htmlElement match 126 | scope.edgeRemoved({url: url}); 127 | } 128 | } 129 | 130 | facebookService.ready.then(function () { 131 | FB.XFBML.parse(element[0]); 132 | facebookService.Event.subscribe('edge.create', edgeCreatedHandler); 133 | facebookService.Event.subscribe('edge.remove', edgeRemovedHandler); 134 | }); 135 | 136 | // Listen for scope removal and unsubscribe some previously added events. 137 | scope.$on('$destroy', function () { 138 | facebookService.Event.unsubscribe('edge.create', edgeCreatedHandler); 139 | facebookService.Event.unsubscribe('edge.remove', edgeRemovedHandler); 140 | }); 141 | } 142 | }; 143 | } 144 | 145 | FacebookLikeDirective.$inject = ['facebookService']; 146 | 147 | angular.module('angularjs-facebook-sdk.directives') 148 | .directive('afbLike', FacebookLikeDirective); 149 | function FacebookLoginDirective(facebookService) { 150 | return { 151 | restrict: 'E', 152 | replace: true, 153 | template: '', 154 | scope: { 155 | label: '@label', 156 | scope: '@scope', 157 | enableProfileSelector: '@enableProfileSelector', 158 | profileSelectorIds: '@profileSelectorIds' 159 | }, 160 | compile: function (tElement, tAttrs) { 161 | var loginOpts = {}; 162 | 163 | if (tAttrs.scope) { 164 | loginOpts.scope = tAttrs.scope; 165 | } 166 | if (tAttrs.enableProfileSelector) { 167 | loginOpts.enable_profile_selector = true; 168 | } 169 | if (tAttrs.profileSelectorIds) { 170 | loginOpts.profile_selector_ids = true; 171 | } 172 | 173 | return function linkFn(scope, element) { 174 | scope.dispatchLogin = function dispatchLogin() { 175 | facebookService.login(loginOpts); 176 | }; 177 | }; 178 | } 179 | }; 180 | } 181 | 182 | FacebookLoginDirective.$inject = ['facebookService']; 183 | 184 | angular.module('angularjs-facebook-sdk.directives') 185 | .directive('afbLogin', FacebookLoginDirective); 186 | function FacebookLogoutDirective(facebookService) { 187 | return { 188 | restrict: 'E', 189 | replace: true, 190 | template: '', 191 | scope: { 192 | label: '@label' 193 | }, 194 | link: function (scope, element) { 195 | scope.dispatchLogout = function dispatchLogin() { 196 | facebookService.logout(); 197 | }; 198 | } 199 | }; 200 | } 201 | 202 | FacebookLogoutDirective.$inject = ['facebookService']; 203 | 204 | angular.module('angularjs-facebook-sdk.directives') 205 | .directive('afbLogout', FacebookLogoutDirective); 206 | function FacebookProfilePicDirective(facebookService) { 207 | return { 208 | restrict: 'E', 209 | replace: true, 210 | template: '', 211 | scope: { 212 | uid: '@uid', 213 | type: '@type', 214 | width: '@width', 215 | height: '@height' 216 | }, 217 | compile: function compileFn(tElement, tAttrs) { 218 | return function linkFn(scope, element) { 219 | facebookService.ready.then(function () { 220 | var pictureUrl = (scope.uid) ? scope.uid + "/picture" : "/me/picture"; 221 | 222 | var apiCall = facebookService.api(pictureUrl, { 223 | redirect: false, 224 | type: scope.type, 225 | width: scope.width, 226 | height: scope.height 227 | }); 228 | 229 | apiCall.then(function (response) { 230 | if (response && !response.error) { 231 | element.attr('src', response.data.url); 232 | } 233 | }); 234 | }); 235 | }; 236 | } 237 | }; 238 | } 239 | 240 | FacebookProfilePicDirective.$inject = ['facebookService']; 241 | 242 | angular.module('angularjs-facebook-sdk.directives') 243 | .directive('afbProfilePic', FacebookProfilePicDirective); 244 | function FacebookSendDirective(facebookService) { 245 | return { 246 | restrict: 'E', 247 | replace: true, 248 | template: '', 249 | scope: { 250 | href: '@href', 251 | colorschema: '@colorschema', 252 | width: '@width', 253 | height: '@height', 254 | // Events 255 | messageSend: '@onMessageSend' 256 | }, 257 | link: function (scope, element) { 258 | function messageSendHandler(url) { 259 | if (url === scope.href) { 260 | // Call the scope event if the htmlElement match 261 | scope.messageSend({ url: url }); 262 | } 263 | } 264 | 265 | facebookService.ready.then(function () { 266 | FB.XFBML.parse(element[0]); 267 | facebookService.Event.subscribe('message.send', messageSendHandler); 268 | }); 269 | 270 | scope.$on('$destroy', function () { 271 | facebookService.Event.unsubscribe('message.send', messageSendHandler); 272 | }); 273 | } 274 | }; 275 | } 276 | 277 | FacebookSendDirective.$inject = ['facebookService']; 278 | 279 | angular.module('angularjs-facebook-sdk.directives') 280 | .directive('afbSend', FacebookSendDirective); 281 | function FacebookShareDirective(facebookService) { 282 | return { 283 | restrict: 'E', 284 | replace: true, 285 | template: '', 286 | scope: { 287 | href: '@href', 288 | type: '@type' 289 | }, 290 | link: function (scope, element) { 291 | facebookService.ready.then(function () { 292 | FB.XFBML.parse(element[0]); 293 | }); 294 | } 295 | }; 296 | } 297 | 298 | FacebookShareDirective.$inject = ['facebookService']; 299 | 300 | angular.module('angularjs-facebook-sdk.directives') 301 | .directive('afbShareButton', FacebookShareDirective); 302 | angular.module('angularjs-facebook-sdk.services') 303 | .provider('facebookConfig', function () { 304 | var _appId = null; 305 | var _sdkVersion = 'v2.9'; 306 | var _userOptions = {}; 307 | var _langCode = 'en_US'; 308 | var _debug = false; 309 | var _autoInit = true; 310 | 311 | /** 312 | * Set the Facebook SDK application ID. 313 | * 314 | * @param {Number} appId The application ID. 315 | */ 316 | this.setAppId = function setAppId(appId) { 317 | _appId = appId; 318 | }; 319 | 320 | /** 321 | * Set the Facebook SDK version. 322 | * 323 | * @param {String} sdkVersion The SDK version. 324 | */ 325 | this.setSdkVersion = function setSdkVersion(sdkVersion) { 326 | _sdkVersion = sdkVersion; 327 | }; 328 | 329 | /** 330 | * Set the language of the framework. 331 | * By default the en_US is used. 332 | * 333 | * @param {String} langCode The language code. 334 | */ 335 | this.setLanguage = function setLanguage(langCode) { 336 | _langCode = langCode; 337 | }; 338 | 339 | /** 340 | * Enable/Disable the debug for Facebook SDK. 341 | * 342 | * @param {Boolean} enableDebug Wheather to enable or disable the debug. 343 | */ 344 | this.setDebug = function setDebug(enableDebug) { 345 | _debug = enableDebug; 346 | }; 347 | 348 | /** 349 | * [setOptions description] 350 | * 351 | * @param {[type]} options [description] 352 | */ 353 | this.setOptions = function setOptions(options) { 354 | _userOptions = options; 355 | }; 356 | 357 | 358 | /** 359 | * Enable/Disable the automatic initialization. 360 | * 361 | * @param {Boolean} enableAutoInit Wheather to enable/disable the auto initialization. 362 | */ 363 | this.autoInit = function autoInit(enableAutoInit) { 364 | _autoInit = enableAutoInit; 365 | }; 366 | 367 | /** 368 | * [FacebookProviderFactoryFn description] 369 | */ 370 | function FacebookProviderFactoryFn($rootScope, $window, $q) { 371 | var defaultOptions = { 372 | appId: _appId, 373 | version: _sdkVersion, 374 | status: true, 375 | xfbml: true 376 | }; 377 | 378 | var initDefer = $q.defer(); 379 | var initOpts = angular.extend(defaultOptions, _userOptions); 380 | 381 | if (initOpts.version != _sdkVersion) { 382 | _sdkVersion = initOpts.version; 383 | } 384 | 385 | /** 386 | * Hook up a method on the window object. This way we can be notified 387 | * when the Facebook SDK is ready to be used. 388 | * 389 | * The initDefer promise is resolved inside this method. 390 | * 391 | * @return {[type]} [description] 392 | */ 393 | $window.fbAsyncInit = function fbAsyncInit() { 394 | FB.init(initOpts); 395 | 396 | $rootScope.$apply(function () { 397 | initDefer.resolve(); 398 | }); 399 | }; 400 | 401 | // The public API 402 | return { 403 | appId: _appId, 404 | sdkVersion: _sdkVersion, 405 | lang: _langCode, 406 | debug: _debug, 407 | autoInit: _autoInit, 408 | 409 | // The initialization promise 410 | initialization: initDefer.promise, 411 | 412 | /** 413 | * Initialize the Facebook SDK for Javascript. 414 | * This will load the SDK using the configuration passed to the provider. 415 | * 416 | * @return {Promise} The initialize Promise instance. 417 | */ 418 | init: function () { 419 | (function (d, s, id) { 420 | var js, fjs = d.getElementsByTagName(s)[0]; 421 | if (d.getElementById(id)) { 422 | return; 423 | } 424 | js = d.createElement(s); 425 | js.id = id; 426 | js.src = "//connect.facebook.net/" + _langCode + (_debug ? "/all/debug.js" : (_sdkVersion.substring(0, 2) == 'v2' ? "/sdk.js" : "/all.js")); 427 | fjs.parentNode.insertBefore(js, fjs); 428 | }(document, 'script', 'facebook-jssdk')); 429 | 430 | return initDefer.promise; 431 | } 432 | }; 433 | } 434 | 435 | FacebookProviderFactoryFn.$inject = ['$rootScope', '$window', '$q']; 436 | 437 | this.$get = FacebookProviderFactoryFn; 438 | }); 439 | function FacebookService(facebookConfig, $q, $rootScope) { 440 | var eventEmitter = $rootScope.$new(); 441 | 442 | return { 443 | ready: facebookConfig.initialization, 444 | 445 | Event: { 446 | /** 447 | * FB.Event.subscribe allows you to define callbacks that will be called when 448 | * certain events take place on your site. These events include: 449 | * 450 | * - Logging in or logging out via Facebook Login 451 | * - Someone likes or unlikes a page via an embedded like button 452 | * - Rendering of social plugins 453 | * - Comments are added or removed 454 | * - Someone sending a message to your page or a friend via an embedded send button 455 | * 456 | * This method is a wrapper for the original event subscriber. We need to wrap the callback 457 | * call in a Scope.prototype.$apply method to let AngularJS know when it need to update bindings, 458 | * dispatch other promises among other things. 459 | * 460 | * @param {String} eventName The event name. 461 | * @return {Promise} 462 | */ 463 | subscribe: function (eventName, callback) { 464 | var eventHandler = function () { 465 | var args = Array.prototype.slice.call(arguments, 0); 466 | 467 | $rootScope.$apply(function () { 468 | callback.apply(null, args); 469 | }); 470 | }; 471 | 472 | // Here we store a reference to the wrapped method so that we can unsubscribe the function correctly. 473 | callback.$$eventHandler = eventHandler; 474 | 475 | // Delegate the subscription to Facebook SDK 476 | FB.Event.subscribe(eventName, eventHandler); 477 | }, 478 | 479 | /** 480 | * Removes handlers on events so that it no longer invokes your callback when the event fires. 481 | * 482 | * @return {[type]} [description] 483 | */ 484 | unsubscribe: function (eventName, callback) { 485 | FB.Event.unsubscribe(eventName, callback.$$eventHandler); 486 | } 487 | }, 488 | 489 | /** 490 | * This method lets you make calls to the Graph API. 491 | * 492 | * @param {string} path 493 | * This is the Graph API endpoint path that you want to call. 494 | * You can read the Graph API reference docs to see which endpoint you want to use. 495 | * This is a required parameter. 496 | * 497 | * @param {enum{get, post, delete}} method 498 | * This is the HTTP method that you want to use for the API request. 499 | * Consult the Graph API reference docs to see which method you need to use. 500 | * Default is get 501 | * 502 | * @param {object} params 503 | * This is an object consisting of any parameters that you want to pass into your Graph API call. 504 | * The parameters that can be used vary depending on the endpoint being called, so check the 505 | * Graph API reference docs for full lists of available parameters. One parameter of note is 506 | * access_token which you can use to make an API call with a Page access token. 507 | * App access tokens should never be used in this SDK as it is client-side, and your app secret would be exposed. 508 | * 509 | * @param {Function} callback 510 | * This is the function that is triggered whenever the API returns a response. 511 | * The response object available to this function contains the API result. 512 | * 513 | * @return {Promise} 514 | */ 515 | api: function (path, method, params) { 516 | var args = Array.prototype.slice.call(arguments, 0); 517 | var defer = $q.defer(); 518 | 519 | this.ready.then(function () { 520 | args.push(function apiCallback(response) { 521 | // We need to use $apply here because the FB.api callback 522 | // is outside the AngularJS kingdom. So we're telling it to 523 | // dispatch the deferred resolution ASAP. 524 | $rootScope.$apply(function () { 525 | defer.resolve(response); 526 | }); 527 | }); 528 | 529 | // Where we delegate the call to the FB.api method. 530 | FB.api.apply(null, args); 531 | }); 532 | 533 | return defer.promise; 534 | }, 535 | 536 | /** 537 | * This method is used to trigger different forms of Facebook created UI dialogs. 538 | * 539 | * @param {[type]} params 540 | * A collection of parameters that control which dialog is loaded, and relevant settings. Click for more info. 541 | * 542 | * @return {Promise} 543 | */ 544 | ui: function (params) { 545 | var args = Array.prototype.slice.call(arguments, 0); 546 | var defer = $q.defer(); 547 | 548 | this.ready.then(function () { 549 | args.push(function apiCallback(response) { 550 | // We need to use $apply here because the FB.api callback 551 | // is outside the AngularJS kingdom. So we're telling it to 552 | // dispatch the deferred resolution ASAP. 553 | $rootScope.$apply(function () { 554 | defer.resolve(response); 555 | }); 556 | }); 557 | 558 | // Where we delegate the call to the FB.api method. 559 | FB.ui.apply(null, args); 560 | }); 561 | 562 | return defer.promise; 563 | }, 564 | 565 | /** 566 | * Calling FB.login prompts the user to authenticate your application using the OAuth Dialog. 567 | * 568 | * Calling FB.login results in the JS SDK attempting to open a popup window. As such, this method should only 569 | * be called after a user click event, otherwise the popup window will be blocked by most browsers. 570 | * 571 | * On Canvas, if the user is 'unknown' (that is, when the login status == 'unknown'), do not use the JS SDK 572 | * to sign in the user, instead do a full redirect of the page to the oauth dialog so that we get a consistent state. 573 | * 574 | * @return {Promise} 575 | */ 576 | login: function (opts) { 577 | opts = opts || {}; 578 | 579 | var defer = $q.defer(); 580 | 581 | this.ready.then(function () { 582 | FB.login(function () { 583 | var loginArgs = arguments; 584 | $rootScope.$apply(function () { 585 | defer.resolve.apply(this, loginArgs); 586 | }); 587 | }, opts); 588 | }); 589 | 590 | return defer.promise; 591 | }, 592 | 593 | /** 594 | * Log the user out of your site and Facebook 595 | * 596 | * @return {Promise} 597 | */ 598 | logout: function () { 599 | var defer = $q.defer(); 600 | 601 | this.ready.then(function () { 602 | FB.logout(function () { 603 | defer.resolve.apply(this, arguments); 604 | }); 605 | }); 606 | 607 | return defer.promise; 608 | }, 609 | 610 | /** 611 | * FB.getLoginStatus allows you to determine if a user is logged in to Facebook and has authenticated your app. 612 | * 613 | * There are three possible states for a user: 614 | * - the user is logged into Facebook and has authenticated your application (connected) 615 | * - the user is logged into Facebook but has not authenticated your application (not_authorized) 616 | * - the user is not logged into Facebook at this time and so we don't know if they've authenticated your 617 | * application or not (unknown) 618 | * - With social application, knowing which of the these three states the user is in is one of the 619 | * first things your application needs to know upon page load. 620 | * 621 | * Reponse example: 622 | * { 623 | * status: 'connected', 624 | * authResponse: { 625 | * accessToken: '...', 626 | * expiresIn:'...', 627 | * signedRequest:'...', 628 | * userID:'...' 629 | * } 630 | * } 631 | * 632 | * @return {Promise} 633 | */ 634 | getLoginStatus: function () { 635 | var defer = $q.defer(); 636 | 637 | this.ready.then(function () { 638 | FB.getLoginStatus(function () { 639 | defer.resolve.apply(this, arguments); 640 | }); 641 | }); 642 | 643 | return defer.promise; 644 | } 645 | }; 646 | } 647 | 648 | FacebookService.$inject = ['facebookConfig', '$q', '$rootScope']; 649 | 650 | angular.module('angularjs-facebook-sdk.services') 651 | .factory('facebookService', FacebookService); 652 | })(window, document); 653 | --------------------------------------------------------------------------------